opt_struct 0.9.0 → 1.2.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: 54518e9eca18b69463f611c221bd896a94cbd5293bd804a23319b0dd7441573d
4
- data.tar.gz: 36584d846f30ebf6517d541a31668678a1a8dbd9025a4d9bef032eea2372c50f
3
+ metadata.gz: 824012017028badde180165fa6280f398cbf138f09f8600319625e92fbaf67ed
4
+ data.tar.gz: 2c612d601c220eb88aaaf656917cd06d0edc7a87b70f84c67cda6b17e6cbbe94
5
5
  SHA512:
6
- metadata.gz: ff0a53a81253354676e0578028d775785eda00d30c7201b3f36414009b26ad551893f789dc9aabf82ec212b7abd5544432a045cfe4f973e59136ffeec1258867
7
- data.tar.gz: fbbd6f407b889e2cca7b6b9d5ce891cdad58bb73db10a1e437515d74d1221af442da0cbb7715f8f20db05ea0799035951e094d9ad5bece86775f7c05fdd17c1e
6
+ metadata.gz: f7cf9e8c1d9e0b9c40a2f08c1f32784fa61b38a14edac39f4bef3f887845827a57f9b813e2f8df6dbb0436734c8f5895d7b25f45adb2bff3fa82eb7e87766fee
7
+ data.tar.gz: aea1084efba08f15951e7d8629c1a8211d66bddd720dfee19a1c1ec5a8eb52d6c73f047ac4ae8c5b7a969912113b0093249f48f991415ca932170d64e69b956d
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # The Opt Struct
1
+ # The Opt Struct [![Build Status][travis-image]][travis-link]
2
+
3
+ [travis-image]: https://travis-ci.org/carlzulauf/opt_struct.svg?branch=master
4
+ [travis-link]: http://travis-ci.org/carlzulauf/opt_struct
2
5
 
3
6
  A struct around a hash. Great for encapsulating actions with complex configuration, like interactor/action classes.
4
7
 
@@ -6,137 +9,342 @@ A struct around a hash. Great for encapsulating actions with complex configurati
6
9
  gem "opt_struct"
7
10
  ```
8
11
 
9
- ## Example 1
12
+ # Examples
10
13
 
11
- Can work mostly like a regular struct, while accepting options
14
+ ## Creating an OptStruct
12
15
 
13
16
  ```ruby
14
- MyClass = OptStruct.new(:foo, :bar)
17
+ class User < OptStruct.new
18
+ required :email, :name
19
+ option :role, default: "member"
20
+
21
+ def formatted_email
22
+ %{"#{name}" <#{email}>}
23
+ end
24
+ end
25
+ ```
15
26
 
16
- MyClass.new
17
- # => argument error
27
+ ## Using an OptStruct
18
28
 
19
- MyClass.new "foo", "bar"
20
- # => #<MyClass>
29
+ ```ruby
30
+ user = User.new(email: "admin@user.com", name: "Ms. Admin", role: "admin")
31
+
32
+ # option accessors are available
33
+ user.name
34
+ # => "Ms. Admin"
35
+ user.formatted_email
36
+ # => "\"Ms. Admin\" <admin@user.com>"
37
+ user.name = "Amber Admin"
38
+ # => "Amber Admin"
39
+
40
+ # values are also accessible through the `#options` Hash
41
+ user.options
42
+ # => {:email=>"admin@user.com", :name=>"Amber Admin", :role=>"admin"}
43
+ user.options.fetch(:role)
44
+ # => "admin"
45
+ ```
21
46
 
22
- MyClass.new foo: "foo", bar: "bar"
23
- # => #<MyClass>
47
+ # Documentation
24
48
 
25
- i = MyClass.new "foo", "bar", yin: "yang"
26
- i.options
27
- # => {yin: "yang"}
28
- i.fetch(:yin)
29
- # => "yang"
30
- ```
49
+ ## Use As Inheritable Class
50
+
51
+ `OptStruct.new` returns an instance of `Class` that can be inherited or initialized directly.
31
52
 
32
- ## Example 2
53
+ The following are functionally equivalent
33
54
 
34
- Passing a hash promotes the keys (`:foo` below) to an `option` giving it getter/setter methods on the class. The value becomes the default. This is equivalent and can be combined with using the `option` macro.
55
+ ```ruby
56
+ class User < OptStruct.new
57
+ required :email
58
+ option :name
59
+ end
60
+ ```
61
+
62
+ ```ruby
63
+ User = OptStruct.new do
64
+ required :email
65
+ option :name
66
+ end
67
+ ```
35
68
 
36
- If an option is required it needs to be called out as such using `required`.
69
+ `OptStruct` classes can safely have descendants with their own isolated options.
37
70
 
38
71
  ```ruby
39
- class MyClass < OptStruct.new(foo: "bar")
40
- required :yin # equivalent to: `option :yin, required: true`
41
- option :bar, default: "foo"
72
+ class AdminUser < User
73
+ required :token
42
74
  end
43
75
 
44
- MyClass.new
45
- # => missing keyword argument :yin
76
+ User.new(email: "regular@user.com")
77
+ # => #<User:0x0... @options={:email=>"regular@user.com"}>
78
+
79
+ AdminUser.new(email: "admin@user.com")
80
+ # ArgumentError: missing required keywords: [:token]
46
81
 
47
- i = MyClass.new yin: "yang"
48
- # => #<MyClass>
49
- i.foo
50
- # => "bar"
51
- i.bar
52
- # => "foo"
53
- i.foo = "foo"
54
- i.options
55
- # => {foo: "foo", bar: "foo", yin: "yang"}
82
+ AdminUser.new(email: "admin@user.com", token: "a2236843f0227af2")
83
+ # => #<AdminUser:0x0... @options={:email=>"admin@user.com", :token=>"..."}>
56
84
  ```
57
85
 
58
- ## Example 3
86
+ ## Use As Mixin Module
59
87
 
60
- Works as a plain old mixin as well.
88
+ `OptStruct.build` returns an instance of `Module` that can be included into a class or another module.
89
+
90
+ The following are functionally equivalent
61
91
 
62
92
  ```ruby
63
- class MyClass
64
- include OptStruct
65
- required :foo
93
+ module Visitable
94
+ include OptStruct.build
95
+ options :expected_at, :arrived_at, :departed_at
96
+ end
97
+
98
+ class AuditLog
99
+ include Visitable
66
100
  end
101
+ ```
67
102
 
68
- MyClass.new
69
- # => missing keyword argument :foo
103
+ ```ruby
104
+ Visitable = OptStruct.build { options :expected_at, :arrived_at, :departed_at }
70
105
 
71
- MyClass.new(foo: "bar").foo
72
- # => "bar"
106
+ class AuditLog
107
+ include Visitable
108
+ end
73
109
  ```
74
110
 
75
- ## Example 4
111
+ These examples result in an `AuditLog` class with identical behavior, but no explicit `Visitable` module.
76
112
 
77
- Options passed to `new` can be passed to `build` when used in module form.
113
+ ```ruby
114
+ class AuditLog
115
+ include OptStruct.build
116
+ options :expected_at, :arrived_at, :departed_at
117
+ end
118
+ ```
78
119
 
79
120
  ```ruby
80
- class MyClass
81
- include OptStruct.build(:foo, bar: nil)
121
+ class AuditLog
122
+ include(OptStruct.build do
123
+ options :expected_at, :arrived_at, :departed_at
124
+ end)
82
125
  end
126
+ ```
127
+
128
+ ## Optional Arguments
129
+
130
+ Optional arguments are simply accessor methods for values expected to be in the `#options` Hash. Optional arguments can be defined in multiple ways.
83
131
 
84
- MyClass.new
85
- # => argument error
132
+ All of the examples in this section are functionally equivalent.
86
133
 
87
- i = MyClass.new("something", bar: "foo")
88
- [i.foo, i.bar]
89
- # => ["something", "foo"]
134
+ ```ruby
135
+ class User < OptStruct.new
136
+ option :email
137
+ option :role, default: "member"
138
+ end
90
139
  ```
91
140
 
92
- ## Example 5
141
+ ```ruby
142
+ class User < OptStruct.new
143
+ options :email, role: "member"
144
+ end
145
+ ```
146
+
147
+ ```ruby
148
+ class User < OptStruct.new
149
+ options email: nil, role: "member"
150
+ end
151
+ ```
93
152
 
94
- Both `build` and `new` accept a block.
153
+ Passing a Hash to `.new` or `.build` is equivalent to passing the same hash to `options`
95
154
 
96
155
  ```ruby
97
- PersonClass = OptStruct.new do
98
- required :first_name
99
- option :last_name
156
+ User = OptStruct.new(email: nil, role: "member")
157
+ ```
100
158
 
101
- def name
102
- [first_name, last_name].compact.join(" ")
103
- end
159
+ Default blocks can also be used and are late evaluated on the each struct instance.
160
+
161
+ ```ruby
162
+ class User < OptStruct.new
163
+ option :email, default: -> { nil }
164
+ option :role, -> { "member" }
104
165
  end
166
+ ```
105
167
 
106
- t = PersonClass.new(first_name: "Trish")
107
- # => #<PersonClass>
108
- t.name
109
- # => "Trish"
110
- t.last_name = "Smith"
111
- t.name
112
- # => "Trish Smith"
168
+ ```ruby
169
+ class User < OptStruct.new
170
+ options :email, role: -> { "member" }
171
+ end
172
+ ```
113
173
 
114
- CarModule = OptStruct.build do
115
- required :make, :model
116
- options year: -> { Date.today.year }, transmission: :default_transmission
174
+ ```ruby
175
+ class User < OptStruct.new
176
+ option :email, nil
177
+ option :role, -> { default_role }
178
+
179
+ private
180
+
181
+ def default_role
182
+ "member"
183
+ end
184
+ end
185
+ ```
117
186
 
118
- def default_transmission
119
- "Automatic"
187
+ Default symbols are treated as method calls if the struct `#respond_to?` the method.
188
+
189
+ ```ruby
190
+ class User < OptStruct.new
191
+ options :email, :role => :default_role
192
+
193
+ def default_role
194
+ "member"
120
195
  end
196
+ end
197
+ ```
198
+
199
+ ## Required Arguments
200
+
201
+ Required arguments are just like optional arguments, except they are also added to the `.required_keys` collection, which is checked when an OptStruct is initialized. If the `#options` Hash does not contain all `.required_keys` then an `ArgumentError` is raised.
202
+
203
+ The following examples are functionally equivalent.
204
+
205
+ ```ruby
206
+ class Student < OptStruct.new
207
+ required :name
208
+ end
209
+ ```
210
+
211
+ ```ruby
212
+ class Student < OptStruct.new
213
+ option :name, required: true
214
+ end
215
+ ```
216
+
217
+ ```ruby
218
+ class Student < OptStruct.new
219
+ option :name
220
+ required_keys << :name
221
+ end
222
+ ```
223
+
224
+ ### Expected Arguments
225
+
226
+ OptStructs can accept non-keyword arguments if the struct knows to expect them.
227
+
228
+ For code like this to work...
229
+
230
+ ```ruby
231
+ user = User.new("admin@user.com", "admin")
232
+ user.email # => "admin@user.com"
233
+ user.role # => "admin"
234
+ ```
235
+
236
+ ... the OptStruct needs to have some `.expected_arguments`.
237
+
238
+ The following `User` class examples are functionally equivalent and allow the code above to function.
239
+
240
+ ```ruby
241
+ User = OptStruct.new(:email, :role)
242
+ ```
243
+
244
+ ```ruby
245
+ class User < OptStruct.new(:email)
246
+ expect_argument :role
247
+ end
248
+ ```
249
+
250
+ ```ruby
251
+ class User
252
+ include OptStruct.build(:email, :role)
253
+ end
254
+ ```
255
+
256
+ ```ruby
257
+ class User
258
+ include OptStruct.build
259
+ expect_arguments :email, :role
260
+ end
261
+ ```
121
262
 
263
+ ```ruby
264
+ class User < OptStruct.new(:email)
265
+ expected_arguments << :role
266
+ end
267
+ ```
268
+
269
+ Expected arguments are similar to required arguments, except they are in `.expected_arguments` collection, which is checked when an OptStruct is initialized.
270
+
271
+ Expected arguments can also be supplied using keywords. An `ArgumentError` is only raised if the expected argument is not in the list of arguments passed to `OptStruct#new` **and** the argument is not present in the `#options` Hash.
272
+
273
+ The following examples will initialize any of the `User` class examples above without error.
274
+
275
+ ```ruby
276
+ User.new(email: "example@user.com", role: "member")
277
+ User.new("example@user.com", role: "member")
278
+ User.new(role: "member", email: "example@user.com")
279
+ ```
280
+
281
+ ## The `#options` Hash
282
+
283
+ All OptStruct arguments are read from and stored in a single `Hash` instance. This Hash can be accessed directly using the `options` method.
284
+
285
+ ```ruby
286
+ Person = OptStruct.new(:name)
287
+ Person.new(name: "John", age: 32).options
288
+ # => {:name=>"John", :age=>32}
289
+ ```
290
+
291
+ Feel free to write your own accessor methods for things like dependent options or other complex/private behavior.
292
+
293
+ ```ruby
294
+ class Person < OptStruct.new
295
+ option :given_name
296
+ option :family_name
297
+
122
298
  def name
123
- [year, make, model].compact.join(" ")
299
+ options.fetch(:name) { "#{given_name} #{family_name}" }
124
300
  end
125
301
  end
302
+ ```
303
+
304
+ ## On Initialization
126
305
 
127
- class CarClass
128
- include CarModule
306
+ All of the following examples are functionally equivalent.
307
+
308
+ OptStruct classes are initialized in an `initialize` method (in `OptStruct::InstanceMethods`) like most classes. Also, like most classes, you can override `initialize` as long as you remember to call `super` properly to retain `OptStruct` functionality.
309
+
310
+ ```ruby
311
+ class UserReportBuilder < OptStruct.new(:user)
312
+ attr_reader :report
313
+
314
+ def initialize(*)
315
+ super
316
+ @report = []
317
+ end
129
318
  end
319
+ ```
130
320
 
131
- c = CarClass.new(make: "Infiniti", model: "G37", year: 2012)
132
- c.name
133
- # => "2012 Infinit G37"
321
+ `OptStruct` also provides initialization callbacks to make hooking into and customizing the initialization of OptStruct classes easier and require less code.
134
322
 
135
- c = CarClass.new(model: "WRX", make: "Subaru", year: nil)
136
- c.name
137
- # => "Subaru WRX"
323
+ ```ruby
324
+ class UserReportBuilder < OptStruct.new(:user)
325
+ attr_reader :report
326
+ init { @report = [] }
327
+ end
328
+ ```
138
329
 
139
- c = CarClass.new(model: "BRZ", make: "Subaru")
140
- c.name
141
- # => "2017 Subaru BRZ"
330
+ ```ruby
331
+ class UserReportBuilder < OptStruct.new(:user)
332
+ attr_reader :report
333
+
334
+ around_init do |instance|
335
+ instance.call
336
+ @report = []
337
+ end
338
+ end
142
339
  ```
340
+
341
+ Available callbacks
342
+
343
+ * `around_init`
344
+ * `before_init`
345
+ * `init`
346
+ * `after_init`
347
+
348
+ ## Inheritance, Expanded
349
+
350
+ See `spec/inheritance_spec.rb` for examples of just how crazy you can get.
data/lib/opt_struct.rb CHANGED
@@ -3,10 +3,11 @@ require "opt_struct/module_methods"
3
3
  require "opt_struct/instance_methods"
4
4
 
5
5
  module OptStruct
6
+ RESERVED_WORDS = %i(class defaults options fetch check_required_args check_required_keys).freeze
6
7
 
7
- def self._inject_struct(target, source, args = [], defaults = {}, &callback)
8
+ def self._inject_struct(target, source, args = [], **defaults, &callback)
8
9
  structs = Array(source.instance_variable_get(:@_opt_structs)).dup
9
- if args.any? || defaults.any? || callback
10
+ if args.any? || defaults.any? || block_given?
10
11
  structs << [args, defaults, callback]
11
12
  end
12
13
  target.instance_variable_set(:@_opt_structs, structs)
@@ -18,7 +19,7 @@ module OptStruct
18
19
  end
19
20
  structs.each do |s_args, s_defaults, s_callback|
20
21
  target.expect_arguments *s_args if s_args.any?
21
- target.options s_defaults if s_defaults.any?
22
+ target.options **s_defaults if s_defaults.any?
22
23
  target.class_exec(&s_callback) if s_callback
23
24
  end
24
25
  else
@@ -38,10 +39,10 @@ module OptStruct
38
39
  end
39
40
 
40
41
  def self.new(*args, **defaults, &callback)
41
- _inject_struct(Class.new, self, args.map(&:to_sym), defaults, &callback)
42
+ _inject_struct(Class.new, self, args.map(&:to_sym), **defaults, &callback)
42
43
  end
43
44
 
44
45
  def self.build(*args, **defaults, &callback)
45
- _inject_struct(Module.new, self, args.map(&:to_sym), defaults, &callback)
46
+ _inject_struct(Module.new, self, args.map(&:to_sym), **defaults, &callback)
46
47
  end
47
48
  end
@@ -1,75 +1,81 @@
1
1
  module OptStruct
2
2
  module ClassMethods
3
3
  def inherited(subclass)
4
- instance_variables.each do |v|
5
- ivar = instance_variable_get(v)
6
- subclass.send(:instance_variable_set, v, ivar.dup) if ivar
4
+ opt_struct_class_constants.each do |c|
5
+ subclass.const_set(c, const_get(c)) if const_defined?(c)
7
6
  end
8
7
  end
9
8
 
9
+ # overwritten if `required` is called
10
10
  def required_keys
11
- @required_keys ||= []
11
+ [].freeze
12
12
  end
13
13
 
14
- def required(*keys)
15
- required_keys.concat keys
16
- option_accessor *keys
14
+ def required(*keys, **options)
15
+ add_required_keys *keys
16
+ option_accessor *keys, **options
17
17
  end
18
18
 
19
- def option_reader(*keys)
20
- check_reserved_words(keys)
21
-
19
+ def option_reader(*keys, **options)
22
20
  keys.each do |key|
23
- define_method(key) do
24
- if options.key?(key)
25
- options[key]
26
- elsif defaults.key?(key)
27
- options[key] = read_default_value(key)
21
+ class_eval <<~RUBY
22
+ #{options[:private] ? "private" : ""} def #{key}
23
+ options[:#{key}]
28
24
  end
29
- end
25
+ RUBY
30
26
  end
31
27
  end
32
28
 
33
- def option_writer(*keys)
34
- check_reserved_words(keys)
35
-
29
+ def option_writer(*keys, **options)
36
30
  keys.each do |key|
37
- define_method("#{key}=") { |value| options[key] = value }
31
+ class_eval <<~RUBY
32
+ #{options[:private] ? "private" : ""} def #{key}=(value)
33
+ options[:#{key}] = value
34
+ end
35
+ RUBY
38
36
  end
39
37
  end
40
38
 
41
- def option_accessor(*keys)
42
- option_reader *keys
43
- option_writer *keys
39
+ def option_accessor(*keys, **options)
40
+ check_reserved_words(keys)
41
+ option_reader *keys, **options
42
+ option_writer *keys, **options
44
43
  end
45
44
 
46
- def option(key, default = nil, **options)
45
+ def option(key, default = nil, required: false, **options)
47
46
  default = options[:default] if options.key?(:default)
48
- defaults[key] = default
49
- required_keys << key if options[:required]
50
- option_accessor key
47
+ add_defaults key => default
48
+ add_required_keys key if required
49
+ option_accessor key, **options
51
50
  end
52
51
 
53
52
  def options(*keys, **keys_defaults)
54
53
  option_accessor *keys if keys.any?
55
54
  if keys_defaults.any?
56
- defaults.merge!(keys_defaults)
55
+ add_defaults keys_defaults
57
56
  option_accessor *(keys_defaults.keys - expected_arguments)
58
57
  end
59
58
  end
60
59
 
61
60
  def defaults
62
- @defaults ||= {}
61
+ const_defined?(:OPT_DEFAULTS) ? const_get(:OPT_DEFAULTS) : {}
63
62
  end
64
63
 
65
- def expect_arguments(*arguments)
66
- required(*arguments)
67
- expected_arguments.concat(arguments)
64
+ # overwritten if `expect_arguments` is called
65
+ def expected_arguments
66
+ [].freeze
68
67
  end
69
68
 
70
- def expected_arguments
71
- @expected_arguments ||= []
69
+ def expect_arguments(*arguments)
70
+ required(*arguments)
71
+ combined = expected_arguments + arguments
72
+ class_eval <<~EVAL
73
+ def self.expected_arguments
74
+ #{combined.inspect}.freeze
75
+ end
76
+ EVAL
72
77
  end
78
+ alias_method :expect_argument, :expect_arguments
73
79
 
74
80
  def init(meth = nil, &blk)
75
81
  add_callback(:init, meth || blk)
@@ -84,23 +90,60 @@ module OptStruct
84
90
  add_callback(:around_init, meth || blk)
85
91
  end
86
92
 
87
- def add_callback(name, callback)
88
- @_callbacks ||= {}
89
- @_callbacks[name] ||= []
90
- @_callbacks[name] << callback
93
+ def all_callbacks
94
+ const_defined?(:OPT_CALLBACKS) ? const_get(:OPT_CALLBACKS) : {}.freeze
91
95
  end
92
96
 
93
- def all_callbacks
94
- @_callbacks
97
+ def shareable?
98
+ const_defined?(:SHAREABLE) && const_get(:SHAREABLE)
99
+ end
100
+
101
+ def shareable!
102
+ return if shareable?
103
+ const_set(:SHAREABLE, true)
95
104
  end
96
105
 
97
106
  private
98
107
 
99
- RESERVED_WORDS = %i(class defaults options fetch check_required_args check_required_keys)
108
+ def share(value)
109
+ return value unless shareable?
110
+ defined?(Ractor) ? Ractor.make_shareable(value) : value
111
+ end
112
+
113
+ def add_required_keys(*keys)
114
+ combined = required_keys + keys
115
+ class_eval <<~RUBY
116
+ def self.required_keys
117
+ #{combined.inspect}.freeze
118
+ end
119
+ RUBY
120
+ end
121
+
122
+ def add_defaults(defaults_to_add)
123
+ freezer = defaults.dup
124
+ defaults_to_add.each { |k, v| freezer[k] = share(v) }
125
+ remove_const(:OPT_DEFAULTS) if const_defined?(:OPT_DEFAULTS)
126
+ const_set(:OPT_DEFAULTS, freezer.freeze)
127
+ end
128
+
129
+ def add_callback(name, callback)
130
+ if const_defined?(:OPT_CALLBACKS)
131
+ callbacks_for_name = (all_callbacks[name] || []) + [callback]
132
+ callbacks_hash = all_callbacks.merge(name => callbacks_for_name).freeze
133
+ remove_const(:OPT_CALLBACKS)
134
+ const_set(:OPT_CALLBACKS, callbacks_hash)
135
+ else
136
+ const_set(:OPT_CALLBACKS, { name => [ callback ] })
137
+ end
138
+ end
139
+
140
+ def opt_struct_class_constants
141
+ [:OPT_DEFAULTS, :OPT_CALLBACKS]
142
+ end
100
143
 
101
144
  def check_reserved_words(words)
102
145
  Array(words).each do |word|
103
- if RESERVED_WORDS.member?(word)
146
+ if OptStruct::RESERVED_WORDS.member?(word)
104
147
  raise ArgumentError, "Use of reserved word is not permitted: #{word.inspect}"
105
148
  end
106
149
  end
@@ -4,6 +4,7 @@ module OptStruct
4
4
  with_init_callbacks do
5
5
  @options = options
6
6
  assign_arguments(arguments)
7
+ assign_defaults
7
8
  check_required_keys
8
9
  end
9
10
  end
@@ -24,23 +25,21 @@ module OptStruct
24
25
  raise ArgumentError, "missing required keywords: #{missing.inspect}"
25
26
  end
26
27
  end
27
-
28
+
29
+ def assign_defaults
30
+ defaults.each do |key, default_value|
31
+ next if options.key?(key) # || default_value.nil?
32
+ options[key] = read_default_value(default_value)
33
+ end
34
+ end
35
+
28
36
  def assign_arguments(args)
29
37
  self.class.expected_arguments.map.with_index do |key, i|
30
- if args.length > i
31
- options[key] = args[i]
32
- elsif !options.key?(key)
33
- if defaults.key?(key)
34
- options[key] = read_default_value(key)
35
- else
36
- raise ArgumentError, "missing required argument: #{key}"
37
- end
38
- end
38
+ options[key] = args[i] if args.length > i
39
39
  end
40
40
  end
41
-
42
- def read_default_value(key)
43
- default = defaults[key]
41
+
42
+ def read_default_value(default)
44
43
  case default
45
44
  when Proc
46
45
  instance_exec(&default)
@@ -22,8 +22,8 @@ module OptStruct
22
22
  options
23
23
  expect_arguments
24
24
  ).each do |class_method|
25
- define_method(class_method) do |*args|
26
- @_opt_structs << [[], {}, -> { send(class_method, *args) }]
25
+ define_method(class_method) do |*args, **options|
26
+ @_opt_structs << [[], {}, -> { send(class_method, *args, **options) }]
27
27
  end
28
28
  end
29
29
  end
@@ -1,3 +1,3 @@
1
1
  module OptStruct
2
- VERSION = "0.9.0"
2
+ VERSION = "1.2.0"
3
3
  end
data/opt_struct.gemspec CHANGED
@@ -16,8 +16,4 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files`.split("\n").grep(/^lib/)
17
17
  spec.files += %w(README.md opt_struct.gemspec)
18
18
  spec.require_paths = ["lib"]
19
-
20
- spec.add_development_dependency "bundler", "~> 1.14"
21
- spec.add_development_dependency "rake", "~> 10.0"
22
- spec.add_development_dependency "rspec", "~> 3.0"
23
19
  end
metadata CHANGED
@@ -1,57 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opt_struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Zulauf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-05 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.14'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.14'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.0'
11
+ date: 2021-03-30 00:00:00.000000000 Z
12
+ dependencies: []
55
13
  description: Struct with support for keyword params and mixin support
56
14
  email:
57
15
  - carl@linkleaf.com
@@ -85,7 +43,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
43
  - !ruby/object:Gem::Version
86
44
  version: '0'
87
45
  requirements: []
88
- rubygems_version: 3.0.3
46
+ rubygems_version: 3.1.4
89
47
  signing_key:
90
48
  specification_version: 4
91
49
  summary: The Option Struct