configurations 2.0.0 → 2.2.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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/README.md +48 -29
- data/lib/configurations.rb +1 -1
- data/lib/configurations/arbitrary.rb +9 -7
- data/lib/configurations/blank_object.rb +3 -1
- data/lib/configurations/configurable.rb +78 -19
- data/lib/configurations/configuration.rb +88 -7
- data/lib/configurations/error.rb +5 -0
- data/lib/configurations/strict.rb +6 -1
- data/test/configurations/arbitrary/test_reserved_methods.rb +13 -0
- data/test/configurations/arbitrary/test_reserved_methods_as_methods.rb +15 -0
- data/test/configurations/configuration/test_configure_synchronized.rb +50 -0
- data/test/configurations/configuration/test_inspect.rb +19 -0
- data/test/configurations/configuration/test_instantiation_prevention.rb +8 -0
- data/test/configurations/configuration/test_is_a_configuration.rb +6 -0
- data/test/configurations/shared/hash_methods.rb +18 -0
- data/test/configurations/shared/strict_hash_methods.rb +9 -0
- data/test/configurations/strict/test_reserved_methods.rb +13 -0
- data/test/configurations/strict/test_reserved_methods_as_methods.rb +15 -0
- data/test/support/setup.rb +2 -2
- metadata +18 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a0d503a4163d4238d71c61d2349a78e5f74b59be
         | 
| 4 | 
            +
              data.tar.gz: 21343c5d0ff8b12c948caced4f73bb74a04d2083
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 71026df8af3278a819d01c1ce0729a27d86ef8a83845596a4301730eee4fb585afeb1ca0f6681c23ac68a1fc74237880fb332bb720d7b6cffb9daecac54f445f
         | 
| 7 | 
            +
              data.tar.gz: 354aea5c774097ef557c2ce645f55c124fe2f5f0684fb0c01e205741c8afc8a2134aa00a0994528303c2e9f44d20c4d17387148f1004871ba19d8877d6d2a9be
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -6,17 +6,21 @@ Configurations provides a unified approach to do configurations using the `MyGem | |
| 6 6 |  | 
| 7 7 | 
             
            ## Install
         | 
| 8 8 |  | 
| 9 | 
            -
             | 
| 9 | 
            +
            ```ruby
         | 
| 10 | 
            +
            gem install configurations
         | 
| 11 | 
            +
            ```
         | 
| 10 12 |  | 
| 11 13 | 
             
            or with Bundler
         | 
| 12 14 |  | 
| 13 | 
            -
             | 
| 15 | 
            +
            ```ruby
         | 
| 16 | 
            +
            gem 'configurations', '~> 2.2.0'
         | 
| 17 | 
            +
            ```
         | 
| 14 18 |  | 
| 15 19 | 
             
            Configurations uses [Semver 2.0](http://semver.org/)
         | 
| 16 20 |  | 
| 17 21 | 
             
            ## Compatibility
         | 
| 18 22 |  | 
| 19 | 
            -
            Compatible with MRI 1.9.2 - 2.2, Rubinius 2. | 
| 23 | 
            +
            Compatible with MRI 1.9.2 - 2.2, Rubinius 2.x, jRuby 1.7 and 9K
         | 
| 20 24 |  | 
| 21 25 | 
             
            ## Why?
         | 
| 22 26 |  | 
| @@ -32,7 +36,7 @@ Less time copy pasting configuration code, more time writing exciting code for y | |
| 32 36 |  | 
| 33 37 | 
             
            Go boom! with ease. This allows your gem / code users to set any value they like.
         | 
| 34 38 |  | 
| 35 | 
            -
            ```
         | 
| 39 | 
            +
            ```ruby
         | 
| 36 40 | 
             
            module MyGem
         | 
| 37 41 | 
             
              include Configurations
         | 
| 38 42 | 
             
            end
         | 
| @@ -40,7 +44,7 @@ end | |
| 40 44 |  | 
| 41 45 | 
             
            Gives your users:
         | 
| 42 46 |  | 
| 43 | 
            -
            ```
         | 
| 47 | 
            +
            ```ruby
         | 
| 44 48 | 
             
            MyGem.configure do |c|
         | 
| 45 49 | 
             
              c.foo.bar.baz = 'fizz'
         | 
| 46 50 | 
             
              c.hi = 'Hello-o'
         | 
| @@ -50,20 +54,20 @@ end | |
| 50 54 |  | 
| 51 55 | 
             
            Gives you:
         | 
| 52 56 |  | 
| 53 | 
            -
            ```
         | 
| 57 | 
            +
            ```ruby
         | 
| 54 58 | 
             
            MyGem.configuration.class #=> 'oooh wow'
         | 
| 55 59 | 
             
            MyGem.configuration.foo.bar.baz #=> 'fizz'
         | 
| 56 60 | 
             
            ```
         | 
| 57 61 |  | 
| 58 62 | 
             
            Undefined properties on an arbitrary configuration will return `nil`
         | 
| 59 63 |  | 
| 60 | 
            -
            ```
         | 
| 64 | 
            +
            ```ruby
         | 
| 61 65 | 
             
            MyGem.configuration.not_set #=> nil
         | 
| 62 66 | 
             
            ```
         | 
| 63 67 |  | 
| 64 68 | 
             
            If you want to define the behaviour for not set properties yourself, use `not_configured`. You can either define a catch-all `not_configured` which will be executed whenever you call a value that has not been configured and has no default:
         | 
| 65 69 |  | 
| 66 | 
            -
            ```
         | 
| 70 | 
            +
            ```ruby
         | 
| 67 71 | 
             
            module MyGem
         | 
| 68 72 | 
             
              not_configured do |prop|
         | 
| 69 73 | 
             
            	raise NoMethodError, "#{prop} must be configured"
         | 
| @@ -73,7 +77,7 @@ end | |
| 73 77 |  | 
| 74 78 | 
             
            Or you can define finer-grained callbacks:
         | 
| 75 79 |  | 
| 76 | 
            -
            ```
         | 
| 80 | 
            +
            ```ruby
         | 
| 77 81 | 
             
            module MyGem
         | 
| 78 82 | 
             
              not_configured my: { nested: :prop } do |prop|
         | 
| 79 83 | 
             
            	raise NoMethodError, "#{prop} must be configured"
         | 
| @@ -85,7 +89,7 @@ end | |
| 85 89 |  | 
| 86 90 | 
             
            If you just want some properties to be configurable, consider this option
         | 
| 87 91 |  | 
| 88 | 
            -
            ```
         | 
| 92 | 
            +
            ```ruby
         | 
| 89 93 | 
             
            module MyGem
         | 
| 90 94 | 
             
              include Configurations
         | 
| 91 95 | 
             
              configurable :foo, bar: :baz, biz: %i(bi ba bu)
         | 
| @@ -94,7 +98,7 @@ end | |
| 94 98 |  | 
| 95 99 | 
             
            Gives your users:
         | 
| 96 100 |  | 
| 97 | 
            -
            ```
         | 
| 101 | 
            +
            ```ruby
         | 
| 98 102 | 
             
            MyGem.configure do |c|
         | 
| 99 103 | 
             
              c.foo = 'FOO'
         | 
| 100 104 | 
             
              c.bar.baz = 'FIZZ'
         | 
| @@ -108,23 +112,23 @@ end | |
| 108 112 |  | 
| 109 113 | 
             
            Gives you:
         | 
| 110 114 |  | 
| 111 | 
            -
            ```
         | 
| 115 | 
            +
            ```ruby
         | 
| 112 116 | 
             
            MyGem.configuration.foo #=> 'FOO'
         | 
| 113 117 | 
             
            MyGem.configuration.bar.baz #=> 'FIZZ'
         | 
| 114 118 | 
             
            ```
         | 
| 115 119 |  | 
| 116 120 | 
             
            Not configured properties on a restricted configuration will raise `NoMethodError`
         | 
| 117 121 |  | 
| 118 | 
            -
            ```
         | 
| 122 | 
            +
            ```ruby
         | 
| 119 123 | 
             
            MyGem.configuration.not_set #=> <#NoMethodError>
         | 
| 120 124 | 
             
            ```
         | 
| 121 125 |  | 
| 122 126 | 
             
            If you want to define the behaviour for not set properties yourself, use `not_configured`. This will only affect properties set to configurable. All not configurable properties will raise `NoMethodError`.
         | 
| 123 127 |  | 
| 124 | 
            -
            ```
         | 
| 128 | 
            +
            ```ruby
         | 
| 125 129 | 
             
            module MyGem
         | 
| 126 130 | 
             
              not_configured :awesome, :nice do |prop| # omit the arguments to get a catch-all not_configured
         | 
| 127 | 
            -
            	warn :not_configured, "Please configure #{prop} or live in danger"
         | 
| 131 | 
            +
            	warn :not_configured, "Please configure #{prop} or live in danger: youtube.com/watch?v=yZ15vCGuvH0"
         | 
| 128 132 | 
             
              end
         | 
| 129 133 | 
             
            end
         | 
| 130 134 | 
             
            ```
         | 
| @@ -133,7 +137,7 @@ end | |
| 133 137 |  | 
| 134 138 | 
             
            If you want to make sure your configurations only accept one type, consider this option
         | 
| 135 139 |  | 
| 136 | 
            -
            ```
         | 
| 140 | 
            +
            ```ruby
         | 
| 137 141 | 
             
            module MyGem
         | 
| 138 142 | 
             
              include Configurations
         | 
| 139 143 | 
             
              configurable String, :foo
         | 
| @@ -143,7 +147,7 @@ end | |
| 143 147 |  | 
| 144 148 | 
             
            Gives your users:
         | 
| 145 149 |  | 
| 146 | 
            -
            ```
         | 
| 150 | 
            +
            ```ruby
         | 
| 147 151 | 
             
            MyGem.configure do |c|
         | 
| 148 152 | 
             
              c.foo = 'FOO'
         | 
| 149 153 | 
             
              c.bar.baz = %w(hello)
         | 
| @@ -158,7 +162,7 @@ end | |
| 158 162 |  | 
| 159 163 | 
             
            If you need further assertions or you need to change a value before it gets stored in the configuration, consider passing a block
         | 
| 160 164 |  | 
| 161 | 
            -
            ```
         | 
| 165 | 
            +
            ```ruby
         | 
| 162 166 | 
             
            module MyGem
         | 
| 163 167 | 
             
              include Configurations
         | 
| 164 168 | 
             
              configurable :foo do |value|
         | 
| @@ -181,7 +185,7 @@ end | |
| 181 185 |  | 
| 182 186 | 
             
            Gives your users:
         | 
| 183 187 |  | 
| 184 | 
            -
            ```
         | 
| 188 | 
            +
            ```ruby
         | 
| 185 189 | 
             
            MyGem.configure do |c|
         | 
| 186 190 | 
             
              c.foo = 'FOO'
         | 
| 187 191 | 
             
              c.bar.baz = %w(bi)
         | 
| @@ -193,7 +197,7 @@ end | |
| 193 197 |  | 
| 194 198 | 
             
            Gives you:
         | 
| 195 199 |  | 
| 196 | 
            -
            ```
         | 
| 200 | 
            +
            ```ruby
         | 
| 197 201 | 
             
            MyGem.configuration.foo #=> 'FOO ooooh my'
         | 
| 198 202 | 
             
            MyGem.configuration.bar.baz #=> one of %w(bi ba bu)
         | 
| 199 203 | 
             
            ```
         | 
| @@ -203,7 +207,7 @@ MyGem.configuration.bar.baz #=> one of %w(bi ba bu) | |
| 203 207 | 
             
            You might want to define methods on your configuration which use configuration values to bring out another value.
         | 
| 204 208 | 
             
            This is what `configuration_method` is here to help you with:
         | 
| 205 209 |  | 
| 206 | 
            -
            ```
         | 
| 210 | 
            +
            ```ruby
         | 
| 207 211 | 
             
            module MyGem
         | 
| 208 212 | 
             
              include Configurations
         | 
| 209 213 | 
             
              configurable :foo, :bar
         | 
| @@ -215,7 +219,7 @@ end | |
| 215 219 |  | 
| 216 220 | 
             
            Your users do:
         | 
| 217 221 |  | 
| 218 | 
            -
            ```
         | 
| 222 | 
            +
            ```ruby
         | 
| 219 223 | 
             
            MyGem.configure do |c|
         | 
| 220 224 | 
             
              c.foo = 'FOO'
         | 
| 221 225 | 
             
              c.bar = 'BAR'
         | 
| @@ -224,13 +228,13 @@ end | |
| 224 228 |  | 
| 225 229 | 
             
            You get:
         | 
| 226 230 |  | 
| 227 | 
            -
            ```
         | 
| 231 | 
            +
            ```ruby
         | 
| 228 232 | 
             
            MyGem.configuration.foobar('ARG') #=> 'FOOBARARG'
         | 
| 229 233 | 
             
            ```
         | 
| 230 234 |  | 
| 231 235 | 
             
            configuration methods can also be installed on nested properties using hashes:
         | 
| 232 236 |  | 
| 233 | 
            -
            ```
         | 
| 237 | 
            +
            ```ruby
         | 
| 234 238 | 
             
            configuration_method foo: :bar do |arg|
         | 
| 235 239 | 
             
              foo + bar + arg
         | 
| 236 240 | 
             
            end
         | 
| @@ -238,7 +242,7 @@ end | |
| 238 242 |  | 
| 239 243 | 
             
            ### Defaults:
         | 
| 240 244 |  | 
| 241 | 
            -
            ```
         | 
| 245 | 
            +
            ```ruby
         | 
| 242 246 | 
             
            module MyGem
         | 
| 243 247 | 
             
              include Configurations
         | 
| 244 248 | 
             
              configuration_defaults do |c|
         | 
| @@ -249,7 +253,7 @@ end | |
| 249 253 |  | 
| 250 254 | 
             
            ### Get a hash if you need it
         | 
| 251 255 |  | 
| 252 | 
            -
            ```
         | 
| 256 | 
            +
            ```ruby
         | 
| 253 257 | 
             
            MyGem.configuration.to_h #=> a Hash
         | 
| 254 258 | 
             
            ```
         | 
| 255 259 |  | 
| @@ -257,7 +261,7 @@ MyGem.configuration.to_h #=> a Hash | |
| 257 261 |  | 
| 258 262 | 
             
            Sometimes your users will have a hash of configuration values which are not handy to press into the block form. In that case, they can use `from_h` inside the `configure` block to either read in the full or a nested configuration. With a everything besides arbitrary configurations, `from_h` can also be used outside the block.
         | 
| 259 263 |  | 
| 260 | 
            -
            ```
         | 
| 264 | 
            +
            ```ruby
         | 
| 261 265 | 
             
            yaml_hash = YAML.load_file('configuration.yml')
         | 
| 262 266 |  | 
| 263 267 | 
             
            MyGem.configure do |c|
         | 
| @@ -268,8 +272,23 @@ end | |
| 268 272 |  | 
| 269 273 | 
             
            ### Some caveats
         | 
| 270 274 |  | 
| 271 | 
            -
             | 
| 272 | 
            -
             | 
| 275 | 
            +
            #### Reserved Methods
         | 
| 276 | 
            +
            These are reserved methods on the configuration instance and should not be defined:
         | 
| 277 | 
            +
            - `initialize`
         | 
| 278 | 
            +
            - `inspect`
         | 
| 279 | 
            +
            - `method_missing`
         | 
| 280 | 
            +
            - `object_id`
         | 
| 281 | 
            +
            - `singleton_class`
         | 
| 282 | 
            +
            - `to_h`
         | 
| 283 | 
            +
            - `to_s`
         | 
| 284 | 
            +
             | 
| 285 | 
            +
            `Configuration` inherits from `BasicObject`, so method names defined through `Kernel` and `Object` are available.
         | 
| 286 | 
            +
             | 
| 287 | 
            +
            ## Thread safety
         | 
| 288 | 
            +
            Configuration is synchronized. Re-configuration via the `configure` block switches out the configuration in place rather than mutating its properties, so don't hold on to configuration objects in another context.
         | 
| 289 | 
            +
            That said, please bear in mind that keeping mutable state in configurations is as bad an idea as every other kind of global mutable state, if you expect values to change at runtime, configurations are not the right place to keep them:
         | 
| 290 | 
            +
             | 
| 291 | 
            +
            Encourage your users to configure once when initializing the environment, reconfigure on reload, but never ever at runtime.
         | 
| 273 292 |  | 
| 274 293 | 
             
            ## Contributing
         | 
| 275 294 |  | 
    
        data/lib/configurations.rb
    CHANGED
    
    
| @@ -3,7 +3,7 @@ module Configurations | |
| 3 3 | 
             
              # Configuration is a blank object in order to allow configuration of
         | 
| 4 4 | 
             
              # various properties including keywords
         | 
| 5 5 | 
             
              #
         | 
| 6 | 
            -
               | 
| 6 | 
            +
              module Arbitrary
         | 
| 7 7 | 
             
                # Initialize a new configuration
         | 
| 8 8 | 
             
                # @param [Hash] options The options to initialize a configuration with
         | 
| 9 9 | 
             
                # @option options [Hash] methods a hash of method names pointing to procs
         | 
| @@ -50,7 +50,8 @@ module Configurations | |
| 50 50 | 
             
                # @return [Configuration] the configuration with values assigned
         | 
| 51 51 | 
             
                # @note can only be accessed during writeable state (in configure block).
         | 
| 52 52 | 
             
                #   Unassignable values are ignored
         | 
| 53 | 
            -
                # @raise [ArgumentError] unless used in writeable state | 
| 53 | 
            +
                # @raise [ArgumentError] unless used in writeable state
         | 
| 54 | 
            +
                #   (in configure block)
         | 
| 54 55 | 
             
                #
         | 
| 55 56 | 
             
                def from_h(h)
         | 
| 56 57 | 
             
                  unless @__writeable__
         | 
| @@ -70,8 +71,8 @@ module Configurations | |
| 70 71 | 
             
                # Set the configuration to writeable or read only. Access to writer methods
         | 
| 71 72 | 
             
                # is only allowed within the configure block, this method is used to invoke
         | 
| 72 73 | 
             
                # writeability for subconfigurations.
         | 
| 73 | 
            -
                # @param [Boolean] data true if the configuration should be writeable, | 
| 74 | 
            -
                #   otherwise
         | 
| 74 | 
            +
                # @param [Boolean] data true if the configuration should be writeable,
         | 
| 75 | 
            +
                #   false otherwise
         | 
| 75 76 | 
             
                #
         | 
| 76 77 | 
             
                def __writeable__=(data)
         | 
| 77 78 | 
             
                  @__writeable__ = data
         | 
| @@ -99,15 +100,16 @@ module Configurations | |
| 99 100 | 
             
                end
         | 
| 100 101 |  | 
| 101 102 | 
             
                # @param [Symbol] method the method to test for
         | 
| 102 | 
            -
                # @return [Boolean] whether the configuration responds to the given | 
| 103 | 
            -
                #   as a method during writeable state
         | 
| 103 | 
            +
                # @return [Boolean] whether the configuration responds to the given
         | 
| 104 | 
            +
                #   property as a method during writeable state
         | 
| 104 105 | 
             
                #
         | 
| 105 106 | 
             
                def __respond_to_method_for_write?(method)
         | 
| 106 107 | 
             
                  !__is_writer?(method) && @__writeable__ && @data[method].is_a?(__class__)
         | 
| 107 108 | 
             
                end
         | 
| 108 109 |  | 
| 109 110 | 
             
                # @param [Symbol] method the method to test for
         | 
| 110 | 
            -
                # @return [Boolean] whether the configuration responds to the | 
| 111 | 
            +
                # @return [Boolean] whether the configuration responds to the
         | 
| 112 | 
            +
                #   given property
         | 
| 111 113 | 
             
                #
         | 
| 112 114 | 
             
                def __respond_to_method_for_read?(method, *args, &block)
         | 
| 113 115 | 
             
                  !__is_writer?(method) && args.empty? && block.nil?
         | 
| @@ -8,6 +8,7 @@ module Configurations | |
| 8 8 | 
             
                  :equal?,
         | 
| 9 9 | 
             
                  :object_id,
         | 
| 10 10 | 
             
                  :__id__,
         | 
| 11 | 
            +
                  :__instance_variables__,
         | 
| 11 12 | 
             
                  :__send__,
         | 
| 12 13 | 
             
                  :method_missing
         | 
| 13 14 | 
             
                ].freeze
         | 
| @@ -26,11 +27,12 @@ module Configurations | |
| 26 27 | 
             
                  :respond_to?,
         | 
| 27 28 | 
             
                  :is_a?,
         | 
| 28 29 | 
             
                  :inspect,
         | 
| 30 | 
            +
                  :to_s,
         | 
| 29 31 | 
             
                  :object_id,
         | 
| 30 32 | 
             
                  # rbx needs the singleton class to access singleton methods
         | 
| 31 33 | 
             
                  :singleton_class,
         | 
| 32 34 | 
             
                  *ALIAS_KERNEL_METHODS.keys
         | 
| 33 | 
            -
                ].freeze
         | 
| 35 | 
            +
                ].compact.freeze
         | 
| 34 36 |  | 
| 35 37 | 
             
                # Undefines every instance method except the kept methods
         | 
| 36 38 | 
             
                #
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'thread'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Configurations
         | 
| 2 4 | 
             
              # Module configurable provides the API of configurations
         | 
| 3 5 | 
             
              #
         | 
| @@ -9,16 +11,32 @@ module Configurations | |
| 9 11 | 
             
                #
         | 
| 10 12 | 
             
                def included(base)
         | 
| 11 13 | 
             
                  install_configure_in(base)
         | 
| 12 | 
            -
                  base. | 
| 14 | 
            +
                  base.instance_eval do
         | 
| 13 15 | 
             
                    extend ClassMethods
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    # call configuration_mutex once to initialize the value
         | 
| 18 | 
            +
                    #
         | 
| 19 | 
            +
                    initialize_configuration!
         | 
| 14 20 | 
             
                  end
         | 
| 15 21 | 
             
                end
         | 
| 16 22 |  | 
| 23 | 
            +
                def underscore_camelized(string)
         | 
| 24 | 
            +
                  string.gsub(/::/, '/')
         | 
| 25 | 
            +
                    .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
         | 
| 26 | 
            +
                    .gsub(/([a-z\d])([A-Z])/, '\1_\2')
         | 
| 27 | 
            +
                    .tr('-', '_')
         | 
| 28 | 
            +
                    .downcase
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 17 31 | 
             
                # Installs #configure in base, and makes sure that it will instantiate
         | 
| 18 32 | 
             
                # configuration as a subclass of the host module
         | 
| 19 33 | 
             
                #
         | 
| 20 34 | 
             
                def install_configure_in(base)
         | 
| 21 | 
            -
                  base. | 
| 35 | 
            +
                  base.instance_eval <<-EOF
         | 
| 36 | 
            +
                    # Configuration class for host module
         | 
| 37 | 
            +
                    #
         | 
| 38 | 
            +
                    #{base.name}::Configuration = Class.new(Configurations::Configuration)
         | 
| 39 | 
            +
             | 
| 22 40 | 
             
                    # The central configure method
         | 
| 23 41 | 
             
                    # @params [Proc] block the block to configure host module with
         | 
| 24 42 | 
             
                    # @raise [ArgumentError] error when not given a block
         | 
| @@ -28,24 +46,50 @@ module Configurations | |
| 28 46 | 
             
                    #   end
         | 
| 29 47 | 
             
                    #
         | 
| 30 48 | 
             
                    def self.configure(&block)
         | 
| 31 | 
            -
                       | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 49 | 
            +
                      semaphore.synchronize do
         | 
| 50 | 
            +
                        fail ArgumentError, "configure needs a block" unless block_given?
         | 
| 51 | 
            +
                        include_configuration_type!(#{base.name}::Configuration)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                        set_configuration!(&block)
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    # A reader for Configuration
         | 
| 58 | 
            +
                    #
         | 
| 59 | 
            +
                    def configuration
         | 
| 60 | 
            +
                      semaphore.synchronize do
         | 
| 61 | 
            +
                        return @configuration if @configuration
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                        if @configuration_defaults
         | 
| 64 | 
            +
                          include_configuration_type!(#{base.name}::Configuration)
         | 
| 65 | 
            +
                          set_configuration! { }
         | 
| 66 | 
            +
                        end
         | 
| 67 | 
            +
                      end
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
             | 
| 71 | 
            +
                    private
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    # Sets the configuration instance variable
         | 
| 74 | 
            +
                    #
         | 
| 75 | 
            +
                    def self.set_configuration!(&block)
         | 
| 76 | 
            +
                      @configuration = #{base.name}::Configuration.__new__(
         | 
| 77 | 
            +
                                                                  configuration_options,
         | 
| 78 | 
            +
                                                                  &block
         | 
| 79 | 
            +
                                                                )
         | 
| 36 80 | 
             
                    end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    @semaphore = Mutex.new
         | 
| 83 | 
            +
                    def self.semaphore
         | 
| 84 | 
            +
                      @semaphore
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
             | 
| 37 87 | 
             
                  EOF
         | 
| 38 88 | 
             
                end
         | 
| 39 89 |  | 
| 40 90 | 
             
                # Class methods that will get installed in the host module
         | 
| 41 91 | 
             
                #
         | 
| 42 92 | 
             
                module ClassMethods
         | 
| 43 | 
            -
                  # A reader for Configuration
         | 
| 44 | 
            -
                  #
         | 
| 45 | 
            -
                  def configuration
         | 
| 46 | 
            -
                    @configuration ||= @configuration_defaults && configure {}
         | 
| 47 | 
            -
                  end
         | 
| 48 | 
            -
             | 
| 49 93 | 
             
                  # Configuration defaults can be used to set the defaults of
         | 
| 50 94 | 
             
                  # any Configuration
         | 
| 51 95 | 
             
                  # @param [Proc] block setting the default values of the configuration
         | 
| @@ -73,7 +117,7 @@ module Configurations | |
| 73 117 | 
             
                  #   end
         | 
| 74 118 | 
             
                  #
         | 
| 75 119 | 
             
                  def configurable(*properties, &block)
         | 
| 76 | 
            -
                    type = properties.shift if properties.first.is_a?( | 
| 120 | 
            +
                    type = properties.shift if properties.first.is_a?(Module)
         | 
| 77 121 |  | 
| 78 122 | 
             
                    @configurable ||= {}
         | 
| 79 123 | 
             
                    @configurable.merge! to_configurable_hash(properties, type, &block)
         | 
| @@ -102,7 +146,10 @@ module Configurations | |
| 102 146 | 
             
                  #   end
         | 
| 103 147 | 
             
                  #
         | 
| 104 148 | 
             
                  def configuration_method(method, &block)
         | 
| 105 | 
            -
                    fail | 
| 149 | 
            +
                    fail(
         | 
| 150 | 
            +
                      ArgumentError,
         | 
| 151 | 
            +
                      "can't be configuration property and a method"
         | 
| 152 | 
            +
                    ) if configurable?(method)
         | 
| 106 153 |  | 
| 107 154 | 
             
                    @configuration_methods ||= {}
         | 
| 108 155 | 
             
                    method_hash = if method.is_a?(Hash)
         | 
| @@ -143,18 +190,30 @@ module Configurations | |
| 143 190 | 
             
                    end
         | 
| 144 191 | 
             
                  end
         | 
| 145 192 |  | 
| 193 | 
            +
                  private
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                  def initialize_configuration!
         | 
| 196 | 
            +
                    @configuration = nil
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                  # Include the configuration type module into the host configuration class
         | 
| 200 | 
            +
                  #
         | 
| 201 | 
            +
                  def include_configuration_type!(base)
         | 
| 202 | 
            +
                    return if base.ancestors.include?(configuration_type)
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    base.send :include, configuration_type
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
             | 
| 146 207 | 
             
                  # @return the class name of the configuration class to use
         | 
| 147 208 | 
             
                  #
         | 
| 148 209 | 
             
                  def configuration_type
         | 
| 149 210 | 
             
                    if @configurable.nil? || @configurable.empty?
         | 
| 150 | 
            -
                       | 
| 211 | 
            +
                      Configurations::Arbitrary
         | 
| 151 212 | 
             
                    else
         | 
| 152 | 
            -
                       | 
| 213 | 
            +
                      Configurations::Strict
         | 
| 153 214 | 
             
                    end
         | 
| 154 215 | 
             
                  end
         | 
| 155 216 |  | 
| 156 | 
            -
                  private
         | 
| 157 | 
            -
             | 
| 158 217 | 
             
                  # Instantiates a configurable hash from a property and a type
         | 
| 159 218 | 
             
                  # @param [Symbol, Hash, Array] properties configurable properties,
         | 
| 160 219 | 
             
                  #   either single or nested
         | 
| @@ -3,6 +3,27 @@ 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 | 
            +
             | 
| 19 | 
            +
                class << self
         | 
| 20 | 
            +
                  # Make new a private method, but allow __new__ alias. Instantiating
         | 
| 21 | 
            +
                  # configurations is not part of the public API.
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  alias_method :__new__, :new
         | 
| 24 | 
            +
                  private :new
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 6 27 | 
             
                # Initialize a new configuration
         | 
| 7 28 | 
             
                # @param [Hash] options The options to initialize a configuration with
         | 
| 8 29 | 
             
                # @option options [Hash] methods a hash of method names pointing to procs
         | 
| @@ -52,19 +73,38 @@ module Configurations | |
| 52 73 | 
             
                # A convenience accessor to instantiate a configuration from a hash
         | 
| 53 74 | 
             
                # @param [Hash] h the hash to read into the configuration
         | 
| 54 75 | 
             
                # @return [Configuration] the configuration with values assigned
         | 
| 76 | 
            +
                # @raise [ConfigurationError] if the given hash ambiguous values
         | 
| 77 | 
            +
                #     - string and symbol keys with the same string value pointing to
         | 
| 78 | 
            +
                #     different values
         | 
| 55 79 | 
             
                #
         | 
| 56 80 | 
             
                def from_h(h)
         | 
| 81 | 
            +
                  __test_ambiguity!(h)
         | 
| 57 82 | 
             
                  h.each do |property, value|
         | 
| 58 | 
            -
                     | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 83 | 
            +
                    p = property.to_sym
         | 
| 84 | 
            +
                    if value.is_a?(::Hash) && __nested?(p)
         | 
| 85 | 
            +
                      @data[p].from_h(value)
         | 
| 86 | 
            +
                    elsif __configurable?(p)
         | 
| 87 | 
            +
                      __assign!(p, value)
         | 
| 62 88 | 
             
                    end
         | 
| 63 89 | 
             
                  end
         | 
| 64 90 |  | 
| 65 91 | 
             
                  self
         | 
| 66 92 | 
             
                end
         | 
| 67 93 |  | 
| 94 | 
            +
                # Inspect a configuration. Implements inspect without exposing internally
         | 
| 95 | 
            +
                # used instance variables.
         | 
| 96 | 
            +
                # @param [TrueClass, FalseClass] debug whether to show internals, defaults
         | 
| 97 | 
            +
                #     to false
         | 
| 98 | 
            +
                # @return [String] The inspect output for this instance
         | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                def inspect(debug = false)
         | 
| 101 | 
            +
                  unless debug
         | 
| 102 | 
            +
                    '#<%s:0x00%x @data=%s>' % [__class__, object_id << 1, @data.inspect]
         | 
| 103 | 
            +
                  else
         | 
| 104 | 
            +
                    super()
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 68 108 | 
             
                # @param [Symbol] property The property to test for configurability
         | 
| 69 109 | 
             
                # @return [Boolean] whether the given property is configurable
         | 
| 70 110 | 
             
                #
         | 
| @@ -91,6 +131,7 @@ module Configurations | |
| 91 131 | 
             
                #
         | 
| 92 132 | 
             
                def __install_configuration_methods__
         | 
| 93 133 | 
             
                  @__methods__.each do |meth, block|
         | 
| 134 | 
            +
                    __test_reserved!(meth)
         | 
| 94 135 | 
             
                    __define_singleton_method__(meth, &block) if block.is_a?(::Proc)
         | 
| 95 136 | 
             
                  end
         | 
| 96 137 | 
             
                end
         | 
| @@ -101,7 +142,8 @@ module Configurations | |
| 101 142 | 
             
                #
         | 
| 102 143 | 
             
                def __options_hash_for__(property)
         | 
| 103 144 | 
             
                  hash = {}
         | 
| 104 | 
            -
                  hash[:not_configured] = | 
| 145 | 
            +
                  hash[:not_configured] =
         | 
| 146 | 
            +
                    __not_configured_hash_for__(property) if @__not_configured__[property]
         | 
| 105 147 | 
             
                  hash[:methods] = @__methods__[property] if @__methods__.key?(property)
         | 
| 106 148 |  | 
| 107 149 | 
             
                  hash
         | 
| @@ -129,7 +171,9 @@ module Configurations | |
| 129 171 | 
             
                #
         | 
| 130 172 | 
             
                def __not_configured_hash_for__(property)
         | 
| 131 173 | 
             
                  hash = ::Hash.new(&@__not_configured__.default_proc)
         | 
| 132 | 
            -
                  hash.merge! | 
| 174 | 
            +
                  hash.merge!(
         | 
| 175 | 
            +
                    @__not_configured__[property]
         | 
| 176 | 
            +
                  ) if @__not_configured__[property].is_a?(::Hash)
         | 
| 133 177 |  | 
| 134 178 | 
             
                  hash
         | 
| 135 179 | 
             
                end
         | 
| @@ -139,7 +183,7 @@ module Configurations | |
| 139 183 | 
             
                #
         | 
| 140 184 | 
             
                def __configuration_hash__
         | 
| 141 185 | 
             
                  ::Hash.new do |h, k|
         | 
| 142 | 
            -
                    h[k] = __class__. | 
| 186 | 
            +
                    h[k] = __class__.__new__(__options_hash_for__(k)) if __configurable?(k)
         | 
| 143 187 | 
             
                  end
         | 
| 144 188 | 
             
                end
         | 
| 145 189 |  | 
| @@ -148,6 +192,7 @@ module Configurations | |
| 148 192 | 
             
                # @param [Any] value the given value
         | 
| 149 193 | 
             
                #
         | 
| 150 194 | 
             
                def __assign!(property, value)
         | 
| 195 | 
            +
                  __test_reserved!(property)
         | 
| 151 196 | 
             
                  @data[property] = value
         | 
| 152 197 | 
             
                end
         | 
| 153 198 |  | 
| @@ -177,6 +222,42 @@ module Configurations | |
| 177 222 | 
             
                  method.to_s[0..-2].to_sym
         | 
| 178 223 | 
             
                end
         | 
| 179 224 |  | 
| 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 | 
            +
             | 
| 180 261 | 
             
                # @param [Hash] a hash to collect blocks from
         | 
| 181 262 | 
             
                # @return [Proc] a proc to call all the procs
         | 
| 182 263 | 
             
                #
         | 
    
        data/lib/configurations/error.rb
    CHANGED
    
    | @@ -2,4 +2,9 @@ module Configurations | |
| 2 2 | 
             
              # A configuration Error, raised when configuration gets misconfigured
         | 
| 3 3 | 
             
              #
         | 
| 4 4 | 
             
              ConfigurationError = Class.new(ArgumentError)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              # A reserved method error, raised when configurable is used with
         | 
| 7 | 
            +
              # reserved methods
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              ReservedMethodError = Class.new(NameError)
         | 
| 5 10 | 
             
            end
         | 
| @@ -3,7 +3,7 @@ module Configurations | |
| 3 3 | 
             
              # StrictConfiguration is a blank object with setters and getters defined
         | 
| 4 4 | 
             
              # according to the configurable settings given
         | 
| 5 5 | 
             
              #
         | 
| 6 | 
            -
               | 
| 6 | 
            +
              module Strict
         | 
| 7 7 | 
             
                # Initialize a new configuration
         | 
| 8 8 | 
             
                # @param [Hash] options The options to initialize a configuration with
         | 
| 9 9 | 
             
                # @option options [Hash] configurable a hash of configurable properties
         | 
| @@ -48,6 +48,8 @@ module Configurations | |
| 48 48 | 
             
                  end
         | 
| 49 49 | 
             
                end
         | 
| 50 50 |  | 
| 51 | 
            +
                # Add a property to a nested configurable
         | 
| 52 | 
            +
                #
         | 
| 51 53 | 
             
                def __add_to_nested_configurables!(property, nested, assertion)
         | 
| 52 54 | 
             
                  @__nested_configurables__ ||= ::Hash.new { |h, k| h[k] = {} }
         | 
| 53 55 | 
             
                  @__nested_configurables__[property].merge!(
         | 
| @@ -55,6 +57,8 @@ module Configurations | |
| 55 57 | 
             
                  )
         | 
| 56 58 | 
             
                end
         | 
| 57 59 |  | 
| 60 | 
            +
                # Get an options hash for a property
         | 
| 61 | 
            +
                #
         | 
| 58 62 | 
             
                def __options_hash_for__(property)
         | 
| 59 63 | 
             
                  super(property).merge(configurable: @__nested_configurables__[property])
         | 
| 60 64 | 
             
                end
         | 
| @@ -85,6 +89,7 @@ module Configurations | |
| 85 89 | 
             
                # @param [Symbol] property the property to install
         | 
| 86 90 | 
             
                #
         | 
| 87 91 | 
             
                def __install_property__(property)
         | 
| 92 | 
            +
                  __test_reserved!(property)
         | 
| 88 93 | 
             
                  __install_setter__(property)
         | 
| 89 94 | 
             
                  __install_getter__(property)
         | 
| 90 95 | 
             
                end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestReservedMethods < ConfigurationsTest
         | 
| 4 | 
            +
              def test_raises_when_setup_with_reserved_methods
         | 
| 5 | 
            +
                assert_raises Configurations::ReservedMethodError do
         | 
| 6 | 
            +
                  self.class.setup_with do |c|
         | 
| 7 | 
            +
                    c.to_s = 'bla'
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  setup
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestArbitraryReservedMethodsAsMethods < ConfigurationsTest
         | 
| 4 | 
            +
              def test_reserved_methods_not_allowed_as_methods
         | 
| 5 | 
            +
                assert_raises Configurations::ReservedMethodError do
         | 
| 6 | 
            +
                  @module.class_eval do
         | 
| 7 | 
            +
                    configuration_method :to_h do
         | 
| 8 | 
            +
                      'h'
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  setup
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestConfigurationSynchronized < MiniTest::Test
         | 
| 4 | 
            +
              module TestModule
         | 
| 5 | 
            +
                include Configurations
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                configuration_defaults do |c|
         | 
| 8 | 
            +
                  c.a = 'b'
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def test_configuration_synchronized
         | 
| 13 | 
            +
                with_gc_disabled do
         | 
| 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)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  assert_equal 100, ids.uniq.size
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def test_one_instance_mutation
         | 
| 30 | 
            +
                there = TestModule.configuration.a
         | 
| 31 | 
            +
                t = Thread.new do
         | 
| 32 | 
            +
                  TestModule.configure do |c|
         | 
| 33 | 
            +
                    c.a = 'c'
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  there = TestModule.configuration.a
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                t.join
         | 
| 40 | 
            +
                here = TestModule.configuration.a
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                assert_equal here, there
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def with_gc_disabled(&_block)
         | 
| 46 | 
            +
                GC.disable
         | 
| 47 | 
            +
                yield
         | 
| 48 | 
            +
                GC.enable
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            class TestInspect < ConfigurationsTest
         | 
| 2 | 
            +
              setup_with {}
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              def inspect_output(_configuration)
         | 
| 5 | 
            +
                "#<#{self.class.name}::TestModule::Configuration:0x00%x @data={}>" % [@configuration.object_id << 1]
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def test_non_debug_inspect
         | 
| 9 | 
            +
                expected = inspect_output(@configuration)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                assert @configuration.inspect == expected, "Expected inspect to produce output #{expected.inspect}, but got #{@configuration.inspect.inspect}"
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def test_debug_inspect
         | 
| 15 | 
            +
                non_debug = inspect_output(@configuration)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                refute @configuration.inspect(true) == non_debug, "Expected debug inspect to delegate to kernel and produce more output, but got #{@configuration.inspect(true).inspect}"
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -35,6 +35,24 @@ module Tests | |
| 35 35 | 
             
                    old_to_h = @configuration.to_h.dup
         | 
| 36 36 | 
             
                    assert_equal(old_to_h, @module.configure { |c| c.from_h(old_to_h) }.to_h)
         | 
| 37 37 | 
             
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def test_from_h_with_strings
         | 
| 40 | 
            +
                    old_to_h = @configuration.to_h.dup
         | 
| 41 | 
            +
                    string_to_h = Hash[old_to_h.map { |k, v| [k.to_s, v] }]
         | 
| 42 | 
            +
                    assert_equal(old_to_h, @module.configure { |c| c.from_h(string_to_h) }.to_h)
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def test_from_h_with_ambiguous_strings_and_symbols
         | 
| 46 | 
            +
                    assert_raises Configurations::ConfigurationError do
         | 
| 47 | 
            +
                      @module.configure { |c| c.from_h('p1' => 'bla', :p1 => 'blu') }
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def test_from_h_with_unambiguous_strings_and_symbols
         | 
| 52 | 
            +
                    c = @module.configure { |c| c.from_h('p1' => 'bla', :p2 => 2) }
         | 
| 53 | 
            +
                    assert_equal 2, c.p2
         | 
| 54 | 
            +
                    assert_equal 'bla', c.p1
         | 
| 55 | 
            +
                  end
         | 
| 38 56 | 
             
                end
         | 
| 39 57 | 
             
              end
         | 
| 40 58 | 
             
            end
         | 
| @@ -6,6 +6,15 @@ module Tests | |
| 6 6 | 
             
                    assert_equal(expected, @module.configure { |c| c.from_h(input) }.to_h)
         | 
| 7 7 | 
             
                  end
         | 
| 8 8 |  | 
| 9 | 
            +
                  def test_from_h_with_strings
         | 
| 10 | 
            +
                    expected, input = expection_and_input
         | 
| 11 | 
            +
                    string_input = Hash[input.map { |k, v| [k.to_s, v] }]
         | 
| 12 | 
            +
                    assert_equal(
         | 
| 13 | 
            +
                      expected,
         | 
| 14 | 
            +
                      @module.configure { |c| c.from_h(string_input) }.to_h
         | 
| 15 | 
            +
                    )
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 9 18 | 
             
                  def test_from_h_outside_block
         | 
| 10 19 | 
             
                    expected, input = expection_and_input
         | 
| 11 20 | 
             
                    assert_equal(expected, @configuration.from_h(input).to_h)
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestStrictReservedMethods < ConfigurationsTest
         | 
| 4 | 
            +
              def test_reserved_methods_not_configurable
         | 
| 5 | 
            +
                assert_raises Configurations::ReservedMethodError do
         | 
| 6 | 
            +
                  @module.class_eval do
         | 
| 7 | 
            +
                    configurable :inspect
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  setup
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require 'test_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestStrictReservedMethodsAsMethods < ConfigurationsTest
         | 
| 4 | 
            +
              def test_reserved_methods_not_allowed_as_methods
         | 
| 5 | 
            +
                assert_raises Configurations::ReservedMethodError do
         | 
| 6 | 
            +
                  @module.class_eval do
         | 
| 7 | 
            +
                    configuration_method :to_h do
         | 
| 8 | 
            +
                      'h'
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  setup
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
    
        data/test/support/setup.rb
    CHANGED
    
    | @@ -45,7 +45,7 @@ module Test | |
| 45 45 |  | 
| 46 46 | 
             
                      features.each do |feature|
         | 
| 47 47 | 
             
                        method = method(feature)
         | 
| 48 | 
            -
                        mod.module_eval{ |m| method.call(m) }
         | 
| 48 | 
            +
                        mod.module_eval { |m| method.call(m) }
         | 
| 49 49 | 
             
                      end
         | 
| 50 50 |  | 
| 51 51 | 
             
                      @configuration_block = block if block_given?
         | 
| @@ -117,7 +117,7 @@ module Test | |
| 117 117 | 
             
                        configurable Hash, p3: { p5: :p7 }
         | 
| 118 118 | 
             
                        configurable Symbol, :class
         | 
| 119 119 | 
             
                        configurable Proc, :module
         | 
| 120 | 
            -
                        configurable  | 
| 120 | 
            +
                        configurable Module, :puts
         | 
| 121 121 | 
             
                      end
         | 
| 122 122 | 
             
                    end
         | 
| 123 123 |  | 
    
        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. | 
| 4 | 
            +
              version: 2.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Beat Richartz
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015- | 
| 11 | 
            +
            date: 2015-07-11 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: minitest
         | 
| @@ -80,6 +80,12 @@ files: | |
| 80 80 | 
             
            - test/configurations/arbitrary/test_methods.rb
         | 
| 81 81 | 
             
            - test/configurations/arbitrary/test_not_configured.rb
         | 
| 82 82 | 
             
            - test/configurations/arbitrary/test_not_configured_default.rb
         | 
| 83 | 
            +
            - test/configurations/arbitrary/test_reserved_methods.rb
         | 
| 84 | 
            +
            - test/configurations/arbitrary/test_reserved_methods_as_methods.rb
         | 
| 85 | 
            +
            - test/configurations/configuration/test_configure_synchronized.rb
         | 
| 86 | 
            +
            - test/configurations/configuration/test_inspect.rb
         | 
| 87 | 
            +
            - test/configurations/configuration/test_instantiation_prevention.rb
         | 
| 88 | 
            +
            - test/configurations/configuration/test_is_a_configuration.rb
         | 
| 83 89 | 
             
            - test/configurations/shared/defaults.rb
         | 
| 84 90 | 
             
            - test/configurations/shared/hash_methods.rb
         | 
| 85 91 | 
             
            - test/configurations/shared/kernel_methods.rb
         | 
| @@ -95,6 +101,8 @@ files: | |
| 95 101 | 
             
            - test/configurations/strict/test_methods.rb
         | 
| 96 102 | 
             
            - test/configurations/strict/test_not_configured.rb
         | 
| 97 103 | 
             
            - test/configurations/strict/test_not_configured_default.rb
         | 
| 104 | 
            +
            - test/configurations/strict/test_reserved_methods.rb
         | 
| 105 | 
            +
            - test/configurations/strict/test_reserved_methods_as_methods.rb
         | 
| 98 106 | 
             
            - test/configurations/strict_types/test.rb
         | 
| 99 107 | 
             
            - test/configurations/strict_types/test_defaults.rb
         | 
| 100 108 | 
             
            - test/configurations/strict_types/test_hash_methods.rb
         | 
| @@ -148,6 +156,12 @@ test_files: | |
| 148 156 | 
             
            - test/configurations/arbitrary/test_methods.rb
         | 
| 149 157 | 
             
            - test/configurations/arbitrary/test_not_configured.rb
         | 
| 150 158 | 
             
            - test/configurations/arbitrary/test_not_configured_default.rb
         | 
| 159 | 
            +
            - test/configurations/arbitrary/test_reserved_methods.rb
         | 
| 160 | 
            +
            - test/configurations/arbitrary/test_reserved_methods_as_methods.rb
         | 
| 161 | 
            +
            - test/configurations/configuration/test_configure_synchronized.rb
         | 
| 162 | 
            +
            - test/configurations/configuration/test_inspect.rb
         | 
| 163 | 
            +
            - test/configurations/configuration/test_instantiation_prevention.rb
         | 
| 164 | 
            +
            - test/configurations/configuration/test_is_a_configuration.rb
         | 
| 151 165 | 
             
            - test/configurations/shared/defaults.rb
         | 
| 152 166 | 
             
            - test/configurations/shared/hash_methods.rb
         | 
| 153 167 | 
             
            - test/configurations/shared/kernel_methods.rb
         | 
| @@ -163,6 +177,8 @@ test_files: | |
| 163 177 | 
             
            - test/configurations/strict/test_methods.rb
         | 
| 164 178 | 
             
            - test/configurations/strict/test_not_configured.rb
         | 
| 165 179 | 
             
            - test/configurations/strict/test_not_configured_default.rb
         | 
| 180 | 
            +
            - test/configurations/strict/test_reserved_methods.rb
         | 
| 181 | 
            +
            - test/configurations/strict/test_reserved_methods_as_methods.rb
         | 
| 166 182 | 
             
            - test/configurations/strict_types/test.rb
         | 
| 167 183 | 
             
            - test/configurations/strict_types/test_defaults.rb
         | 
| 168 184 | 
             
            - test/configurations/strict_types/test_hash_methods.rb
         |