levels 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.gitignore +17 -0
  2. data/.rbenv-version +1 -0
  3. data/CHANGELOG.md +4 -0
  4. data/Gemfile +12 -0
  5. data/Guardfile +14 -0
  6. data/LICENSE +22 -0
  7. data/README.md +315 -0
  8. data/Rakefile +28 -0
  9. data/bin/levels +130 -0
  10. data/examples/01_base.rb +6 -0
  11. data/examples/01_merge_to_json.sh +27 -0
  12. data/examples/01_prod.json +8 -0
  13. data/examples/02_base.rb +4 -0
  14. data/examples/02_merge_with_file.sh +20 -0
  15. data/examples/02_value +1 -0
  16. data/levels.gemspec +20 -0
  17. data/lib/levels.rb +77 -0
  18. data/lib/levels/audit.rb +24 -0
  19. data/lib/levels/audit/group_observer.rb +26 -0
  20. data/lib/levels/audit/nested_group_observer.rb +37 -0
  21. data/lib/levels/audit/root_observer.rb +63 -0
  22. data/lib/levels/audit/value.rb +64 -0
  23. data/lib/levels/audit/value_observer.rb +46 -0
  24. data/lib/levels/audit/values.rb +66 -0
  25. data/lib/levels/configuration.rb +98 -0
  26. data/lib/levels/configured_group.rb +62 -0
  27. data/lib/levels/event_handler.rb +127 -0
  28. data/lib/levels/group.rb +61 -0
  29. data/lib/levels/input/json.rb +17 -0
  30. data/lib/levels/input/ruby.rb +120 -0
  31. data/lib/levels/input/system.rb +63 -0
  32. data/lib/levels/input/yaml.rb +17 -0
  33. data/lib/levels/key.rb +28 -0
  34. data/lib/levels/key_values.rb +54 -0
  35. data/lib/levels/lazy_evaluator.rb +54 -0
  36. data/lib/levels/level.rb +80 -0
  37. data/lib/levels/method_missing.rb +14 -0
  38. data/lib/levels/output/json.rb +33 -0
  39. data/lib/levels/output/system.rb +29 -0
  40. data/lib/levels/output/yaml.rb +19 -0
  41. data/lib/levels/runtime.rb +30 -0
  42. data/lib/levels/setup.rb +132 -0
  43. data/lib/levels/system/constants.rb +8 -0
  44. data/lib/levels/system/key_formatter.rb +15 -0
  45. data/lib/levels/system/key_generator.rb +50 -0
  46. data/lib/levels/system/key_parser.rb +67 -0
  47. data/lib/levels/version.rb +3 -0
  48. data/test/acceptance/audit_test.rb +105 -0
  49. data/test/acceptance/event_handler_test.rb +43 -0
  50. data/test/acceptance/read_json_test.rb +35 -0
  51. data/test/acceptance/read_ruby_test.rb +117 -0
  52. data/test/acceptance/read_system_test.rb +121 -0
  53. data/test/acceptance/read_yaml_test.rb +38 -0
  54. data/test/acceptance/setup_test.rb +115 -0
  55. data/test/acceptance/write_json_test.rb +39 -0
  56. data/test/acceptance/write_system_test.rb +68 -0
  57. data/test/acceptance/write_yaml_test.rb +33 -0
  58. data/test/bin/merge_test.rb +194 -0
  59. data/test/bin/options_test.rb +41 -0
  60. data/test/helper.rb +12 -0
  61. data/test/support/acceptance_spec.rb +58 -0
  62. data/test/support/base_spec.rb +14 -0
  63. data/test/support/bin_spec.rb +65 -0
  64. data/test/support/tempfile_helper.rb +35 -0
  65. data/test/unit/audit/group_observer_test.rb +24 -0
  66. data/test/unit/audit/nested_group_observer_test.rb +28 -0
  67. data/test/unit/audit/root_observer_test.rb +54 -0
  68. data/test/unit/audit/value_observer_test.rb +63 -0
  69. data/test/unit/audit/value_test.rb +41 -0
  70. data/test/unit/audit/values_test.rb +86 -0
  71. data/test/unit/configuration_test.rb +72 -0
  72. data/test/unit/configured_group_test.rb +75 -0
  73. data/test/unit/group_test.rb +105 -0
  74. data/test/unit/input/json_test.rb +32 -0
  75. data/test/unit/input/ruby_test.rb +140 -0
  76. data/test/unit/input/system_test.rb +59 -0
  77. data/test/unit/input/yaml_test.rb +33 -0
  78. data/test/unit/key_test.rb +45 -0
  79. data/test/unit/key_values_test.rb +106 -0
  80. data/test/unit/lazy_evaluator_test.rb +38 -0
  81. data/test/unit/level_test.rb +89 -0
  82. data/test/unit/levels_test.rb +23 -0
  83. data/test/unit/output/json_test.rb +55 -0
  84. data/test/unit/output/system_test.rb +32 -0
  85. data/test/unit/output/yaml_test.rb +38 -0
  86. data/test/unit/runtime_test.rb +40 -0
  87. data/test/unit/system/key_formatter_test.rb +43 -0
  88. data/test/unit/system/key_generator_test.rb +21 -0
  89. data/test/unit/system/key_parser_test.rb +207 -0
  90. 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
+