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,86 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Audit::Values do
4
+
5
+ let(:group_key) { :group }
6
+ let(:value_key) { :value }
7
+ let(:values) { [] }
8
+
9
+ subject { Levels::Audit::Values.new(group_key, value_key, values) }
10
+
11
+ it "exposes the group_key" do
12
+ subject.group_key.must_equal group_key
13
+ end
14
+
15
+ it "exposes the value_key" do
16
+ subject.value_key.must_equal value_key
17
+ end
18
+
19
+ specify "#final" do
20
+ v1 = Levels::Audit::Value.new("a", false)
21
+ v2 = Levels::Audit::Value.new("a", true)
22
+
23
+ values.concat [v1, v2]
24
+
25
+ subject.final.must_equal v2
26
+ end
27
+
28
+ specify "#final_value" do
29
+ v1 = Levels::Audit::Value.new("a", false, "no")
30
+ v2 = Levels::Audit::Value.new("a", true, "hello")
31
+
32
+ values.concat [v1, v2]
33
+
34
+ subject.final_value.must_equal "hello"
35
+ end
36
+
37
+ specify "#each is Enumerable" do
38
+ subject.map.must_be_instance_of Enumerator
39
+ end
40
+
41
+ specify "#only_final?" do
42
+ v1 = MiniTest::Mock.new
43
+ v1.expect(:final?, false)
44
+ v2 = MiniTest::Mock.new
45
+ v2.expect(:final?, true)
46
+
47
+ subject.wont_be :only_final?
48
+
49
+ values << v2
50
+ subject.must_be :only_final?
51
+
52
+ values << v1
53
+ subject.wont_be :only_final?
54
+ end
55
+
56
+ specify "#recursive?" do
57
+ v1 = MiniTest::Mock.new
58
+ 2.times { v1.expect(:recursive?, false) }
59
+ v2 = MiniTest::Mock.new
60
+ v2.expect(:recursive?, true)
61
+
62
+ subject.wont_be :recursive?
63
+
64
+ values << v1
65
+ subject.wont_be :recursive?
66
+
67
+ values << v2
68
+ subject.must_be :recursive?
69
+ end
70
+
71
+ specify "#size" do
72
+ values.size.must_equal 0
73
+
74
+ values << MiniTest::Mock.new
75
+
76
+ values.size.must_equal 1
77
+ end
78
+
79
+ specify "#empty?" do
80
+ values.must_be :empty?
81
+
82
+ values << MiniTest::Mock.new
83
+
84
+ values.wont_be :empty?
85
+ end
86
+ end
@@ -0,0 +1,72 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Configuration do
4
+
5
+ let(:level1) { Levels::Level.new("l1") }
6
+ let(:level2) { Levels::Level.new("l2") }
7
+
8
+ subject { Levels::Configuration.new([level1, level2]) }
9
+
10
+ before do
11
+ level1.set_group(:g1, a: 1)
12
+
13
+ level2.set_group(:g1, a: 9)
14
+ level2.set_group(:g2, b: 2)
15
+ end
16
+
17
+ specify "#to_s" do
18
+ subject.to_s.must_equal "<Levels::Configuration l1, l2>"
19
+ end
20
+
21
+ it "allows groups to be retrieved" do
22
+ subject.g1.must_be_instance_of Levels::ConfiguredGroup
23
+ subject[:g1].must_be_instance_of Levels::ConfiguredGroup
24
+ end
25
+
26
+ it "initializes the configured group with the right levels" do
27
+ subject.g1.a.must_equal 9
28
+ subject.g1.b?.must_equal false
29
+
30
+ subject.g2.b.must_equal 2
31
+ subject.g2.a?.must_equal false
32
+ end
33
+
34
+ it "raises an error if you access an unknown group" do
35
+ proc { subject.nothing }.must_raise Levels::UnknownGroup
36
+ proc { subject[:nothing] }.must_raise Levels::UnknownGroup
37
+ end
38
+
39
+ it "allows the existence of a group to be tested" do
40
+ subject.defined?(:g1).must_equal true
41
+ subject.defined?(:g2).must_equal true
42
+ subject.defined?(:foo).must_equal false
43
+ subject.g1?.must_equal true
44
+ subject.g2?.must_equal true
45
+ subject.foo?.must_equal false
46
+ end
47
+
48
+ it "allows lazy evaluation" do
49
+ level2.set_group(:g3, sum: -> { g1.a + g2.b })
50
+ subject.g3.sum.must_equal 11
51
+ end
52
+
53
+ describe "#to_enum" do
54
+
55
+ it "returns an Enumerator" do
56
+ subject.to_enum.must_be_instance_of Enumerator
57
+ end
58
+
59
+ it "iterates over all groups" do
60
+ result = subject.to_enum.map do |k, v|
61
+ [k.to_sym, v.class]
62
+ end
63
+ expected = [
64
+ [:g1, Enumerator],
65
+ [:g2, Enumerator]
66
+ ]
67
+ result.sort.must_equal expected.sort
68
+ end
69
+ end
70
+ end
71
+
72
+
@@ -0,0 +1,75 @@
1
+ require 'helper'
2
+
3
+ describe Levels::ConfiguredGroup do
4
+
5
+ let(:levels) { [] }
6
+ let(:group_observer) { MiniTest::Mock.new }
7
+
8
+ subject { Levels::ConfiguredGroup.new(levels, :test, group_observer) }
9
+
10
+ def define_value(key, value)
11
+ level = Levels::Level.new("one")
12
+ level.set_group(:test, key => value)
13
+ levels << level
14
+ end
15
+
16
+ def observe_value(key, value)
17
+ observed_values = MiniTest::Mock.new
18
+ observed_values.expect(:final_value, value)
19
+ group_observer.expect(:observe_values, observed_values, [levels, :test, key])
20
+ end
21
+
22
+ describe "checking value existence" do
23
+
24
+ before do
25
+ define_value :a, nil
26
+ end
27
+
28
+ it "allows defined?" do
29
+ subject.defined?(:a).must_equal true
30
+ end
31
+
32
+ it "allows method access" do
33
+ subject.a?.must_equal true
34
+ end
35
+ end
36
+
37
+ describe "reading values" do
38
+
39
+ before do
40
+ define_value :a, nil
41
+ observe_value :a, 1
42
+ end
43
+
44
+ it "allows hash access to any key" do
45
+ subject[:a].must_equal 1
46
+ end
47
+
48
+ it "allows method access" do
49
+ subject.a.must_equal 1
50
+ end
51
+ end
52
+
53
+ describe "#to_enum" do
54
+
55
+ before do
56
+ define_value :a, nil
57
+ observe_value :a, 1
58
+ end
59
+
60
+ it "returns an Enumerator" do
61
+ subject.to_enum.must_be_instance_of Enumerator
62
+ end
63
+
64
+ it "iterates over all keys and values" do
65
+ result = subject.to_enum.map do |k, v|
66
+ [k.to_sym, v]
67
+ end
68
+ expected = [
69
+ [:a, 1],
70
+ ]
71
+ result.sort.must_equal expected.sort
72
+ end
73
+ end
74
+ end
75
+
@@ -0,0 +1,105 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Group do
4
+
5
+ let(:hash) { {} }
6
+ let(:value_transformer) { nil }
7
+
8
+ subject { Levels::Group.new(hash, value_transformer) }
9
+
10
+ before do
11
+ hash[:name] = "ok"
12
+ hash[:value] = 123
13
+ hash[:other] = nil
14
+ end
15
+
16
+ specify "#to_s" do
17
+ subject.to_s.must_equal "<Levels::Group>"
18
+ end
19
+
20
+ it "allows hash access" do
21
+ subject[:name].must_equal "ok"
22
+ subject[:value].must_equal 123
23
+ subject[:other].must_equal nil
24
+ end
25
+
26
+ it "allows dot access" do
27
+ subject.name.must_equal "ok"
28
+ subject.value.must_equal 123
29
+ subject.other.must_equal nil
30
+ end
31
+
32
+ it "raises an error if you access a nonexistent key" do
33
+ proc { subject[:foo] }.must_raise Levels::UnknownKey
34
+ proc { subject.foo }.must_raise Levels::UnknownKey
35
+ end
36
+
37
+ it "allows the existence of a key to be tested" do
38
+ subject.defined?(:name).must_equal true
39
+ subject.defined?(:foo).must_equal false
40
+ subject.name?.must_equal true
41
+ subject.foo?.must_equal false
42
+ end
43
+
44
+ it "makes sure you don't call it wrong" do
45
+ proc { subject.name("ok") }.must_raise ArgumentError
46
+ end
47
+
48
+ describe "initialized with string keys" do
49
+
50
+ it "converts everything to symbols" do
51
+ hash["string"] = 123
52
+ subject.string.must_equal 123
53
+ subject[:string].must_equal 123
54
+ end
55
+ end
56
+
57
+ describe "initialized with a value transformer" do
58
+
59
+ let(:value_transformer) {
60
+ -> key, value { [key, value] }
61
+ }
62
+
63
+ it "returns the value via the transformer" do
64
+ subject.name.must_equal [:name, "ok"]
65
+ subject[:name].must_equal [:name, "ok"]
66
+ subject["name"].must_equal [:name, "ok"]
67
+ end
68
+ end
69
+
70
+ describe "#to_enum" do
71
+
72
+ it "returns an Enumerator" do
73
+ subject.to_enum.must_be_instance_of Enumerator
74
+ end
75
+
76
+ it "iterates over all keys and values" do
77
+ result = subject.to_enum.map do |k, v|
78
+ [k, v]
79
+ end
80
+ expected = [
81
+ [:name, "ok"],
82
+ [:value, 123],
83
+ [:other, nil]
84
+ ]
85
+ result.sort.must_equal expected.sort
86
+ end
87
+ end
88
+
89
+ describe "#eql_hash?" do
90
+
91
+ let(:expected) {
92
+ {
93
+ name: "ok",
94
+ value: 123,
95
+ "other" => nil
96
+ }
97
+ }
98
+
99
+ it "is true if the hash matches the data" do
100
+ subject.eql_hash?(expected).must_equal true
101
+ subject.eql_hash?(a: 1).must_equal false
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,32 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Input::JSON do
4
+
5
+ let(:json_string) {
6
+ <<-STR
7
+ {
8
+ "group1": {
9
+ "key1": "string",
10
+ "key2": 123
11
+ },
12
+ "group2": {
13
+ "key": [1, 2, 3]
14
+ }
15
+ }
16
+ STR
17
+ }
18
+
19
+ subject { Levels::Input::JSON.new(json_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
@@ -0,0 +1,140 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Input::Ruby do
4
+
5
+ let(:level) { Levels::Level.new("Ruby") }
6
+
7
+ subject { Levels::Input::Ruby.new(ruby_string, "file.rb", 1) }
8
+
9
+ describe "successfully" do
10
+
11
+ let(:ruby_string) {
12
+ <<-RUBY
13
+ group :foo
14
+ set value: "ok"
15
+ RUBY
16
+ }
17
+
18
+ it "populates the level" do
19
+ subject.read(level)
20
+ level.eql_hash?(
21
+ foo: {
22
+ value: "ok"
23
+ }
24
+ ).must_equal true
25
+ end
26
+ end
27
+
28
+ describe "with an error" do
29
+
30
+ let(:ruby_string) {
31
+ <<-RUBY
32
+ xgroup :foo
33
+ set value: "ok"
34
+ RUBY
35
+ }
36
+
37
+ it "provides useful information" do
38
+ begin
39
+ subject.read(level)
40
+ rescue => e
41
+ e.class.must_equal NoMethodError
42
+ e.message.must_equal %(undefined method `xgroup' for <Levels>:Levels::Input::Ruby::DSL)
43
+ e.backtrace.first.must_equal "file.rb:1:in `read'"
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ describe Levels::Input::Ruby::DSL do
50
+
51
+ let(:level) { Levels::Level.new("Ruby") }
52
+
53
+ subject { Levels::Input::Ruby::DSL.new(level) }
54
+
55
+ def define(&block)
56
+ subject.instance_eval(&block)
57
+ subject.close_current_group
58
+ end
59
+
60
+ it "defines an empty group" do
61
+ define do
62
+ group :one
63
+ end
64
+ level.defined?(:one).must_equal true
65
+ end
66
+
67
+ it "defines a group with keys" do
68
+ define do
69
+ group :one
70
+ set key: "value"
71
+ end
72
+ level.one.key.must_equal "value"
73
+ end
74
+
75
+ it "is an error to set a key outside of a group" do
76
+ -> {
77
+ define do
78
+ set key: "value"
79
+ end
80
+ }.must_raise(SyntaxError)
81
+ end
82
+
83
+ it "is an error to set a key more than once" do
84
+ -> {
85
+ define do
86
+ group :one
87
+ set key: "value"
88
+ set "key" => "value"
89
+ end
90
+ }.must_raise(RuntimeError)
91
+ end
92
+
93
+ it "is an error to define a group more than once" do
94
+ -> {
95
+ subject.group :one
96
+ subject.close_current_group
97
+ subject.group "one"
98
+ }.must_raise(RuntimeError)
99
+ end
100
+
101
+ describe "the ways to set a value" do
102
+
103
+ before do
104
+ subject.group :one
105
+ end
106
+
107
+ def assert_key
108
+ subject.close_current_group
109
+ level.one.key.must_equal "value"
110
+ end
111
+
112
+ it "can be set as a ruby 1.9 hash" do
113
+ subject.set key: "value"
114
+ assert_key
115
+ end
116
+
117
+ it "can be set as a ruby 1.8 hash" do
118
+ subject.set :key => "value"
119
+ assert_key
120
+ end
121
+
122
+ it "is possible to set multiple keys via a hash" do
123
+ subject.set :key => "value", :bar => "foo"
124
+ assert_key
125
+ level.one.bar.must_equal "foo"
126
+ end
127
+
128
+ it "can be set with two arguments" do
129
+ subject.set :key, "value"
130
+ assert_key
131
+ end
132
+
133
+ it "is an error to pass other types of args" do
134
+ -> { subject.set :a }.must_raise(ArgumentError)
135
+ -> { subject.set :a, 1, :b }.must_raise(ArgumentError)
136
+ -> { subject.set :a, 1, :b, 2 }.must_raise(ArgumentError)
137
+ -> { subject.set :b, :a => 1 }.must_raise(ArgumentError)
138
+ end
139
+ end
140
+ end