marameters 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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