spicerack 0.16.3 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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