config: demote *Environment to interface
In order to support lazily loading the values stored in a user's `.gitconfig`, we must wait until calling `*config.Configuration.loadGitConfig()` until it is _absolutely necessary_. To accomplish this, it was proposed that we introduce a wrapped variant of the `*Environment` type, only for interacting with the `GitFetcher` that was capable of supporting such beahvior. As such, a new implementation of the `Environment` type must be defined. Since previously there only existed the concrete type `*Environment`, this commit demotes that down to `*enviornment`, and introduces the interface `Environment`, which it implements.
This commit is contained in:
parent
b546ba4db3
commit
6c60d2b2db
@ -50,14 +50,13 @@ type Configuration struct {
|
||||
// Os provides a `*Environment` used to access to the system's
|
||||
// environment through os.Getenv. It is the point of entry for all
|
||||
// system environment configuration.
|
||||
Os *Environment
|
||||
Os Environment
|
||||
|
||||
// Git provides a `*Environment` used to access to the various levels of
|
||||
// `.gitconfig`'s. It is the point of entry for all Git environment
|
||||
// configuration.
|
||||
Git *Environment
|
||||
Git Environment
|
||||
|
||||
//
|
||||
gitConfig map[string]string
|
||||
|
||||
CurrentRemote string
|
||||
@ -187,7 +186,7 @@ func (c *Configuration) Unmarshal(v interface{}) error {
|
||||
// both is not.
|
||||
//
|
||||
// If neither field was found, then a nil environment will be returned.
|
||||
func (c *Configuration) parseTag(tag reflect.StructTag) (key string, env *Environment, err error) {
|
||||
func (c *Configuration) parseTag(tag reflect.StructTag) (key string, env Environment, err error) {
|
||||
git, os := tag.Get("git"), tag.Get("os")
|
||||
|
||||
if len(git) != 0 && len(os) != 0 {
|
||||
|
@ -11,33 +11,50 @@ import (
|
||||
// `Environment`s are the primary way to communicate with various configuration
|
||||
// sources, such as the OS environment variables, the `.gitconfig`, and even
|
||||
// `map[string]string`s.
|
||||
type Environment struct {
|
||||
// Fetcher is the `Environment`'s source of data.
|
||||
type Environment interface {
|
||||
// Get is shorthand for calling `e.Fetcher.Get(key)`.
|
||||
Get(key string) (val string, ok bool)
|
||||
|
||||
// Bool returns the boolean state associated with a given key, or the
|
||||
// value "def", if no value was associated.
|
||||
//
|
||||
// The "boolean state associated with a given key" is defined as the
|
||||
// case-insensitive string comparison with the following:
|
||||
//
|
||||
// 1) true if...
|
||||
// "true", "1", "on", "yes", or "t"
|
||||
// 2) false if...
|
||||
// "false", "0", "off", "no", "f", or otherwise.
|
||||
Bool(key string, def bool) (val bool)
|
||||
|
||||
// Int returns the int value associated with a given key, or the value
|
||||
// "def", if no value was associated.
|
||||
//
|
||||
// To convert from a the string value attached to a given key,
|
||||
// `strconv.Atoi(val)` is called. If `Atoi` returned a non-nil error,
|
||||
// then the value "def" will be returned instead.
|
||||
//
|
||||
// Otherwise, if the value was converted `string -> int` successfully,
|
||||
// then it will be returned wholesale.
|
||||
Int(key string, def int) (val int)
|
||||
}
|
||||
|
||||
type environment struct {
|
||||
// Fetcher is the `environment`'s source of data.
|
||||
Fetcher Fetcher
|
||||
}
|
||||
|
||||
// EnvironmentOf creates a new `*Environment` initialized with the givne
|
||||
// EnvironmentOf creates a new `Environment` initialized with the givne
|
||||
// `Fetcher`, "f".
|
||||
func EnvironmentOf(f Fetcher) *Environment {
|
||||
return &Environment{f}
|
||||
func EnvironmentOf(f Fetcher) Environment {
|
||||
return &environment{f}
|
||||
}
|
||||
|
||||
// Get is shorthand for calling `e.Fetcher.Get(key)`.
|
||||
func (e *Environment) Get(key string) (val string, ok bool) {
|
||||
func (e *environment) Get(key string) (val string, ok bool) {
|
||||
return e.Fetcher.Get(key)
|
||||
}
|
||||
|
||||
// Bool returns the boolean state associated with a given key, or the value
|
||||
// "def", if no value was associated.
|
||||
//
|
||||
// The "boolean state associated with a given key" is defined as the
|
||||
// case-insensitive string comparison with the following:
|
||||
//
|
||||
// 1) true if...
|
||||
// "true", "1", "on", "yes", or "t"
|
||||
// 2) false if...
|
||||
// "false", "0", "off", "no", "f", or otherwise.
|
||||
func (e *Environment) Bool(key string, def bool) (val bool) {
|
||||
func (e *environment) Bool(key string, def bool) (val bool) {
|
||||
s, _ := e.Fetcher.Get(key)
|
||||
if len(s) == 0 {
|
||||
return def
|
||||
@ -53,16 +70,7 @@ func (e *Environment) Bool(key string, def bool) (val bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// Int returns the int value associated with a given key, or the value "def",
|
||||
// if no value was associated.
|
||||
//
|
||||
// To convert from a the string value attached to a given key,
|
||||
// `strconv.Atoi(val)` is called. If `Atoi` returned a non-nil error, then the
|
||||
// value "def" will be returned instead.
|
||||
//
|
||||
// Otherwise, if the value was converted `string -> int` successfully, then it
|
||||
// will be returned wholesale.
|
||||
func (e *Environment) Int(key string, def int) (val int) {
|
||||
func (e *environment) Int(key string, def int) (val int) {
|
||||
s, _ := e.Fetcher.Get(key)
|
||||
if len(s) == 0 {
|
||||
return def
|
||||
|
@ -7,13 +7,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEnvironmentOfReturnsCorrectlyInitializedEnvironment(t *testing.T) {
|
||||
fetcher := MapFetcher(map[string]string{})
|
||||
env := EnvironmentOf(fetcher)
|
||||
|
||||
assert.Equal(t, fetcher, env.Fetcher)
|
||||
}
|
||||
|
||||
func TestEnvironmentGetDelegatesToFetcher(t *testing.T) {
|
||||
fetcher := MapFetcher(map[string]string{
|
||||
"foo": "bar",
|
||||
@ -68,18 +61,18 @@ type EnvironmentConversionTestCase struct {
|
||||
Val string
|
||||
Expected interface{}
|
||||
|
||||
GotFn func(env *Environment, key string) interface{}
|
||||
GotFn func(env Environment, key string) interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
GetBoolDefault = func(def bool) func(e *Environment, key string) interface{} {
|
||||
return func(e *Environment, key string) interface{} {
|
||||
GetBoolDefault = func(def bool) func(e Environment, key string) interface{} {
|
||||
return func(e Environment, key string) interface{} {
|
||||
return e.Bool(key, def)
|
||||
}
|
||||
}
|
||||
|
||||
GetIntDefault = func(def int) func(e *Environment, key string) interface{} {
|
||||
return func(e *Environment, key string) interface{} {
|
||||
GetIntDefault = func(def int) func(e Environment, key string) interface{} {
|
||||
return func(e Environment, key string) interface{} {
|
||||
return e.Int(key, def)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user