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.
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,32 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Output::System do
4
+
5
+ let(:data) {
6
+ {
7
+ group1: {
8
+ key: "hello",
9
+ },
10
+ group2: {
11
+ key: "world"
12
+ }
13
+ }
14
+ }
15
+
16
+ subject { Levels::Output::System.new }
17
+
18
+ def result
19
+ subject.generate(data.to_enum)
20
+ end
21
+
22
+ it "converts to environment vars" do
23
+ result.must_equal <<-STR.chomp
24
+ export GROUP1_KEY="hello"
25
+ export GROUP1_KEY_TYPE="string"
26
+ export GROUP2_KEY="world"
27
+ export GROUP2_KEY_TYPE="string"
28
+ STR
29
+ end
30
+ end
31
+
32
+
@@ -0,0 +1,38 @@
1
+ require 'helper'
2
+
3
+ describe Levels::Output::YAML 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
+ subject { Levels::Output::YAML.new }
18
+
19
+ def result
20
+ subject.generate(data.to_enum)
21
+ end
22
+
23
+ it "converts to YAML" do
24
+ result.must_equal <<-STR
25
+ ---
26
+ group1:
27
+ key1: string
28
+ key2: 123
29
+ group2:
30
+ key:
31
+ - 1
32
+ - 2
33
+ - 3
34
+ STR
35
+ end
36
+ end
37
+
38
+
@@ -0,0 +1,40 @@
1
+ require 'helper'
2
+ require 'tempfile'
3
+
4
+ describe Levels::Runtime do
5
+
6
+ let(:klass) {
7
+ Class.new do
8
+ include Levels::Runtime
9
+ end
10
+ }
11
+
12
+ subject { klass.new }
13
+
14
+ describe "#file" do
15
+
16
+ # NOTE: This test uses an absolute path. The test
17
+ # for relative path interpretation is in
18
+ # acceptance/read_ruby_test.rb
19
+ it "returns a proc that reads a file" do
20
+ f = Tempfile.new("f")
21
+ begin
22
+ f.print "hello"
23
+ f.close
24
+ proc = subject.file(f.path)
25
+ proc.call.must_equal "hello"
26
+ ensure
27
+ f.close!
28
+ end
29
+ end
30
+
31
+ it "raises an error from the proc when given a path that doesn't exist" do
32
+ proc = subject.file("/no/file/here")
33
+ -> { proc.call }.must_raise(Levels::Runtime::FileNotFoundError)
34
+ end
35
+
36
+ it "returns nil if given nil" do
37
+ subject.file(nil).must_equal nil
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,43 @@
1
+ require 'helper'
2
+
3
+ describe Levels::System::KeyFormatter do
4
+
5
+ let(:prefix) { nil }
6
+ let(:joiner) { nil }
7
+
8
+ subject { Levels::System::KeyFormatter.new(prefix, joiner) }
9
+
10
+ describe "without a prefix" do
11
+
12
+ it "creates a key" do
13
+ subject.create(:a, "b", "C").must_equal "A_B_C"
14
+ end
15
+ end
16
+
17
+ describe "with a prefix" do
18
+
19
+ let(:prefix) { "PREFIX_" }
20
+
21
+ it "creates a key" do
22
+ subject.create(:a, "b", "C").must_equal "PREFIX_A_B_C"
23
+ end
24
+ end
25
+
26
+ describe "with a custom joiner" do
27
+
28
+ let(:joiner) { "-" }
29
+
30
+ it "changes the joiner" do
31
+ subject.create(:a, "b", "C").must_equal "A-B-C"
32
+ end
33
+
34
+ describe "with a prefix" do
35
+
36
+ let(:prefix) { "PREFIX_" }
37
+
38
+ it "does not affect the prefix" do
39
+ subject.create(:a, "b", "C").must_equal "PREFIX_A-B-C"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ require 'helper'
2
+
3
+ describe Levels::System::KeyGenerator do
4
+
5
+ subject { Levels::System::KeyGenerator.new }
6
+
7
+ it "generates key/values for the data and typecasting" do
8
+ enum = [
9
+ [:group, :key1, "string"],
10
+ [:group, :key2, 123]
11
+ ].to_enum
12
+ keys = subject.generate(enum)
13
+ keys.must_equal(
14
+ "GROUP_KEY1" => "string",
15
+ "GROUP_KEY1_TYPE" => "string",
16
+ "GROUP_KEY2" => "123",
17
+ "GROUP_KEY2_TYPE" => "integer"
18
+ )
19
+ end
20
+ end
21
+
@@ -0,0 +1,207 @@
1
+ require 'helper'
2
+
3
+ describe Levels::System::KeyParser do
4
+
5
+ subject { Levels::System::KeyParser.new }
6
+
7
+ describe "basic parsing rules" do
8
+
9
+ it "returns nil if the value is empty" do
10
+ env = {
11
+ "K" => ""
12
+ }
13
+ value = subject.parse(env, "K", "template is string")
14
+ value.must_equal nil
15
+ end
16
+
17
+ it "returns a value based on typecast info if the template value is nil" do
18
+ env = {
19
+ "K" => "123",
20
+ "K_TYPE" => "integer"
21
+ }
22
+ value = subject.parse(env, "K", nil)
23
+ value.must_equal 123
24
+ end
25
+
26
+ it "returns a value based on the template if no typecast info is available" do
27
+ env = {
28
+ "K" => "123"
29
+ }
30
+ value = subject.parse(env, "K", 999)
31
+ value.must_equal 123
32
+ end
33
+
34
+ it "returns a value based on typecast info if both template and typecast info exist" do
35
+ env = {
36
+ "K" => "123",
37
+ "K_TYPE" => "integer"
38
+ }
39
+ value = subject.parse(env, "K", "template is a string")
40
+ value.must_equal 123
41
+ end
42
+
43
+ it "returns a string if neither typecast or template are available" do
44
+ env = {
45
+ "K" => "123"
46
+ }
47
+ value = subject.parse(env, "K", nil)
48
+ value.must_equal "123"
49
+ end
50
+ end
51
+
52
+ describe "parsing simple types" do
53
+
54
+ describe "from typecast info" do
55
+
56
+ specify "string" do
57
+ env = {
58
+ "K" => "hello",
59
+ "K_TYPE" => "string"
60
+ }
61
+ subject.parse(env, "K", nil).must_equal "hello"
62
+ end
63
+
64
+ specify "integer" do
65
+ env = {
66
+ "K" => "123",
67
+ "K_TYPE" => "integer"
68
+ }
69
+ subject.parse(env, "K", nil).must_equal 123
70
+ end
71
+
72
+ specify "float" do
73
+ env = {
74
+ "K" => "1.5",
75
+ "K_TYPE" => "float"
76
+ }
77
+ subject.parse(env, "K", nil).must_equal 1.5
78
+ end
79
+
80
+ specify "boolean" do
81
+ env = {
82
+ "T" => "true",
83
+ "T_TYPE" => "boolean",
84
+ "O" => "1",
85
+ "O_TYPE" => "boolean",
86
+ "F" => "false",
87
+ "F_TYPE" => "boolean",
88
+ "X" => "blah",
89
+ "X_TYPE" => "boolean"
90
+ }
91
+ subject.parse(env, "T", nil).must_equal true
92
+ subject.parse(env, "O", nil).must_equal true
93
+ subject.parse(env, "F", nil).must_equal false
94
+ subject.parse(env, "X", nil).must_equal false
95
+ end
96
+
97
+ specify "an unknown type" do
98
+ env = {
99
+ "K" => "hello",
100
+ "K_TYPE" => "other"
101
+ }
102
+ -> { subject.parse(env, "K", nil) }.must_raise(ArgumentError)
103
+ end
104
+ end
105
+
106
+ describe "from the template value" do
107
+
108
+ specify "string" do
109
+ env = {
110
+ "K" => "hello"
111
+ }
112
+ subject.parse(env, "K", "str").must_equal "hello"
113
+ end
114
+
115
+ specify "integer" do
116
+ env = {
117
+ "K" => "123"
118
+ }
119
+ subject.parse(env, "K", 999).must_equal 123
120
+ end
121
+
122
+ specify "float" do
123
+ env = {
124
+ "K" => "1.5"
125
+ }
126
+ subject.parse(env, "K", 1.0).must_equal 1.5
127
+ end
128
+
129
+ specify "boolean" do
130
+ env = {
131
+ "T" => "true",
132
+ "O" => "1",
133
+ "F" => "false",
134
+ "X" => "blah"
135
+ }
136
+ subject.parse(env, "T", false).must_equal true
137
+ subject.parse(env, "O", false).must_equal true
138
+ subject.parse(env, "F", true).must_equal false
139
+ subject.parse(env, "X", true).must_equal false
140
+ end
141
+
142
+ specify "an unknown type" do
143
+ env = {
144
+ "K" => "hello"
145
+ }
146
+ -> { subject.parse(env, "K", Object.new) }.must_raise(ArgumentError)
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "parsing an array" do
152
+
153
+ describe "from typecast info" do
154
+
155
+ it "parses from the array" do
156
+ env = {
157
+ "K" => "a:b:c",
158
+ "K_TYPE" => "array"
159
+ }
160
+ subject.parse(env, "K", nil).must_equal ["a", "b", "c"]
161
+ end
162
+
163
+ it "parses the array values" do
164
+ env = {
165
+ "K" => "1:2:3",
166
+ "K_TYPE" => "array",
167
+ "K_TYPE_TYPE" => "integer"
168
+ }
169
+ subject.parse(env, "K", nil).must_equal [1, 2, 3]
170
+ end
171
+ end
172
+
173
+ describe "from the template value" do
174
+
175
+ it "it parses the array" do
176
+ env = {
177
+ "K" => "a:b:c"
178
+ }
179
+ subject.parse(env, "K", []).must_equal ["a", "b", "c"]
180
+ end
181
+
182
+ it "parses the array values" do
183
+ env = {
184
+ "K" => "1:2:3"
185
+ }
186
+ subject.parse(env, "K", [1]).must_equal [1, 2, 3]
187
+ end
188
+
189
+ it "parses the array values from typecast info" do
190
+ env = {
191
+ "K" => "1:2:3",
192
+ "K_TYPE_TYPE" => "integer"
193
+ }
194
+ subject.parse(env, "K", []).must_equal [1, 2, 3]
195
+ subject.parse(env, "K", ["string"]).must_equal [1, 2, 3]
196
+ end
197
+ end
198
+
199
+ it "uses another delimiter" do
200
+ env = {
201
+ "K" => "a,b,c",
202
+ "K_DELIMITER" => ","
203
+ }
204
+ subject.parse(env, "K", []).must_equal ["a", "b", "c"]
205
+ end
206
+ end
207
+ end
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: levels
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Carver
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '4.0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '4.0'
46
+ description: A tool for reading and writing configuration data.
47
+ email:
48
+ - ryan@ryancarver.com
49
+ executables:
50
+ - levels
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - .rbenv-version
56
+ - CHANGELOG.md
57
+ - Gemfile
58
+ - Guardfile
59
+ - LICENSE
60
+ - README.md
61
+ - Rakefile
62
+ - bin/levels
63
+ - examples/01_base.rb
64
+ - examples/01_merge_to_json.sh
65
+ - examples/01_prod.json
66
+ - examples/02_base.rb
67
+ - examples/02_merge_with_file.sh
68
+ - examples/02_value
69
+ - levels.gemspec
70
+ - lib/levels.rb
71
+ - lib/levels/audit.rb
72
+ - lib/levels/audit/group_observer.rb
73
+ - lib/levels/audit/nested_group_observer.rb
74
+ - lib/levels/audit/root_observer.rb
75
+ - lib/levels/audit/value.rb
76
+ - lib/levels/audit/value_observer.rb
77
+ - lib/levels/audit/values.rb
78
+ - lib/levels/configuration.rb
79
+ - lib/levels/configured_group.rb
80
+ - lib/levels/event_handler.rb
81
+ - lib/levels/group.rb
82
+ - lib/levels/input/json.rb
83
+ - lib/levels/input/ruby.rb
84
+ - lib/levels/input/system.rb
85
+ - lib/levels/input/yaml.rb
86
+ - lib/levels/key.rb
87
+ - lib/levels/key_values.rb
88
+ - lib/levels/lazy_evaluator.rb
89
+ - lib/levels/level.rb
90
+ - lib/levels/method_missing.rb
91
+ - lib/levels/output/json.rb
92
+ - lib/levels/output/system.rb
93
+ - lib/levels/output/yaml.rb
94
+ - lib/levels/runtime.rb
95
+ - lib/levels/setup.rb
96
+ - lib/levels/system/constants.rb
97
+ - lib/levels/system/key_formatter.rb
98
+ - lib/levels/system/key_generator.rb
99
+ - lib/levels/system/key_parser.rb
100
+ - lib/levels/version.rb
101
+ - test/acceptance/audit_test.rb
102
+ - test/acceptance/event_handler_test.rb
103
+ - test/acceptance/read_json_test.rb
104
+ - test/acceptance/read_ruby_test.rb
105
+ - test/acceptance/read_system_test.rb
106
+ - test/acceptance/read_yaml_test.rb
107
+ - test/acceptance/setup_test.rb
108
+ - test/acceptance/write_json_test.rb
109
+ - test/acceptance/write_system_test.rb
110
+ - test/acceptance/write_yaml_test.rb
111
+ - test/bin/merge_test.rb
112
+ - test/bin/options_test.rb
113
+ - test/helper.rb
114
+ - test/support/acceptance_spec.rb
115
+ - test/support/base_spec.rb
116
+ - test/support/bin_spec.rb
117
+ - test/support/tempfile_helper.rb
118
+ - test/unit/audit/group_observer_test.rb
119
+ - test/unit/audit/nested_group_observer_test.rb
120
+ - test/unit/audit/root_observer_test.rb
121
+ - test/unit/audit/value_observer_test.rb
122
+ - test/unit/audit/value_test.rb
123
+ - test/unit/audit/values_test.rb
124
+ - test/unit/configuration_test.rb
125
+ - test/unit/configured_group_test.rb
126
+ - test/unit/group_test.rb
127
+ - test/unit/input/json_test.rb
128
+ - test/unit/input/ruby_test.rb
129
+ - test/unit/input/system_test.rb
130
+ - test/unit/input/yaml_test.rb
131
+ - test/unit/key_test.rb
132
+ - test/unit/key_values_test.rb
133
+ - test/unit/lazy_evaluator_test.rb
134
+ - test/unit/level_test.rb
135
+ - test/unit/levels_test.rb
136
+ - test/unit/output/json_test.rb
137
+ - test/unit/output/system_test.rb
138
+ - test/unit/output/yaml_test.rb
139
+ - test/unit/runtime_test.rb
140
+ - test/unit/system/key_formatter_test.rb
141
+ - test/unit/system/key_generator_test.rb
142
+ - test/unit/system/key_parser_test.rb
143
+ homepage: https://github.com/rcarver/levels
144
+ licenses: []
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ segments:
156
+ - 0
157
+ hash: 352126220844248083
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ none: false
160
+ requirements:
161
+ - - ! '>='
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ segments:
165
+ - 0
166
+ hash: 352126220844248083
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 1.8.23
170
+ signing_key:
171
+ specification_version: 3
172
+ summary: A tool for reading and writing configuration data.
173
+ test_files:
174
+ - test/acceptance/audit_test.rb
175
+ - test/acceptance/event_handler_test.rb
176
+ - test/acceptance/read_json_test.rb
177
+ - test/acceptance/read_ruby_test.rb
178
+ - test/acceptance/read_system_test.rb
179
+ - test/acceptance/read_yaml_test.rb
180
+ - test/acceptance/setup_test.rb
181
+ - test/acceptance/write_json_test.rb
182
+ - test/acceptance/write_system_test.rb
183
+ - test/acceptance/write_yaml_test.rb
184
+ - test/bin/merge_test.rb
185
+ - test/bin/options_test.rb
186
+ - test/helper.rb
187
+ - test/support/acceptance_spec.rb
188
+ - test/support/base_spec.rb
189
+ - test/support/bin_spec.rb
190
+ - test/support/tempfile_helper.rb
191
+ - test/unit/audit/group_observer_test.rb
192
+ - test/unit/audit/nested_group_observer_test.rb
193
+ - test/unit/audit/root_observer_test.rb
194
+ - test/unit/audit/value_observer_test.rb
195
+ - test/unit/audit/value_test.rb
196
+ - test/unit/audit/values_test.rb
197
+ - test/unit/configuration_test.rb
198
+ - test/unit/configured_group_test.rb
199
+ - test/unit/group_test.rb
200
+ - test/unit/input/json_test.rb
201
+ - test/unit/input/ruby_test.rb
202
+ - test/unit/input/system_test.rb
203
+ - test/unit/input/yaml_test.rb
204
+ - test/unit/key_test.rb
205
+ - test/unit/key_values_test.rb
206
+ - test/unit/lazy_evaluator_test.rb
207
+ - test/unit/level_test.rb
208
+ - test/unit/levels_test.rb
209
+ - test/unit/output/json_test.rb
210
+ - test/unit/output/system_test.rb
211
+ - test/unit/output/yaml_test.rb
212
+ - test/unit/runtime_test.rb
213
+ - test/unit/system/key_formatter_test.rb
214
+ - test/unit/system/key_generator_test.rb
215
+ - test/unit/system/key_parser_test.rb