Skip to content

Commit

Permalink
refactor: config -> environment
Browse files Browse the repository at this point in the history
  • Loading branch information
siyul-park committed Nov 30, 2023
1 parent f848a95 commit 08ec3e2
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 40 deletions.
30 changes: 15 additions & 15 deletions pkg/config/apply.go → pkg/environment/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ import (

var placeholder = regexp.MustCompile(`\$\{\{\s*([^\}]*)\s*\}\}`)

// Apply applies the configuration represented by 'config' to the input value 'val'.
// It replaces placeholders in the input value with corresponding values from the configuration.
func Apply(val any, config *Config) (any, error) {
config.mu.RLock()
defer config.mu.RUnlock()
// Apply applies the environment represented by 'environment' to the input value 'val'.
// It replaces placeholders in the input value with corresponding values from the environment.
func Apply(val any, environment *Environment) (any, error) {
environment.mu.RLock()
defer environment.mu.RUnlock()

v := reflect.ValueOf(val)
result := deepUnSpecify(v)

if err := applyRecursive(result, config.data); err != nil {
if err := applyRecursive(result, environment.data); err != nil {
return nil, err
}

return result.Interface(), nil
}

func applyRecursive(node reflect.Value, config map[string]any) error {
func applyRecursive(node reflect.Value, environment map[string]any) error {
switch node.Kind() {
case reflect.Map:
for _, key := range node.MapKeys() {
Expand All @@ -35,22 +35,22 @@ func applyRecursive(node reflect.Value, config map[string]any) error {
switch value.Kind() {
case reflect.String:
strValue := value.String()
newValue, err := replacePlaceholders(strValue, config)
newValue, err := replacePlaceholders(strValue, environment)
if err != nil {
return err
}

node.SetMapIndex(key, reflect.ValueOf(newValue))
case reflect.Map, reflect.Slice:
if err := applyRecursive(value, config); err != nil {
if err := applyRecursive(value, environment); err != nil {
return err
}
}
}
case reflect.Slice:
for i := 0; i < node.Len(); i++ {
elem := reflect.ValueOf(node.Index(i).Interface())
err := applyRecursive(elem, config)
err := applyRecursive(elem, environment)
if err != nil {
return err
}
Expand All @@ -59,14 +59,14 @@ func applyRecursive(node reflect.Value, config map[string]any) error {
return nil
}

func replacePlaceholders(input string, config map[string]any) (any, error) {
func replacePlaceholders(input string, environment map[string]any) (any, error) {
matches := placeholder.FindAllStringSubmatch(input, -1)

if len(matches) == 0 {
return input, nil
}
if len(matches) == 1 {
return evaluateExpression(matches[0][1], config)
return evaluateExpression(matches[0][1], environment)
}

return placeholder.ReplaceAllStringFunc(input, func(match string) string {
Expand All @@ -76,7 +76,7 @@ func replacePlaceholders(input string, config map[string]any) (any, error) {
}
expression := matches[1]

value, err := evaluateExpression(expression, config)
value, err := evaluateExpression(expression, environment)
if err != nil {
return match
}
Expand All @@ -85,12 +85,12 @@ func replacePlaceholders(input string, config map[string]any) (any, error) {
}), nil
}

func evaluateExpression(expression string, config map[string]any) (any, error) {
func evaluateExpression(expression string, environment map[string]any) (any, error) {
exp, err := jsonata.Compile(expression)
if err != nil {
return nil, err
}
exp.RegisterVars(config)
exp.RegisterVars(environment)
return exp.Eval(nil)
}

Expand Down
File renamed without changes.
46 changes: 29 additions & 17 deletions pkg/config/config.go → pkg/environment/environment.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package config

import (
"fmt"
"reflect"
"strings"
"sync"
)

// Config represents the configuration of your application.
type Config struct {
// Environment represents the environment of your application.
type Environment struct {
data map[string]any
mu sync.RWMutex
}

var typeAny = reflect.TypeOf((*any)(nil)).Elem()

// New creates a new configuration instance.
func New() *Config {
return &Config{
// New creates a new environment instance.
func New() *Environment {
return &Environment{
data: make(map[string]any),
}
}

// Set sets the value for the specified key in the configuration.
func (c *Config) Set(key string, val any) bool {
// Set sets the value for the specified key in the environment.
func (c *Environment) Set(key string, val any) error {
c.mu.Lock()
defer c.mu.Unlock()

Expand All @@ -34,12 +35,12 @@ func (c *Config) Set(key string, val any) bool {
t := reflect.ValueOf(token)

if node.Kind() != reflect.Map || node.Type().Key().Kind() != reflect.String {
return false
return fmt.Errorf("invalid map type for key %s", key)
}

if i == len(tokens)-1 {
node.SetMapIndex(t, v)
return true
return nil
}

child := node.MapIndex(t)
Expand All @@ -49,12 +50,12 @@ func (c *Config) Set(key string, val any) bool {
}
node = reflect.ValueOf(child.Interface())
}
return false
return nil
}

// Get retrieves the value for the specified key from the configuration.
// Get retrieves the value for the specified key from the environment.
// If the key is not present, it returns a default value and a boolean indicating the key's existence.
func (c *Config) Get(key string) (any, bool) {
func (c *Environment) Get(key string) (any, bool) {
c.mu.RLock()
defer c.mu.RUnlock()

Expand All @@ -78,17 +79,28 @@ func (c *Config) Get(key string) (any, bool) {
return node.Interface(), true
}

// Delete removes the specified key from the configuration.
func (c *Config) Delete(key string) bool {
// Delete removes the specified key from the environment.
func (c *Environment) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()

tokens := strings.Split(key, ".")
return c.deleteRecursive(reflect.ValueOf(c.data), tokens)
c.deleteRecursive(reflect.ValueOf(c.data), tokens)
}

// GetData returns a read-only copy of the environment data.
func (c *Environment) GetData() map[string]any {
c.mu.RLock()
defer c.mu.RUnlock()

result := make(map[string]any, len(c.data))
for k, v := range c.data {
result[k] = v
}
return result
}

// deleteRecursive is a recursive helper function for Delete.
func (c *Config) deleteRecursive(node reflect.Value, tokens []string) bool {
func (c *Environment) deleteRecursive(node reflect.Value, tokens []string) bool {
t := reflect.ValueOf(tokens[0])

if node.Kind() != reflect.Map || node.Type().Key().Kind() != reflect.String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,30 @@ import (
"github.com/stretchr/testify/assert"
)

func TestConfig_GetAndSetAndDelete(t *testing.T) {
c := New()
func TestEnvironment_GetAndSetAndDelete(t *testing.T) {
env := New()

key1 := faker.Word()
key2 := faker.Word()

key := fmt.Sprintf("%s.%s", key1, key2)
value := faker.Word()

c.Set(key, value)
env.Set(key, value)

r1, ok := c.Get(key)
r1, ok := env.Get(key)
assert.True(t, ok)
assert.Equal(t, value, r1)

_, ok = c.Get(key1)
_, ok = env.Get(key1)
assert.True(t, ok)

c.Delete(key)
env.Delete(key)

r2, ok := c.Get(key)
r2, ok := env.Get(key)
assert.False(t, ok)
assert.Nil(t, r2)

_, ok = c.Get(key1)
_, ok = env.Get(key1)
assert.False(t, ok)
}

0 comments on commit 08ec3e2

Please sign in to comment.