azeroth 0.6.1 → 0.6.2

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: 4cdaf99f5d37798d446e0a2c73f3cfdb47de9e3c67f6eb57fde3bbb57163c852
4
- data.tar.gz: 815480871c9eee75490205182da462072090e6697577e54d6e72d5212ae5d153
3
+ metadata.gz: 75366fe54c6684c1e58e55ced58c72570a211ba6e463c46d06504bc8b803a667
4
+ data.tar.gz: 45548e777bf55688478af05716b200421c7629b6542222a4abab559bb24dd966
5
5
  SHA512:
6
- metadata.gz: a3a790fe5214a693590f8f9bbe1d6da897425009046fccae35097de89a4cbac1bd0be1c2257e41fc1929c29a92d500dd28db31beacb706b40d8ca357c5f943d9
7
- data.tar.gz: 401a2ba4604c1f36f76f346888158cdcd067f5c4e83ed05c418781a0176ef9309b1a2b0aa691b2c45d35969b7688880a44fc2c4bed980e21237d54cb03dc7dad
6
+ metadata.gz: 19602b6e52d2f20ef53c1c8f555bf9d7b55de7cd898fe201b91fdd6afd5714ad9c9ec1ffaa4136219180e6631f94440bfaea3bc449ea9031e79691f281caae49
7
+ data.tar.gz: 9f02bc1df351a23f01bd964ffda1d51169dd84e25b4835847b4a709e6efab9ce08612407de771371d90280d6c029a0a2f49613d5dad2d1be40ced130f1d649f3
data/README.md CHANGED
@@ -11,4 +11,4 @@ Azeroth
11
11
 
12
12
  Yard Documentation
13
13
  -------------------
14
- [https://www.rubydoc.info/gems/azeroth/0.6.1](https://www.rubydoc.info/gems/azeroth/0.6.1)
14
+ [https://www.rubydoc.info/gems/azeroth/0.6.2](https://www.rubydoc.info/gems/azeroth/0.6.2)
@@ -1,4 +1,5 @@
1
1
  ignore:
2
+ - lib/azeroth/decorator/options.rb
2
3
  - lib/azeroth/resourceable/class_methods.rb
3
4
  - lib/azeroth/resourceable.rb
4
5
  - lib/azeroth/version.rb
data/lib/azeroth.rb CHANGED
@@ -12,7 +12,6 @@ require 'sinclair'
12
12
  module Azeroth
13
13
  autoload :Decorator, 'azeroth/decorator'
14
14
  autoload :DummyDecorator, 'azeroth/dummy_decorator'
15
- autoload :Exception, 'azeroth/exception'
16
15
  autoload :Model, 'azeroth/model'
17
16
  autoload :RequestHandler, 'azeroth/request_handler'
18
17
  autoload :Resourceable, 'azeroth/resourceable'
@@ -41,6 +41,7 @@ module Azeroth
41
41
  # # }
42
42
  class Decorator
43
43
  autoload :HashBuilder, 'azeroth/decorator/hash_builder'
44
+ autoload :Options, 'azeroth/decorator/options'
44
45
 
45
46
  class << self
46
47
  # @api private
@@ -101,7 +102,9 @@ module Azeroth
101
102
  # end
102
103
  # end
103
104
  # end
104
- def expose(attribute, **options)
105
+ def expose(attribute, **options_hash)
106
+ options = Decorator::Options.new(options_hash)
107
+
105
108
  builder = Sinclair.new(self)
106
109
  builder.add_method(attribute, "@object.#{attribute}")
107
110
  builder.build
@@ -56,9 +56,23 @@ module Azeroth
56
56
  def add_attribute(method, options)
57
57
  return unless add_attribute?(options)
58
58
 
59
- key = options[:as] || method
59
+ key = options.as || method
60
60
 
61
- hash[key.to_s] = decorator.public_send(method)
61
+ hash[key.to_s] = json_for(method)
62
+ end
63
+
64
+ def json_for(method)
65
+ value = decorator.public_send(method)
66
+
67
+ decorator_class_for(value).new(value).as_json
68
+ end
69
+
70
+ def decorator_class_for(value)
71
+ return value.class::Decorator unless value.is_a?(Enumerable)
72
+
73
+ decorator_class_for(value.first)
74
+ rescue NameError
75
+ Azeroth::DummyDecorator
62
76
  end
63
77
 
64
78
  # Check if an attribute should be added to the hash
@@ -70,7 +84,7 @@ module Azeroth
70
84
  #
71
85
  # @return [Object] result of method call from decorator
72
86
  def add_attribute?(options)
73
- conditional = options[:if]
87
+ conditional = options.if
74
88
  return true unless conditional.present?
75
89
 
76
90
  block = proc(&conditional)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Azeroth
4
+ class Decorator
5
+ # @api private
6
+ # @author Darthjee
7
+ #
8
+ # Resource buiilding options for decorator
9
+ #
10
+ # @see https://www.rubydoc.info/gems/sinclair/1.6.4/Sinclair/Options
11
+ # Sinclair::Options
12
+ class Options < Sinclair::Options
13
+ DEFAULT_OPTIONS = {
14
+ as: nil,
15
+ if: nil
16
+ }.freeze
17
+
18
+ with_options DEFAULT_OPTIONS
19
+
20
+ # @method as
21
+ # @api private
22
+ # @public
23
+ #
24
+ # key to use when exposing the field
25
+ #
26
+ # when nil, the name of the field
27
+ #
28
+ # @return [Symbol,String]
29
+
30
+ # @method if
31
+ # @api private
32
+ # @public
33
+ #
34
+ # conditional to be checked when exposing field
35
+ #
36
+ # when conditional returns false, the
37
+ # field will not be exposed
38
+ #
39
+ # when if is a {Proc} the proc will be used,
40
+ # when it is a {Symbol} or {String} this will be
41
+ # the name of the method called in the decorator
42
+ # to evaluate the condition
43
+ end
44
+ end
45
+ end
@@ -5,7 +5,10 @@ module Azeroth
5
5
  # @author Darthjee
6
6
  #
7
7
  # Resource buiilding options
8
- class Options < ::OpenStruct
8
+ #
9
+ # @see https://www.rubydoc.info/gems/sinclair/1.6.4/Sinclair/Options
10
+ # Sinclair::Options
11
+ class Options < Sinclair::Options
9
12
  # Default options
10
13
  DEFAULT_OPTIONS = {
11
14
  only: %i[create destroy edit index new show update],
@@ -13,18 +16,7 @@ module Azeroth
13
16
  decorator: true
14
17
  }.freeze
15
18
 
16
- # @param options [Hash] hash with options (see {Options::DEFAULT_OPTIONS})
17
- # @option options only [Array<Symbol,String>] List of
18
- # actions to be built
19
- # @option options except [Array<Symbol,String>] List of
20
- # actions to not to be built
21
- # @option options decorator [Azeroth::Decorator,TrueClass,FalseClass]
22
- # Decorator class or flag allowing/disallowing decorators
23
- def initialize(options = {})
24
- check_options(options)
25
-
26
- super(DEFAULT_OPTIONS.merge(options))
27
- end
19
+ with_options DEFAULT_OPTIONS
28
20
 
29
21
  # Actions to be built
30
22
  #
@@ -33,21 +25,33 @@ module Azeroth
33
25
  [only].flatten.map(&:to_sym) - [except].flatten.map(&:to_sym)
34
26
  end
35
27
 
36
- private
37
-
38
- # @private
39
- #
40
- # check if given options are allowed
28
+ # @method only
29
+ # @api private
30
+ # @public
41
31
  #
42
- # @raise Azeroth::Exception::InvalidOptions
32
+ # filter of only actions to be built
43
33
  #
44
- # @return [NilClass]
45
- def check_options(options)
46
- invalid_keys = options.keys - DEFAULT_OPTIONS.keys
34
+ # @return [Array<String,Symbol>]
47
35
 
48
- return if invalid_keys.empty?
36
+ # @method except
37
+ # @api private
38
+ # @public
39
+ #
40
+ # actions to be ignored
41
+ #
42
+ # @return [Array<String,Symbol>]
49
43
 
50
- raise Azeroth::Exception::InvalidOptions, invalid_keys
51
- end
44
+ # @method decorator
45
+ # @api private
46
+ # @public
47
+ #
48
+ # decorator class to be used
49
+ #
50
+ # when set as true/false, it either infer
51
+ # the class (model_class::Decorator) or
52
+ # do not use a decorator at all calling
53
+ # model.as_json
54
+ #
55
+ # @return [Decorator,TrueClass,FalseClass]
52
56
  end
53
57
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Azeroth
4
- VERSION = '0.6.1'
4
+ VERSION = '0.6.2'
5
5
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Factory < ActiveRecord::Base
4
+ has_many :products
5
+ has_one :main_product, class_name: 'Product'
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Factory
4
+ class DecoratorWithProduct < Azeroth::Decorator
5
+ expose :name
6
+ expose :main_product
7
+ expose :products
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Product < ActiveRecord::Base
4
+ belongs_to :factory
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Product
4
+ class Decorator < Azeroth::Decorator
5
+ expose :name
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Product
4
+ class DecoratorWithFactory < Azeroth::Decorator
5
+ expose :name
6
+ expose :factory
7
+ end
8
+ end
@@ -13,4 +13,13 @@ ActiveRecord::Schema.define do
13
13
  t.string :email
14
14
  t.string :reference
15
15
  end
16
+
17
+ create_table :factories, force: true do |t|
18
+ t.string :name
19
+ end
20
+
21
+ create_table :products, force: true do |t|
22
+ t.integer :factory_id
23
+ t.string :name
24
+ end
16
25
  end
@@ -33,7 +33,7 @@ describe Azeroth::Decorator::HashBuilder do
33
33
  errors: {
34
34
  first_name: ["can't be blank"]
35
35
  }
36
- }.stringify_keys
36
+ }.deep_stringify_keys
37
37
  end
38
38
 
39
39
  it 'include the conditional attributes' do
@@ -8,6 +8,59 @@ describe Azeroth::Decorator do
8
8
  let(:model) { build(:dummy_model) }
9
9
  let(:object) { model }
10
10
 
11
+ describe '.expose' do
12
+ subject(:decorator) { Class.new(described_class) }
13
+
14
+ let(:expected_options) do
15
+ Azeroth::Decorator::Options.new
16
+ end
17
+
18
+ it do
19
+ expect { decorator.send(:expose, :name) }
20
+ .to change(decorator, :attributes_map)
21
+ .from({})
22
+ .to({ name: expected_options })
23
+ end
24
+
25
+ it do
26
+ expect { decorator.send(:expose, :name) }
27
+ .to add_method(:name).to(decorator)
28
+ end
29
+
30
+ context 'when passing options' do
31
+ let(:expected_options) do
32
+ Azeroth::Decorator::Options.new(if: :valid?)
33
+ end
34
+
35
+ it do
36
+ expect { decorator.send(:expose, :name, if: :valid?) }
37
+ .to change(decorator, :attributes_map)
38
+ .from({})
39
+ .to({ name: expected_options })
40
+ end
41
+
42
+ it do
43
+ expect { decorator.send(:expose, :name, if: :valid?) }
44
+ .to add_method(:name).to(decorator)
45
+ end
46
+ end
47
+
48
+ context 'when passing invalid options' do
49
+ it do
50
+ expect { decorator.send(:expose, :name, invalid_option: :valid?) }
51
+ .to not_change(decorator, :attributes_map)
52
+ .and raise_error(Sinclair::Exception::InvalidOptions)
53
+ end
54
+
55
+ it do
56
+ expect { decorator.send(:expose, :name, invalid_option: :valid?) }
57
+ .to not_add_method(:name)
58
+ .to(decorator)
59
+ .and raise_error(Sinclair::Exception::InvalidOptions)
60
+ end
61
+ end
62
+ end
63
+
11
64
  describe '#as_json' do
12
65
  context 'when object is just a model' do
13
66
  let(:expected_json) do
@@ -33,7 +86,7 @@ describe Azeroth::Decorator do
33
86
  errors: {
34
87
  first_name: ["can't be blank"]
35
88
  }
36
- }.stringify_keys
89
+ }.deep_stringify_keys
37
90
  end
38
91
 
39
92
  it 'include the conditional attributes' do
@@ -59,11 +112,11 @@ describe Azeroth::Decorator do
59
112
  {
60
113
  name: "#{model.first_name} #{model.last_name}",
61
114
  age: model.age,
62
- pokemon: model.favorite_pokemon
115
+ pokemon: model.favorite_pokemon.to_s
63
116
  }, {
64
117
  name: "#{other_model.first_name} #{other_model.last_name}",
65
118
  age: other_model.age,
66
- pokemon: other_model.favorite_pokemon
119
+ pokemon: other_model.favorite_pokemon.to_s
67
120
  }
68
121
  ].map(&:stringify_keys)
69
122
  end
@@ -141,7 +194,7 @@ describe Azeroth::Decorator do
141
194
  errors: {
142
195
  name: ["can't be blank"]
143
196
  }
144
- }.stringify_keys
197
+ }.deep_stringify_keys
145
198
  end
146
199
 
147
200
  it 'returns meta data defined json' do
@@ -149,6 +202,59 @@ describe Azeroth::Decorator do
149
202
  end
150
203
  end
151
204
  end
205
+
206
+ context 'when decorator decorates relation' do
207
+ context 'when relation object has no decorator' do
208
+ subject(:decorator) do
209
+ Product::DecoratorWithFactory.new(product)
210
+ end
211
+
212
+ let(:product) { create(:product) }
213
+ let(:factory) { product.factory }
214
+
215
+ let(:expected_json) do
216
+ {
217
+ name: product.name,
218
+ factory: factory.as_json
219
+ }.stringify_keys
220
+ end
221
+
222
+ it 'exposes relation' do
223
+ expect(decorator.as_json).to eq(expected_json)
224
+ end
225
+ end
226
+
227
+ context 'when relation object has decorator' do
228
+ subject(:decorator) do
229
+ Factory::DecoratorWithProduct.new(factory)
230
+ end
231
+
232
+ let(:main_product) { create(:product) }
233
+ let(:factory) { main_product.factory }
234
+
235
+ let!(:other_product) do
236
+ create(:product, factory: factory)
237
+ end
238
+
239
+ let(:expected_json) do
240
+ {
241
+ name: factory.name,
242
+ main_product: {
243
+ name: main_product.name
244
+ },
245
+ products: [{
246
+ name: main_product.name
247
+ }, {
248
+ name: other_product.name
249
+ }]
250
+ }.deep_stringify_keys
251
+ end
252
+
253
+ it 'exposes relation' do
254
+ expect(decorator.as_json).to eq(expected_json)
255
+ end
256
+ end
257
+ end
152
258
  end
153
259
 
154
260
  describe '#method_missing' do
@@ -157,7 +157,7 @@ describe Azeroth::Model do
157
157
  errors: {
158
158
  name: ["can't be blank"]
159
159
  }
160
- }.stringify_keys
160
+ }.deep_stringify_keys
161
161
  end
162
162
 
163
163
  it 'object.as_json' do
@@ -9,7 +9,7 @@ describe Azeroth::Options do
9
9
  context 'when initializing with invalid options' do
10
10
  it do
11
11
  expect { described_class.new(invalid_option: 1) }
12
- .to raise_error(Azeroth::Exception::InvalidOptions)
12
+ .to raise_error(Sinclair::Exception::InvalidOptions)
13
13
  end
14
14
  end
15
15
  end
data/spec/spec_helper.rb CHANGED
@@ -17,10 +17,14 @@ require File.expand_path('spec/dummy/config/environment')
17
17
  require File.expand_path('spec/dummy/db/schema.rb')
18
18
  require 'rspec/rails'
19
19
  require 'active_support/railtie'
20
+ require 'sinclair/matchers'
20
21
 
21
22
  support_files = File.expand_path('spec/support/**/*.rb')
22
23
  Dir[support_files].sort.each { |file| require file }
23
24
 
25
+ RSpec::Matchers.define_negated_matcher :not_change, :change
26
+ RSpec::Matchers.define_negated_matcher :not_add_method, :add_method
27
+
24
28
  RSpec.configure do |config|
25
29
  config.infer_spec_type_from_file_location!
26
30
  config.run_all_when_everything_filtered = true
@@ -28,6 +32,7 @@ RSpec.configure do |config|
28
32
  config.filter_run_excluding :integration unless ENV['ALL']
29
33
 
30
34
  config.order = 'random'
35
+ config.include Sinclair::Matchers
31
36
 
32
37
  config.around do |example|
33
38
  Document.delete_all
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :factory, class: '::Factory' do
5
+ sequence(:name) { |n| "Factory ###{n}" }
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :product, class: '::Product' do
5
+ sequence(:name) { |n| "Product ###{n}" }
6
+ association :factory
7
+ end
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: azeroth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darthjee
@@ -416,8 +416,8 @@ files:
416
416
  - lib/azeroth.rb
417
417
  - lib/azeroth/decorator.rb
418
418
  - lib/azeroth/decorator/hash_builder.rb
419
+ - lib/azeroth/decorator/options.rb
419
420
  - lib/azeroth/dummy_decorator.rb
420
- - lib/azeroth/exception.rb
421
421
  - lib/azeroth/model.rb
422
422
  - lib/azeroth/options.rb
423
423
  - lib/azeroth/request_handler.rb
@@ -462,6 +462,11 @@ files:
462
462
  - spec/dummy/app/models/document/decorator_with_error.rb
463
463
  - spec/dummy/app/models/dummy_model.rb
464
464
  - spec/dummy/app/models/dummy_model/decorator.rb
465
+ - spec/dummy/app/models/factory.rb
466
+ - spec/dummy/app/models/factory/decorator_with_product.rb
467
+ - spec/dummy/app/models/product.rb
468
+ - spec/dummy/app/models/product/decorator.rb
469
+ - spec/dummy/app/models/product/decorator_with_factory.rb
465
470
  - spec/dummy/app/models/user.rb
466
471
  - spec/dummy/app/views/documents/edit.html
467
472
  - spec/dummy/app/views/documents/index.html
@@ -513,11 +518,9 @@ files:
513
518
  - spec/dummy/tmp/.keep
514
519
  - spec/dummy/tmp/storage/.keep
515
520
  - spec/integration/yard/azeroth/decorator_spec.rb
516
- - spec/integration/yard/azeroth/exception/invalid_options_spec.rb
517
521
  - spec/lib/azeroth/decorator/hash_builder_spec.rb
518
522
  - spec/lib/azeroth/decorator_spec.rb
519
523
  - spec/lib/azeroth/dummy_decorator_spec.rb
520
- - spec/lib/azeroth/exception/invalid_options_spec.rb
521
524
  - spec/lib/azeroth/model_spec.rb
522
525
  - spec/lib/azeroth/options_spec.rb
523
526
  - spec/lib/azeroth/request_handler/create_spec.rb
@@ -538,6 +541,8 @@ files:
538
541
  - spec/support/app/controllers/resource_route_builder_controller.rb
539
542
  - spec/support/factories/document.rb
540
543
  - spec/support/factories/dummy_model.rb
544
+ - spec/support/factories/factory.rb
545
+ - spec/support/factories/product.rb
541
546
  - spec/support/factories/user.rb
542
547
  - spec/support/factory_bot.rb
543
548
  - spec/support/matchers/add_method.rb
@@ -594,6 +599,11 @@ test_files:
594
599
  - spec/dummy/app/models/document/decorator_with_error.rb
595
600
  - spec/dummy/app/models/dummy_model.rb
596
601
  - spec/dummy/app/models/dummy_model/decorator.rb
602
+ - spec/dummy/app/models/factory.rb
603
+ - spec/dummy/app/models/factory/decorator_with_product.rb
604
+ - spec/dummy/app/models/product.rb
605
+ - spec/dummy/app/models/product/decorator.rb
606
+ - spec/dummy/app/models/product/decorator_with_factory.rb
597
607
  - spec/dummy/app/models/user.rb
598
608
  - spec/dummy/app/views/documents/edit.html
599
609
  - spec/dummy/app/views/documents/index.html
@@ -645,11 +655,9 @@ test_files:
645
655
  - spec/dummy/tmp/.keep
646
656
  - spec/dummy/tmp/storage/.keep
647
657
  - spec/integration/yard/azeroth/decorator_spec.rb
648
- - spec/integration/yard/azeroth/exception/invalid_options_spec.rb
649
658
  - spec/lib/azeroth/decorator/hash_builder_spec.rb
650
659
  - spec/lib/azeroth/decorator_spec.rb
651
660
  - spec/lib/azeroth/dummy_decorator_spec.rb
652
- - spec/lib/azeroth/exception/invalid_options_spec.rb
653
661
  - spec/lib/azeroth/model_spec.rb
654
662
  - spec/lib/azeroth/options_spec.rb
655
663
  - spec/lib/azeroth/request_handler/create_spec.rb
@@ -670,6 +678,8 @@ test_files:
670
678
  - spec/support/app/controllers/resource_route_builder_controller.rb
671
679
  - spec/support/factories/document.rb
672
680
  - spec/support/factories/dummy_model.rb
681
+ - spec/support/factories/factory.rb
682
+ - spec/support/factories/product.rb
673
683
  - spec/support/factories/user.rb
674
684
  - spec/support/factory_bot.rb
675
685
  - spec/support/matchers/add_method.rb
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Azeroth
4
- # @api private
5
- # @author Darthjee
6
- #
7
- # Excaptions raised by azeroth
8
- class Exception < ::StandardError
9
- # @api private
10
- # @author Darthjee
11
- #
12
- # Exception raised when invalid options are given
13
- #
14
- # @example Usage
15
- # exception = Azeroth::Exception::InvalidOptions.new(%i[invalid options])
16
- # exception.message
17
- # # return 'Invalid keys on options initialization (invalid options)'
18
- class InvalidOptions < Azeroth::Exception
19
- # @param invalid_keys [Array<Symbol>] list of invalid keys
20
- def initialize(invalid_keys = [])
21
- @invalid_keys = invalid_keys
22
- end
23
-
24
- # Exception string showing invalid keys
25
- #
26
- # @return [String]
27
- #
28
- # @example (see InvalidOptions)
29
- def message
30
- keys = invalid_keys.join(' ')
31
- "Invalid keys on options initialization (#{keys})"
32
- end
33
-
34
- private
35
-
36
- attr_reader :invalid_keys
37
- # @method invalid_keys
38
- # @api private
39
- # @private
40
- #
41
- # invalid keys on options initialization
42
- #
43
- # @return [Array<Symbol>]
44
- end
45
- end
46
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Azeroth::Exception::InvalidOptions do
6
- describe '#message' do
7
- let(:exception) { described_class.new(%i[invalid options]) }
8
- let(:expected_message) do
9
- 'Invalid keys on options initialization (invalid options)'
10
- end
11
-
12
- it 'shows invalid keys' do
13
- expect(exception.message).to eq(expected_message)
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Azeroth::Exception::InvalidOptions do
6
- describe '#message' do
7
- let(:exception) { described_class.new(%i[invalid options]) }
8
- let(:expected_message) do
9
- 'Invalid keys on options initialization (invalid options)'
10
- end
11
-
12
- it 'shows invalid keys' do
13
- expect(exception.message).to eq(expected_message)
14
- end
15
- end
16
- end