marameters 3.12.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +261 -124
- data/lib/marameters/categorizer.rb +12 -19
- data/lib/marameters/models/forward.rb +10 -0
- data/lib/marameters/probe.rb +13 -21
- data/lib/marameters/signature.rb +4 -3
- data/lib/marameters/signatures/builder.rb +31 -0
- data/lib/marameters/signatures/defaulter.rb +20 -0
- data/lib/marameters/signatures/forwarder.rb +18 -0
- data/lib/marameters/signatures/inheritor.rb +39 -0
- data/lib/marameters/signatures/super.rb +55 -0
- data/lib/marameters/sources/extractor.rb +33 -0
- data/lib/marameters/sources/reader.rb +45 -0
- data/lib/marameters.rb +1 -1
- data/marameters.gemspec +4 -4
- data.tar.gz.sig +0 -0
- metadata +15 -17
- metadata.gz.sig +0 -0
- data/lib/marameters/builder.rb +0 -28
- data/lib/marameters/defaulter.rb +0 -14
- data/lib/marameters/splat.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b120830ab23db1facffaa30df5ddbc96557d37d9910a24c9b531dd7ad755c1e0
|
4
|
+
data.tar.gz: ed8fa0e3aaed0a2ce8c7ad0a5954a8574eaa4242206c5aeff81fcfb5a2b5321b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 959d5a7edfafad4f1da16a02ea1a54fbfd23e3cb165230eb6239bd811b0d895e18f65a1d9b08fed8971e1cea6b306b87d095e3451e7c4ca4755a520e81722b93
|
7
|
+
data.tar.gz: 5932395cedf488a17862bfe5f820972d4d92cce26f19ff384134d44393ac3ea35219160d9dfca6150e9096ae7e9e5b0de9ab2a6d1881441333bd6c959e66aeda
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
:amazing_print_link: link:https://github.com/amazing-print/amazing_print[Amazing Print]
|
6
6
|
:article_link: link:https://alchemists.io/articles/ruby_method_parameters_and_arguments[method parameters and arguments]
|
7
|
+
:infusible_link: link:/projects/infusible[Infusible]
|
7
8
|
|
8
9
|
= Marameters
|
9
10
|
|
@@ -62,40 +63,66 @@ require "marameters"
|
|
62
63
|
|
63
64
|
At a high level, you can use `Marameters` as a single Object API for accessing all capabilities provided by this gem. Here's an overview:
|
64
65
|
|
66
|
+
*Setup*
|
67
|
+
|
65
68
|
[source,ruby]
|
66
69
|
----
|
67
|
-
# Setup
|
68
70
|
def demo(one, two = 2, three: 3) = puts "One: #{one}, Two: #{two}, Three: #{three}"
|
69
71
|
|
70
72
|
parameters = method(:demo).parameters
|
71
73
|
arguments = %w[one two]
|
74
|
+
----
|
72
75
|
|
73
|
-
|
76
|
+
*Categorize*
|
74
77
|
|
78
|
+
[source,ruby]
|
79
|
+
----
|
75
80
|
Marameters.categorize parameters, arguments
|
76
|
-
# #<struct Marameters::
|
81
|
+
# #<struct Marameters::Models::Forward positionals=["one", "two"], keywords={}, block=nil>
|
82
|
+
----
|
77
83
|
|
78
|
-
|
84
|
+
*Probe*
|
79
85
|
|
86
|
+
[source,ruby]
|
87
|
+
----
|
80
88
|
Marameters.of self, :demo # []
|
81
89
|
|
82
90
|
probe = Marameters.for parameters
|
83
|
-
probe.to_a # [[:req, :one], [:opt, :two], [:key, :three]]
|
84
91
|
probe.positionals # [:one, :two]
|
85
92
|
probe.keywords # [:three]
|
86
|
-
probe.
|
93
|
+
probe.to_a # [[:req, :one], [:opt, :two], [:key, :three]]
|
94
|
+
----
|
87
95
|
|
88
|
-
|
96
|
+
*Signature*
|
89
97
|
|
90
|
-
|
91
|
-
# one, two = 2, three: 3
|
98
|
+
[source,ruby]
|
92
99
|
----
|
100
|
+
Marameters.signature([%i[req one], [:opt, :two, 2], [:key, :three, 3]]).to_s
|
101
|
+
# "one, two = 2, three: 3"
|
102
|
+
----
|
103
|
+
|
104
|
+
=== Constants
|
105
|
+
|
106
|
+
The `KINDS` constant allows you to know the kinds of parameters allowed:
|
93
107
|
|
94
|
-
|
108
|
+
[source,ruby]
|
109
|
+
----
|
110
|
+
Marameters::KINDS
|
111
|
+
# [
|
112
|
+
# :req,
|
113
|
+
# :opt,
|
114
|
+
# :rest,
|
115
|
+
# :nokey,
|
116
|
+
# :keyreq,
|
117
|
+
# :key,
|
118
|
+
# :keyrest,
|
119
|
+
# :block
|
120
|
+
# ]
|
121
|
+
----
|
95
122
|
|
96
123
|
=== Probe
|
97
124
|
|
98
|
-
The probe allows you to analyze a method's parameters. To understand how, consider the following:
|
125
|
+
The probe (`Marameters::Probe`) allows you to analyze a method's parameters. To understand how, consider the following:
|
99
126
|
|
100
127
|
[source,ruby]
|
101
128
|
----
|
@@ -120,58 +147,93 @@ You can then probe the `#all` method's parameters as follows:
|
|
120
147
|
|
121
148
|
[source,ruby]
|
122
149
|
----
|
123
|
-
probe = Marameters
|
124
|
-
|
125
|
-
probe.
|
126
|
-
probe.
|
127
|
-
probe.
|
128
|
-
probe.keywords
|
129
|
-
probe.keywords?
|
130
|
-
probe.
|
131
|
-
probe.
|
132
|
-
|
133
|
-
probe.
|
134
|
-
|
135
|
-
|
136
|
-
probe.
|
137
|
-
|
138
|
-
probe.
|
139
|
-
|
140
|
-
|
141
|
-
probe.
|
142
|
-
probe.
|
143
|
-
|
144
|
-
|
145
|
-
|
150
|
+
probe = Marameters.for Demo.instance_method(:all).parameters
|
151
|
+
|
152
|
+
probe.deconstruct # (same as to_a, see below)
|
153
|
+
probe.empty? # false
|
154
|
+
probe.include? %i[req one] # true
|
155
|
+
probe.keywords # [:four, :five]
|
156
|
+
probe.keywords? # true
|
157
|
+
probe.keywords_for :four, four: :demo # {four: :demo}
|
158
|
+
probe.kind?(:keyrest) # true
|
159
|
+
|
160
|
+
probe.kinds
|
161
|
+
# [:req, :opt, :rest, :keyreq, :key, :keyrest, :block]
|
162
|
+
|
163
|
+
probe.name?(:three) # true
|
164
|
+
|
165
|
+
probe.names
|
166
|
+
# [:one, :two, :three, :four, :five, :six, :seven]
|
167
|
+
|
168
|
+
probe.only_bare_splats? # false
|
169
|
+
probe.only_double_splats? # false
|
170
|
+
probe.only_single_splats? # false
|
171
|
+
probe.positionals # [:one, :two]
|
172
|
+
probe.positionals? # true
|
173
|
+
probe.positionals_and_maybe_keywords? # true
|
174
|
+
|
175
|
+
probe.to_a
|
176
|
+
# [
|
177
|
+
# [:req, :one],
|
178
|
+
# [:opt, :two],
|
179
|
+
# [:rest, :three],
|
180
|
+
# [:keyreq, :four],
|
181
|
+
# [:key, :five],
|
182
|
+
# [:keyrest, :six],
|
183
|
+
# [:block, :seven]
|
184
|
+
# ]
|
185
|
+
----
|
186
|
+
|
187
|
+
In contrast to the above, we can probe the `#none` method which has no parameters for a completely
|
146
188
|
different result:
|
147
189
|
|
148
190
|
[source,ruby]
|
149
191
|
----
|
150
|
-
probe = Marameters
|
192
|
+
probe = Marameters.for Demo.instance_method(:none).parameters
|
151
193
|
|
152
|
-
probe.
|
153
|
-
probe.
|
154
|
-
probe.
|
155
|
-
probe.keywords
|
156
|
-
probe.keywords?
|
157
|
-
probe.
|
158
|
-
probe.
|
159
|
-
probe.
|
160
|
-
probe.
|
161
|
-
probe.
|
162
|
-
probe.
|
163
|
-
probe.
|
164
|
-
probe.
|
165
|
-
probe.positionals
|
166
|
-
probe.
|
167
|
-
probe.
|
168
|
-
probe.to_a
|
169
|
-
probe.to_h # {}
|
194
|
+
probe.deconstruct # (same as to_a, see below)
|
195
|
+
probe.empty? # true
|
196
|
+
probe.include? %i[req one] # false
|
197
|
+
probe.keywords # []
|
198
|
+
probe.keywords? # false
|
199
|
+
probe.keywords_for :four, four: :demo # {}
|
200
|
+
probe.kind?(:req) # true
|
201
|
+
probe.kinds # []
|
202
|
+
probe.name?(:three) # false
|
203
|
+
probe.names # []
|
204
|
+
probe.only_bare_splats? # false
|
205
|
+
probe.only_double_splats? # false
|
206
|
+
probe.only_single_splats? # false
|
207
|
+
probe.positionals # []
|
208
|
+
probe.positionals? # false
|
209
|
+
probe.positionals_and_maybe_keywords? # false
|
210
|
+
probe.to_a # []
|
170
211
|
----
|
171
212
|
|
172
|
-
|
213
|
+
The `#keywords_for` method might need additional explaining because it's meant for selecting keywords which adhere to _either_ of the following criteria:
|
173
214
|
|
174
|
-
The
|
215
|
+
* The given keys don't match any key in the given attributes.
|
216
|
+
* The given keys match the parameter keywords.
|
217
|
+
|
218
|
+
[source,ruby]
|
219
|
+
----
|
220
|
+
module Demo
|
221
|
+
def self.keywords(four:, five: 5, **six) = puts "Four: #{four}, Five: #{five}, Six: #{six}"
|
222
|
+
end
|
223
|
+
|
224
|
+
probe = Marameters.for Demo.method(:keywords).parameters
|
225
|
+
|
226
|
+
probe.keywords_for :a, a: 1, four: 4 # {four: 4}
|
227
|
+
probe.keywords_for :four, a: 1 # {a: 1}
|
228
|
+
probe.keywords_for :a, four: 4, five: :five # {four: 4, five: :five}
|
229
|
+
probe.keywords_for :a, six: {name: :test} # {six: {name: :test}}
|
230
|
+
----
|
231
|
+
|
232
|
+
This useful in gems, like {infusible_link}, when determining which keyword arguments to pass up to the superclass.
|
233
|
+
|
234
|
+
=== Categorize
|
235
|
+
|
236
|
+
Categorization (`Marameters::Categorizer`) allows you to dynamically build positional, keyword, and block arguments for message passing. This is most valuable when you know the object and method while needing to align the arguments in the right order. Here's a demonstration where {amazing_print_link} (i.e. `ap`) is used to format the output:
|
175
237
|
|
176
238
|
[source,ruby]
|
177
239
|
----
|
@@ -191,18 +253,18 @@ end
|
|
191
253
|
|
192
254
|
module Inspector
|
193
255
|
def self.call arguments
|
194
|
-
Marameters
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
256
|
+
Marameters.categorize(Demo.method(:test).parameters, arguments)
|
257
|
+
.then do |record|
|
258
|
+
ap record
|
259
|
+
puts
|
260
|
+
Demo.test(*record.positionals, **record.keywords, &record.block)
|
261
|
+
end
|
200
262
|
end
|
201
263
|
end
|
202
264
|
|
203
265
|
Inspector.call [1, nil, nil, {four: 4}]
|
204
266
|
|
205
|
-
# #<Struct:Marameters::
|
267
|
+
# #<Struct:Marameters::Models::Forward:0x00021930
|
206
268
|
# block = nil,
|
207
269
|
# keywords = {
|
208
270
|
# :four => 4
|
@@ -226,7 +288,7 @@ Inspector.call [1, nil, nil, {four: 4}]
|
|
226
288
|
When we step through the above implementation and output, we see the following unfold:
|
227
289
|
|
228
290
|
. The `Demo` module allows us to define a maximum set of parameters and then print the arguments received for inspection purposes.
|
229
|
-
. The `Inspector` module provides a wrapper around the
|
291
|
+
. The `Inspector` module provides a wrapper around the categorization so we can conveniently pass in different arguments for experimentation purposes.
|
230
292
|
. We pass in our arguments to `Inspector.call` where `nil` is used for optional arguments and hashes for keyword arguments.
|
231
293
|
. Once inside `Inspector.call`, the `Categorizer` is initialized with the `Demo.test` method parameters.
|
232
294
|
. Then the `splat` (i.e. Struct) is printed out so you can see the categorized positional, keyword, and block arguments.
|
@@ -240,7 +302,7 @@ Inspector.call [1, 2, [98, 99], {four: 4}, {five: 5}, {twenty: 20, thirty: 30},
|
|
240
302
|
|
241
303
|
# Output
|
242
304
|
|
243
|
-
# #<Struct:Marameters::
|
305
|
+
# #<Struct:Marameters::Models::Forward:0x00029cc0
|
244
306
|
# block = #<Proc:0x000000010a88cec0 (irb):1>,
|
245
307
|
# keywords = {
|
246
308
|
# :four => 4,
|
@@ -296,109 +358,184 @@ ap arguments
|
|
296
358
|
| `%i[block seven]` | `#<Proc:0x0000000108edc778>`
|
297
359
|
|===
|
298
360
|
|
299
|
-
This also means
|
361
|
+
This also means:
|
300
362
|
|
301
|
-
* All positions must be filled if you want to supply arguments beyond the first couple of positions because everything is positional due to the nature of how link:https://
|
363
|
+
* All positions must be filled if you want to supply arguments beyond the first couple of positions because everything is positional due to the nature of how link:https://docs.ruby-lang.org/en/master/Method.html#method-i-parameters[Method#parameters] works. Use `nil` to fill an optional argument when you don't need it.
|
302
364
|
* The `:rest` (single splat) argument must be an array or `nil` if not present because even though it is _optional_, it is still _positional_.
|
303
365
|
* The `:keyrest` (double splat) argument -- much like the `:rest` argument -- must be a hash or `nil` if not present.
|
304
366
|
|
305
|
-
Lastly, in all of the above examples, only an array of arguments has been used but you can pass in a single argument too (i.e. non-array). This is handy for method signatures which have only a single parameter or only use splats.
|
367
|
+
Lastly, in all of the above examples, only an array of arguments has been used but you can pass in a single argument too (i.e. non-array). This is handy for method signatures which have only a single parameter or only use splats.
|
368
|
+
|
369
|
+
For C-based primitives, like `Struct`, `Data`, etc., you'll want to provide a conversion method. Example:
|
306
370
|
|
307
371
|
[source,ruby]
|
308
372
|
----
|
309
|
-
url = Struct.new
|
373
|
+
url = Struct.new(:label, :url) do
|
374
|
+
def self.for(**) = new(**)
|
375
|
+
end
|
310
376
|
|
311
|
-
Marameters.categorize(url.method(:
|
312
|
-
.then { |
|
377
|
+
Marameters.categorize(url.method(:for).parameters, label: "Example", url: "https://example.com")
|
378
|
+
.then { |record| url.for(**record.keywords) }
|
313
379
|
|
314
|
-
# Yields: #<struct label="
|
380
|
+
# Yields: #<struct label="Example", url="https://example.com">
|
315
381
|
----
|
316
382
|
|
317
|
-
For further details, please refer back to my {article_link} article mentioned in the
|
383
|
+
For further details, please refer back to my {article_link} article mentioned in the xref:_requirements[Requirements] section.
|
318
384
|
|
319
385
|
=== Signature
|
320
386
|
|
321
|
-
The signature
|
387
|
+
The signature (`Marameters::Signature`) is the opposite of the probe class which allows you to turn a raw array of parameters into a method signature. This is most useful when metaprogramming and needing to dynamically build method signatures. Example:
|
388
|
+
|
389
|
+
[source,ruby]
|
390
|
+
----
|
391
|
+
signature = Marameters.signature [[:opt, :text, "This is a test."]]
|
392
|
+
|
393
|
+
Example = Module.new do
|
394
|
+
module_eval <<~METHOD, __FILE__, __LINE__ + 1
|
395
|
+
def self.say(#{signature}) = text
|
396
|
+
METHOD
|
397
|
+
end
|
398
|
+
|
399
|
+
puts Example.say # "This is a test."
|
400
|
+
puts Example.say("Hello") # "Hello"
|
401
|
+
----
|
402
|
+
|
403
|
+
==== Keys
|
322
404
|
|
323
|
-
The following demonstrates how you
|
405
|
+
The following demonstrates how you can construct a method signature with all possible parameters using the same keys as used by `Method#parameters`:
|
324
406
|
|
325
407
|
[source,ruby]
|
326
408
|
----
|
327
|
-
signature = Marameters
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
}
|
337
|
-
)
|
409
|
+
signature = Marameters.signature [
|
410
|
+
%i[req one],
|
411
|
+
%i[opt two],
|
412
|
+
%i[rest three],
|
413
|
+
%i[keyreq four],
|
414
|
+
%i[key five],
|
415
|
+
%i[keyrest six],
|
416
|
+
%i[block seven]
|
417
|
+
]
|
338
418
|
|
339
419
|
puts signature
|
340
|
-
# one, two =
|
420
|
+
# "one, two = nil, *three, four:, five: nil, **six, &seven"
|
421
|
+
----
|
422
|
+
|
423
|
+
==== Values
|
424
|
+
|
425
|
+
With the above examples, each sub-array uses a simple key/value pair to map the kind of parameter with the corresponding name. You can also provide a _third_ value when needing to provide a default value for _optional_ parameters. Example:
|
426
|
+
|
427
|
+
[source,ruby]
|
428
|
+
----
|
429
|
+
puts Marameters.signature([[:opt, :one, 1], [:key, :two, 2]])
|
430
|
+
# one = 1, two: 2
|
341
431
|
----
|
342
432
|
|
343
|
-
You'll notice that the parameters are a hash _and_ some values can be tuples. The reason is that
|
344
|
-
it's easier to write a hash than a double nested array as normally produced by the probe or directly
|
345
|
-
from `Method#parameters`. The optional positional and keyword parameters use tuples because you
|
346
|
-
might want to supply a default value and this provides a way for you to do that with minimal syntax.
|
347
433
|
This can be demonstrated further by using optional keywords (same applies for optional positionals):
|
348
434
|
|
349
435
|
[source,ruby]
|
350
436
|
----
|
351
|
-
# With
|
352
|
-
puts Marameters
|
353
|
-
# demo: nil
|
437
|
+
# With implicit nil.
|
438
|
+
puts Marameters.signature([%i[key demo]])
|
439
|
+
# "demo: nil"
|
440
|
+
|
441
|
+
# With explicit nil.
|
442
|
+
puts Marameters.signature([[:key, :demo, nil]])
|
443
|
+
# "demo: nil"
|
354
444
|
|
355
|
-
# With
|
356
|
-
puts Marameters
|
357
|
-
# demo:
|
445
|
+
# With any primitive.
|
446
|
+
puts Marameters.signature([[:key, :demo, :test]])
|
447
|
+
# "demo: :test"
|
358
448
|
|
359
|
-
# With
|
360
|
-
puts Marameters
|
361
|
-
# demo: "
|
449
|
+
# With proc (no parameters).
|
450
|
+
puts Marameters.signature([[:key, :demo, proc { Object.new }]])
|
451
|
+
# "demo: Object.new"
|
452
|
+
# ⚠️ The above will answer "demo: nil" if used in IRB since the source can't be found.
|
362
453
|
|
363
|
-
# With
|
364
|
-
puts Marameters
|
365
|
-
#
|
454
|
+
# With proc (with parameters).
|
455
|
+
puts Marameters.signature([[:key, :demo, proc { |no| no }]])
|
456
|
+
# Avoid using parameters for proc defaults. (ArgumentError)
|
366
457
|
|
367
|
-
# With
|
368
|
-
puts Marameters
|
369
|
-
#
|
458
|
+
# With lambda.
|
459
|
+
puts Marameters.signature([[:key, :demo, -> { Object.new }]])
|
460
|
+
# Use procs instead of lambdas for defaults. (TypeError)
|
370
461
|
----
|
371
462
|
|
372
|
-
|
373
|
-
(`*`) so the signature builder won't confuse them as normal strings. There are two reasons why this
|
374
|
-
is important:
|
463
|
+
You can use any primitive, custom object, etc. as a default despite the limited examples shown above.
|
375
464
|
|
376
|
-
|
377
|
-
also not being confused as a normal string.
|
378
|
-
* Objects wrapped as strings allows your dependency to be lazy loaded. Otherwise, if `Object.new`
|
379
|
-
was pass in directly, you'd be passing the evaluated instance (i.e.
|
380
|
-
`#<Object:0x0000000107df4028>`) which is not what you want until much later when your method is
|
381
|
-
defined.
|
465
|
+
Procs _must_ be used when supplying complex objects as default values. _Avoid_ using parameters when using procs because only the source (body) of your proc will be used as a _literal_ string when building the method signature in order to ensure lazy evaluation.
|
382
466
|
|
383
|
-
|
467
|
+
Lastly, you can use anonymous splats/blocks by only supplying their kind. Example:
|
384
468
|
|
385
469
|
[source,ruby]
|
386
470
|
----
|
387
|
-
|
471
|
+
puts Marameters.signature([[:rest], [:keyrest], [:block]])
|
472
|
+
# "*, **, &"
|
473
|
+
----
|
388
474
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
475
|
+
You can supply `nil` as a second element (i.e. the name) for each kind but that is the equivalent of the above.
|
476
|
+
|
477
|
+
==== Argument Forwarding
|
478
|
+
|
479
|
+
Use `:all` for building a method signature with argument forwarding. Example:
|
480
|
+
|
481
|
+
[source, ruby]
|
482
|
+
----
|
483
|
+
puts Marameters.signature(:all)
|
484
|
+
# "..."
|
485
|
+
----
|
486
|
+
|
487
|
+
Use of `:all` is special in that you must _only_ supply `:all` with no other keys/values or you'll get an `ArgumentError`.
|
488
|
+
|
489
|
+
💡 This is only provided for convenience and completeness. In truth, you're better off writing `my_method(+...+)`, for example, than using this class.
|
490
|
+
|
491
|
+
==== Bare
|
492
|
+
|
493
|
+
Use an empty array when you need a bare method signature. Example:
|
494
|
+
|
495
|
+
[source,ruby]
|
496
|
+
----
|
497
|
+
puts Marameters.signature []
|
498
|
+
# ""
|
499
|
+
----
|
500
|
+
|
501
|
+
💡 This is only provided for convenience and completeness. In truth, if you need a bare method, then you don't need to use this class.
|
502
|
+
|
503
|
+
==== Inheritance
|
504
|
+
|
505
|
+
Object/method inheritance is more complicated than building a signature for a single method because you need to blend the super and sub parameters as a unified set of parameters. Additionally, you have to account for the arguments that need to be forwarded to the super method via the `super` keyword. To aid in this endeavor, the following objects are available to help you build these more complex method parameters and arguments:
|
506
|
+
|
507
|
+
* `Marameters::Signatures::Inheritor`: Blends super and sub parameters to produce a unified set of parameters you can turn into a method signature.
|
508
|
+
* `Marameters::Signatures::Super`: Blends super and sub parameters to produce arguments for forwarding via the `super` keyword. _This does not support disabled block forwarding (i.e. `&nil`) since there is no way to determine this from the super and sub parameters alone._
|
509
|
+
|
510
|
+
Here's an example which incorporates both of the above:
|
511
|
+
|
512
|
+
[source,ruby]
|
513
|
+
----
|
514
|
+
module Demo
|
515
|
+
def self.parent(one, two = 2, *three, &block) = nil
|
393
516
|
end
|
394
517
|
|
395
|
-
|
396
|
-
|
518
|
+
super_parameters = Marameters.for Demo.method(:parent).parameters
|
519
|
+
|
520
|
+
sub_parameters = Marameters.for [
|
521
|
+
[:opt, :two, 22],
|
522
|
+
%i[keyreq four],
|
523
|
+
[:key, :five, 5],
|
524
|
+
%i[keyrest six]
|
525
|
+
]
|
526
|
+
|
527
|
+
inheritor = Marameters::Signatures::Inheritor.new
|
528
|
+
forwarder = Marameters::Signatures::Super.new
|
397
529
|
|
398
|
-
puts
|
399
|
-
#
|
530
|
+
puts Marameters.signature inheritor.call(super_parameters, sub_parameters)
|
531
|
+
# "one, two = 22, *three, four:, five: 5, **six, &block"
|
532
|
+
|
533
|
+
puts forwarder.call(super_parameters, sub_parameters)
|
534
|
+
# "one, two, *three, &block"
|
400
535
|
----
|
401
536
|
|
537
|
+
As you can see, the above combines the parameters of your super method with the parameters of your sub method in order to produce a method signature -- with no duplicates -- while ensuring you can forward all necessary parameters that the `super` keyword requires. Defaults, if given, will override previously defined defaults as is identical with standard object inheritance.
|
538
|
+
|
402
539
|
== Development
|
403
540
|
|
404
541
|
To contribute, run:
|
@@ -1,40 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "refinements/struct"
|
4
|
-
|
5
3
|
module Marameters
|
6
4
|
# Builds the primary argument categories based on method parameters and arguments.
|
7
5
|
class Categorizer
|
8
|
-
|
9
|
-
|
10
|
-
def initialize parameters, model: Splat
|
11
|
-
@parameters = parameters
|
6
|
+
def initialize model: Models::Forward
|
12
7
|
@model = model
|
13
8
|
end
|
14
9
|
|
15
|
-
def call arguments
|
10
|
+
def call parameters, arguments
|
16
11
|
@record = model.new
|
17
|
-
|
18
|
-
record
|
12
|
+
|
13
|
+
return record if arguments.empty?
|
14
|
+
|
15
|
+
map parameters, arguments
|
19
16
|
end
|
20
17
|
|
21
18
|
private
|
22
19
|
|
23
|
-
attr_reader :
|
24
|
-
|
25
|
-
def map arguments
|
26
|
-
return record if arguments.empty?
|
20
|
+
attr_reader :model, :record
|
27
21
|
|
22
|
+
def map parameters, arguments
|
28
23
|
size = arguments.size
|
29
|
-
|
30
|
-
|
31
|
-
filter pair, arguments[index] if index < size
|
32
|
-
end
|
24
|
+
parameters.each.with_index { |pair, index| filter pair, arguments[index] if index < size }
|
25
|
+
record
|
33
26
|
end
|
34
27
|
|
35
28
|
def filter pair, value
|
36
29
|
case pair
|
37
|
-
in [:rest] | [:rest, :*] then
|
30
|
+
in [:rest] | [:rest, :*] then to_array value
|
38
31
|
in [:keyrest] | [:keyrest, :**] then record.keywords = Hash value
|
39
32
|
in [:req, *] | [:opt, *] then record.positionals.append value
|
40
33
|
in [:rest, *] then record.positionals.append(*value)
|
@@ -48,7 +41,7 @@ module Marameters
|
|
48
41
|
raise TypeError, "#{value.inspect} is an invalid #{pair.first.inspect} value."
|
49
42
|
end
|
50
43
|
|
51
|
-
def
|
44
|
+
def to_array value
|
52
45
|
return unless value
|
53
46
|
|
54
47
|
record.positionals = value.is_a?(Array) ? value : [value]
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Models
|
5
|
+
# Models arguments, by category, for forwarding.
|
6
|
+
Forward = Struct.new :positionals, :keywords, :block do
|
7
|
+
def initialize(positionals: [], keywords: {}, block: nil) = super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/marameters/probe.rb
CHANGED
@@ -7,11 +7,7 @@ module Marameters
|
|
7
7
|
class Probe
|
8
8
|
extend Forwardable
|
9
9
|
|
10
|
-
CATEGORIES = {
|
11
|
-
positionals: %i[req opt],
|
12
|
-
keywords: %i[keyreq key],
|
13
|
-
splats: %i[rest keyrest]
|
14
|
-
}.freeze
|
10
|
+
CATEGORIES = {positionals: %i[req opt], keywords: %i[keyreq key]}.freeze
|
15
11
|
|
16
12
|
def self.of klass, name, collection: []
|
17
13
|
method = klass.instance_method name
|
@@ -22,32 +18,28 @@ module Marameters
|
|
22
18
|
collection
|
23
19
|
end
|
24
20
|
|
25
|
-
delegate %i[deconstruct empty? include? to_a] => :parameters
|
21
|
+
delegate %i[any? deconstruct empty? hash include? inspect to_a] => :parameters
|
26
22
|
|
27
|
-
attr_reader :keywords, :positionals
|
23
|
+
attr_reader :keywords, :positionals
|
28
24
|
|
29
25
|
def initialize parameters, categories: CATEGORIES
|
30
26
|
@parameters = parameters
|
31
27
|
categories.each { |category, kinds| define_variable category, kinds }
|
28
|
+
freeze
|
32
29
|
end
|
33
30
|
|
34
|
-
def
|
31
|
+
def ==(other) = hash == other.hash
|
35
32
|
|
36
|
-
|
33
|
+
alias eql? ==
|
37
34
|
|
38
|
-
def
|
39
|
-
warn "`#{self.class}##{__method__}` is deprecated, use `#keywords_for` instead.",
|
40
|
-
category: :deprecated
|
35
|
+
def <=>(other) = to_a <=> other.to_a
|
41
36
|
|
42
|
-
|
43
|
-
end
|
37
|
+
def keywords? = keywords.any?
|
44
38
|
|
45
39
|
def keywords_for(*keys, **attributes)
|
46
40
|
attributes.select { |key| !keys.include?(key) || keywords.include?(key) }
|
47
41
|
end
|
48
42
|
|
49
|
-
def keywords? = keywords.any?
|
50
|
-
|
51
43
|
def kind?(value) = parameters.any? { |kind, _name| kind == value }
|
52
44
|
|
53
45
|
def kinds = parameters.map { |kind, _name| kind }
|
@@ -58,10 +50,10 @@ module Marameters
|
|
58
50
|
|
59
51
|
def only_bare_splats?
|
60
52
|
parameters in [[:rest]] \
|
61
|
-
| [[:keyrest]] \
|
62
|
-
| [[:rest], [:keyrest]] \
|
63
53
|
| [[:rest, :*]] \
|
54
|
+
| [[:keyrest]] \
|
64
55
|
| [[:keyrest, :**]] \
|
56
|
+
| [[:rest], [:keyrest]] \
|
65
57
|
| [[:rest, :*], [:keyrest, :**]]
|
66
58
|
end
|
67
59
|
|
@@ -71,9 +63,9 @@ module Marameters
|
|
71
63
|
|
72
64
|
def positionals? = positionals.any?
|
73
65
|
|
74
|
-
def
|
75
|
-
|
76
|
-
|
66
|
+
def positionals_and_maybe_keywords?
|
67
|
+
(positionals? && !keywords?) || (positionals? && keywords?)
|
68
|
+
end
|
77
69
|
|
78
70
|
private
|
79
71
|
|
data/lib/marameters/signature.rb
CHANGED
@@ -3,12 +3,13 @@
|
|
3
3
|
module Marameters
|
4
4
|
# Builds a method's parameter signature.
|
5
5
|
class Signature
|
6
|
-
def initialize parameters, builder: Builder.new
|
6
|
+
def initialize parameters, builder: Signatures::Builder.new
|
7
7
|
@parameters = parameters
|
8
8
|
@builder = builder
|
9
|
+
freeze
|
9
10
|
end
|
10
11
|
|
11
|
-
def to_s = build.join
|
12
|
+
def to_s = parameters == :all ? "..." : build.join(", ")
|
12
13
|
|
13
14
|
alias to_str to_s
|
14
15
|
|
@@ -17,7 +18,7 @@ module Marameters
|
|
17
18
|
attr_reader :parameters, :builder
|
18
19
|
|
19
20
|
def build
|
20
|
-
parameters.reduce [] do |signature, (kind,
|
21
|
+
parameters.reduce [] do |signature, (kind, name, default)|
|
21
22
|
signature << builder.call(kind, name, default:)
|
22
23
|
end
|
23
24
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Signatures
|
5
|
+
# Builds a single parameter for a method's signature.
|
6
|
+
class Builder
|
7
|
+
def initialize defaulter: Defaulter
|
8
|
+
@defaulter = defaulter
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def call kind, name = nil, default: nil
|
13
|
+
case kind
|
14
|
+
when :req then name
|
15
|
+
when :opt then "#{name} = #{defaulter.call default}"
|
16
|
+
when :rest then "*#{name}"
|
17
|
+
when :nokey then "**nil"
|
18
|
+
when :keyreq then "#{name}:"
|
19
|
+
when :key then "#{name}: #{defaulter.call default}"
|
20
|
+
when :keyrest then "**#{name}"
|
21
|
+
when :block then "&#{name}"
|
22
|
+
else fail ArgumentError, "Wrong kind (#{kind}), name (#{name}), or default (#{default})."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :defaulter
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Signatures
|
5
|
+
# Computes a method parameter's default value.
|
6
|
+
Defaulter = lambda do |value, extractor: Sources::Extractor.new|
|
7
|
+
case value
|
8
|
+
when Proc
|
9
|
+
fail TypeError, "Use procs instead of lambdas for defaults." if value.lambda?
|
10
|
+
fail ArgumentError, "Avoid using parameters for proc defaults." if value.arity.nonzero?
|
11
|
+
|
12
|
+
extractor.call value
|
13
|
+
when String then value.dump
|
14
|
+
when Symbol then value.inspect
|
15
|
+
when nil then "nil"
|
16
|
+
else value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Signatures
|
5
|
+
# Builds single argument for super method's signature when argument forwarding.
|
6
|
+
Forwarder = lambda do |kind, name = nil|
|
7
|
+
case kind
|
8
|
+
when :req, :opt then name
|
9
|
+
when :rest then "*#{name}"
|
10
|
+
when :nokey then ""
|
11
|
+
when :keyreq, :key then "#{name}:"
|
12
|
+
when :keyrest then "**#{name}"
|
13
|
+
when :block then "&#{name}"
|
14
|
+
else fail ArgumentError, "Unable to forward unknown kind: #{kind.inspect}."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Signatures
|
5
|
+
# Blends ancestor and descendant method parameters together while allowing default overrides.
|
6
|
+
class Inheritor
|
7
|
+
def initialize key_length: 1, kinds: KINDS
|
8
|
+
@key_length = key_length
|
9
|
+
@kinds = kinds
|
10
|
+
freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
def call ancestor, descendant
|
14
|
+
merge(ancestor, descendant).values.sort_by! { |(kind, *)| kinds.index kind }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :key_length, :kinds
|
20
|
+
|
21
|
+
def merge ancestor, descendant
|
22
|
+
ancestor.to_a.union(descendant.to_a).each.with_object({}) do |parameter, all|
|
23
|
+
key = parameter[..key_length]
|
24
|
+
kind = key.first
|
25
|
+
|
26
|
+
case kind
|
27
|
+
when :req, :opt then all[key] = parameter if descendant.positionals_and_maybe_keywords?
|
28
|
+
when :nokey then all
|
29
|
+
when :keyreq, :key
|
30
|
+
different = ancestor.keywords? && ancestor.keywords.sort != descendant.keywords.sort
|
31
|
+
all[:keyrest] = [:keyrest] if different
|
32
|
+
all[key] = parameter if descendant.include? parameter
|
33
|
+
else all[kind] = parameter
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Signatures
|
5
|
+
# Blends ancestor and descendant method arguments for forwarding to the super keyword.
|
6
|
+
class Super
|
7
|
+
def initialize key_length: 1, kinds: KINDS, forwarder: Signatures::Forwarder
|
8
|
+
@key_length = key_length
|
9
|
+
@kinds = kinds
|
10
|
+
@forwarder = forwarder
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
def call ancestor, descendant
|
15
|
+
return "" if ancestor.empty?
|
16
|
+
|
17
|
+
merge(ancestor, descendant).values
|
18
|
+
.sort_by! { |(kind, *)| kinds.index kind }
|
19
|
+
.then { |parameters| build parameters }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :key_length, :kinds, :forwarder
|
25
|
+
|
26
|
+
def merge ancestor, descendant
|
27
|
+
ancestor.to_a.union(descendant.to_a).each.with_object({}) do |parameter, all|
|
28
|
+
key = parameter[..key_length]
|
29
|
+
kind, name = key
|
30
|
+
|
31
|
+
case kind
|
32
|
+
when :req, :opt
|
33
|
+
if ancestor.positionals? && !descendant.positionals? then all[:rest] = [:rest]
|
34
|
+
elsif ancestor.name? name then all[key] = parameter
|
35
|
+
else all
|
36
|
+
end
|
37
|
+
when :nokey then all.delete_if { |key, _| %i[keyreq key keyrest].include? key }
|
38
|
+
when :keyreq, :key
|
39
|
+
included = ancestor.name?(name) && descendant.name?(name)
|
40
|
+
different = ancestor.keywords? && ancestor.keywords.sort != descendant.keywords.sort
|
41
|
+
|
42
|
+
all[key] = parameter if included
|
43
|
+
all[:keyrest] = [:keyrest] if different
|
44
|
+
else all[kind] = parameter if ancestor.kind? kind
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def build parameters
|
50
|
+
parameters.filter_map { |kind, name| forwarder.call kind, name }
|
51
|
+
.join ", "
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Sources
|
5
|
+
# Extracts the literal source of a Proc's body.
|
6
|
+
class Extractor
|
7
|
+
PATTERN = /
|
8
|
+
proc # Proc statement.
|
9
|
+
\s* # Optional space.
|
10
|
+
\{ # Block open.
|
11
|
+
(?<body>.*?) # Source code body.
|
12
|
+
\} # Block close.
|
13
|
+
/x
|
14
|
+
|
15
|
+
def initialize pattern: PATTERN, reader: Reader.new
|
16
|
+
@pattern = pattern
|
17
|
+
@reader = reader
|
18
|
+
@fallback = "nil"
|
19
|
+
freeze
|
20
|
+
end
|
21
|
+
|
22
|
+
def call function
|
23
|
+
reader.call(function).then do |line|
|
24
|
+
line.match?(pattern) ? line.match(pattern)[:body].strip : fallback
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :pattern, :reader, :fallback
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Marameters
|
4
|
+
module Sources
|
5
|
+
# Reads object source code from memory or file (assumes implementation is a one-liner).
|
6
|
+
class Reader
|
7
|
+
def initialize offset: 1, parser: RubyVM::InstructionSequence, io: File
|
8
|
+
@offset = offset
|
9
|
+
@parser = parser
|
10
|
+
@io = io
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
def call object
|
15
|
+
instructions = parser.of object
|
16
|
+
|
17
|
+
fail StandardError, "Unable to load source for: #{object.inspect}." unless instructions
|
18
|
+
|
19
|
+
process object, instructions
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :offset, :parser, :io
|
25
|
+
|
26
|
+
def process object, instructions
|
27
|
+
lines = instructions.script_lines
|
28
|
+
|
29
|
+
return lines.first if lines
|
30
|
+
return extract(*object.source_location) if io.readable? instructions.absolute_path
|
31
|
+
|
32
|
+
fail StandardError, "Unable to load source for: #{object.inspect}."
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract(path, line_number) = io.open(path) { |body| pluck body, line_number }
|
36
|
+
|
37
|
+
def pluck body, line_number
|
38
|
+
body.each_line
|
39
|
+
.with_index
|
40
|
+
.find { |_line, index| index + offset == line_number }
|
41
|
+
.first
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/marameters.rb
CHANGED
@@ -16,7 +16,7 @@ module Marameters
|
|
16
16
|
@loader ||= registry.loaders.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.categorize(parameters, arguments) = Categorizer.new
|
19
|
+
def self.categorize(parameters, arguments) = Categorizer.new.call parameters, arguments
|
20
20
|
|
21
21
|
def self.of(...) = Probe.of(...)
|
22
22
|
|
data/marameters.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "marameters"
|
5
|
-
spec.version = "
|
5
|
+
spec.version = "4.0.0"
|
6
6
|
spec.authors = ["Brooke Kuhlmann"]
|
7
7
|
spec.email = ["brooke@alchemists.io"]
|
8
8
|
spec.homepage = "https://alchemists.io/projects/marameters"
|
9
|
-
spec.summary = "A dynamic method parameter
|
9
|
+
spec.summary = "A dynamic method parameter enhancer."
|
10
10
|
spec.license = "Hippocratic-2.1"
|
11
11
|
|
12
12
|
spec.metadata = {
|
@@ -22,8 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.signing_key = Gem.default_key_path
|
23
23
|
spec.cert_chain = [Gem.default_cert_path]
|
24
24
|
|
25
|
-
spec.required_ruby_version = "
|
26
|
-
spec.add_dependency "refinements", "~>
|
25
|
+
spec.required_ruby_version = "~> 3.4"
|
26
|
+
spec.add_dependency "refinements", "~> 13.0"
|
27
27
|
spec.add_dependency "zeitwerk", "~> 2.7"
|
28
28
|
|
29
29
|
spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marameters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brooke Kuhlmann
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain:
|
11
10
|
- |
|
@@ -35,7 +34,7 @@ cert_chain:
|
|
35
34
|
3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
|
36
35
|
gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
|
37
36
|
-----END CERTIFICATE-----
|
38
|
-
date: 2024-
|
37
|
+
date: 2024-12-27 00:00:00.000000000 Z
|
39
38
|
dependencies:
|
40
39
|
- !ruby/object:Gem::Dependency
|
41
40
|
name: refinements
|
@@ -43,14 +42,14 @@ dependencies:
|
|
43
42
|
requirements:
|
44
43
|
- - "~>"
|
45
44
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
45
|
+
version: '13.0'
|
47
46
|
type: :runtime
|
48
47
|
prerelease: false
|
49
48
|
version_requirements: !ruby/object:Gem::Requirement
|
50
49
|
requirements:
|
51
50
|
- - "~>"
|
52
51
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
52
|
+
version: '13.0'
|
54
53
|
- !ruby/object:Gem::Dependency
|
55
54
|
name: zeitwerk
|
56
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -65,7 +64,6 @@ dependencies:
|
|
65
64
|
- - "~>"
|
66
65
|
- !ruby/object:Gem::Version
|
67
66
|
version: '2.7'
|
68
|
-
description:
|
69
67
|
email:
|
70
68
|
- brooke@alchemists.io
|
71
69
|
executables: []
|
@@ -77,12 +75,17 @@ files:
|
|
77
75
|
- LICENSE.adoc
|
78
76
|
- README.adoc
|
79
77
|
- lib/marameters.rb
|
80
|
-
- lib/marameters/builder.rb
|
81
78
|
- lib/marameters/categorizer.rb
|
82
|
-
- lib/marameters/
|
79
|
+
- lib/marameters/models/forward.rb
|
83
80
|
- lib/marameters/probe.rb
|
84
81
|
- lib/marameters/signature.rb
|
85
|
-
- lib/marameters/
|
82
|
+
- lib/marameters/signatures/builder.rb
|
83
|
+
- lib/marameters/signatures/defaulter.rb
|
84
|
+
- lib/marameters/signatures/forwarder.rb
|
85
|
+
- lib/marameters/signatures/inheritor.rb
|
86
|
+
- lib/marameters/signatures/super.rb
|
87
|
+
- lib/marameters/sources/extractor.rb
|
88
|
+
- lib/marameters/sources/reader.rb
|
86
89
|
- marameters.gemspec
|
87
90
|
homepage: https://alchemists.io/projects/marameters
|
88
91
|
licenses:
|
@@ -95,16 +98,12 @@ metadata:
|
|
95
98
|
label: Marameters
|
96
99
|
rubygems_mfa_required: 'true'
|
97
100
|
source_code_uri: https://github.com/bkuhlmann/marameters
|
98
|
-
post_install_message:
|
99
101
|
rdoc_options: []
|
100
102
|
require_paths:
|
101
103
|
- lib
|
102
104
|
required_ruby_version: !ruby/object:Gem::Requirement
|
103
105
|
requirements:
|
104
|
-
- - "
|
105
|
-
- !ruby/object:Gem::Version
|
106
|
-
version: '3.3'
|
107
|
-
- - "<="
|
106
|
+
- - "~>"
|
108
107
|
- !ruby/object:Gem::Version
|
109
108
|
version: '3.4'
|
110
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -113,8 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
112
|
- !ruby/object:Gem::Version
|
114
113
|
version: '0'
|
115
114
|
requirements: []
|
116
|
-
rubygems_version: 3.
|
117
|
-
signing_key:
|
115
|
+
rubygems_version: 3.6.2
|
118
116
|
specification_version: 4
|
119
|
-
summary: A dynamic method parameter
|
117
|
+
summary: A dynamic method parameter enhancer.
|
120
118
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|
data/lib/marameters/builder.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Marameters
|
4
|
-
# Builds a single parameter of a method's parameter signature.
|
5
|
-
class Builder
|
6
|
-
def initialize defaulter: Defaulter
|
7
|
-
@defaulter = defaulter
|
8
|
-
end
|
9
|
-
|
10
|
-
def call kind, name = nil, default: nil
|
11
|
-
case kind
|
12
|
-
when :req then name
|
13
|
-
when :opt then "#{name} = #{defaulter.call default}"
|
14
|
-
when :rest then "*#{name}"
|
15
|
-
when :nokey then "**nil"
|
16
|
-
when :keyreq then "#{name}:"
|
17
|
-
when :key then "#{name}: #{defaulter.call default}"
|
18
|
-
when :keyrest then "**#{name}"
|
19
|
-
when :block then "&#{name}"
|
20
|
-
else fail ArgumentError, "Wrong kind (#{kind}), name (#{name}), or default (#{default})."
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
attr_reader :defaulter
|
27
|
-
end
|
28
|
-
end
|
data/lib/marameters/defaulter.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Marameters
|
4
|
-
# Computes a method parameter's default value.
|
5
|
-
Defaulter = lambda do |value, passthrough: "*"|
|
6
|
-
case value
|
7
|
-
when /\A#{Regexp.escape passthrough}/ then value.delete_prefix passthrough
|
8
|
-
when String then value.dump
|
9
|
-
when Symbol then value.inspect
|
10
|
-
when nil then "nil"
|
11
|
-
else value
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/lib/marameters/splat.rb
DELETED