configurations 1.1.0 → 1.3.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 CHANGED
@@ -3,3 +3,4 @@
3
3
  Gemfile.lock
4
4
  doc
5
5
  coverage
6
+ *.gem
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.0.0-p481
1
+ 1.9.3-p547
data/README.md CHANGED
@@ -112,13 +112,81 @@ MyGem.configure do |c|
112
112
  end
113
113
  ```
114
114
 
115
+ ### Fourth way: Custom asserted or changed values
116
+
117
+ If you need further assertions or you need to change a value before it gets stored in the configuration, consider passing a block
118
+
119
+ ```
120
+ module MyGem
121
+ include Configurations
122
+ configurable :foo do |value|
123
+
124
+ # The return value is what gets assigned, unless it is nil,
125
+ # in which case the original value persists
126
+ #
127
+ value + ' ooooh my'
128
+ end
129
+ configurable String, bar: :baz do |value|
130
+
131
+ # value is guaranteed to be a string at this point
132
+ #
133
+ unless %w(bi ba bu).include?(value)
134
+ raise ArgumentError, 'baz needs to be one of bi, ba, bu'
135
+ end
136
+ end
137
+ end
138
+ ```
139
+
140
+ Gives your users:
141
+
142
+ ```
143
+ MyGem.configure do |c|
144
+ c.foo = 'FOO'
145
+ c.bar.baz = %w(bi)
146
+
147
+ # This would raise the ArgumentError in the block
148
+ # c.bar.baz = %w(boooh)
149
+ end
150
+ ```
151
+
115
152
  Gives you:
116
153
 
117
154
  ```
118
- MyGem.configuration.foo #=> 100% String
119
- MyGem.configuration.bar.baz #=> 100% Array
155
+ MyGem.configuration.foo #=> 'FOO ooooh my'
156
+ MyGem.configuration.bar.baz #=> one of %w(bi ba bu)
120
157
  ```
121
158
 
159
+ ### Configuration Methods
160
+
161
+ You might want to define methods on your configuration which use configuration values to bring out another value.
162
+ This is what `configuration_method` is here to help you with:
163
+
164
+ ```
165
+ module MyGem
166
+ include Configurations
167
+ configurable :foo, :bar
168
+ configuration_method :foobar do |arg|
169
+ foo + bar + arg
170
+ end
171
+ end
172
+ ```
173
+
174
+ Your users do:
175
+
176
+ ```
177
+ MyGem.configure do |c|
178
+ c.foo = 'FOO'
179
+ c.bar = 'BAR'
180
+ end
181
+ ```
182
+
183
+ You get:
184
+
185
+ ```
186
+ MyGem.configuration.foobar('ARG') #=> 'FOOBARARG'
187
+ ```
188
+
189
+
122
190
  ### Defaults:
123
191
 
124
192
  ```
@@ -134,7 +202,6 @@ end
134
202
 
135
203
  ```
136
204
  MyGem.configuration.to_h #=> a Hash
137
-
138
205
  ```
139
206
 
140
207
  ### Some caveats
@@ -12,5 +12,5 @@ module Configurations
12
12
 
13
13
  # Version number of Configurations
14
14
  #
15
- VERSION = '1.1.0'
15
+ VERSION = '1.3.0'
16
16
  end
@@ -49,11 +49,31 @@ module Configurations
49
49
  # configurable can be used to set the properties which should be configurable, as well as a type which
50
50
  # the given property should be asserted to
51
51
  # @param [Class, Symbol, Hash] properties a type as a first argument to type assert (if any) or nested properties to allow for setting
52
+ # @param [Proc] block a block with arity 2 to evaluate when a property is set. It will be given: property name and value
52
53
  #
53
- def configurable(*properties)
54
+ def configurable(*properties, &block)
54
55
  type = properties.shift if properties.first.is_a?(Class)
55
56
  @configurable ||= {}
56
- @configurable.merge!(to_configurable_hash(properties, type))
57
+ @configurable.merge!(to_configurable_hash(properties, type, &block))
58
+ end
59
+
60
+ # returns whether a property is set to be configurable
61
+ # @param [Symbol] property the property to ask status for
62
+ #
63
+ def configurable?(property)
64
+ @configurable.is_a?(Hash) && @configurable.has_key?(property)
65
+ end
66
+
67
+ # configuration method can be used to retrieve properties from the configuration which use your gem's context
68
+ # @param [Class, Symbol, Hash] properties properties for retrieval
69
+ # @param [Proc] block the block to evaluate
70
+ #
71
+ def configuration_method(method, &block)
72
+ raise ArgumentError, "#{method} can not be both a configurable property and a configuration method" if configurable?(method)
73
+
74
+ Configuration.class_eval do
75
+ define_method method, &block
76
+ end
57
77
  end
58
78
 
59
79
  private
@@ -63,8 +83,13 @@ module Configurations
63
83
  # @param [Class] type the type to assert, if any
64
84
  # @return a hash with configurable values pointing to their types
65
85
  #
66
- def to_configurable_hash(properties, type)
67
- Hash[properties.zip(Array(type) * properties.size)]
86
+ def to_configurable_hash(properties, type, &block)
87
+ assertion_hash = {}
88
+ assertion_hash.merge! block: block if block_given?
89
+ assertion_hash.merge! type: type if type
90
+
91
+ assertions = ([assertion_hash] * properties.size)
92
+ Hash[properties.zip(assertions)]
68
93
  end
69
94
  end
70
95
  end
@@ -59,21 +59,21 @@ module Configurations
59
59
  #
60
60
  def method_missing(method, *args, &block)
61
61
  property = method.to_s[0..-2].to_sym
62
+ value = args.first
62
63
 
63
64
  if _is_writer?(method) && @_writeable && _configurable?(property)
64
- _assert_type!(property, args.first)
65
- @configuration[property] = args.first
65
+ _assign!(property, value)
66
66
  elsif !_is_writer?(method) && @_writeable || _configured?(method)
67
67
  @configuration[method]
68
68
  else
69
- super
69
+ ::Kernel.send(method, *args, &block)
70
70
  end
71
71
  end
72
72
 
73
73
  # Respond to missing according to the method_missing implementation
74
74
  #
75
75
  def respond_to_missing?(method, include_private = false)
76
- is_setter?(method) || @_writeable || _configured?(method) || super
76
+ is_setter?(method) || @_writeable || _configured?(method) || ::Kernel.respond_to_missing?(method, include_private)
77
77
  end
78
78
 
79
79
  # Set the configuration to writeable or read only. Access to writer methods is only allowed within the
@@ -98,8 +98,6 @@ module Configurations
98
98
  end
99
99
  end
100
100
 
101
- private
102
-
103
101
  # @param [Symbol] property The property to test for configurability
104
102
  # @return [Boolean] whether the given property is configurable
105
103
  #
@@ -107,6 +105,15 @@ module Configurations
107
105
  _arbitrarily_configurable? or @configurable.has_key?(property)
108
106
  end
109
107
 
108
+
109
+ # @return [Boolean] whether this configuration is arbitrarily configurable
110
+ #
111
+ def _arbitrarily_configurable?
112
+ @configurable.nil? or @configurable.empty?
113
+ end
114
+
115
+ private
116
+
110
117
  # @param [Symbol] property The property to test for
111
118
  # @return [Boolean] whether the given property has been configured
112
119
  #
@@ -127,10 +134,10 @@ module Configurations
127
134
  def _evaluate_configurable!
128
135
  return if _arbitrarily_configurable?
129
136
 
130
- @configurable.each do |k, type|
137
+ @configurable.each do |k, assertion|
131
138
  if k.is_a?(::Hash)
132
139
  k.each do |property, nested|
133
- @configuration[property] = Configuration.new(nil, _to_configurable_hash(nested, type))
140
+ @configuration[property] = Configuration.new(nil, _to_configurable_hash(nested, assertion))
134
141
  end
135
142
  end
136
143
  end
@@ -140,9 +147,20 @@ module Configurations
140
147
  # @param [Class] type the type to assert, if any
141
148
  # @return a hash with configurable values pointing to their types
142
149
  #
143
- def _to_configurable_hash(value, type)
150
+ def _to_configurable_hash(value, assertion)
144
151
  value = [value] unless value.is_a?(::Array)
145
- ::Hash[value.zip([type].flatten*value.size)]
152
+ ::Hash[value.zip([assertion].flatten*value.size)]
153
+ end
154
+
155
+ # Assigns a value after running the assertions
156
+ # @param [Symbol] property the property to type test
157
+ # @param [Any] value the given value
158
+ #
159
+ def _assign!(property, value)
160
+ v = _evaluate_block!(property, value)
161
+ value = v unless v.nil?
162
+ _assert_type!(property, value)
163
+ @configuration[property] = value
146
164
  end
147
165
 
148
166
  # Type assertion for configurable properties
@@ -151,18 +169,29 @@ module Configurations
151
169
  # @raise [ConfigurationError] if the given value has the wrong type
152
170
  #
153
171
  def _assert_type!(property, value)
154
- return if _arbitrarily_configurable?
172
+ return unless _evaluable?(property, :type)
155
173
 
156
- expected_type = @configurable[property]
157
- return if expected_type.nil?
174
+ assertion = @configurable[property][:type]
175
+ ::Kernel.raise ConfigurationError, "Expected #{property} to be configured with #{expected_type}, but got #{value.class.inspect}", caller unless value.is_a?(assertion)
176
+ end
158
177
 
159
- ::Kernel.raise ConfigurationError, "Expected #{property} to be configured with #{expected_type}, but got #{value.class.inspect}", caller unless value.is_a?(expected_type)
178
+ # Block assertion for configurable properties
179
+ # @param [Symbol] property the property to type test
180
+ # @param [Any] value the given value
181
+ #
182
+ def _evaluate_block!(property, value)
183
+ return value unless _evaluable?(property, :block)
184
+
185
+ evaluation = @configurable[property][:block]
186
+ evaluation.call(value)
160
187
  end
161
188
 
162
- # @return [Boolean] whether this configuration is arbitrarily configurable
189
+ # @param [Symbol] property The property to test for
190
+ # @param [Symbol] assertion_type The evaluation type type to test for
191
+ # @return [Boolean] whether the given property is assertable
163
192
  #
164
- def _arbitrarily_configurable?
165
- @configurable.nil? or @configurable.empty?
193
+ def _evaluable?(property, evaluation)
194
+ @configurable and @configurable.has_key?(property) and @configurable[property].is_a?(::Hash) and @configurable[property].has_key?(evaluation)
166
195
  end
167
196
 
168
197
  # @param [Symbol] method the method to test for
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ class TestStricterConfigurationWithBlock < Minitest::Test
4
+
5
+ BlocksConfigurationTestModule = testmodule_for(Configurations)
6
+ BlocksConfigurationTestModule.module_eval do
7
+ configurable :property1, :property2 do |value|
8
+ value.to_s + 'oooh'
9
+ end
10
+ configurable String, :property3, property4: [:property5, :property6] do |value|
11
+ raise ArgumentError, 'TEST2' unless %w(hello bye).include?(value)
12
+ value
13
+ end
14
+ end
15
+
16
+ def setup
17
+ BlocksConfigurationTestModule.configure do |c|
18
+ c.property1 = :one
19
+ c.property2 = :two
20
+ c.property3 = 'hello'
21
+ c.property4.property5 = 'hello'
22
+ c.property4.property6 = 'bye'
23
+ end
24
+
25
+ @configuration = BlocksConfigurationTestModule.configuration
26
+ end
27
+
28
+ def test_configurable_when_set_configurable_with_block
29
+ assert_equal 'oneoooh', @configuration.property1
30
+ assert_equal 'twooooh', @configuration.property2
31
+ end
32
+
33
+ def test_nested_configurable_when_set_configurable_with_block
34
+ assert_equal 'hello', @configuration.property4.property5
35
+ assert_equal 'bye', @configuration.property4.property6
36
+ end
37
+
38
+ def test_evaluates_block_for_nested_properties_when_set_configurable_with_block
39
+ assert_raises ArgumentError, 'TEST2' do
40
+ BlocksConfigurationTestModule.configure do |c|
41
+ c.property4.property5 = 'oh'
42
+ end
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ class TestConfigurationMethods < Minitest::Test
4
+
5
+ ConfigurationMethodsClassModule = testmodule_for(Configurations)
6
+ ConfigurationMethodsClassModule.module_eval do
7
+ class MyClass
8
+ attr_reader :props
9
+ def initialize(*props)
10
+ @props = props
11
+ end
12
+ end
13
+
14
+ context = 'CONTEXT'
15
+ configurable :property1, :property2
16
+ configuration_method :method1 do
17
+ MyClass.new(property1, property2)
18
+ end
19
+ configuration_method :method2 do
20
+ context + property1.to_s
21
+ end
22
+ configuration_method :method3 do |arg|
23
+ arg + property1.to_s
24
+ end
25
+ configuration_method :kernel_raise do
26
+ raise StandardError, 'hell'
27
+ end
28
+ end
29
+
30
+ def setup
31
+ ConfigurationMethodsClassModule.configure do |c|
32
+ c.property1 = :one
33
+ c.property2 = :two
34
+ end
35
+
36
+ @configuration = ConfigurationMethodsClassModule.configuration
37
+ end
38
+
39
+ def test_configuration_method
40
+ assert_equal [:one, :two], @configuration.method1.props
41
+ end
42
+
43
+ def test_configuration_method_with_context
44
+ assert_equal 'CONTEXTone', @configuration.method2
45
+ end
46
+
47
+ def test_configuration_method_with_arguments
48
+ assert_equal 'ARGone', @configuration.method3('ARG')
49
+ end
50
+
51
+ def test_kernel_methods_in_configuration_method
52
+ assert_raises StandardError, 'hell' do
53
+ @configuration.kernel_raise
54
+ end
55
+ end
56
+
57
+ def test_configuration_method_overwrite
58
+ assert_raises ArgumentError do
59
+ ConfigurationMethodsClassModule.module_eval do
60
+ configuration_method :property2 do |c|
61
+ MyClass.new(c.property2)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: configurations
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Beat Richartz
@@ -13,6 +14,7 @@ dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: minitest
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - ~>
18
20
  - !ruby/object:Gem::Version
@@ -20,6 +22,7 @@ dependencies:
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - ~>
25
28
  - !ruby/object:Gem::Version
@@ -27,6 +30,7 @@ dependencies:
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: yard
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
35
  - - ~>
32
36
  - !ruby/object:Gem::Version
@@ -34,6 +38,7 @@ dependencies:
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
43
  - - ~>
39
44
  - !ruby/object:Gem::Version
@@ -41,6 +46,7 @@ dependencies:
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: rake
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
51
  - - ~>
46
52
  - !ruby/object:Gem::Version
@@ -48,6 +54,7 @@ dependencies:
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
59
  - - ~>
53
60
  - !ruby/object:Gem::Version
@@ -72,37 +79,42 @@ files:
72
79
  - lib/configurations/configurable.rb
73
80
  - lib/configurations/configuration.rb
74
81
  - lib/configurations/error.rb
82
+ - test/configurations/test_configurable_with_blocks_configuration.rb
75
83
  - test/configurations/test_configuration.rb
84
+ - test/configurations/test_configuration_methods.rb
76
85
  - test/configurations/test_stricter_configuration.rb
77
86
  - test/support/testmodules.rb
78
87
  - test/test_helper.rb
79
88
  homepage: http://github.com/beatrichartz/configurations
80
89
  licenses:
81
90
  - MIT
82
- metadata: {}
83
91
  post_install_message:
84
92
  rdoc_options: []
85
93
  require_paths:
86
94
  - lib
87
95
  required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
88
97
  requirements:
89
- - - '>='
98
+ - - ! '>='
90
99
  - !ruby/object:Gem::Version
91
100
  version: '0'
92
101
  required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
93
103
  requirements:
94
- - - '>='
104
+ - - ! '>='
95
105
  - !ruby/object:Gem::Version
96
106
  version: '0'
97
107
  requirements: []
98
108
  rubyforge_project:
99
- rubygems_version: 2.0.14
109
+ rubygems_version: 1.8.23.2
100
110
  signing_key:
101
- specification_version: 4
111
+ specification_version: 3
102
112
  summary: Configurations with a configure block from arbitrary to type-restricted for
103
113
  your gem or other ruby code.
104
114
  test_files:
115
+ - test/configurations/test_configurable_with_blocks_configuration.rb
105
116
  - test/configurations/test_configuration.rb
117
+ - test/configurations/test_configuration_methods.rb
106
118
  - test/configurations/test_stricter_configuration.rb
107
119
  - test/support/testmodules.rb
108
120
  - test/test_helper.rb
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 039597b55adc73ff8cddc05edd7c199f5f2c252f
4
- data.tar.gz: 1dec69ab7582283ab60f950dc3caa96e92ff2b95
5
- SHA512:
6
- metadata.gz: e7a927942a4bce9f187a1f491f9469ac898cc62e2687c3b2111163d6b8b665ebaea70767f52fabcdb2e11c1544bc005168610317632ecabe8211373c993897d3
7
- data.tar.gz: 97ae55c4e7c2ccae76aab97aa75c912c4b79bbf4a5fc7ebdb752b7150d9b0be821598fc9f060f484e7b456a1a153072a5a5672260c2ca96548d1c2789c6ca89e