configurations 2.2.0 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -6
- data/Rakefile +1 -0
- data/configurations.gemspec +2 -0
- data/lib/configurations.rb +8 -4
- data/lib/configurations/arbitrary.rb +8 -13
- data/lib/configurations/blank_object.rb +5 -0
- data/lib/configurations/configurable.rb +39 -91
- data/lib/configurations/configuration.rb +30 -102
- data/lib/configurations/data.rb +44 -0
- data/lib/configurations/maps.rb +6 -0
- data/lib/configurations/maps/blocks.rb +62 -0
- data/lib/configurations/maps/data.rb +30 -0
- data/lib/configurations/maps/properties.rb +48 -0
- data/lib/configurations/maps/readers.rb +1 -0
- data/lib/configurations/maps/readers/tolerant.rb +13 -0
- data/lib/configurations/maps/types.rb +56 -0
- data/lib/configurations/maps/writers.rb +1 -0
- data/lib/configurations/maps/writers/default.rb +17 -0
- data/lib/configurations/path.rb +22 -0
- data/lib/configurations/strict.rb +25 -83
- data/lib/configurations/validators.rb +2 -0
- data/lib/configurations/validators/ambiguity.rb +26 -0
- data/lib/configurations/validators/reserved_methods.rb +39 -0
- data/test/configurations/configuration/test_configure_synchronized.rb +17 -31
- data/test/configurations/shared/hash_methods.rb +3 -3
- data/test/run +4 -0
- data/test/test_helper.rb +1 -0
- data/test/watch +9 -0
- metadata +52 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64f706300eff0c3494e39c9e560b63b198513d07
|
4
|
+
data.tar.gz: 82d0bbb8af8484bc6dbcd9c1162f659690d867a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44aa42ce5c00099190352575d9f76fd20ab2fe9135d97a3a6a1df3a24633e512303f55b4eb96d7e263b9b717c33034728d91bc3f699c6ad282db5060da64dfc4
|
7
|
+
data.tar.gz: e42634d42c69e015e6e47b499519c121b0076562983edea0a4f8c40bb0b3cb4e6024bd7f08b489bea51b0b800d1d11315e1df85a705611295ba8ec4a8b745c8a
|
data/.travis.yml
CHANGED
@@ -3,14 +3,12 @@ branches:
|
|
3
3
|
only:
|
4
4
|
- master
|
5
5
|
rvm:
|
6
|
-
- 1.9.2
|
7
|
-
- 1.9.3
|
8
6
|
- 2.0.0
|
9
|
-
- 2.1.
|
10
|
-
- 2.2.
|
11
|
-
-
|
7
|
+
- 2.1.10
|
8
|
+
- 2.2.5
|
9
|
+
- 2.3.1
|
10
|
+
- rbx-2
|
12
11
|
- jruby-19mode
|
13
12
|
- jruby-20mode
|
14
|
-
- jruby-head
|
15
13
|
|
16
14
|
script: CODECLIMATE_REPO_TOKEN=36cf84c73264d3c361003f66903eec8aa5fb2b3494496f3a9676630518ecc9f9 rake
|
data/Rakefile
CHANGED
data/configurations.gemspec
CHANGED
@@ -20,6 +20,8 @@ SUMMARY
|
|
20
20
|
s.test_files = `git ls-files -- test/*`.split("\n")
|
21
21
|
|
22
22
|
s.add_development_dependency 'minitest', '~> 5.4'
|
23
|
+
s.add_development_dependency 'minitest-focus', '~> 1.1'
|
24
|
+
s.add_development_dependency 'test-unit', '~> 3'
|
23
25
|
s.add_development_dependency 'yard', '~> 0.8'
|
24
26
|
s.add_development_dependency 'rake', '~> 10'
|
25
27
|
end
|
data/lib/configurations.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
require_relative 'configurations/
|
1
|
+
require_relative 'configurations/arbitrary'
|
2
2
|
require_relative 'configurations/blank_object'
|
3
|
+
require_relative 'configurations/configurable'
|
3
4
|
require_relative 'configurations/configuration'
|
4
|
-
require_relative 'configurations/
|
5
|
+
require_relative 'configurations/data'
|
6
|
+
require_relative 'configurations/error'
|
7
|
+
require_relative 'configurations/maps'
|
8
|
+
require_relative 'configurations/path'
|
5
9
|
require_relative 'configurations/strict'
|
6
|
-
require_relative 'configurations/
|
10
|
+
require_relative 'configurations/validators'
|
7
11
|
|
8
12
|
# Configurations provides a unified approach to do configurations
|
9
13
|
# with the flexibility to do everything from arbitrary configurations
|
@@ -16,5 +20,5 @@ module Configurations
|
|
16
20
|
|
17
21
|
# Version number of Configurations
|
18
22
|
#
|
19
|
-
VERSION = '2.2.
|
23
|
+
VERSION = '2.2.1'
|
20
24
|
end
|
@@ -30,7 +30,9 @@ module Configurations
|
|
30
30
|
elsif __respond_to_method_for_write?(method)
|
31
31
|
@data[method]
|
32
32
|
elsif __respond_to_method_for_read?(method, *args, &block)
|
33
|
-
@data.fetch(method
|
33
|
+
@data.fetch(method) do
|
34
|
+
@not_configured_blocks.evaluate!(@path.add(method), method)
|
35
|
+
end
|
34
36
|
else
|
35
37
|
super
|
36
38
|
end
|
@@ -54,20 +56,13 @@ module Configurations
|
|
54
56
|
# (in configure block)
|
55
57
|
#
|
56
58
|
def from_h(h)
|
57
|
-
unless @
|
59
|
+
unless @writeable
|
58
60
|
fail ::ArgumentError, 'can not dynamically assign values from a hash'
|
59
61
|
end
|
60
62
|
|
61
63
|
super
|
62
64
|
end
|
63
65
|
|
64
|
-
# @param [Symbol] property The property to test for configurability
|
65
|
-
# @return [Boolean] whether the given property is configurable
|
66
|
-
#
|
67
|
-
def __configurable?(_property)
|
68
|
-
true
|
69
|
-
end
|
70
|
-
|
71
66
|
# Set the configuration to writeable or read only. Access to writer methods
|
72
67
|
# is only allowed within the configure block, this method is used to invoke
|
73
68
|
# writeability for subconfigurations.
|
@@ -75,8 +70,8 @@ module Configurations
|
|
75
70
|
# false otherwise
|
76
71
|
#
|
77
72
|
def __writeable__=(data)
|
78
|
-
@
|
79
|
-
return
|
73
|
+
@writeable = data
|
74
|
+
return unless defined?(@data) && @data
|
80
75
|
|
81
76
|
@data.each do |_k, v|
|
82
77
|
v.__writeable__ = data if v.is_a?(__class__)
|
@@ -104,7 +99,7 @@ module Configurations
|
|
104
99
|
# property as a method during writeable state
|
105
100
|
#
|
106
101
|
def __respond_to_method_for_write?(method)
|
107
|
-
!__is_writer?(method) && @
|
102
|
+
!__is_writer?(method) && @writeable && @data[method].is_a?(__class__)
|
108
103
|
end
|
109
104
|
|
110
105
|
# @param [Symbol] method the method to test for
|
@@ -120,7 +115,7 @@ module Configurations
|
|
120
115
|
# state
|
121
116
|
#
|
122
117
|
def __respond_to_writer?(method)
|
123
|
-
@
|
118
|
+
@writeable && __is_writer?(method)
|
124
119
|
end
|
125
120
|
end
|
126
121
|
end
|
@@ -31,6 +31,11 @@ module Configurations
|
|
31
31
|
:object_id,
|
32
32
|
# rbx needs the singleton class to access singleton methods
|
33
33
|
:singleton_class,
|
34
|
+
# rbx needs its private methods
|
35
|
+
:__instance_variable_defined_p__,
|
36
|
+
:__instance_variable_get__,
|
37
|
+
:__instance_variable_set__,
|
38
|
+
:__instance_variable__,
|
34
39
|
*ALIAS_KERNEL_METHODS.keys
|
35
40
|
].compact.freeze
|
36
41
|
|
@@ -117,10 +117,22 @@ module Configurations
|
|
117
117
|
# end
|
118
118
|
#
|
119
119
|
def configurable(*properties, &block)
|
120
|
-
|
120
|
+
@configurable_properties ||= Maps::Properties.new
|
121
|
+
@configurable_types ||= Maps::Types.new
|
122
|
+
@configurable_blocks ||= Maps::Blocks.new
|
123
|
+
|
124
|
+
type, properties = extract_type(properties)
|
125
|
+
@configurable_properties.add(properties)
|
126
|
+
@configurable_types.add(type, properties)
|
127
|
+
@configurable_blocks.add(block, properties)
|
128
|
+
end
|
121
129
|
|
122
|
-
|
123
|
-
|
130
|
+
def extract_type(properties)
|
131
|
+
if properties.first.is_a?(Module)
|
132
|
+
[properties.first, properties[1...properties.size]]
|
133
|
+
else
|
134
|
+
[nil, properties]
|
135
|
+
end
|
124
136
|
end
|
125
137
|
|
126
138
|
# returns whether a property is set to be configurable
|
@@ -128,7 +140,9 @@ module Configurations
|
|
128
140
|
# @return [Boolean] whether the property is configurable
|
129
141
|
#
|
130
142
|
def configurable?(property)
|
131
|
-
|
143
|
+
defined?(@configurable_properties) &&
|
144
|
+
@configurable_properties &&
|
145
|
+
@configurable_properties.configurable?(Path.new([property]))
|
132
146
|
end
|
133
147
|
|
134
148
|
# configuration method can be used to retrieve properties
|
@@ -151,14 +165,8 @@ module Configurations
|
|
151
165
|
"can't be configuration property and a method"
|
152
166
|
) if configurable?(method)
|
153
167
|
|
154
|
-
@
|
155
|
-
|
156
|
-
ingest_configuration_block!(method, &block)
|
157
|
-
else
|
158
|
-
{ method => block }
|
159
|
-
end
|
160
|
-
|
161
|
-
@configuration_methods.merge! method_hash
|
168
|
+
@configuration_method_blocks ||= Maps::Blocks.new
|
169
|
+
@configuration_method_blocks.add(block, [method])
|
162
170
|
end
|
163
171
|
|
164
172
|
# not_configured defines the behaviour when a property has not been
|
@@ -181,12 +189,11 @@ module Configurations
|
|
181
189
|
# end
|
182
190
|
#
|
183
191
|
def not_configured(*properties, &block)
|
184
|
-
@
|
192
|
+
@not_configured_blocks ||= Maps::Blocks.new
|
193
|
+
@not_configured_blocks.add(block, properties)
|
185
194
|
|
186
195
|
if properties.empty?
|
187
|
-
@
|
188
|
-
else
|
189
|
-
nested_merge_not_configured_hash(*properties, &block)
|
196
|
+
@not_configured_blocks.add_default(block)
|
190
197
|
end
|
191
198
|
end
|
192
199
|
|
@@ -207,41 +214,10 @@ module Configurations
|
|
207
214
|
# @return the class name of the configuration class to use
|
208
215
|
#
|
209
216
|
def configuration_type
|
210
|
-
if @
|
211
|
-
Configurations::Arbitrary
|
212
|
-
else
|
217
|
+
if defined?(@configurable_properties) && @configurable_properties && !@configurable_properties.empty?
|
213
218
|
Configurations::Strict
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
# Instantiates a configurable hash from a property and a type
|
218
|
-
# @param [Symbol, Hash, Array] properties configurable properties,
|
219
|
-
# either single or nested
|
220
|
-
# @param [Class] type the type to assert, if any
|
221
|
-
# @return a hash with configurable values pointing to their types
|
222
|
-
#
|
223
|
-
def to_configurable_hash(properties, type, &block)
|
224
|
-
assertion_hash = {}
|
225
|
-
assertion_hash.merge! block: block if block_given?
|
226
|
-
assertion_hash.merge! type: type if type
|
227
|
-
|
228
|
-
zip_to_hash(assertion_hash, *properties)
|
229
|
-
end
|
230
|
-
|
231
|
-
# Makes all values of hash point to block
|
232
|
-
# @param [Hash] hash the hash to modify
|
233
|
-
# @param [Proc] block the block to point to
|
234
|
-
# @return a hash with all previous values being keys pointing to block
|
235
|
-
#
|
236
|
-
def ingest_configuration_block!(hash, &block)
|
237
|
-
hash.each do |k, v|
|
238
|
-
value = if v.is_a?(Hash)
|
239
|
-
ingest_configuration_block!(v, &block)
|
240
|
-
else
|
241
|
-
zip_to_hash(block, *Array(v))
|
242
|
-
end
|
243
|
-
|
244
|
-
hash.merge! k => value
|
219
|
+
else
|
220
|
+
Configurations::Arbitrary
|
245
221
|
end
|
246
222
|
end
|
247
223
|
|
@@ -249,47 +225,19 @@ module Configurations
|
|
249
225
|
#
|
250
226
|
def configuration_options
|
251
227
|
{
|
252
|
-
defaults:
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
nested = properties.last.is_a?(Hash) ? properties.pop : {}
|
266
|
-
nested = ingest_configuration_block!(nested, &block)
|
267
|
-
props = zip_to_hash(block, *properties)
|
268
|
-
|
269
|
-
@not_configured.merge! nested, &method(:configuration_deep_merge)
|
270
|
-
@not_configured.merge! props, &method(:configuration_deep_merge)
|
271
|
-
end
|
272
|
-
|
273
|
-
# Solves merge conflicts when merging
|
274
|
-
# @param [Symbol] key the key that conflicts
|
275
|
-
# @param [Anything] oldval the value of the left side of the merge
|
276
|
-
# @param [Anything] newval the value of the right side of the merge
|
277
|
-
# @return a mergable value with conflicts solved
|
278
|
-
#
|
279
|
-
def configuration_deep_merge(_key, oldval, newval)
|
280
|
-
if oldval.is_a?(Hash) && newval.is_a?(Hash)
|
281
|
-
oldval.merge(newval, &method(:configuration_deep_merge))
|
282
|
-
else
|
283
|
-
Array(oldval) + Array(newval)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
# Zip a value with keys to a hash so all keys point to the value
|
288
|
-
# @param [Anything] value the value to point to
|
289
|
-
# @param [Array] keys the keys to install
|
290
|
-
#
|
291
|
-
def zip_to_hash(value, *keys)
|
292
|
-
Hash[keys.zip([value] * keys.size)]
|
228
|
+
defaults:
|
229
|
+
defined?(@configuration_defaults) && @configuration_defaults,
|
230
|
+
properties:
|
231
|
+
defined?(@configurable_properties) && @configurable_properties,
|
232
|
+
types:
|
233
|
+
defined?(@configurable_types) && @configurable_types,
|
234
|
+
blocks:
|
235
|
+
defined?(@configurable_blocks) && @configurable_blocks,
|
236
|
+
method_blocks:
|
237
|
+
defined?(@configuration_method_blocks) && @configuration_method_blocks,
|
238
|
+
not_configured_blocks:
|
239
|
+
defined?(@not_configured_blocks) && @not_configured_blocks,
|
240
|
+
}.keep_if { |_, value| value }
|
293
241
|
end
|
294
242
|
end
|
295
243
|
end
|
@@ -3,18 +3,6 @@ module Configurations
|
|
3
3
|
# of various properties including keywords
|
4
4
|
#
|
5
5
|
class Configuration < BlankObject
|
6
|
-
# Reserved methods are not assignable. They define behaviour needed for
|
7
|
-
# the configuration object to work properly.
|
8
|
-
#
|
9
|
-
RESERVED_METHODS = [
|
10
|
-
:initialize,
|
11
|
-
:inspect,
|
12
|
-
:method_missing,
|
13
|
-
:object_id,
|
14
|
-
:singleton_class, # needed by rbx
|
15
|
-
:to_h,
|
16
|
-
:to_s # needed by rbx / 1.9.3 for inspect
|
17
|
-
]
|
18
6
|
|
19
7
|
class << self
|
20
8
|
# Make new a private method, but allow __new__ alias. Instantiating
|
@@ -31,10 +19,16 @@ module Configurations
|
|
31
19
|
# not_configured properties
|
32
20
|
|
33
21
|
def initialize(options = {}, &block)
|
34
|
-
@
|
35
|
-
@
|
22
|
+
@data = Data.new(__configuration_hash__)
|
23
|
+
@path = options.fetch(:path) { Path.new }
|
24
|
+
@data_map = options.fetch(:data) { Maps::Data.new }
|
25
|
+
|
26
|
+
@methods = options.fetch(:methods) { ::Hash.new }
|
27
|
+
@method_blocks = options.fetch(:method_blocks) { Maps::Blocks.new }
|
28
|
+
@not_configured_blocks = options.fetch(:not_configured_blocks) { Maps::Blocks.new }
|
36
29
|
|
37
|
-
@
|
30
|
+
@reserved_method_validator = Validators::ReservedMethods.new
|
31
|
+
@key_ambiguity_validator = Validators::Ambiguity.new
|
38
32
|
|
39
33
|
__instance_eval__(&options[:defaults]) if options[:defaults]
|
40
34
|
__instance_eval__(&block) if block
|
@@ -78,7 +72,8 @@ module Configurations
|
|
78
72
|
# different values
|
79
73
|
#
|
80
74
|
def from_h(h)
|
81
|
-
|
75
|
+
@key_ambiguity_validator.validate!(h)
|
76
|
+
|
82
77
|
h.each do |property, value|
|
83
78
|
p = property.to_sym
|
84
79
|
if value.is_a?(::Hash) && __nested?(p)
|
@@ -108,8 +103,12 @@ module Configurations
|
|
108
103
|
# @param [Symbol] property The property to test for configurability
|
109
104
|
# @return [Boolean] whether the given property is configurable
|
110
105
|
#
|
111
|
-
def __configurable?(
|
112
|
-
|
106
|
+
def __configurable?(property)
|
107
|
+
if defined?(@configurable_properties) && @configurable_properties
|
108
|
+
@configurable_properties.configurable?(@path.add(property))
|
109
|
+
else
|
110
|
+
true
|
111
|
+
end
|
113
112
|
end
|
114
113
|
|
115
114
|
# @param [Symbol] property The property to test for
|
@@ -130,9 +129,10 @@ module Configurations
|
|
130
129
|
# as singleton methods
|
131
130
|
#
|
132
131
|
def __install_configuration_methods__
|
133
|
-
@
|
134
|
-
|
135
|
-
|
132
|
+
entries = @method_blocks.entries_at(@path)
|
133
|
+
entries.each do |meth, entry|
|
134
|
+
@reserved_method_validator.validate!(meth)
|
135
|
+
__define_singleton_method__(meth, &entry.block)
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
@@ -141,39 +141,17 @@ module Configurations
|
|
141
141
|
# @return [Hash] a hash to be used for configuration initialization
|
142
142
|
#
|
143
143
|
def __options_hash_for__(property)
|
144
|
-
|
145
|
-
hash[:not_configured] =
|
146
|
-
__not_configured_hash_for__(property) if @__not_configured__[property]
|
147
|
-
hash[:methods] = @__methods__[property] if @__methods__.key?(property)
|
148
|
-
|
149
|
-
hash
|
150
|
-
end
|
151
|
-
|
152
|
-
# @param [Symbol] property the property to return the callback for
|
153
|
-
# @return [Proc] a block to use when property is called before
|
154
|
-
# configuration, defaults to a block yielding nil
|
155
|
-
#
|
156
|
-
def __not_configured_callback_for__(property)
|
157
|
-
not_configured = @__not_configured__[property] || ::Proc.new { nil }
|
144
|
+
nested_path = @path.add(property)
|
158
145
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
146
|
+
hash = {}
|
147
|
+
hash[:path] = nested_path
|
148
|
+
hash[:data] = @data_map
|
149
|
+
hash[:properties] = defined?(@properties) && @properties
|
163
150
|
|
164
|
-
|
165
|
-
end
|
151
|
+
hash[:not_configured_blocks] = @not_configured_blocks
|
166
152
|
|
167
|
-
|
168
|
-
|
169
|
-
# @return [Hash] a hash which can be used as a not configured
|
170
|
-
# hash in options
|
171
|
-
#
|
172
|
-
def __not_configured_hash_for__(property)
|
173
|
-
hash = ::Hash.new(&@__not_configured__.default_proc)
|
174
|
-
hash.merge!(
|
175
|
-
@__not_configured__[property]
|
176
|
-
) if @__not_configured__[property].is_a?(::Hash)
|
153
|
+
hash[:method_blocks] = @method_blocks
|
154
|
+
hash[:methods] = @methods[property] if @methods.key?(property)
|
177
155
|
|
178
156
|
hash
|
179
157
|
end
|
@@ -192,7 +170,7 @@ module Configurations
|
|
192
170
|
# @param [Any] value the given value
|
193
171
|
#
|
194
172
|
def __assign!(property, value)
|
195
|
-
|
173
|
+
@data_map.add_entry(@path.add(property), value)
|
196
174
|
@data[property] = value
|
197
175
|
end
|
198
176
|
|
@@ -222,55 +200,5 @@ module Configurations
|
|
222
200
|
method.to_s[0..-2].to_sym
|
223
201
|
end
|
224
202
|
|
225
|
-
# @param [Symbol] method the method to test for reservedness
|
226
|
-
# @raise [Configurations::ReservedMethodError] raises this error if
|
227
|
-
# a property is a reserved method.
|
228
|
-
#
|
229
|
-
def __test_reserved!(method)
|
230
|
-
::Kernel.fail(
|
231
|
-
::Configurations::ReservedMethodError,
|
232
|
-
"#{method} is a reserved method and can not be assigned"
|
233
|
-
) if __is_reserved?(method)
|
234
|
-
end
|
235
|
-
|
236
|
-
# @param [Hash] the hash to test for ambiguity
|
237
|
-
# @raise [Configurations::ConfigurationError] raises this error if
|
238
|
-
# a property is defined ambiguously
|
239
|
-
#
|
240
|
-
def __test_ambiguity!(h)
|
241
|
-
symbols, others = h.keys.partition { |k| k.is_a?(::Symbol) }
|
242
|
-
ambiguous = symbols.map(&:to_s) & others
|
243
|
-
|
244
|
-
unless ambiguous.empty?
|
245
|
-
::Kernel.fail(
|
246
|
-
::Configurations::ConfigurationError,
|
247
|
-
"Can not resolve configuration values for #{ambiguous.join(', ')} " \
|
248
|
-
"defined as both Symbol and #{others.first.class.name} keys. " \
|
249
|
-
'Please resolve the ambiguity.'
|
250
|
-
)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
# @param [Symbol] method the method to test for
|
255
|
-
# @return [TrueClass, FalseClass] whether the method is reserved
|
256
|
-
#
|
257
|
-
def __is_reserved?(method)
|
258
|
-
RESERVED_METHODS.include?(method)
|
259
|
-
end
|
260
|
-
|
261
|
-
# @param [Hash] a hash to collect blocks from
|
262
|
-
# @return [Proc] a proc to call all the procs
|
263
|
-
#
|
264
|
-
def __collect_blocks__(hash)
|
265
|
-
hash.reduce([]) do |array, (k, v)|
|
266
|
-
array << if v.is_a?(::Hash)
|
267
|
-
__collect_blocks__(v)
|
268
|
-
else
|
269
|
-
v || k
|
270
|
-
end
|
271
|
-
|
272
|
-
array
|
273
|
-
end.flatten
|
274
|
-
end
|
275
203
|
end
|
276
204
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Configurations
|
2
|
+
# Configuration is a blank object in order to allow configuration
|
3
|
+
# of various properties including keywords
|
4
|
+
#
|
5
|
+
class Data
|
6
|
+
def initialize(
|
7
|
+
data,
|
8
|
+
reserved_method_validator = Validators::ReservedMethods.new
|
9
|
+
)
|
10
|
+
@data = data
|
11
|
+
@reserved_method_validator = reserved_method_validator
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
@data[key]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
@reserved_method_validator.validate!(key)
|
20
|
+
|
21
|
+
@data[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def key?(key)
|
25
|
+
@data.key?(key)
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch(key, &block)
|
29
|
+
@data.fetch(key, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def each(&block)
|
33
|
+
@data.each(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def reduce(acc, &block)
|
37
|
+
@data.reduce(acc, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
@data.inspect
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Configurations
|
2
|
+
module Maps
|
3
|
+
class Blocks
|
4
|
+
class Entry
|
5
|
+
attr_reader :block
|
6
|
+
|
7
|
+
def initialize(block)
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate!(value)
|
12
|
+
return value unless @block
|
13
|
+
block.call(value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(reader = Readers::Tolerant.new)
|
18
|
+
@map = {}
|
19
|
+
@reader = reader
|
20
|
+
@default = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_default(block)
|
24
|
+
@default = Entry.new(block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(block, properties)
|
28
|
+
properties.each do |property|
|
29
|
+
add_entry(property, block, @map)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def entries_at(path)
|
34
|
+
entries = @reader.read(@map, path) || {}
|
35
|
+
entries.dup.keep_if { |_, v| v.is_a?(Entry) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def evaluate!(path, value)
|
39
|
+
entry = @reader.read(@map, path) || @default
|
40
|
+
return unless entry
|
41
|
+
|
42
|
+
entry.evaluate!(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_entry(property, block, subtree)
|
46
|
+
if property.is_a?(Hash)
|
47
|
+
property.each do |key, val|
|
48
|
+
subtree[key] = add_entry(val, block, subtree.fetch(key, {}))
|
49
|
+
end
|
50
|
+
elsif property.is_a?(Array)
|
51
|
+
property.each do |val|
|
52
|
+
add_entry(val, block, subtree)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
subtree[property] = Entry.new(block)
|
56
|
+
end
|
57
|
+
|
58
|
+
subtree
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Configurations
|
2
|
+
module Maps
|
3
|
+
class Data
|
4
|
+
class Entry
|
5
|
+
def initialize(value)
|
6
|
+
@value = value
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(
|
11
|
+
reader = Readers::Tolerant.new,
|
12
|
+
writer = Writers::Default.new { |value|
|
13
|
+
Entry.new(value)
|
14
|
+
}
|
15
|
+
)
|
16
|
+
@map = {}
|
17
|
+
@reader = reader
|
18
|
+
@writer = writer
|
19
|
+
end
|
20
|
+
|
21
|
+
def nested?(path)
|
22
|
+
@reader.read(@map, path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_entry(path, value)
|
26
|
+
@writer.write(@map, path, value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Configurations
|
2
|
+
module Maps
|
3
|
+
class Properties
|
4
|
+
attr_reader :map
|
5
|
+
class Entry
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(reader = Readers::Tolerant.new)
|
9
|
+
@map = {}
|
10
|
+
@reader = reader
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty?
|
14
|
+
@map.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(properties)
|
18
|
+
properties.each do |property|
|
19
|
+
add_entry(property, @map)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def entries_at(path)
|
24
|
+
@reader.read(@map, path) || {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def configurable?(path)
|
28
|
+
!!@reader.read(@map, path)
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_entry(property, subtree)
|
32
|
+
if property.is_a?(Hash)
|
33
|
+
property.each do |key, val|
|
34
|
+
subtree[key] = add_entry(val, subtree.fetch(key, {}))
|
35
|
+
end
|
36
|
+
elsif property.is_a?(Array)
|
37
|
+
property.each do |val|
|
38
|
+
add_entry(val, subtree)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
subtree[property] = Entry.new
|
42
|
+
end
|
43
|
+
|
44
|
+
subtree
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'readers/tolerant'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Configurations
|
2
|
+
module Maps
|
3
|
+
class Types
|
4
|
+
attr_reader :map
|
5
|
+
class Entry
|
6
|
+
attr_reader :type
|
7
|
+
|
8
|
+
def initialize(type)
|
9
|
+
@type = type
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
!@type || value.is_a?(@type)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(reader = Readers::Tolerant.new)
|
18
|
+
@map = {}
|
19
|
+
@reader = reader
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(type, properties)
|
23
|
+
properties.each do |property|
|
24
|
+
add_entry(property, type, @map)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test!(path, value)
|
29
|
+
entry = @reader.read(@map, path)
|
30
|
+
return unless entry
|
31
|
+
|
32
|
+
fail(
|
33
|
+
ConfigurationError,
|
34
|
+
"#{path.print} must be configured with #{entry.type} (got #{value})",
|
35
|
+
caller
|
36
|
+
) unless entry.valid?(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_entry(property, type, subtree)
|
40
|
+
if property.is_a?(Hash)
|
41
|
+
property.each do |key, val|
|
42
|
+
subtree[key] = add_entry(val, type, subtree.fetch(key, {}))
|
43
|
+
end
|
44
|
+
elsif property.is_a?(Array)
|
45
|
+
property.each do |val|
|
46
|
+
add_entry(val, type, subtree)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
subtree[property] = Entry.new(type)
|
50
|
+
end
|
51
|
+
|
52
|
+
subtree
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'writers/default'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Configurations
|
2
|
+
class Path
|
3
|
+
def initialize(path = [])
|
4
|
+
@path = path
|
5
|
+
end
|
6
|
+
|
7
|
+
def add(*path)
|
8
|
+
Path.new(@path + path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def reduce(initial, &block)
|
12
|
+
@path.reduce(initial, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
@path.join(".")
|
17
|
+
end
|
18
|
+
alias :inspect :to_s
|
19
|
+
alias :print :to_s
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -16,65 +16,43 @@ module Configurations
|
|
16
16
|
# @return [HostModule::Configuration] a configuration
|
17
17
|
#
|
18
18
|
def initialize(options = {}, &block)
|
19
|
-
@
|
19
|
+
@reserved_method_validator = Validators::ReservedMethods.new
|
20
|
+
|
21
|
+
@path = options.fetch(:path) { Path.new }
|
22
|
+
@properties = options.fetch(:properties) { Maps::Properties.new }
|
23
|
+
@types = options.fetch(:types)
|
24
|
+
@blocks = options.fetch(:blocks)
|
25
|
+
|
20
26
|
__evaluate_configurable!
|
21
27
|
|
22
28
|
super
|
23
29
|
end
|
24
30
|
|
25
|
-
# @param [Symbol] property The property to test for configurability
|
26
|
-
# @return [Boolean] whether the given property is configurable
|
27
|
-
#
|
28
|
-
def __configurable?(property)
|
29
|
-
@__configurable__.key?(property) ||
|
30
|
-
@__nested_configurables__.key?(property)
|
31
|
-
end
|
32
|
-
|
33
31
|
private
|
34
32
|
|
35
33
|
# Evaluates configurable properties and passes eventual hashes
|
36
34
|
# down to subconfigurations
|
37
35
|
#
|
38
36
|
def __evaluate_configurable!
|
39
|
-
@
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
__install_nested_getter__(property)
|
44
|
-
end
|
37
|
+
entries = @properties.entries_at(@path)
|
38
|
+
entries.each do |property, value|
|
39
|
+
if value.is_a?(Maps::Properties::Entry)
|
40
|
+
__install_property__(property)
|
45
41
|
else
|
46
|
-
|
42
|
+
__install_nested_getter__(property)
|
47
43
|
end
|
48
44
|
end
|
49
45
|
end
|
50
46
|
|
51
|
-
# Add a property to a nested configurable
|
52
|
-
#
|
53
|
-
def __add_to_nested_configurables!(property, nested, assertion)
|
54
|
-
@__nested_configurables__ ||= ::Hash.new { |h, k| h[k] = {} }
|
55
|
-
@__nested_configurables__[property].merge!(
|
56
|
-
__configurable_hash__(property, nested, assertion)
|
57
|
-
)
|
58
|
-
end
|
59
|
-
|
60
47
|
# Get an options hash for a property
|
61
48
|
#
|
62
49
|
def __options_hash_for__(property)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# either single or nested
|
70
|
-
# @param [Hash] assertion assertion if any
|
71
|
-
# @return a hash with configurable values pointing to their types
|
72
|
-
#
|
73
|
-
def __configurable_hash__(_property, value, assertion)
|
74
|
-
value = [value] unless value.is_a?(::Array)
|
75
|
-
hash = ::Hash[value.zip([assertion].flatten * value.size)]
|
76
|
-
|
77
|
-
hash
|
50
|
+
_nested_path = @path.add(property)
|
51
|
+
super(property).merge(
|
52
|
+
properties: @properties,
|
53
|
+
types: @types,
|
54
|
+
blocks: @blocks
|
55
|
+
)
|
78
56
|
end
|
79
57
|
|
80
58
|
# @param [Symbol] property the property to test for
|
@@ -89,7 +67,7 @@ module Configurations
|
|
89
67
|
# @param [Symbol] property the property to install
|
90
68
|
#
|
91
69
|
def __install_property__(property)
|
92
|
-
|
70
|
+
@reserved_method_validator.validate!(property)
|
93
71
|
__install_setter__(property)
|
94
72
|
__install_getter__(property)
|
95
73
|
end
|
@@ -108,7 +86,9 @@ module Configurations
|
|
108
86
|
#
|
109
87
|
def __install_getter__(property)
|
110
88
|
__define_singleton_method__ property do
|
111
|
-
@data.fetch(property
|
89
|
+
@data.fetch(property) do
|
90
|
+
@not_configured_blocks.evaluate!(@path.add(property), property)
|
91
|
+
end
|
112
92
|
end
|
113
93
|
end
|
114
94
|
|
@@ -127,49 +107,11 @@ module Configurations
|
|
127
107
|
# @param [Any] value the given value
|
128
108
|
#
|
129
109
|
def __assign!(property, value)
|
130
|
-
|
131
|
-
v =
|
110
|
+
@types.test!(@path.add(property), value)
|
111
|
+
v = @blocks.evaluate!(@path.add(property), value)
|
112
|
+
|
132
113
|
value = v unless v.nil?
|
133
114
|
super(property, value)
|
134
115
|
end
|
135
|
-
|
136
|
-
# Type assertion for configurable properties
|
137
|
-
# @param [Symbol] property the property to type test
|
138
|
-
# @param [Any] value the given value
|
139
|
-
# @raise [ConfigurationError] if the given value has the wrong type
|
140
|
-
#
|
141
|
-
def __assert_type!(property, value)
|
142
|
-
return unless __evaluable?(property, :type)
|
143
|
-
|
144
|
-
assertion = @__configurable__[property][:type]
|
145
|
-
return if value.is_a?(assertion)
|
146
|
-
|
147
|
-
::Kernel.fail(
|
148
|
-
ConfigurationError,
|
149
|
-
"#{property} must be configured with #{assertion} (got #{value.class})",
|
150
|
-
caller
|
151
|
-
)
|
152
|
-
end
|
153
|
-
|
154
|
-
# Block assertion for configurable properties
|
155
|
-
# @param [Symbol] property the property to type test
|
156
|
-
# @param [Any] value the given value
|
157
|
-
#
|
158
|
-
def __evaluate_block!(property, value)
|
159
|
-
return value unless __evaluable?(property, :block)
|
160
|
-
|
161
|
-
evaluation = @__configurable__[property][:block]
|
162
|
-
evaluation.call(value)
|
163
|
-
end
|
164
|
-
|
165
|
-
# @param [Symbol] property The property to test for
|
166
|
-
# @param [Symbol] assertion_type The evaluation type type to test for
|
167
|
-
# @return [Boolean] whether the given property is assertable
|
168
|
-
#
|
169
|
-
def __evaluable?(property, evaluation)
|
170
|
-
__configurable?(property) &&
|
171
|
-
@__configurable__[property].is_a?(::Hash) &&
|
172
|
-
@__configurable__[property].key?(evaluation)
|
173
|
-
end
|
174
116
|
end
|
175
117
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Configurations
|
2
|
+
module Validators
|
3
|
+
class Ambiguity
|
4
|
+
# @param [Hash] the hash to test for ambiguity
|
5
|
+
# @raise [Configurations::ConfigurationError] raises this error if
|
6
|
+
# a property is defined ambiguously
|
7
|
+
#
|
8
|
+
def validate!(h)
|
9
|
+
symbols, others = h.keys.partition { |k|
|
10
|
+
k.is_a?(::Symbol)
|
11
|
+
}
|
12
|
+
|
13
|
+
ambiguous = symbols.map(&:to_s) & others
|
14
|
+
|
15
|
+
unless ambiguous.empty?
|
16
|
+
::Kernel.fail(
|
17
|
+
::Configurations::ConfigurationError,
|
18
|
+
"Can not resolve configuration values for #{ambiguous.join(', ')} " \
|
19
|
+
"defined as both Symbol and #{others.first.class.name} keys. " \
|
20
|
+
'Please resolve the ambiguity.'
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Configurations
|
2
|
+
module Validators
|
3
|
+
class ReservedMethods
|
4
|
+
# @param [Symbol] method the method to test for reservedness
|
5
|
+
# @raise [Configurations::ReservedMethodError] raises this error if
|
6
|
+
# a property is a reserved method.
|
7
|
+
#
|
8
|
+
def validate!(method)
|
9
|
+
::Kernel.fail(
|
10
|
+
::Configurations::ReservedMethodError,
|
11
|
+
"#{method} is a reserved method and can not be assigned"
|
12
|
+
) if reserved?(method)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Reserved methods are not assignable. They define behaviour needed for
|
18
|
+
# the configuration object to work properly.
|
19
|
+
#
|
20
|
+
RESERVED_METHODS = [
|
21
|
+
:initialize,
|
22
|
+
:inspect,
|
23
|
+
:method_missing,
|
24
|
+
:object_id,
|
25
|
+
:singleton_class, # needed by rbx
|
26
|
+
:to_h,
|
27
|
+
:to_s # needed by rbx / 1.9.3 for inspect
|
28
|
+
]
|
29
|
+
|
30
|
+
# @param [Symbol] method the method to test for
|
31
|
+
# @return [TrueClass, FalseClass] whether the method is reserved
|
32
|
+
#
|
33
|
+
def reserved?(method)
|
34
|
+
RESERVED_METHODS.include?(method)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,50 +1,36 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class TestConfigurationSynchronized < MiniTest::Test
|
4
|
-
module
|
4
|
+
module TestModuleA
|
5
5
|
include Configurations
|
6
6
|
|
7
7
|
configuration_defaults do |c|
|
8
|
-
c.a =
|
8
|
+
c.a = -1
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
ids = []
|
15
|
-
threads = 100.times.map do |i|
|
16
|
-
Thread.new do
|
17
|
-
sleep rand(1000) / 1000.0
|
18
|
-
ids << TestModule.configure do |c|
|
19
|
-
c.a = i
|
20
|
-
end.a
|
21
|
-
end
|
22
|
-
end
|
23
|
-
threads.each(&:join)
|
12
|
+
module TestModuleB
|
13
|
+
include Configurations
|
24
14
|
|
25
|
-
|
15
|
+
configuration_defaults do |c|
|
16
|
+
c.a = -1
|
26
17
|
end
|
27
18
|
end
|
28
19
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
20
|
+
def test_configuration_synchronized
|
21
|
+
collector = []
|
22
|
+
semaphore = Mutex.new
|
23
|
+
threads = 100.times.map do |i|
|
24
|
+
Thread.new do
|
25
|
+
sleep i%50 / 1000.0
|
26
|
+
collector << TestModuleA.configure do |c|
|
27
|
+
c.a = i
|
28
|
+
end.a
|
34
29
|
end
|
35
|
-
|
36
|
-
there = TestModule.configuration.a
|
37
30
|
end
|
31
|
+
threads.each(&:join)
|
38
32
|
|
39
|
-
|
40
|
-
here = TestModule.configuration.a
|
41
|
-
|
42
|
-
assert_equal here, there
|
33
|
+
assert_equal 100, collector.uniq.size
|
43
34
|
end
|
44
35
|
|
45
|
-
def with_gc_disabled(&_block)
|
46
|
-
GC.disable
|
47
|
-
yield
|
48
|
-
GC.enable
|
49
|
-
end
|
50
36
|
end
|
@@ -49,9 +49,9 @@ module Tests
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_from_h_with_unambiguous_strings_and_symbols
|
52
|
-
|
53
|
-
assert_equal 2,
|
54
|
-
assert_equal 'bla',
|
52
|
+
config = @module.configure { |c| c.from_h('p1' => 'bla', :p2 => 2) }
|
53
|
+
assert_equal 2, config.p2
|
54
|
+
assert_equal 'bla', config.p1
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
data/test/run
ADDED
data/test/test_helper.rb
CHANGED
data/test/watch
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configurations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Beat Richartz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -17,13 +17,41 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '5.4'
|
20
|
-
type: :development
|
21
20
|
prerelease: false
|
21
|
+
type: :development
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest-focus
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: yard
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -31,8 +59,8 @@ dependencies:
|
|
31
59
|
- - "~>"
|
32
60
|
- !ruby/object:Gem::Version
|
33
61
|
version: '0.8'
|
34
|
-
type: :development
|
35
62
|
prerelease: false
|
63
|
+
type: :development
|
36
64
|
version_requirements: !ruby/object:Gem::Requirement
|
37
65
|
requirements:
|
38
66
|
- - "~>"
|
@@ -45,8 +73,8 @@ dependencies:
|
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
75
|
version: '10'
|
48
|
-
type: :development
|
49
76
|
prerelease: false
|
77
|
+
type: :development
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
@@ -72,8 +100,22 @@ files:
|
|
72
100
|
- lib/configurations/blank_object.rb
|
73
101
|
- lib/configurations/configurable.rb
|
74
102
|
- lib/configurations/configuration.rb
|
103
|
+
- lib/configurations/data.rb
|
75
104
|
- lib/configurations/error.rb
|
105
|
+
- lib/configurations/maps.rb
|
106
|
+
- lib/configurations/maps/blocks.rb
|
107
|
+
- lib/configurations/maps/data.rb
|
108
|
+
- lib/configurations/maps/properties.rb
|
109
|
+
- lib/configurations/maps/readers.rb
|
110
|
+
- lib/configurations/maps/readers/tolerant.rb
|
111
|
+
- lib/configurations/maps/types.rb
|
112
|
+
- lib/configurations/maps/writers.rb
|
113
|
+
- lib/configurations/maps/writers/default.rb
|
114
|
+
- lib/configurations/path.rb
|
76
115
|
- lib/configurations/strict.rb
|
116
|
+
- lib/configurations/validators.rb
|
117
|
+
- lib/configurations/validators/ambiguity.rb
|
118
|
+
- lib/configurations/validators/reserved_methods.rb
|
77
119
|
- test/configurations/arbitrary/test.rb
|
78
120
|
- test/configurations/arbitrary/test_defaults.rb
|
79
121
|
- test/configurations/arbitrary/test_hash_methods.rb
|
@@ -121,9 +163,11 @@ files:
|
|
121
163
|
- test/configurations/strict_with_blocks/test_methods.rb
|
122
164
|
- test/configurations/strict_with_blocks/test_not_configured.rb
|
123
165
|
- test/configurations/strict_with_blocks/test_not_configured_default.rb
|
166
|
+
- test/run
|
124
167
|
- test/support/setup.rb
|
125
168
|
- test/support/shared.rb
|
126
169
|
- test/test_helper.rb
|
170
|
+
- test/watch
|
127
171
|
homepage: http://github.com/beatrichartz/configurations
|
128
172
|
licenses:
|
129
173
|
- MIT
|
@@ -144,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
188
|
version: '0'
|
145
189
|
requirements: []
|
146
190
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.
|
191
|
+
rubygems_version: 2.5.1
|
148
192
|
signing_key:
|
149
193
|
specification_version: 4
|
150
194
|
summary: Configurations with a configure block from arbitrary to type-restricted for
|
@@ -197,7 +241,9 @@ test_files:
|
|
197
241
|
- test/configurations/strict_with_blocks/test_methods.rb
|
198
242
|
- test/configurations/strict_with_blocks/test_not_configured.rb
|
199
243
|
- test/configurations/strict_with_blocks/test_not_configured_default.rb
|
244
|
+
- test/run
|
200
245
|
- test/support/setup.rb
|
201
246
|
- test/support/shared.rb
|
202
247
|
- test/test_helper.rb
|
248
|
+
- test/watch
|
203
249
|
has_rdoc:
|