azeroth 0.6.1 → 0.6.2

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: 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