marameters 0.1.0 → 0.3.1

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: 0e9a67405793129c6913e84a4ead90cbc6eda2abbec139f00764a677aa6d30b1
4
- data.tar.gz: fe3d699a7717e37ae79d07773870cf1137ad0b4b14a761c3eaaa56ed9a4f9fdd
3
+ metadata.gz: 8f31405cf6109f53ee8ea25db37e48dd65520397f634f49ccbeb63403c02ac97
4
+ data.tar.gz: be9f7277b4099c0b6f6edafde1b3fafd3cb8cb63ce0894f067fc7bfbc663e8f4
5
5
  SHA512:
6
- metadata.gz: ded0a8de22a2f67bdb2f308bbfc02db520fb98028b1595825d9e4ab82396b6bdb062a5a602c1df52ced38862963c5b0eb3285cdee586a6934f5f888a6777d313
7
- data.tar.gz: bc840a326f4116973cda051c23b411f92e74b53e2f704e69adb9536159ef178a16b094c29f52b038dfb17af65be2f26fbe10e7d062da2b5e222bb704895a7793
6
+ metadata.gz: a96509751fe29351233ab41b79b730b6e16f7fb7f7a72f59dd4cf8083b042860679fb18f9f3b4ab60e17a918211bc645466414fcf38072f1801e15a8e7c25824
7
+ data.tar.gz: ed832277fba30755bee9162eb427ef65ae0f434fbdae7b8a35b90b6c5213202c199c95575458d28e637ad9e5a4e8b226f293f25146a2d639123dfc4e40597826
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -4,9 +4,9 @@
4
4
 
5
5
  = Marameters
6
6
 
7
- Marameters is short for method parameters (i.e. `[m]ethod + p[arameters] = marameters`) which is
8
- designed to provide additional insight and diagnostics to method parameters. For context, the
9
- difference between a method's parameters and arguments is:
7
+ Marameters is a portmanteau (i.e. `[m]ethod + p[arameters] = marameters`) which is designed to
8
+ provide additional insight and diagnostics to method parameters. For context, the difference between
9
+ a method's parameters and arguments is:
10
10
 
11
11
  * *Parameters*: Represents the _expected_ values to be passed to a method when
12
12
  messaged as defined when the method is implemented. Example: `def demo(one, two: nil)`.
@@ -14,13 +14,13 @@ difference between a method's parameters and arguments is:
14
14
  Example: `demo 1, two: 2`.
15
15
 
16
16
  This gem will help you debug methods or -- more importantly -- aid your workflow when
17
- metaprogramming and architecting more sophisticated applications.
17
+ metaprogramming, as used in the link:https://www.alchemists.io/projects/auto_injector[Auto Injector]
18
+ gem, when architecting more sophisticated applications.
18
19
 
19
20
  toc::[]
20
21
 
21
22
  == Features
22
23
 
23
- * Provides a core object as a primary interface.
24
24
  * Provides specialized objects for keyword, positional, and splatted parameters.
25
25
 
26
26
  == Requirements
@@ -45,8 +45,16 @@ gem "marameters"
45
45
 
46
46
  == Usage
47
47
 
48
- The primary object you'll want to interact with is the `Marameters::Analyzer` class. To understand
49
- how to _analyze_ a method's parameters, consider the following demonstration class:
48
+ There are two main objects you'll want to interact with:
49
+
50
+ * *Marameters::Probe*: Allows you to analyze a method's parameters.
51
+ * *Marameters::Signature*: Allows you to dynamically build a method signature from raw parameters.
52
+
53
+ Both of these objects are meant to serve as building blocks to more complex architectures.
54
+
55
+ === Probe
56
+
57
+ To understand how to analyze a method's parameters, consider the following demonstration class:
50
58
 
51
59
  [source,ruby]
52
60
  ----
@@ -55,40 +63,154 @@ class Demo
55
63
  @logger = logger
56
64
  end
57
65
 
58
- def example one, two = nil, *three, four:, five: nil, **six, &seven
66
+ def all one, two = nil, *three, four:, five: nil, **six, &seven
59
67
  logger.debug [one, two, three, four, five, six, seven]
60
68
  end
61
69
 
70
+ def none = logger.debug "Nothing to see here."
71
+
62
72
  private
63
73
 
64
74
  attr_reader :logger
65
75
  end
66
76
  ----
67
77
 
68
- We can then analyze the above `#example` method's parameters as follows:
78
+ You can then probe the `#all` method's parameters as follows:
79
+
80
+ [source,ruby]
81
+ ----
82
+ probe = Marameters::Probe.new Demo.instance_method(:all).parameters
83
+
84
+ probe.block # :seven
85
+ probe.block? # true
86
+ probe.empty? # false
87
+ probe.keywords # [:four, :five]
88
+ probe.keywords? # true
89
+ probe.kind?(:keyrest) # true
90
+ probe.kinds # [:req, :opt, :rest, :keyreq, :key, :keyrest, :block]
91
+ probe.name?(:three) # true
92
+ probe.names # [:one, :two, :three, :four, :five, :six, :seven]
93
+ probe.only_bare_splats? # false
94
+ probe.only_double_splats? # false
95
+ probe.only_single_splats? # false
96
+ probe.positionals # [:one, :two]
97
+ probe.positionals? # true
98
+ probe.splats # [:three, :six]
99
+ probe.splats? # true
100
+ probe.to_a # [[:req, :one], [:opt, :two], [:rest, :three], [:keyreq, :four], [:key, :five], [:keyrest, :six], [:block, :seven]]
101
+ probe.to_h # {:req=>:one, :opt=>:two, :rest=>:three, :keyreq=>:four, :key=>:five, :keyrest=>:six, :block=>:seven}
102
+ ----
103
+
104
+ In contrast the above, we can also probe the `#none` method which has no parameters for a completely
105
+ different result:
69
106
 
70
107
  [source,ruby]
71
108
  ----
72
- analyzer = Marameters::Analyzer.new Demo.instance_method(:example).parameters
73
-
74
- analyzer.block # :seven
75
- analyzer.block? # true
76
- analyzer.empty? # false
77
- analyzer.keywords # [:four, :five]
78
- analyzer.keywords? # true
79
- analyzer.kind?(:keyrest) # true
80
- analyzer.kinds # [:req, :opt, :rest, :keyreq, :key, :keyrest, :block]
81
- analyzer.name?(:three) # true
82
- analyzer.names # [:one, :two, :three, :four, :five, :six, :seven]
83
- analyzer.only_bare_splats? # false
84
- analyzer.only_double_splats? # false
85
- analyzer.only_single_splats? # false
86
- analyzer.positionals # [:one, :two]
87
- analyzer.positionals? # true
88
- analyzer.splats # [:three, :six]
89
- analyzer.splats? # true
90
- analyzer.to_a # [[:req, :one], [:opt, :two], [:rest, :three], [:keyreq, :four], [:key, :five], [:keyrest, :six], [:block, :seven]]
91
- analyzer.to_h # {:req=>:one, :opt=>:two, :rest=>:three, :keyreq=>:four, :key=>:five, :keyrest=>:six, :block=>:seven}
109
+ probe = Marameters::Probe.new Demo.instance_method(:none).parameters
110
+
111
+ probe.block # nil
112
+ probe.block? # false
113
+ probe.empty? # true
114
+ probe.keywords # []
115
+ probe.keywords? # false
116
+ probe.kind?(:req) # true
117
+ probe.kinds # []
118
+ probe.name?(:three) # false
119
+ probe.names # []
120
+ probe.only_bare_splats? # false
121
+ probe.only_double_splats? # false
122
+ probe.only_single_splats? # false
123
+ probe.positionals # []
124
+ probe.positionals? # false
125
+ probe.splats # []
126
+ probe.splats? # false
127
+ probe.to_a # []
128
+ probe.to_h # {}
129
+ ----
130
+
131
+ === Signature
132
+
133
+ The signature class is the opposite of the probe in that you want to feed it parameters for turning
134
+ into a method signature. This is useful when dynamically building method signatures or using the
135
+ same signature when metaprogramming multiple methods.
136
+
137
+ The following demonstrates how you might construct a method signature with all possible parameters:
138
+
139
+ [source,ruby]
140
+ ----
141
+ signature = Marameters::Signature.new(
142
+ {
143
+ req: :one,
144
+ opt: [:two, 2],
145
+ rest: :three,
146
+ keyreq: :four,
147
+ key: [:five, 5],
148
+ keyrest: :six,
149
+ block: :seven
150
+ }
151
+ )
152
+
153
+ puts signature
154
+ # one, two = 2, *three, four:, five: 5, **six, &seven
155
+ ----
156
+
157
+ You'll notice that the parameters are a hash _and_ some values can be tuples. The reason is that
158
+ it's easier to write a hash than a double nested array as normally produced by the probe or directly
159
+ from `Method#parameters`. The optional positional and keyword parameters use tuples because you
160
+ might want to supply a default value and this provides a way for you to do that with minimal syntax.
161
+ This can be demonstrated further by using optional keywords (same applies for optional positionals):
162
+
163
+ [source,ruby]
164
+ ----
165
+ # With no default
166
+ puts Marameters::Signature.new({key: :demo})
167
+ # demo: nil
168
+
169
+ # With explicit nil as default
170
+ puts Marameters::Signature.new({key: [:demo, nil]})
171
+ # demo: nil
172
+
173
+ # With string as default
174
+ puts Marameters::Signature.new({key: [:demo, "test"]})
175
+ # demo: "test"
176
+
177
+ # With symbol as default
178
+ puts Marameters::Signature.new({key: [:demo, :test]})
179
+ # demo: :test
180
+
181
+ # With object(dependency) as default
182
+ puts Marameters::Signature.new({key: [:demo, "*Object.new"]})
183
+ # demo: Object.new
184
+ ----
185
+
186
+ In the case of object dependencies, you need to wrap these in a string _and_ prefix them with a star
187
+ (`*`) so the signature builder won't confuse them as normal strings. There are two reasons why this
188
+ is important:
189
+
190
+ * The star (`*`) signifies you want an object to be passed through without further processing while
191
+ also not being confused as a normal string.
192
+ * Objects wrapped as strings allows your dependency to be lazy loaded. Otherwise, if `Object.new`
193
+ was pass in directly, you'd be passing the evaluated instance (i.e.
194
+ `#<Object:0x0000000107df4028>`) which is not what you want until much later when your method is
195
+ defined.
196
+
197
+ When you put all of this together, you can dynamically build a method as follows:
198
+
199
+ [source,ruby]
200
+ ----
201
+ signature = Marameters::Signature.new({opt: [:text, "This is a test."]})
202
+
203
+ Example = Module.new do
204
+ module_eval <<~DEFINITION, __FILE__, __LINE__ + 1
205
+ def self.say(#{signature}) = text
206
+ DEFINITION
207
+ end
208
+
209
+ puts Example.say
210
+ # This is a test.
211
+
212
+ puts Example.say "Hello"
213
+ # Hello
92
214
  ----
93
215
 
94
216
  == Development
@@ -0,0 +1,28 @@
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
+ # :reek:DuplicateMethodCall
11
+ def call kind, name, default: nil
12
+ case kind
13
+ when :req then name
14
+ when :opt then "#{name} = #{defaulter.call default}"
15
+ when :rest then "*#{name}"
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
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Marameters
4
+ # Calculates the default for a given value when used within a method's parameter.
5
+ class Defaulter
6
+ PASSTHROUGH = "*"
7
+
8
+ def self.call(...) = new(...).call
9
+
10
+ def initialize value, passthrough: PASSTHROUGH
11
+ @value = value
12
+ @passthrough = passthrough
13
+ end
14
+
15
+ def call
16
+ case value
17
+ when nil then "nil"
18
+ when /\A#{Regexp.escape passthrough}/ then value.delete_prefix passthrough
19
+ when String then value.dump
20
+ when Symbol then value.inspect
21
+ else value
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :value, :passthrough
28
+ end
29
+ end
@@ -3,8 +3,8 @@
3
3
  require "refinements/arrays"
4
4
 
5
5
  module Marameters
6
- # Provides analysis of a method's parameters.
7
- class Analyzer
6
+ # Provides insight into a method's parameters.
7
+ class Probe
8
8
  using Refinements::Arrays
9
9
 
10
10
  # :reek:TooManyStatements
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Marameters
4
+ # Produces a method signature for given parameters.
5
+ class Signature
6
+ def initialize parameters, builder: Builder.new
7
+ @parameters = parameters
8
+ @builder = builder
9
+ end
10
+
11
+ def to_s = build.join ", "
12
+
13
+ alias to_str to_s
14
+
15
+ private
16
+
17
+ attr_reader :parameters, :builder
18
+
19
+ def build
20
+ parameters.reduce [] do |signature, (kind, (name, default))|
21
+ signature << builder.call(kind, name, default:)
22
+ end
23
+ end
24
+ end
25
+ end
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 = "0.1.0"
5
+ spec.version = "0.3.1"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://www.alchemists.io/projects/marameters"
9
- spec.summary = "Provides method parameter introspection which is useful when metaprogramming."
9
+ spec.summary = "Provides dynamic method parameter construction and deconstruction."
10
10
  spec.license = "Hippocratic-2.1"
11
11
 
12
12
  spec.metadata = {
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marameters
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -10,9 +10,9 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIC/jCCAeagAwIBAgIBBDANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpicm9v
14
- a2UvREM9YWxjaGVtaXN0cy9EQz1pbzAeFw0yMTAzMTkxMjQ4MDZaFw0yMjAzMTkx
15
- MjQ4MDZaMCUxIzAhBgNVBAMMGmJyb29rZS9EQz1hbGNoZW1pc3RzL0RDPWlvMIIB
13
+ MIIC/jCCAeagAwIBAgIBBTANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpicm9v
14
+ a2UvREM9YWxjaGVtaXN0cy9EQz1pbzAeFw0yMjAzMTkxNzI0MzJaFw0yMzAzMTkx
15
+ NzI0MzJaMCUxIzAhBgNVBAMMGmJyb29rZS9EQz1hbGNoZW1pc3RzL0RDPWlvMIIB
16
16
  IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6l1qpXTiomH1RfMRloyw7MiE
17
17
  xyVx/x8Yc3EupdH7uhNaTXQGyORN6aOY//1QXXMHIZ9tW74nZLhesWMSUMYy0XhB
18
18
  brs+KkurHnc9FnEJAbG7ebGvl/ncqZt72nQvaxpDxvuCBHgJAz+8i5wl6FhLw+oT
@@ -20,15 +20,15 @@ cert_chain:
20
20
  D5vkU0YlAm1r98BymuJlcQ1qdkVEI1d48ph4kcS0S0nv1RiuyVb6TCAR3Nu3VaVq
21
21
  3fPzZKJLZBx67UvXdbdicWPiUR75elI4PXpLIic3xytaF52ZJYyKZCNZJhNwfQID
22
22
  AQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU0nzow9vc
23
- 2CdikiiE3fJhP/gY4ggwDQYJKoZIhvcNAQELBQADggEBAEjpaOXHHp8s/7GL2qCb
24
- YAs7urOLv9VHSPfQWAwaTMVnSsIf3Sw4xzISOP/mmfEPBPXtz61K5esrE/uTFtgb
25
- FyjxQk2H0sEWgrRXGGNHBWQRhhEs7LP/TByoC15A0br++xLxRz4r7HBLGAWQQDpg
26
- 66BJ2TBVjxS6K64tKbq7+ACyrOZGgTfNHACh4M076y0x0oRf/rwBrU39/KRfuhbb
27
- cm+nNCEtO35gTmZ2bVDHLGvWazi3gJt6+huQjfXTCUUG2YYBxwhu+GPdAGQPxpf9
28
- lkHilIrX69jq8wMPpBhlaw2mRmeSL50Wv5u6xVBvOHhXFSP1crXM95vfLhLyRYod
29
- W2A=
23
+ 2CdikiiE3fJhP/gY4ggwDQYJKoZIhvcNAQELBQADggEBAJbbNyWzFjqUNVPPCUCo
24
+ IMrhDa9xf1xkORXNYYbmXgoxRy/KyNbUr+jgEEoWJAm9GXlcqxxWAUI6pK/i4/Qi
25
+ X6rPFEFmeObDOHNvuqy8Hd6AYsu+kP94U/KJhe9wnWGMmGoNKJNU3EkW3jM/osSl
26
+ +JRxiH5t4WtnDiVyoYl5nYC02rYdjJkG6VMxDymXTqn7u6HhYgZkGujq1UPar8x2
27
+ hNIWJblDKKSu7hA2d6+kUthuYo13o1sg1Da/AEDg0hoZSUvhqDEF5Hy232qb3pDt
28
+ CxDe2+VuChj4I1nvIHdu+E6XoEVlanUPKmSg6nddhkKn2gC45Kyzh6FZqnzH/CRp
29
+ RFE=
30
30
  -----END CERTIFICATE-----
31
- date: 2022-03-11 00:00:00.000000000 Z
31
+ date: 2022-04-09 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: refinements
@@ -70,7 +70,10 @@ files:
70
70
  - LICENSE.adoc
71
71
  - README.adoc
72
72
  - lib/marameters.rb
73
- - lib/marameters/analyzer.rb
73
+ - lib/marameters/builder.rb
74
+ - lib/marameters/defaulter.rb
75
+ - lib/marameters/probe.rb
76
+ - lib/marameters/signature.rb
74
77
  - marameters.gemspec
75
78
  homepage: https://www.alchemists.io/projects/marameters
76
79
  licenses:
@@ -97,8 +100,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
100
  - !ruby/object:Gem::Version
98
101
  version: '0'
99
102
  requirements: []
100
- rubygems_version: 3.3.8
103
+ rubygems_version: 3.3.11
101
104
  signing_key:
102
105
  specification_version: 4
103
- summary: Provides method parameter introspection which is useful when metaprogramming.
106
+ summary: Provides dynamic method parameter construction and deconstruction.
104
107
  test_files: []
metadata.gz.sig CHANGED
Binary file