spicerack 0.16.3 → 0.17.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab658b1a460b32983639d4d8e3e39f293e285ddb90f48806388f100b1908f5b9
4
- data.tar.gz: 0df60d065dde766fe6bb21f8b33adec402d293a77ffa20572a6c8a0fe38d9880
3
+ metadata.gz: c92116412b94f90920f84dd05d8419d0bc7a4c2ffa3b33482ee6b53e32ad2032
4
+ data.tar.gz: 432943870f985ad4301e95b7f40bf936696c73d3f7d60eefaea27f85fb20bbe6
5
5
  SHA512:
6
- metadata.gz: 1feee1e4d22e6e90a393d8d0736edda1a6e472a1dbab79d7296f068f6ea6e4ae3c735dd2b9095460017e6cdf725f166239c5fa9d7005f92c3d9de1383443eae4
7
- data.tar.gz: 87efaba97f8eb03e43126f669ab739daf7a553fff86aa47aba4910d587bd3d8c8cb0bf804c13552002365d33c495a2361bf0c750714389ab89e829cd12cc4c53
6
+ metadata.gz: 3cccd7de009826d22e34d5de0534ac5d7543e7873db5e72e6c2951814b56089d4dc30ec47076fc91bc40b6329c0c99d97a6f061426dbb6b031c6e80ec3ae3093
7
+ data.tar.gz: bad53b799446ca49f068ca3931be811d225b1681d3b141de3bbd21dd314c49ffc61d4f5d1ef48c7ac6e36a7394abd2c475958db8033bd06bdacadaaa885b81c5
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "configurable/config_builder"
4
+ require_relative "configurable/config_delegation"
5
+ require_relative "configurable/config_object"
6
+ require_relative "configurable/evaluator"
4
7
  require_relative "configurable/reader"
5
8
 
6
9
  # NOTE: This is still a pre-release feature! Use at your own risk - it may change before being released.
@@ -16,6 +19,12 @@ require_relative "configurable/reader"
16
19
  # configuration_options do
17
20
  # option :some_config_option
18
21
  # option :some_option_with_a_default, default: "I probably know what's best"
22
+ #
23
+ # nested :whats_behind do
24
+ # option :door_one, default: "It's a goat"
25
+ # option :door_two, default: "Another goat"
26
+ # option :door_three, default: "It's a car!"
27
+ # end
19
28
  # end
20
29
  # end
21
30
  # end
@@ -24,14 +33,27 @@ require_relative "configurable/reader"
24
33
  # SomeGem::Configuration.configure do |config|
25
34
  # config.some_config_option = 12345
26
35
  # config.some_option_with_a_default = "Nope, you really don't"
36
+ #
37
+ # config.whats_behind do |nested|
38
+ # nested.door_one = "It's a boat!"
39
+ # nested.door_three = "The teletubbies on repeat 😱"
40
+ # end
27
41
  # end
28
42
  #
29
43
  # # Then, back in your gem code:
30
44
  # puts Configuration.config.some_config_option
31
45
  # => 12345
46
+ # puts Configuration.config.whats_behind.door_one
47
+ # => "It's a boat!"
48
+ #
49
+ # # Or, if you want to select dynamically:
50
+ # doors = %i[door_one door_two door_three]
51
+ # Configuration.config.config_eval(whats_behind, doors.sample).read
52
+ # => "The teletubbies on repeat 😱"
53
+ #
32
54
  module Spicerack
33
55
  module Configurable
34
- delegate :configure, to: :_config_builder
56
+ delegate :configure, :config_eval, to: :_config_builder
35
57
 
36
58
  def config
37
59
  _config_builder.reader
@@ -3,27 +3,39 @@
3
3
  module Spicerack
4
4
  module Configurable
5
5
  class ConfigBuilder
6
+ delegate :config_eval, to: :reader
7
+
6
8
  def reader
7
9
  @reader ||= Reader.new(configuration)
8
10
  end
9
11
 
10
12
  def configure
11
- yield configuration
13
+ mutex.synchronize do
14
+ yield configuration
15
+ end
12
16
  end
13
17
 
14
18
  # NOTE: options must be set up before {#configure} is called
15
- def option(*args)
16
- config_class.__send__(:option, *args)
19
+ def option(*args, &block)
20
+ config_class.__send__(:option, *args, &block)
21
+ end
22
+
23
+ def nested(*args, &block)
24
+ config_class.__send__(:nested, *args, &block)
17
25
  end
18
26
 
19
27
  private
20
28
 
21
29
  def configuration
22
- @configuration ||= config_class.new
30
+ config_class.instance
23
31
  end
24
32
 
25
33
  def config_class
26
- @config_class ||= Class.new(InputObject)
34
+ @config_class ||= Class.new(ConfigObject)
35
+ end
36
+
37
+ def mutex
38
+ @mutex = Mutex.new
27
39
  end
28
40
  end
29
41
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Spicerack
6
+ module Configurable
7
+ module ConfigDelegation
8
+ extend ActiveSupport::Concern
9
+
10
+ DEFAULT_CONFIGURATION_MODULE_NAME = "Configuration"
11
+
12
+ module ClassMethods
13
+ delegate :config, :configure, to: :_configuration_module
14
+
15
+ private
16
+
17
+ # Sets up delegation from a top-level class to a nested Configuration module.
18
+ #
19
+ # @example
20
+ # class SomeClass
21
+ # include Spicerack::Configurable::ConfigDelegation
22
+ #
23
+ # delegates_to_configuration
24
+ # end
25
+ #
26
+ # module SomeClass::Configuration
27
+ # include Spicerack::Configurable
28
+ # end
29
+ #
30
+ # SomeClass.config
31
+ # => returns SomeClass::Configuration.config
32
+ # SomeClass.configure do { |config| # config is the yielded config object from SomeClass::Configuration.configure }
33
+ #
34
+ # @param config_class [Spicerack::Configurable] A module that extends Spicerack::Configurable. Defaults to the module +YourGem::Configuration+
35
+ def delegates_to_configuration(config_class = nil)
36
+ @_configuration_module = config_class || "#{self}::#{DEFAULT_CONFIGURATION_MODULE_NAME}".constantize
37
+ end
38
+
39
+ def _configuration_module
40
+ raise NoMethodError, "Configuration not set up for #{self}. Did you forget to call delegates_to_configuration?" if @_configuration_module.nil?
41
+
42
+ @_configuration_module
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spicerack
4
+ module Configurable
5
+ class ConfigObject < InputObject
6
+ include Singleton
7
+ include ActiveModel::AttributeAssignment
8
+
9
+ alias_method :assign, :assign_attributes
10
+
11
+ RESERVED_WORDS = %i[config_eval].freeze
12
+
13
+ class_attribute :_nested_options, instance_writer: false, default: []
14
+ class_attribute :_nested_builders, instance_writer: false, default: {}
15
+
16
+ class << self
17
+ def name
18
+ super.presence || "#{superclass}:0x#{object_id.to_s(16)}"
19
+ end
20
+
21
+ def inspect
22
+ "#<#{name}>"
23
+ end
24
+
25
+ private
26
+
27
+ def option(name, *)
28
+ _ensure_safe_option_name(name)
29
+
30
+ super
31
+ end
32
+
33
+ def nested(namespace, &block)
34
+ _ensure_safe_option_name(namespace)
35
+
36
+ nested_config_builder_for(namespace).tap do |builder|
37
+ builder.instance_exec(&block)
38
+
39
+ _nested_options << namespace.to_sym
40
+ define_method(namespace) { builder.__send__ :configuration }
41
+ end
42
+ end
43
+
44
+ def nested_config_builder_for(namespace)
45
+ _nested_builders[namespace.to_sym] ||= ConfigBuilder.new
46
+ end
47
+
48
+ def _ensure_safe_option_name(name)
49
+ raise ArgumentError, "#{name.inspect} is reserved and cannot be used at a config option" if name.to_sym.in? RESERVED_WORDS
50
+ raise ArgumentError, "#{name.inspect} is already in use" if _nested_options.include?(name.to_sym)
51
+
52
+ puts "Warning: the config option #{name} is already defined" if _options.include?(name.to_sym) # rubocop:disable Rails/Output
53
+ end
54
+
55
+ def inherited(base)
56
+ base._nested_options = _nested_options.dup
57
+ base._nested_builders = _nested_builders.dup
58
+ super
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spicerack
4
+ module Configurable
5
+ class Evaluator
6
+ # @param path [Array<Symbol, String>] A message path for the desired config
7
+ # @param configuration [Spicerack::Configurable::Reader]
8
+ def initialize(path, configuration)
9
+ @path = path
10
+ @configuration = configuration
11
+ end
12
+
13
+ def read
14
+ path.inject(configuration, &:public_send)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :path, :configuration
20
+ end
21
+ end
22
+ end
@@ -7,18 +7,31 @@ module Spicerack
7
7
  @config = config
8
8
  end
9
9
 
10
+ def config_eval(*path)
11
+ Evaluator.new(path, self)
12
+ end
13
+
10
14
  private
11
15
 
12
16
  attr_reader :config
13
17
 
14
18
  def method_missing(method_name, *)
15
- return config.public_send(method_name) if config._options.map(&:to_sym).include?(method_name.to_sym)
19
+ name = method_name.to_sym
20
+
21
+ return mutex.synchronize { config.public_send(name) } if config._options.map(&:to_sym).include?(name)
22
+ return config._nested_builders[name].reader if config._nested_builders.key?(name)
16
23
 
17
24
  super
18
25
  end
19
26
 
20
27
  def respond_to_missing?(method_name, *)
21
- config._options.map(&:to_sym).include?(method_name.to_sym) || super
28
+ config._options.map(&:to_sym).include?(method_name.to_sym) ||
29
+ config._nested_builders.key?(name) ||
30
+ super
31
+ end
32
+
33
+ def mutex
34
+ @mutex ||= Mutex.new
22
35
  end
23
36
  end
24
37
  end
@@ -25,12 +25,14 @@ module Spicerack
25
25
  end
26
26
 
27
27
  class Value
28
+ include Tablesalt::Isolation
29
+
28
30
  def initialize(static: nil, &block)
29
31
  @value = (static.nil? && block_given?) ? block : static
30
32
  end
31
33
 
32
34
  def value
33
- (@value.respond_to?(:call) ? instance_eval(&@value) : @value).dup
35
+ isolate(@value.respond_to?(:call) ? instance_eval(&@value) : @value)
34
36
  end
35
37
  end
36
38
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "matchers"
4
+
5
+ module Spicerack
6
+ module RSpec
7
+ module Configurable
8
+ module DSL
9
+ def nested_config_option(config_name, &block)
10
+ in_nested_config_stack(config_name) do |nested_stack|
11
+ describe(config_name.to_s, caller: caller) do
12
+ subject { nested_config }
13
+
14
+ let(:parent_config) { parent_config_for_nested(nested_stack) }
15
+ let(:nested_config) { parent_config.public_send(nested_stack.last) }
16
+
17
+ it "defines nested config object #{config_name}" do
18
+ expect(parent_config).to respond_to config_name
19
+ expect(parent_config._nested_options).to include config_name.to_sym
20
+ expect(parent_config.public_send(config_name)).to be_a Spicerack::Configurable::ConfigObject
21
+ end
22
+
23
+ instance_eval(&block)
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.included(base)
29
+ base.extend DSL
30
+ super
31
+ end
32
+
33
+ private
34
+
35
+ def parent_config_for_nested(nested_stack)
36
+ @parent_config ||= {}
37
+
38
+ @parent_config[nested_stack] ||= described_class.
39
+ __send__(:_config_builder).
40
+ __send__(:configuration).
41
+ yield_self do |config|
42
+ nested_stack[0..-2].inject(config) do |conf, nested_name|
43
+ conf.public_send(nested_name)
44
+ end
45
+ end
46
+ end
47
+
48
+ def in_nested_config_stack(name)
49
+ _nested_config_stack << name.to_sym
50
+
51
+ yield _nested_config_stack.dup
52
+
53
+ _nested_config_stack.pop
54
+ end
55
+
56
+ def _nested_config_stack
57
+ Thread.current[:nested_config_stack] ||= []
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spicerack
4
+ module RSpec
5
+ module Configurable
6
+ module Matchers
7
+ extend ::RSpec::Matchers::DSL
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ require_relative "matchers/define_config_option"
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spicerack
4
+ module RSpec
5
+ module Configurable
6
+ module Matchers
7
+ # RSpec matcher to test options of a Configurable class
8
+ #
9
+ # class ExampleConfiguration
10
+ # include Spicerack::Configurable
11
+ #
12
+ # option :foo
13
+ # option :bar, default: :baz
14
+ # end
15
+ #
16
+ # RSpec.describe ExampleConfiguration, type: :configuration do
17
+ # subject { described_class.new }
18
+ #
19
+ # it { is_expected.to define_config_option :foo }
20
+ # it { is_expected.to define_config_option :bar, default: :baz }
21
+ # end
22
+ define :define_config_option do |option, default: nil|
23
+ description { "define config option #{option}" }
24
+ failure_message { "expected #{subject} to define config option #{option} #{with_default(default)}".strip }
25
+
26
+ match do |obj|
27
+ if obj.is_a? Spicerack::Configurable::ConfigObject
28
+ expect(obj).to define_option option, default: default
29
+ else
30
+ expect(obj).to respond_to :config
31
+ expect(obj.config.instance_variable_get(:@config)).to be_present
32
+ expect(obj.config.instance_variable_get(:@config)).to define_option option, default: default
33
+ end
34
+ end
35
+
36
+ def with_default(default)
37
+ "with default #{default}" unless default.nil?
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "matchers"
4
+ require_relative "dsl"
5
+
6
+ RSpec.configure do |config|
7
+ config.include(Spicerack::RSpec::Configurable::Matchers, type: :configuration)
8
+ config.include(Spicerack::RSpec::Configurable::DSL, type: :configuration)
9
+ end
@@ -4,4 +4,3 @@ require_relative "custom_matchers/define_argument"
4
4
  require_relative "custom_matchers/define_attribute"
5
5
  require_relative "custom_matchers/define_field"
6
6
  require_relative "custom_matchers/define_option"
7
- require_relative "custom_matchers/define_config_option"
@@ -3,7 +3,9 @@
3
3
  require "rspice"
4
4
  require "redis_hash/spec_helper"
5
5
  require "technologic/spec_helper"
6
+ require "tablesalt/spec_helper"
6
7
 
7
8
  require_relative "rspec/custom_matchers"
8
9
  require_relative "rspec/shared_examples"
9
10
  require_relative "rspec/shoulda_matcher_helper"
11
+ require_relative "rspec/configurable/spec_helper"
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Spicerack
4
4
  # This constant is managed by spicerack
5
- VERSION = "0.16.3"
5
+ VERSION = "0.17.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spicerack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.3
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Garside
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-09-19 00:00:00.000000000 Z
14
+ date: 2019-10-01 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: around_the_world
@@ -19,98 +19,98 @@ dependencies:
19
19
  requirements:
20
20
  - - '='
21
21
  - !ruby/object:Gem::Version
22
- version: 0.16.3
22
+ version: 0.17.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.16.3
29
+ version: 0.17.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: collectible
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - '='
35
35
  - !ruby/object:Gem::Version
36
- version: 0.16.3
36
+ version: 0.17.0
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - '='
42
42
  - !ruby/object:Gem::Version
43
- version: 0.16.3
43
+ version: 0.17.0
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: facet
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - '='
49
49
  - !ruby/object:Gem::Version
50
- version: 0.16.3
50
+ version: 0.17.0
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - '='
56
56
  - !ruby/object:Gem::Version
57
- version: 0.16.3
57
+ version: 0.17.0
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: redis_hash
60
60
  requirement: !ruby/object:Gem::Requirement
61
61
  requirements:
62
62
  - - '='
63
63
  - !ruby/object:Gem::Version
64
- version: 0.16.3
64
+ version: 0.17.0
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - '='
70
70
  - !ruby/object:Gem::Version
71
- version: 0.16.3
71
+ version: 0.17.0
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: short_circu_it
74
74
  requirement: !ruby/object:Gem::Requirement
75
75
  requirements:
76
76
  - - '='
77
77
  - !ruby/object:Gem::Version
78
- version: 0.16.3
78
+ version: 0.17.0
79
79
  type: :runtime
80
80
  prerelease: false
81
81
  version_requirements: !ruby/object:Gem::Requirement
82
82
  requirements:
83
83
  - - '='
84
84
  - !ruby/object:Gem::Version
85
- version: 0.16.3
85
+ version: 0.17.0
86
86
  - !ruby/object:Gem::Dependency
87
87
  name: technologic
88
88
  requirement: !ruby/object:Gem::Requirement
89
89
  requirements:
90
90
  - - '='
91
91
  - !ruby/object:Gem::Version
92
- version: 0.16.3
92
+ version: 0.17.0
93
93
  type: :runtime
94
94
  prerelease: false
95
95
  version_requirements: !ruby/object:Gem::Requirement
96
96
  requirements:
97
97
  - - '='
98
98
  - !ruby/object:Gem::Version
99
- version: 0.16.3
99
+ version: 0.17.0
100
100
  - !ruby/object:Gem::Dependency
101
101
  name: tablesalt
102
102
  requirement: !ruby/object:Gem::Requirement
103
103
  requirements:
104
104
  - - '='
105
105
  - !ruby/object:Gem::Version
106
- version: 0.16.3
106
+ version: 0.17.0
107
107
  type: :runtime
108
108
  prerelease: false
109
109
  version_requirements: !ruby/object:Gem::Requirement
110
110
  requirements:
111
111
  - - '='
112
112
  - !ruby/object:Gem::Version
113
- version: 0.16.3
113
+ version: 0.17.0
114
114
  - !ruby/object:Gem::Dependency
115
115
  name: bundler
116
116
  requirement: !ruby/object:Gem::Requirement
@@ -235,28 +235,28 @@ dependencies:
235
235
  requirements:
236
236
  - - '='
237
237
  - !ruby/object:Gem::Version
238
- version: 0.16.3
238
+ version: 0.17.0
239
239
  type: :development
240
240
  prerelease: false
241
241
  version_requirements: !ruby/object:Gem::Requirement
242
242
  requirements:
243
243
  - - '='
244
244
  - !ruby/object:Gem::Version
245
- version: 0.16.3
245
+ version: 0.17.0
246
246
  - !ruby/object:Gem::Dependency
247
247
  name: spicerack-styleguide
248
248
  requirement: !ruby/object:Gem::Requirement
249
249
  requirements:
250
250
  - - '='
251
251
  - !ruby/object:Gem::Version
252
- version: 0.16.3
252
+ version: 0.17.0
253
253
  type: :development
254
254
  prerelease: false
255
255
  version_requirements: !ruby/object:Gem::Requirement
256
256
  requirements:
257
257
  - - '='
258
258
  - !ruby/object:Gem::Version
259
- version: 0.16.3
259
+ version: 0.17.0
260
260
  - !ruby/object:Gem::Dependency
261
261
  name: will_paginate
262
262
  requirement: !ruby/object:Gem::Requirement
@@ -323,6 +323,9 @@ files:
323
323
  - lib/spicerack/attribute_object.rb
324
324
  - lib/spicerack/configurable.rb
325
325
  - lib/spicerack/configurable/config_builder.rb
326
+ - lib/spicerack/configurable/config_delegation.rb
327
+ - lib/spicerack/configurable/config_object.rb
328
+ - lib/spicerack/configurable/evaluator.rb
326
329
  - lib/spicerack/configurable/reader.rb
327
330
  - lib/spicerack/hash_model.rb
328
331
  - lib/spicerack/input_model.rb
@@ -333,10 +336,13 @@ files:
333
336
  - lib/spicerack/objects/options.rb
334
337
  - lib/spicerack/redis_model.rb
335
338
  - lib/spicerack/root_object.rb
339
+ - lib/spicerack/rspec/configurable/dsl.rb
340
+ - lib/spicerack/rspec/configurable/matchers.rb
341
+ - lib/spicerack/rspec/configurable/matchers/define_config_option.rb
342
+ - lib/spicerack/rspec/configurable/spec_helper.rb
336
343
  - lib/spicerack/rspec/custom_matchers.rb
337
344
  - lib/spicerack/rspec/custom_matchers/define_argument.rb
338
345
  - lib/spicerack/rspec/custom_matchers/define_attribute.rb
339
- - lib/spicerack/rspec/custom_matchers/define_config_option.rb
340
346
  - lib/spicerack/rspec/custom_matchers/define_field.rb
341
347
  - lib/spicerack/rspec/custom_matchers/define_option.rb
342
348
  - lib/spicerack/rspec/shared_examples.rb
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # RSpec matcher to test options of a Configurable class
4
- #
5
- # class ExampleConfiguration
6
- # include Spicerack::Configurable
7
- #
8
- # option :foo
9
- # option :bar, default: :baz
10
- # end
11
- #
12
- # RSpec.describe ExampleConfiguration, type: :configuration do
13
- # subject { described_class.new }
14
- #
15
- # it { is_expected.to define_config_option :foo }
16
- # it { is_expected.to define_config_option :bar, default: :baz }
17
- # end
18
-
19
- RSpec::Matchers.define :define_config_option do |option, default: nil|
20
- description { "define config option #{option}" }
21
- failure_message { "expected #{subject} to define config option #{option} #{with_default(default)}".strip }
22
-
23
- match do |obj|
24
- expect(obj).to respond_to :config
25
- expect(obj.config.instance_variable_get(:@config)).to be_present
26
- expect(obj.config.instance_variable_get(:@config)).to define_option option, default: default
27
- end
28
-
29
- def with_default(default)
30
- "with default #{default}" unless default.nil?
31
- end
32
- end