marameters 0.1.0 → 0.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: 0e9a67405793129c6913e84a4ead90cbc6eda2abbec139f00764a677aa6d30b1
4
- data.tar.gz: fe3d699a7717e37ae79d07773870cf1137ad0b4b14a761c3eaaa56ed9a4f9fdd
3
+ metadata.gz: a3daee40e52b7df55680618be8c5a37a6a62c3ca7f62b88128fbc724f4222c50
4
+ data.tar.gz: 3b4d527a40fc8ed6500faea3e6676b45be484a2fb9288b5e79ee38684ac0bec0
5
5
  SHA512:
6
- metadata.gz: ded0a8de22a2f67bdb2f308bbfc02db520fb98028b1595825d9e4ab82396b6bdb062a5a602c1df52ced38862963c5b0eb3285cdee586a6934f5f888a6777d313
7
- data.tar.gz: bc840a326f4116973cda051c23b411f92e74b53e2f704e69adb9536159ef178a16b094c29f52b038dfb17af65be2f26fbe10e7d062da2b5e222bb704895a7793
6
+ metadata.gz: 459d04fcc654dcf3ef58d23dfaaff01f5df52e0ffbb8d670cb0d1a9f59f10f91d0e9ff424e5871c9e892a1ba7f2b4cbdb236a287e3b3ffbdf32a1e56de9b5f97
7
+ data.tar.gz: 92df818d39aeacd231721b69299e0e23705b0f889db54360fefd0f269355fcbf40499b62c59bfc30a22b99dac39874b8a168c381e825ae4b2891a18b6fd9f53f
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -14,7 +14,8 @@ 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
 
@@ -45,8 +46,16 @@ gem "marameters"
45
46
 
46
47
  == Usage
47
48
 
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:
49
+ There are two main objects you'll want to interact with:
50
+
51
+ * *Analyzer*: Allows you to analyze a method's parameters.
52
+ * *Signature*: Allows you to dynamically build a method signature.
53
+
54
+ Both of these objects are meant to serve as building blocks to more complex architectures.
55
+
56
+ === Analyzer
57
+
58
+ To understand how to _analyze_ a method's parameters, consider the following demonstration class:
50
59
 
51
60
  [source,ruby]
52
61
  ----
@@ -55,21 +64,23 @@ class Demo
55
64
  @logger = logger
56
65
  end
57
66
 
58
- def example one, two = nil, *three, four:, five: nil, **six, &seven
67
+ def all one, two = nil, *three, four:, five: nil, **six, &seven
59
68
  logger.debug [one, two, three, four, five, six, seven]
60
69
  end
61
70
 
71
+ def none = logger.debug "Nothing to see here."
72
+
62
73
  private
63
74
 
64
75
  attr_reader :logger
65
76
  end
66
77
  ----
67
78
 
68
- We can then analyze the above `#example` method's parameters as follows:
79
+ You can then analyze the `#all` method's parameters as follows:
69
80
 
70
81
  [source,ruby]
71
82
  ----
72
- analyzer = Marameters::Analyzer.new Demo.instance_method(:example).parameters
83
+ analyzer = Marameters::Analyzer.new Demo.instance_method(:all).parameters
73
84
 
74
85
  analyzer.block # :seven
75
86
  analyzer.block? # true
@@ -91,6 +102,119 @@ analyzer.to_a # [[:req, :one], [:opt, :two], [:rest, :three], [:
91
102
  analyzer.to_h # {:req=>:one, :opt=>:two, :rest=>:three, :keyreq=>:four, :key=>:five, :keyrest=>:six, :block=>:seven}
92
103
  ----
93
104
 
105
+ In contrast the above, we can also analyze the `#none` method which has no parameters for a
106
+ completely different result:
107
+
108
+ [source,ruby]
109
+ ----
110
+ analyzer = Marameters::Analyzer.new Demo.instance_method(:none).parameters
111
+
112
+ analyzer.block # nil
113
+ analyzer.block? # false
114
+ analyzer.empty? # true
115
+ analyzer.keywords # []
116
+ analyzer.keywords? # false
117
+ analyzer.kind?(:req) # true
118
+ analyzer.kinds # []
119
+ analyzer.name?(:three) # false
120
+ analyzer.names # []
121
+ analyzer.only_bare_splats? # false
122
+ analyzer.only_double_splats? # false
123
+ analyzer.only_single_splats? # false
124
+ analyzer.positionals # []
125
+ analyzer.positionals? # false
126
+ analyzer.splats # []
127
+ analyzer.splats? # false
128
+ analyzer.to_a # []
129
+ analyzer.to_h # {}
130
+ ----
131
+
132
+ === Signature
133
+
134
+ The signature class is the opposite of the analyzer in that you want to feed it parameters for
135
+ turning into a method signature. This is useful when dynamically building method signatures or using
136
+ the same signature for multiple methods when metaprogramming.
137
+
138
+ The following demonstrates how you might construct a method signature with all possible parameters:
139
+
140
+ [source,ruby]
141
+ ----
142
+ signature = Marameters::Signature.new(
143
+ {
144
+ req: :one,
145
+ opt: [:two, 2],
146
+ rest: :three,
147
+ keyreq: :four,
148
+ key: [:five, 5],
149
+ keyrest: :six,
150
+ block: :seven
151
+ }
152
+ )
153
+
154
+ puts signature
155
+ # one, two = 2, *three, four:, five: 5, **six, &seven
156
+ ----
157
+
158
+ You'll notice that the parameters is a hash _and_ some values can be tuples. The reason is that it's
159
+ easier to write a hash than a double nested array as normally produced by the analyzer or directly
160
+ from `Method#parameters`. The optional positional and keyword parameters use tuples because you
161
+ might want to supply a default value and this provides a way for you to do that with minimal syntax.
162
+ This can be demonstrated further by using optional keywords (same applies for optional positionals):
163
+
164
+ [source,ruby]
165
+ ----
166
+ # With no default
167
+ puts Marameters::Signature.new({key: :demo})
168
+ # demo: nil
169
+
170
+ # With explicit nil as default
171
+ puts Marameters::Signature.new({key: [:demo, nil]})
172
+ # demo: nil
173
+
174
+ # With string as default
175
+ puts Marameters::Signature.new({key: [:demo, "test"]})
176
+ # demo: "test"
177
+
178
+ # With symbol as default
179
+ puts Marameters::Signature.new({key: [:demo, :test]})
180
+ # demo: :test
181
+
182
+ # With object(dependency) as default
183
+ puts Marameters::Signature.new({key: [:demo, "*Object.new"]})
184
+ # demo: Object.new
185
+ ----
186
+
187
+ In the case of object dependencies you need to wrap these in a string _and_ prefix them with a star
188
+ (`*`) so the signature builder won't confuse these as a normal string. There are two reasons why
189
+ this is important:
190
+
191
+ * The star (`*`) signifies that you want the object to be passed through without any further
192
+ processing while also not being confused normal strings.
193
+ * Objects wrapped as strings allows your dependency to be lazy loaded. Otherwise, if `Object.new`
194
+ was pass directly, you'd be passing the evaluated instance (i.e. `#<Object:0x0000000107df4028>`)
195
+ which is not what you want until much later when your method is 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}
206
+ text
207
+ end
208
+ DEFINITION
209
+ end
210
+
211
+ puts Example.say
212
+ # This is a test.
213
+
214
+ puts Example.say "Hello"
215
+ # Hello
216
+ ----
217
+
94
218
  == Development
95
219
 
96
220
  You can also use the IRB console for direct access to all objects:
@@ -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
@@ -0,0 +1,23 @@
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
+ private
14
+
15
+ attr_reader :parameters, :builder
16
+
17
+ def build
18
+ parameters.reduce [] do |signature, (kind, (name, default))|
19
+ signature << builder.call(kind, name, default:)
20
+ end
21
+ end
22
+ end
23
+ 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.2.0"
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.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -28,7 +28,7 @@ cert_chain:
28
28
  lkHilIrX69jq8wMPpBhlaw2mRmeSL50Wv5u6xVBvOHhXFSP1crXM95vfLhLyRYod
29
29
  W2A=
30
30
  -----END CERTIFICATE-----
31
- date: 2022-03-11 00:00:00.000000000 Z
31
+ date: 2022-03-12 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: refinements
@@ -71,6 +71,9 @@ files:
71
71
  - README.adoc
72
72
  - lib/marameters.rb
73
73
  - lib/marameters/analyzer.rb
74
+ - lib/marameters/builder.rb
75
+ - lib/marameters/defaulter.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.9
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