levels 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/.rbenv-version +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +12 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +315 -0
- data/Rakefile +28 -0
- data/bin/levels +130 -0
- data/examples/01_base.rb +6 -0
- data/examples/01_merge_to_json.sh +27 -0
- data/examples/01_prod.json +8 -0
- data/examples/02_base.rb +4 -0
- data/examples/02_merge_with_file.sh +20 -0
- data/examples/02_value +1 -0
- data/levels.gemspec +20 -0
- data/lib/levels.rb +77 -0
- data/lib/levels/audit.rb +24 -0
- data/lib/levels/audit/group_observer.rb +26 -0
- data/lib/levels/audit/nested_group_observer.rb +37 -0
- data/lib/levels/audit/root_observer.rb +63 -0
- data/lib/levels/audit/value.rb +64 -0
- data/lib/levels/audit/value_observer.rb +46 -0
- data/lib/levels/audit/values.rb +66 -0
- data/lib/levels/configuration.rb +98 -0
- data/lib/levels/configured_group.rb +62 -0
- data/lib/levels/event_handler.rb +127 -0
- data/lib/levels/group.rb +61 -0
- data/lib/levels/input/json.rb +17 -0
- data/lib/levels/input/ruby.rb +120 -0
- data/lib/levels/input/system.rb +63 -0
- data/lib/levels/input/yaml.rb +17 -0
- data/lib/levels/key.rb +28 -0
- data/lib/levels/key_values.rb +54 -0
- data/lib/levels/lazy_evaluator.rb +54 -0
- data/lib/levels/level.rb +80 -0
- data/lib/levels/method_missing.rb +14 -0
- data/lib/levels/output/json.rb +33 -0
- data/lib/levels/output/system.rb +29 -0
- data/lib/levels/output/yaml.rb +19 -0
- data/lib/levels/runtime.rb +30 -0
- data/lib/levels/setup.rb +132 -0
- data/lib/levels/system/constants.rb +8 -0
- data/lib/levels/system/key_formatter.rb +15 -0
- data/lib/levels/system/key_generator.rb +50 -0
- data/lib/levels/system/key_parser.rb +67 -0
- data/lib/levels/version.rb +3 -0
- data/test/acceptance/audit_test.rb +105 -0
- data/test/acceptance/event_handler_test.rb +43 -0
- data/test/acceptance/read_json_test.rb +35 -0
- data/test/acceptance/read_ruby_test.rb +117 -0
- data/test/acceptance/read_system_test.rb +121 -0
- data/test/acceptance/read_yaml_test.rb +38 -0
- data/test/acceptance/setup_test.rb +115 -0
- data/test/acceptance/write_json_test.rb +39 -0
- data/test/acceptance/write_system_test.rb +68 -0
- data/test/acceptance/write_yaml_test.rb +33 -0
- data/test/bin/merge_test.rb +194 -0
- data/test/bin/options_test.rb +41 -0
- data/test/helper.rb +12 -0
- data/test/support/acceptance_spec.rb +58 -0
- data/test/support/base_spec.rb +14 -0
- data/test/support/bin_spec.rb +65 -0
- data/test/support/tempfile_helper.rb +35 -0
- data/test/unit/audit/group_observer_test.rb +24 -0
- data/test/unit/audit/nested_group_observer_test.rb +28 -0
- data/test/unit/audit/root_observer_test.rb +54 -0
- data/test/unit/audit/value_observer_test.rb +63 -0
- data/test/unit/audit/value_test.rb +41 -0
- data/test/unit/audit/values_test.rb +86 -0
- data/test/unit/configuration_test.rb +72 -0
- data/test/unit/configured_group_test.rb +75 -0
- data/test/unit/group_test.rb +105 -0
- data/test/unit/input/json_test.rb +32 -0
- data/test/unit/input/ruby_test.rb +140 -0
- data/test/unit/input/system_test.rb +59 -0
- data/test/unit/input/yaml_test.rb +33 -0
- data/test/unit/key_test.rb +45 -0
- data/test/unit/key_values_test.rb +106 -0
- data/test/unit/lazy_evaluator_test.rb +38 -0
- data/test/unit/level_test.rb +89 -0
- data/test/unit/levels_test.rb +23 -0
- data/test/unit/output/json_test.rb +55 -0
- data/test/unit/output/system_test.rb +32 -0
- data/test/unit/output/yaml_test.rb +38 -0
- data/test/unit/runtime_test.rb +40 -0
- data/test/unit/system/key_formatter_test.rb +43 -0
- data/test/unit/system/key_generator_test.rb +21 -0
- data/test/unit/system/key_parser_test.rb +207 -0
- metadata +215 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::Input::System do
|
4
|
+
|
5
|
+
let(:template) { {} }
|
6
|
+
let(:key_formatter) { nil }
|
7
|
+
let(:env_hash) { {} }
|
8
|
+
|
9
|
+
subject { Levels::Input::System.new(template.to_enum, key_formatter, env_hash) }
|
10
|
+
|
11
|
+
[nil, "MY_"].each do |prefix|
|
12
|
+
describe "finding data in the System with #{prefix || 'no'} prefix" do
|
13
|
+
|
14
|
+
let(:key_formatter) { Levels::System::KeyFormatter.new(prefix) }
|
15
|
+
|
16
|
+
before do
|
17
|
+
template[:sample] = { hello: "world" }.to_enum
|
18
|
+
template[:settings] = { hello: "world" }.to_enum
|
19
|
+
end
|
20
|
+
|
21
|
+
it "finds variables that exist in the template" do
|
22
|
+
env_hash["#{prefix}SAMPLE_HELLO"] = "universe"
|
23
|
+
|
24
|
+
assert_input_equals_hash(
|
25
|
+
sample: {
|
26
|
+
hello: "universe"
|
27
|
+
}
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "does not find variables not in the template" do
|
32
|
+
env_hash["#{prefix}SAMPLE_WORLD"] = "this"
|
33
|
+
env_hash["#{prefix}OTHER_HELLO"] = "that"
|
34
|
+
|
35
|
+
assert_input_equals_hash({})
|
36
|
+
end
|
37
|
+
|
38
|
+
it "does not find variables with another prefix" do
|
39
|
+
env_hash["OTHER_SAMPLE_HELLO"] = "ok"
|
40
|
+
|
41
|
+
assert_input_equals_hash({})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "typecasting data from the system" do
|
47
|
+
|
48
|
+
it "converts data to the right type" do
|
49
|
+
env_hash["SAMPLE_NUMBER"] = "123"
|
50
|
+
env_hash["SAMPLE_NUMBER_TYPE"] = "integer"
|
51
|
+
|
52
|
+
assert_input_equals_hash(
|
53
|
+
sample: {
|
54
|
+
number: 123
|
55
|
+
}
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::Input::YAML do
|
4
|
+
|
5
|
+
let(:yaml_string) {
|
6
|
+
<<-STR
|
7
|
+
---
|
8
|
+
group1:
|
9
|
+
key1: string
|
10
|
+
key2: 123
|
11
|
+
group2:
|
12
|
+
key:
|
13
|
+
- 1
|
14
|
+
- 2
|
15
|
+
- 3
|
16
|
+
STR
|
17
|
+
}
|
18
|
+
|
19
|
+
subject { Levels::Input::YAML.new(yaml_string) }
|
20
|
+
|
21
|
+
it "reads data from the JSON structure" do
|
22
|
+
assert_input_equals_hash(
|
23
|
+
group1: {
|
24
|
+
key1: "string",
|
25
|
+
key2: 123
|
26
|
+
},
|
27
|
+
group2: {
|
28
|
+
key: [1, 2, 3]
|
29
|
+
}
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::Key do
|
4
|
+
|
5
|
+
let(:input) { "settings" }
|
6
|
+
|
7
|
+
subject { Levels::Key.new(input) }
|
8
|
+
|
9
|
+
specify "#to_sym" do
|
10
|
+
subject.to_sym.must_equal :settings
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "#inspect" do
|
14
|
+
subject.inspect.must_equal "<Levels::Key :settings>"
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "#to_s" do
|
18
|
+
subject.to_s.must_equal subject.inspect
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "comparisons" do
|
22
|
+
|
23
|
+
let(:a) { Levels::Key.new(:a) }
|
24
|
+
let(:b) { Levels::Key.new(:a) }
|
25
|
+
let(:c) { Levels::Key.new(:b) }
|
26
|
+
|
27
|
+
specify "equality" do
|
28
|
+
(a == b).must_equal true
|
29
|
+
(b == a).must_equal true
|
30
|
+
(a == c).must_equal false
|
31
|
+
(a == :a).must_equal false
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "hashing" do
|
35
|
+
hash = {}
|
36
|
+
hash[a] = true
|
37
|
+
hash[a].must_equal true
|
38
|
+
hash[b].must_equal true
|
39
|
+
hash[c].must_equal nil
|
40
|
+
hash[:a].must_equal nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::KeyValues do
|
4
|
+
|
5
|
+
let(:data) { nil }
|
6
|
+
|
7
|
+
subject { Levels::KeyValues.new(data) }
|
8
|
+
|
9
|
+
describe "in general" do
|
10
|
+
|
11
|
+
let(:data) { { "a" => 1 } }
|
12
|
+
|
13
|
+
describe "#[]" do
|
14
|
+
|
15
|
+
it "handles string keys" do
|
16
|
+
subject["a"].must_equal 1
|
17
|
+
end
|
18
|
+
|
19
|
+
it "handles symbol keys" do
|
20
|
+
subject[:a].must_equal 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns nil when the key does not exist" do
|
24
|
+
subject[:b].must_equal nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#pair" do
|
29
|
+
|
30
|
+
it "returns a Key and the value" do
|
31
|
+
key, value = subject.pair(:a)
|
32
|
+
key.must_equal Levels::Key.new(:a)
|
33
|
+
value.must_equal 1
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns a Key and nil if the key does not exist" do
|
37
|
+
key, value = subject.pair(:b)
|
38
|
+
key.must_equal Levels::Key.new(:b)
|
39
|
+
value.must_equal nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#[]=" do
|
44
|
+
|
45
|
+
it "handles string keys" do
|
46
|
+
subject["a"] = 2
|
47
|
+
subject[:a].must_equal 2
|
48
|
+
end
|
49
|
+
|
50
|
+
it "handles Symbol keys" do
|
51
|
+
subject[:a] = 2
|
52
|
+
subject[:a].must_equal 2
|
53
|
+
end
|
54
|
+
|
55
|
+
it "can add new keys" do
|
56
|
+
subject[:b] = 1
|
57
|
+
subject[:b].must_equal 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#key?" do
|
62
|
+
|
63
|
+
it "handles string keys" do
|
64
|
+
subject.key?("a").must_equal true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "handles symbol keys" do
|
68
|
+
subject.key?(:a).must_equal true
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns false if the key does not exist" do
|
72
|
+
subject.key?(:b).must_equal false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "#inspect" do
|
77
|
+
subject.inspect.must_equal "<Levels::KeyValues>"
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "#to_s" do
|
81
|
+
subject.to_s.must_equal subject.inspect
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "comparisons" do
|
86
|
+
|
87
|
+
let(:a) { Levels::KeyValues.new(a: 1) }
|
88
|
+
let(:b) { Levels::KeyValues.new(a: 1) }
|
89
|
+
let(:c) { Levels::KeyValues.new(b: 1) }
|
90
|
+
|
91
|
+
specify "equality" do
|
92
|
+
(a == b).must_equal true
|
93
|
+
(a == c).must_equal false
|
94
|
+
(a == {a:1}).must_equal false
|
95
|
+
end
|
96
|
+
|
97
|
+
specify "hashing" do
|
98
|
+
hash = {}
|
99
|
+
hash[a] = true
|
100
|
+
hash[a].must_equal true
|
101
|
+
hash[b].must_equal true
|
102
|
+
hash[c].must_equal nil
|
103
|
+
hash[{a:1}].must_equal nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::LazyEvaluator do
|
4
|
+
|
5
|
+
let(:level) { Levels::Level.new("level") }
|
6
|
+
|
7
|
+
subject { Levels::LazyEvaluator.new(level) }
|
8
|
+
|
9
|
+
it "returns a value" do
|
10
|
+
subject.call(123).must_equal 123
|
11
|
+
end
|
12
|
+
|
13
|
+
it "executes a proc" do
|
14
|
+
subject.call(-> { 123 }).must_equal 123
|
15
|
+
end
|
16
|
+
|
17
|
+
it "executes a proc recursively" do
|
18
|
+
subject.call(-> { -> { 123 } }).must_equal 123
|
19
|
+
end
|
20
|
+
|
21
|
+
it "allows the level to be accessed directly" do
|
22
|
+
level.set_group(:sample, message: "hello")
|
23
|
+
subject.call(-> { sample.message }).must_equal "hello"
|
24
|
+
subject.call(-> { sample[:message] }).must_equal "hello"
|
25
|
+
subject.call(-> { sample.defined?(:message) }).must_equal true
|
26
|
+
subject.call(-> { sample.message? }).must_equal true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "evaluates values within an array" do
|
30
|
+
subject.call([-> { 123 }]).must_equal [123]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "allows shell style interpolation" do
|
34
|
+
skip "for now"
|
35
|
+
level.set_group(:sample, message: "hello")
|
36
|
+
subject.call("${SAMPLE_HELLO} world").must_equal "hello world"
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::Level do
|
4
|
+
|
5
|
+
subject { Levels::Level.new("test") }
|
6
|
+
|
7
|
+
specify "#_level_name" do
|
8
|
+
subject._level_name.must_equal "test"
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "#to_s" do
|
12
|
+
subject.to_s.must_equal "<Levels::Level \"test\">"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "allows groups to be defined and accessed" do
|
16
|
+
subject.set_group(:test, key: 123)
|
17
|
+
subject.test.must_be_instance_of Levels::Group
|
18
|
+
subject[:test].must_be_instance_of Levels::Group
|
19
|
+
end
|
20
|
+
|
21
|
+
it "handls a string group name" do
|
22
|
+
subject.set_group("test", key: 123)
|
23
|
+
subject.test.must_be_instance_of Levels::Group
|
24
|
+
subject[:test].must_be_instance_of Levels::Group
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises an error if you access an unknown group" do
|
28
|
+
proc { subject.nothing }.must_raise Levels::UnknownGroup
|
29
|
+
proc { subject[:nothing] }.must_raise Levels::UnknownGroup
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allows the existence of a group to be tested" do
|
33
|
+
subject.set_group(:test, key: 123)
|
34
|
+
subject.defined?(:test).must_equal true
|
35
|
+
subject.defined?(:foo).must_equal false
|
36
|
+
subject.test?.must_equal true
|
37
|
+
subject.foo?.must_equal false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "does not allow a group to be redefined" do
|
41
|
+
subject.set_group(:test, key: 123)
|
42
|
+
proc { subject.set_group(:test, key: 123) }.must_raise Levels::DuplicateGroup
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#to_enum" do
|
46
|
+
|
47
|
+
it "returns an Enumerator" do
|
48
|
+
subject.to_enum.must_be_instance_of Enumerator
|
49
|
+
end
|
50
|
+
|
51
|
+
it "iterates over all groups" do
|
52
|
+
subject.set_group(:test1, key: 123)
|
53
|
+
subject.set_group(:test2, key: 123)
|
54
|
+
result = subject.to_enum.map do |k, v|
|
55
|
+
[k, v.class]
|
56
|
+
end
|
57
|
+
expected = [
|
58
|
+
[:test1, Enumerator],
|
59
|
+
[:test2, Enumerator]
|
60
|
+
]
|
61
|
+
result.sort.must_equal expected.sort
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#eql_hash?" do
|
66
|
+
|
67
|
+
let(:expected) {
|
68
|
+
{
|
69
|
+
test1: {
|
70
|
+
key: 123
|
71
|
+
},
|
72
|
+
"test2" => {
|
73
|
+
"key" => 123
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
before do
|
79
|
+
subject.set_group(:test1, key: 123)
|
80
|
+
subject.set_group(:test2, key: 123)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "is true if the hash matches the data" do
|
84
|
+
subject.eql_hash?(expected).must_equal true
|
85
|
+
subject.eql_hash?(a: 1).must_equal false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels do
|
4
|
+
|
5
|
+
specify ".setup" do
|
6
|
+
Levels.setup.must_be_instance_of Levels::Setup
|
7
|
+
end
|
8
|
+
|
9
|
+
specify ".merge" do
|
10
|
+
Levels.merge.must_be_instance_of Levels::Configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
specify ".merge with a block" do
|
14
|
+
block_called = false
|
15
|
+
configuration = Levels.merge do |setup|
|
16
|
+
block_called = true
|
17
|
+
setup.must_be_instance_of Levels::Setup
|
18
|
+
end
|
19
|
+
block_called.must_equal true
|
20
|
+
configuration.must_be_instance_of Levels::Configuration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Levels::Output::JSON do
|
4
|
+
|
5
|
+
let(:data) {
|
6
|
+
{
|
7
|
+
group1: {
|
8
|
+
key1: "string",
|
9
|
+
key2: 123
|
10
|
+
},
|
11
|
+
group2: {
|
12
|
+
key: [1, 2, 3]
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
let(:json_opts) { nil }
|
18
|
+
|
19
|
+
subject { Levels::Output::JSON.new(json_opts) }
|
20
|
+
|
21
|
+
def result
|
22
|
+
subject.generate(data.to_enum)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "converts to JSON" do
|
26
|
+
result.must_equal <<-STR.chomp
|
27
|
+
{
|
28
|
+
"group1": {
|
29
|
+
"key1": "string",
|
30
|
+
"key2": 123
|
31
|
+
},
|
32
|
+
"group2": {
|
33
|
+
"key": [
|
34
|
+
1,
|
35
|
+
2,
|
36
|
+
3
|
37
|
+
]
|
38
|
+
}
|
39
|
+
}
|
40
|
+
STR
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
describe "initialized with json opts" do
|
45
|
+
|
46
|
+
let(:json_opts) { {} }
|
47
|
+
|
48
|
+
it "changes the formatting" do
|
49
|
+
result.must_equal <<-STR.chomp
|
50
|
+
{"group1":{"key1":"string","key2":123},"group2":{"key":[1,2,3]}}
|
51
|
+
STR
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|