object_forge 0.3.0 → 0.4.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.
@@ -5,7 +5,12 @@ require_relative "forge_dsl"
5
5
  require_relative "molds"
6
6
 
7
7
  module ObjectForge
8
- # Object instantitation forge.
8
+ # Object building forge.
9
+ #
10
+ # Usually created through {.define} or {Forgeyard#define} using {ForgeDSL}.
11
+ # Alternatively, can be directly initalized with {Parameters} if you prefer not using the DSL.
12
+ #
13
+ # Then, {#forge} can be called to build instances of {#forge_target}.
9
14
  #
10
15
  # @since 0.1.0
11
16
  class Forge
@@ -14,62 +19,72 @@ module ObjectForge
14
19
  # through means other than {ForgeDSL}.
15
20
  #
16
21
  # @!attribute [r] attributes
17
- # Non-trait values of the attributes.
18
- # @return [Hash{Symbol => Any}]
22
+ # Default values of the attributes.
23
+ # @return [Hash{Symbol => Proc, Any}]
19
24
  #
20
25
  # @!attribute [r] traits
21
26
  # Attributes belonging to traits.
22
- # @return [Hash{Symbol => Hash{Symbol => Any}}]
23
- #
24
- # @!attribute [r] settings
25
- # A forge's settings.
26
- # Must include a +:mold+ key, containing an object that knows how to build the instance
27
- # with a +call+ method that takes a class and a hash of attributes.
27
+ # @return [Hash{Symbol => Hash{Symbol => Proc, Any}}]
28
+ #
29
+ # @!attribute [r] options
30
+ # A forge's options.
31
+ # Known options:
32
+ # - +:mold+ — a +call+able object that knows how to build the instance,
33
+ # taking a class and a hash of attributes.
34
+ # - +:crucible+ — a +call+able object that knows how to resolve attributes,
35
+ # taking a hash of initial attributes.
36
+ # - +:after_forge+/+:after_build+ — a +call+able object that is passed
37
+ # the forged instance and can do anything with it.
28
38
  # @since 0.3.0
29
39
  # @return [Hash{Symbol => Any}]
30
- Parameters = Struct.new(:attributes, :traits, :settings, keyword_init: true)
40
+ Parameters = Struct.new(:attributes, :traits, :options, keyword_init: true)
31
41
 
32
- # Define (and create) a forge using DSL.
42
+ # Define (and initialize) a forge using DSL.
33
43
  #
34
44
  # @see ForgeDSL
35
45
  # @thread_safety Thread-safe if DSL definition is thread-safe.
36
46
  #
37
- # @param forged [Class, Any] class or object to forge
47
+ # @param forge_target [Class, Any] class or object to forge
38
48
  # @param name [Symbol, nil] forge name
39
- # @yieldparam f [ForgeDSL]
49
+ # @yieldparam dsl [ForgeDSL]
40
50
  # @yieldreturn [void]
41
51
  # @return [Forge] forge
42
- def self.define(forged, name: nil, &)
43
- new(forged, ForgeDSL.new(&), name:)
52
+ def self.define(forge_target, name: nil, &)
53
+ new(forge_target, ForgeDSL.new(&), name:)
44
54
  end
45
55
 
46
- # @return [Symbol, nil] forge name
56
+ # @return [Symbol, nil] forge name, only used for identification purposes
47
57
  attr_reader :name
48
58
 
49
59
  # @return [Class, Any] class or object to forge
50
- attr_reader :forged
60
+ # @since 0.4.0
61
+ attr_reader :forge_target
62
+ alias target forge_target
51
63
 
52
64
  # @return [Parameters, ForgeDSL] forge parameters
53
65
  attr_reader :parameters
54
66
 
55
- # @param forged [Class, Any] class or object to forge
67
+ # @param forge_target [Class, Any] class or object to forge,
68
+ # will be passed to mold as +forge_target+ argument
56
69
  # @param parameters [Parameters, ForgeDSL] forge parameters
57
- # @param name [Symbol, nil] forge name;
58
- # only used for identification purposes
59
- def initialize(forged, parameters, name: nil)
70
+ # @param name [Symbol, nil] forge name
71
+ #
72
+ # @raise [ObjectInterfaceError] if forge options do not have expected interface;
73
+ # see {Parameters#options} for details
74
+ def initialize(forge_target, parameters, name: nil)
60
75
  @name = name
61
- @forged = forged
76
+ @forge_target = forge_target
62
77
  @parameters = parameters
63
- @mold = determine_mold(forged, parameters.settings[:mold])
78
+
79
+ options = @parameters.options
80
+ @crucible = determine_crucible(options)
81
+ @mold = determine_mold(forge_target, options)
82
+ @after_forge_hook = determine_after_forge_hook(options)
64
83
  end
65
84
 
66
- # Forge a new instance.
85
+ # Forge a new instance, applying attributes to forge target.
67
86
  #
68
- # @overload forge(*traits, **overrides, &)
69
- # @overload forge(traits, overrides, &)
70
- #
71
- # Positional arguments are taken as trait names, keyword arguments as attribute overrides,
72
- # unless there are exactly two positional arguments: an array and a hash.
87
+ # Positional arguments are taken as trait names, keyword arguments as attribute overrides.
73
88
  #
74
89
  # All traits and overrides are applied in argument order,
75
90
  # with overrides always applied after traits.
@@ -80,13 +95,16 @@ module ObjectForge
80
95
  # +traits+ and +overrides+ are thread-safe.
81
96
  #
82
97
  # @param traits [Array<Symbol>] traits to apply
83
- # @param overrides [Hash{Symbol => Any}] attribute overrides
98
+ # @param overrides [Hash{Symbol => Proc, Any}] attribute overrides
84
99
  # @yieldparam object [Any] forged instance
85
100
  # @yieldreturn [void]
86
- # @return [Any] built instance
101
+ # @return [Any] forged instance
102
+ #
103
+ # @raise [ArgumentError] if a trait name is unknown
87
104
  def forge(*traits, **overrides)
88
105
  resolved_attributes = resolve_attributes(traits, overrides)
89
- instance = @mold.call(forged: @forged, attributes: resolved_attributes)
106
+ instance = @mold.call(forge_target: @forge_target, attributes: resolved_attributes)
107
+ @after_forge_hook&.call(instance)
90
108
  yield instance if block_given?
91
109
  instance
92
110
  end
@@ -96,31 +114,83 @@ module ObjectForge
96
114
 
97
115
  private
98
116
 
117
+ # Get a crucible object based on parameters.
118
+ #
119
+ # It's either the object provided in options, or {Crucible}.
120
+ #
121
+ # @param options [Hash]
122
+ # @option options [#call, nil] :crucible
123
+ # @return [#call]
124
+ #
125
+ # @raise [ObjectInterfaceError]
126
+ #
127
+ # @since 0.4.0
128
+ def determine_crucible(options)
129
+ crucible = options[:crucible] || Crucible
130
+
131
+ unless crucible.respond_to?(:call)
132
+ raise ObjectInterfaceError, "crucible must respond to #call"
133
+ end
134
+
135
+ crucible
136
+ end
137
+
99
138
  # Get appropriate mold based on parameters.
100
139
  #
101
140
  # If +mold+ is already set, it will be used directly, or,
102
141
  # if it is Class, it will be wrapped in {Molds::WrappedMold} if posssible.
103
- # If +nil+, a mold will be selected based on +forged+ class.
142
+ # If +nil+, a mold will be selected based on +forge_target+ class.
104
143
  #
105
- # @param forged [Class, Any]
106
- # @param mold [#call, Class, nil]
144
+ # @param forge_target [Class, Any]
145
+ # @param options [Hash]
146
+ # @option options [#call, Class, nil] :mold
107
147
  # @return [#call]
108
148
  #
109
- # @raise [MoldError]
149
+ # @raise [ObjectInterfaceError]
110
150
  #
111
151
  # @since 0.3.0
112
- def determine_mold(forged, mold)
113
- Molds.wrap_mold(mold) || Molds.mold_for(forged)
152
+ def determine_mold(forge_target, options)
153
+ Molds.wrap_mold(options[:mold]) || Molds.mold_for(forge_target)
154
+ end
155
+
156
+ # Get after-forge hook if specified.
157
+ #
158
+ # Both +:after_forge+ and +:after_build+ are accepted, but +:after_forge+
159
+ # wins if both are present.
160
+ #
161
+ # @param options [Hash]
162
+ # @option options [#call, nil] :after_forge
163
+ # @option options [#call, nil] :after_build
164
+ # @return [#call, nil]
165
+ #
166
+ # @raise [ObjectInterfaceError]
167
+ #
168
+ # @since 0.4.0
169
+ def determine_after_forge_hook(options)
170
+ hook = options[:after_forge] || options[:after_build] || nil
171
+
172
+ unless hook.nil? || hook.respond_to?(:call)
173
+ raise ObjectInterfaceError, "after-forge hook must respond to #call"
174
+ end
175
+
176
+ hook
114
177
  end
115
178
 
116
179
  # Resolve attributes using default attributes, specified traits and overrides.
117
180
  #
118
181
  # @param traits [Array<Symbol>]
119
- # @param overrides [Hash{Symbol => Any}]
182
+ # @param overrides [Hash{Symbol => Proc, Any}]
120
183
  # @return [Hash{Symbol => Any}]
184
+ #
185
+ # @raise [ArgumentError]
121
186
  def resolve_attributes(traits, overrides)
187
+ unless (unknown_traits = traits.difference(@parameters.traits.keys)).empty?
188
+ raise ArgumentError,
189
+ "unknown traits for forge#{" #{name}" if name}: #{unknown_traits.join(", ")}"
190
+ end
191
+
122
192
  attributes = @parameters.attributes.merge(*@parameters.traits.values_at(*traits), overrides)
123
- Crucible.new(attributes).resolve!
193
+ @crucible.call(attributes)
124
194
  end
125
195
  end
126
196
  end
@@ -27,8 +27,8 @@ module ObjectForge
27
27
  # @return [Hash{Symbol => Hash{Symbol => Proc}}] trait definitions
28
28
  attr_reader :traits
29
29
 
30
- # @return [Hash{Symbol => Any}] settings for forge, such as mold
31
- attr_reader :settings
30
+ # @return [Hash{Symbol => Any}] options for forge, such as mold
31
+ attr_reader :options
32
32
 
33
33
  # Define forge's parameters through DSL.
34
34
  #
@@ -39,7 +39,7 @@ module ObjectForge
39
39
  #
40
40
  # @example with block parameter
41
41
  # ForgeDSL.new do |f|
42
- # f.mold = ObjectForge::Molds::KeywordsMolds.new
42
+ # f.mold = ObjectForge::Molds::KeywordsMold.new
43
43
  # f.attribute(:name) { "Name" }
44
44
  # f[:description] { name.upcase }
45
45
  # f.duration { rand(1000) }
@@ -47,27 +47,27 @@ module ObjectForge
47
47
  #
48
48
  # @example without block parameter
49
49
  # ForgeDSL.new do
50
- # self.mold = ::ObjectForge::Molds::KeywordsMolds.new
50
+ # self.mold = ::ObjectForge::Molds::KeywordsMold.new
51
51
  # attribute(:name) { "Name" }
52
52
  # self[:description] { name.upcase }
53
53
  # duration { rand(1000) }
54
54
  # end
55
55
  #
56
- # @yieldparam f [ForgeDSL] self
56
+ # @yieldparam dsl [ForgeDSL] self
57
57
  # @yieldreturn [void]
58
58
  def initialize(&dsl)
59
59
  super
60
60
  @attributes = {}
61
61
  @sequences = {}
62
62
  @traits = {}
63
- @settings = {}
63
+ @options = {}
64
64
 
65
65
  dsl.arity.zero? ? instance_exec(&dsl) : yield(self)
66
66
 
67
67
  freeze
68
68
  end
69
69
 
70
- # Freezes the instance, including +settings+, +attributes+, +sequences+ and +traits+.
70
+ # Freezes the instance, including +options+, +attributes+, +sequences+ and +traits+.
71
71
  # Prevents further responses through +#method_missing+.
72
72
  #
73
73
  # @note Called automatically in {#initialize}.
@@ -78,40 +78,42 @@ module ObjectForge
78
78
  @attributes.freeze
79
79
  @sequences.freeze
80
80
  @traits.freeze
81
- @settings.freeze
81
+ @options.freeze
82
82
  self
83
83
  end
84
84
 
85
- # Set a value for a forge's setting.
85
+ # Set a value for a forge's option.
86
86
  #
87
- # Possible settings depend on used forge, but for default {Forge} a +mold+ is expected.
87
+ # Possible options depend on used forge, but for default {Forge} a +:mold+ is expected.
88
+ # Check its documentation for full list of available options.
88
89
  #
89
- # It is also possible to set settings through +method_missing+, using name with a +=+ suffix.
90
+ # It is also possible to set options through +method_missing+, using name with a +=+ suffix.
90
91
  #
91
92
  # @see Molds
93
+ # @see Forge::Parameters#options
92
94
  #
93
95
  # @example
94
- # f.setting(:mold, ->(forged:, attributes:, **) { forge.new(**attributes) })
96
+ # f.option(:mold, ->(forge_target:, attributes:, **) { forge.new(**attributes) })
95
97
  # f.mold = ObjectForge::Molds::SingleArgumentMold.new
96
98
  #
97
- # @param name [Sumbol] setting name
98
- # @param value [Any] value for the setting
99
- # @return [Symbol] setting name
99
+ # @param name [Symbol] option name
100
+ # @param value [Any] value for the option
101
+ # @return [Symbol] option name
100
102
  #
101
- # @raise [ArgumentError] if +name+ is not a Symbol
102
- def setting(name, value)
103
+ # @raise [TypeError] if +name+ is not a Symbol
104
+ def option(name, value)
103
105
  unless ::Symbol === name
104
- raise ::ArgumentError, "setting name must be a Symbol, #{name.class} given"
106
+ raise ::TypeError, "option name must be a Symbol, #{name.class} given"
105
107
  end
106
108
 
107
- @settings[name] = value
109
+ @options[name] = value
108
110
 
109
111
  name
110
112
  end
111
113
 
112
114
  # Define an attribute, possibly transient.
113
115
  #
114
- # DSL does not know or care what attributes the forged class has,
116
+ # DSL does not know or care what attributes the target class has,
115
117
  # so the only difference between "real" and "transient" attributes
116
118
  # is how the class itself treats them.
117
119
  #
@@ -125,6 +127,7 @@ module ObjectForge
125
127
  # f.attribute(:name) { "Name" }
126
128
  # f[:description] { name.downcase }
127
129
  # f.duration { rand(1000) }
130
+ #
128
131
  # @example using conflicting and reserved names
129
132
  # f.attribute(:[]) { "Brackets" }
130
133
  # f.attribute(:[]=) { "#{self[:[]]} are brackets" }
@@ -134,11 +137,11 @@ module ObjectForge
134
137
  # @yieldreturn [Any] attribute value
135
138
  # @return [Symbol] attribute name
136
139
  #
137
- # @raise [ArgumentError] if +name+ is not a Symbol
140
+ # @raise [TypeError] if +name+ is not a Symbol
138
141
  # @raise [DSLError] if no block is given
139
142
  def attribute(name, &definition)
140
143
  unless ::Symbol === name
141
- raise ::ArgumentError,
144
+ raise ::TypeError,
142
145
  "attribute name must be a Symbol, #{name.class} given (in #{name.inspect})"
143
146
  end
144
147
  unless block_given?
@@ -166,9 +169,11 @@ module ObjectForge
166
169
  # f.sequence(:date, Date.today)
167
170
  # f.sequence(:id) { _1.to_s }
168
171
  # f.sequence(:dated_id, 10) { |n| "#{Date.today}/#{n}-#{id}" }
172
+ #
169
173
  # @example using external sequence
170
174
  # seq = Sequence.new(1)
171
175
  # f.sequence(:global_id, seq)
176
+ #
172
177
  # @example sequence reuse
173
178
  # f.sequence(:id, "a") # => "a", "b", ...
174
179
  # f.trait :new_id do
@@ -181,11 +186,11 @@ module ObjectForge
181
186
  # @yieldreturn [Any] attribute value
182
187
  # @return [Symbol] attribute name
183
188
  #
184
- # @raise [ArgumentError] if +name+ is not a Symbol
185
- # @raise [DSLError] if +initial+ does not respond to #succ and is not a {Sequence}
189
+ # @raise [TypeError] if +name+ is not a Symbol
190
+ # @raise [ObjectInterfaceError] if +initial+ does not respond to #succ and is not a {Sequence}
186
191
  def sequence(name, initial = 1, **nil, &)
187
192
  unless ::Symbol === name
188
- raise ::ArgumentError,
193
+ raise ::TypeError,
189
194
  "sequence name must be a Symbol, #{name.class} given (in #{name.inspect})"
190
195
  end
191
196
 
@@ -210,6 +215,7 @@ module ObjectForge
210
215
  # f.name { "***xXxSPECIALxXx***" }
211
216
  # f.sequence(:special_id) { "~~~ SpEcIaL #{_1} ~~~" }
212
217
  # end
218
+ #
213
219
  # @example externally defined trait
214
220
  # # Variable defined outside of DSL:
215
221
  # success_trait = ->(ft) do
@@ -227,13 +233,12 @@ module ObjectForge
227
233
  # @yieldreturn [void]
228
234
  # @return [Symbol] trait name
229
235
  #
230
- # @raise [ArgumentError] if +name+ is not a Symbol
236
+ # @raise [TypeError] if +name+ is not a Symbol
231
237
  # @raise [DSLError] if no block is given
232
238
  # @raise [DSLError] if called inside of another trait definition
233
239
  def trait(name, **nil)
234
240
  unless ::Symbol === name
235
- raise ::ArgumentError,
236
- "trait name must be a Symbol, #{name.class} given (in #{name.inspect})"
241
+ raise ::TypeError, "trait name must be a Symbol, #{name.class} given (in #{name.inspect})"
237
242
  end
238
243
  if @current_trait
239
244
  raise DSLError, "can not define trait inside of another trait (in #{name.inspect})"
@@ -261,12 +266,12 @@ module ObjectForge
261
266
 
262
267
  private
263
268
 
264
- # Define an attribute (like +name+) or set a setting (like +name=+) using a shorthand.
269
+ # Define an attribute (like +name+) or set a option (like +name=+) using a shorthand.
265
270
  #
266
271
  # Can not be used with reserved names.
267
272
  # Trying to use a conflicting name will lead to usual issues
268
273
  # with calling random methods.
269
- # When in doubt, use {#attribute} or {#setting} instead.
274
+ # When in doubt, use {#attribute} or {#option} instead.
270
275
  #
271
276
  # Reserved names are:
272
277
  # - all names ending in +?+, +!+
@@ -274,16 +279,16 @@ module ObjectForge
274
279
  # (operators, +`+, +[]+, +[]=+)
275
280
  # - +rand+
276
281
  #
277
- # @param name [Symbol] attribute or setting name
278
- # @param value [Any] value for setting
282
+ # @param name [Symbol] attribute or option name
283
+ # @param value [Any] value for option
279
284
  # @yieldreturn [Any] attribute value
280
- # @return [Symbol] attribute or setting name
285
+ # @return [Symbol] attribute or option name
281
286
  #
282
287
  # @raise [DSLError] if a reserved +name+ is used
283
288
  def method_missing(name, value = nil, **nil, &)
284
289
  return super(name) if frozen?
285
- if valid_setting_method?(name)
286
- return setting(name[...-1].to_sym, value) # steep:ignore NoMethod
290
+ if valid_option_method?(name)
291
+ return option(name[...-1].to_sym, value) # steep:ignore NoMethod
287
292
  end
288
293
  return attribute(name, &) if respond_to_missing?(name, false)
289
294
 
@@ -291,12 +296,12 @@ module ObjectForge
291
296
  end
292
297
 
293
298
  def respond_to_missing?(name, _include_all)
294
- return false if frozen?
299
+ return super if frozen?
295
300
 
296
301
  !name.end_with?("?", "!") && !name.match?(/\A(?=\p{ASCII})\P{Word}/) && name != :rand
297
302
  end
298
303
 
299
- def valid_setting_method?(name)
304
+ def valid_option_method?(name)
300
305
  name.match?(/\A\p{Word}.*=\z/)
301
306
  end
302
307
  end
@@ -22,12 +22,12 @@ module ObjectForge
22
22
  # @see Forge.define
23
23
  #
24
24
  # @param name [Symbol] name to register forge under
25
- # @param forged [Class, Any] class or object to forge
26
- # @yieldparam f [ForgeDSL]
25
+ # @param forge_target [Class, Any] class or object to forge
26
+ # @yieldparam dsl [ForgeDSL]
27
27
  # @yieldreturn [void]
28
28
  # @return [Forge] forge
29
- def define(name, forged, &)
30
- register(name, Forge.define(forged, name: name, &))
29
+ def define(name, forge_target, &)
30
+ register(name, Forge.define(forge_target, name: name, &))
31
31
  end
32
32
 
33
33
  # Add a forge under a specified name.
@@ -59,14 +59,15 @@ module ObjectForge
59
59
  #
60
60
  # @see Forge#forge
61
61
  #
62
- # @param name [Symbol] name of the forge
63
- # @param traits [Array<Symbol>] traits to apply
64
- # @param overrides [Hash{Symbol => Any}] attribute overrides
65
- # @yieldparam object [Any] forged instance
66
- # @yieldreturn [void]
67
- # @return [Any] built instance
68
- #
69
- # @raise [KeyError] if forge with the specified name is not registered
62
+ # @overload forge(name, *traits, **overrides)
63
+ # @param name [Symbol] name of the forge
64
+ # @param traits [Array<Symbol>] traits to apply
65
+ # @param overrides [Hash{Symbol => Any}] attribute overrides
66
+ # @yieldparam object [Any] forged instance
67
+ # @yieldreturn [void]
68
+ # @return [Any] forged instance
69
+ # @raise [ArgumentError] if a trait name is unknown
70
+ # @raise [KeyError] if forge with the specified name is not registered
70
71
  def forge(name, ...)
71
72
  @forges.fetch(name).call(...)
72
73
  end
@@ -36,15 +36,15 @@ module ObjectForge
36
36
  @default_proc = default_proc
37
37
  end
38
38
 
39
- # Build a new hash using +forged.[]+.
39
+ # Build a new hash using +forge_target.[]+.
40
40
  #
41
41
  # @see Hash.[]
42
42
  #
43
- # @param forged [Class] Hash or a subclass of Hash
43
+ # @param forge_target [Class] Hash or a subclass of Hash
44
44
  # @param attributes [Hash{Symbol => Any}]
45
45
  # @return [Hash]
46
- def call(forged:, attributes:, **_)
47
- hash = forged[attributes]
46
+ def call(forge_target:, attributes:, **_)
47
+ hash = forge_target[attributes]
48
48
  hash.default = @default if @default
49
49
  hash.default_proc = @default_proc if @default_proc
50
50
  hash
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ObjectForge
4
4
  module Molds
5
- # Basic mold which calls +forged.new(**attributes)+.
5
+ # Basic mold which calls +forge_target.new(**attributes)+.
6
6
  #
7
7
  # Can be used instead of {SingleArgumentMold}
8
8
  # due to how keyword arguments are treated in Ruby,
@@ -11,13 +11,13 @@ module ObjectForge
11
11
  # @thread_safety Thread-safe.
12
12
  # @since 0.2.0
13
13
  class KeywordsMold
14
- # Instantiate +forged+ with a hash of attributes.
14
+ # Instantiate forge target with a hash of attributes.
15
15
  #
16
- # @param forged [Class, #new]
16
+ # @param forge_target [Class, #new]
17
17
  # @param attributes [Hash{Symbol => Any}]
18
18
  # @return [Any]
19
- def call(forged:, attributes:, **_)
20
- forged.new(**attributes)
19
+ def call(forge_target:, attributes:, **_)
20
+ forge_target.new(**attributes)
21
21
  end
22
22
  end
23
23
  end
@@ -2,18 +2,18 @@
2
2
 
3
3
  module ObjectForge
4
4
  module Molds
5
- # Basic mold which calls +forged.new(attributes)+.
5
+ # Basic mold which calls +forge_target.new(attributes)+.
6
6
  #
7
7
  # @thread_safety Thread-safe.
8
8
  # @since 0.2.0
9
9
  class SingleArgumentMold
10
- # Instantiate +forged+ with a hash of attributes.
10
+ # Instantiate forge target with a hash of attributes.
11
11
  #
12
- # @param forged [Class, #new]
12
+ # @param forge_target [Class, #new]
13
13
  # @param attributes [Hash{Symbol => Any}]
14
14
  # @return [Any]
15
- def call(forged:, attributes:, **_)
16
- forged.new(attributes)
15
+ def call(forge_target:, attributes:, **_)
16
+ forge_target.new(attributes)
17
17
  end
18
18
  end
19
19
  end
@@ -32,18 +32,22 @@ module ObjectForge
32
32
  @lax = lax
33
33
  end
34
34
 
35
- # Instantiate +forged+ struct with a hash of attributes.
35
+ # Instantiate target struct with a hash of attributes.
36
36
  #
37
- # @param forged [Class] a subclass of Struct
37
+ # @param forge_target [Class] a subclass of Struct
38
38
  # @param attributes [Hash{Symbol => Any}]
39
39
  # @return [Struct]
40
- def call(forged:, attributes:, **_)
41
- if forged.keyword_init?
42
- lax ? forged.new(attributes.slice(*forged.members)) : forged.new(attributes)
43
- elsif forged.keyword_init? == false
44
- forged.new(*attributes.values_at(*forged.members))
40
+ def call(forge_target:, attributes:, **_)
41
+ if forge_target.keyword_init?
42
+ if lax
43
+ forge_target.new(attributes.slice(*forge_target.members))
44
+ else
45
+ forge_target.new(attributes)
46
+ end
47
+ elsif forge_target.keyword_init? == false
48
+ forge_target.new(*attributes.values_at(*forge_target.members))
45
49
  else
46
- build_struct_with_unspecified_keyword_init(forged, attributes)
50
+ build_struct_with_unspecified_keyword_init(forge_target, attributes)
47
51
  end
48
52
  end
49
53
 
@@ -51,18 +55,18 @@ module ObjectForge
51
55
 
52
56
  if RUBY_FEATURE_AUTO_KEYWORDS
53
57
  # Build struct by using keywords to specify member values.
54
- def build_struct_with_unspecified_keyword_init(forged, attributes)
58
+ def build_struct_with_unspecified_keyword_init(forge_target, attributes)
55
59
  if lax
56
- forged.new(**attributes.slice(*forged.members))
60
+ forge_target.new(**attributes.slice(*forge_target.members))
57
61
  else
58
- forged.new(**attributes)
62
+ forge_target.new(**attributes)
59
63
  end
60
64
  end
61
65
  else
62
66
  # :nocov:
63
67
  # Build struct by using positional arguments to specify member values.
64
- def build_struct_with_unspecified_keyword_init(forged, attributes)
65
- forged.new(*attributes.values_at(*forged.members))
68
+ def build_struct_with_unspecified_keyword_init(forge_target, attributes)
69
+ forge_target.new(*attributes.values_at(*forge_target.members))
66
70
  end
67
71
  # :nocov:
68
72
  end
@@ -20,10 +20,10 @@ module ObjectForge
20
20
  @wrapped_mold = wrapped_mold
21
21
  end
22
22
 
23
- # @overload call(...)
24
23
  # Instantiate {wrapped_mold} and call it.
25
24
  #
26
- # @return [Any] result of +wrapped_mold.new.call(...)+
25
+ # @overload call(...)
26
+ # @return [Any] result of +wrapped_mold.new.call(...)+
27
27
  def call(...)
28
28
  wrapped_mold.new.call(...)
29
29
  end