candor 0.2.0 → 0.3.0

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: 413521a77b9a26be85cbfe5ba7078da7a1c9192cb879da37f8d3be0d7c973ecc
4
- data.tar.gz: 7b8a583a71fe52f567b7a9c931d9b46dfa9aae0d4d3f8daf2b412e08201cb7c8
3
+ metadata.gz: 0dff88c7b13476b57de0595389deb4323892303938997b9efb7a6b15fa25d27e
4
+ data.tar.gz: 9764a01e552d1495f3c23b6decff65ddb22e1f0ace5fd9309563cc89cb7cd73a
5
5
  SHA512:
6
- metadata.gz: 9f1bf8cc569d1c3924b42ae8d299fb9779c8efef396da6eaa9c95ffe625b97c7aa94ba27077f61decb275b3fd6e58aed98d2e2e39f2b1a512e2211e0a0830b20
7
- data.tar.gz: 476fd93d7089c5b2ffc2d276f611dd833dcf468f35014662586d5fb536533cbe0e0ba3558c7632fc64d53bd29bf5b9642492335168ae451488710dd4dc1c3bba
6
+ metadata.gz: 63307d1909064c401480dc8dde0a255069dd79ac545f5aeb4d6760608debe6fe10f480a68deadb06cdf86cc8a77e7631b6445cd59d77686314301daa4f5797ab
7
+ data.tar.gz: 0713713d5d03034c5fdcda76db29c78329e62650633dfc9632d75eabc6b45792506d26d84315ca3e4b1bd136c3eedbf4f0f01ba9fb385ddc343c43741f2f315a
data/CHANGELOG.md CHANGED
@@ -4,20 +4,37 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.3.0] - 2026-10-06
10
+
11
+ ### Changed
12
+ - Ruby 3.3 or newer is now required. Ruby 3.2 is no longer supported.
13
+ - Update all development dependencies and Bundler to their latest stable releases.
14
+
15
+ ## [0.2.1] - 2026-07-31
16
+
17
+ No change to the library.
18
+
19
+ The gem now ships from a tagged CI run through RubyGems trusted publishing. This release and every later one carries a sigstore attestation, which rubygems.org serves at `https://rubygems.org/api/v1/attestations/candor-0.2.1.json`.
20
+
7
21
  ## [0.2.0] - 2026-07-10
8
22
 
9
23
  ### Added
10
- - `Candor.define(..., source_location:)` — the location every fabricated name reports, overriding the body's. A caller whose body is a proc it generated on the user's behalf can now point the wrapper at what the user actually wrote, rather than at the generator. It is also the only way to fabricate from a body carrying no location of its own — a curried proc, a symbol-to-proc, a C-defined method — which is the caller assuming responsibility for the honesty the gem otherwise derives. A `#call` object is not one of them and no `source_location:` rescues it: that refusal is about the kind. A `source_location:` that is not a `[String, Integer]` pair, or whose line is one `eval` will not take, raises `ArgumentError` before the target is touched.
11
- - `Candor::Signature.source_location!` — the location gate, public beside `method_name!` and `parameters!`. `Signature.compile` calls it, so a consumer installing dispatch itself can no longer forge a location `eval` refuses, nor one it silently misreads. Its line must fit `eval`'s: a C `int`.
24
+ - `Candor.define(..., source_location:)`, the location every fabricated name reports, overriding the body's. A caller whose body is a proc it generated on the user's behalf can now point the wrapper at what the user actually wrote, rather than at the generator. It is also the only way to fabricate from a body carrying no location of its own (a curried proc, a symbol-to-proc, a C-defined method), which is the caller assuming responsibility for the honesty the gem otherwise derives. A `#call` object is not one of them and no `source_location:` rescues it: that refusal is about the kind. A `source_location:` that is not a `[String, Integer]` pair, or whose line is one `eval` will not take, raises `ArgumentError` before the target is touched.
25
+ - `Candor::Signature.source_location!`, the location gate, public beside `method_name!` and `parameters!`. `Signature.compile` calls it, so a consumer installing dispatch itself can no longer forge a location `eval` refuses, nor one it silently misreads. Its line must fit `eval`'s: a C `int`.
12
26
 
13
27
  ## [0.1.0] - 2026-07-10
14
28
 
15
29
  ### Added
16
- - `Candor.define(target, name, aliases:, via:, parameters:, body:)` — fabricates a real method whose arity, `parameters` kinds and `source_location` are the body's. Bodies may be a block, a `Proc`, a `Method` or an `UnboundMethod`; a `#call` object or any body with a `nil` `source_location` (a curried proc, a C-defined method) raises `TypeError`. With `via:` every call routes to that interceptor, which reaches the body through `Candor.body_name`; without it the wrapper forwards straight to the body. A wrong-arity call or an unknown keyword raises `ArgumentError` at the wrapper, before the interceptor or the body runs. An unpassed optional is dropped from the forwarded arguments, so the body applies its own default.
17
- - `Candor::Signature` — the low-level compiler, public on its own: a parameter shape, a call-site name and a `source_location` in, a dispatch lambda out. Renders off a parameter's kind, never its name, so `end:`, `it`, `_1`, `**nil` and destructuring parameters all wrap at full fidelity. Both call-site names are validated against a strict method-name pattern, and a malformed `parameters` shape raises `ArgumentError` rather than a `SyntaxError` from inside `eval` — including a shape whose entries are each legal but whose combination Ruby's parser rejects, which is compiled before the target is mutated so a rejected fabrication cannot destroy the method it was replacing.
30
+ - `Candor.define(target, name, aliases:, via:, parameters:, body:)` fabricates a real method whose arity, `parameters` kinds and `source_location` are the body's. Bodies may be a block, a `Proc`, a `Method` or an `UnboundMethod`; a `#call` object or any body with a `nil` `source_location` (a curried proc, a C-defined method) raises `TypeError`. With `via:` every call routes to that interceptor, which reaches the body through `Candor.body_name`; without it the wrapper forwards straight to the body. A wrong-arity call or an unknown keyword raises `ArgumentError` at the wrapper, before the interceptor or the body runs. An unpassed optional is dropped from the forwarded arguments, so the body applies its own default.
31
+ - `Candor::Signature`, the low-level compiler, public on its own: a parameter shape, a call-site name and a `source_location` in, a dispatch lambda out. Renders off a parameter's kind, never its name, so `end:`, `it`, `_1`, `**nil` and destructuring parameters all wrap at full fidelity. Both call-site names are validated against a strict method-name pattern, and a malformed `parameters` shape raises `ArgumentError` rather than a `SyntaxError` from inside `eval`. That includes a shape whose entries are each legal but whose combination Ruby's parser rejects, which is compiled before the target is mutated so a rejected fabrication cannot destroy the method it was replacing.
18
32
  - Dispatch allocates nothing for shapes up to `Candor::Signature::KEYWORD_BRANCH_LIMIT` (2) optional keywords; beyond it, exactly one Hash per call. Past the limit a body's keyrest *is* that Hash, so a `**kw` in the signature costs only the capture and re-splat Ruby charges any wrapper. Exact from Ruby 3.4: on earlier Rubies the VM charges a `define_method`-created method for arguments crossing into it, and both the wrapper and the body are ones. A call carrying no keyword allocates nothing on every supported Ruby.
19
33
  - Fabrication is thread-safe through one global `Monitor`; call-time dispatch takes no lock and never needs one. Re-fabricating a name overwrites the wrapper and the body in place, so it is warning-free under `ruby -w`, leaves no orphaned body, and a concurrent caller sees the old method or the new one, never a `NoMethodError`. A frozen target, an unbindable `Method`/`UnboundMethod` body, a name under the reserved `Candor::BODY_PREFIX`, an uncallable `via:` and a malformed `parameters:` all raise before the target is touched.
20
34
  - `sig/` ships RBS for the public API: `Candor.define`, `Candor.body_name`, `BODY_PREFIX`, and `Candor::Signature` with `KINDS` and `KEYWORD_BRANCH_LIMIT`. Everything else is `private_constant`, which RBS cannot express and therefore does not declare.
21
35
 
36
+ [Unreleased]: https://github.com/svyatov/candor/compare/v0.3.0...HEAD
37
+ [0.3.0]: https://github.com/svyatov/candor/compare/v0.2.1...v0.3.0
38
+ [0.2.1]: https://github.com/svyatov/candor/releases/tag/v0.2.1
22
39
  [0.2.0]: https://github.com/svyatov/candor/releases/tag/v0.2.0
23
40
  [0.1.0]: https://github.com/svyatov/candor/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,21 +1,33 @@
1
- # Candor
1
+ # Candor [![Gem Version](https://img.shields.io/gem/v/candor)](https://rubygems.org/gems/candor) [![Codecov](https://img.shields.io/codecov/c/github/svyatov/candor)](https://app.codecov.io/gh/svyatov/candor) [![CI](https://github.com/svyatov/candor/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/svyatov/candor/actions?query=workflow%3ACI)
2
2
 
3
- [![Gem Version](https://img.shields.io/gem/v/candor)](https://rubygems.org/gems/candor)
4
- [![CI](https://github.com/svyatov/candor/actions/workflows/main.yml/badge.svg)](https://github.com/svyatov/candor/actions/workflows/main.yml)
5
- [![codecov](https://codecov.io/gh/svyatov/candor/branch/main/graph/badge.svg)](https://codecov.io/gh/svyatov/candor)
3
+ Turn a block or a callable into a real Ruby method that reports the body's own arity, parameters and
4
+ source location.
6
5
 
7
- **Ruby's missing `functools.wraps`.** Turn a block or a callable into a real method that reports the
8
- *body's* arity, the *body's* `parameters` and the *body's* `source_location`, and rejects a bad call
9
- before anything of yours runs.
6
+ - **Zero runtime dependencies.** Ruby 3.3 or newer and nothing else. Tested on 3.3, 3.4, 4.0 and
7
+ `ruby-head`.
8
+ - **Every shape Ruby can express.** All eight parameter kinds wrap at full fidelity, including `end:`,
9
+ `it`, `_1`, `**nil` and destructuring. There is no degraded fallback.
10
+ - **Faster than the `|*args, **kwargs|` wrapper it replaces.** 52 ns and zero allocations per call
11
+ against 122 ns and two, on the no-argument shape. Full table below.
12
+ - **RBS signatures shipped.** `sig/` declares the public API, and the test suite pins it against the
13
+ code in both directions.
10
14
 
11
- Zero runtime dependencies. Ruby >= 3.2.
15
+ ## Install
16
+
17
+ ```sh
18
+ bundle add candor
19
+ ```
20
+
21
+ Or drop `gem "candor"` into your Gemfile, or run `gem install candor` without Bundler.
22
+
23
+ Then, anywhere in your code:
12
24
 
13
25
  ```ruby
14
26
  Candor.define(Greeter, :greet) { |name, greeting: "hi"| "#{greeting}, #{name}" }
15
27
 
16
28
  Greeter.instance_method(:greet).arity # => -2
17
29
  Greeter.instance_method(:greet).parameters # => [[:req, :__p0], [:key, :greeting]]
18
- Greeter.instance_method(:greet).source_location # => ["app/greeter.rb", 3] ← the block, not the gem
30
+ Greeter.instance_method(:greet).source_location # => ["app/greeter.rb", 3] the block, not the gem
19
31
 
20
32
  Greeter.new.greet # => ArgumentError: wrong number of arguments (given 0, expected 1)
21
33
  Greeter.new.greet("bob", grating: "yo") # => ArgumentError: unknown keyword: :grating
@@ -37,12 +49,6 @@ Candor generates the parameter list as source and `eval`s it, once, at definitio
37
49
  degraded fallback: every shape Ruby can express wraps at full fidelity, including `end:`, `it`, `_1`,
38
50
  `**nil`, and destructuring parameters.
39
51
 
40
- ## Install
41
-
42
- ```ruby
43
- gem "candor"
44
- ```
45
-
46
52
  ## Use
47
53
 
48
54
  ### Direct forward
@@ -103,14 +109,16 @@ klass.define_method(:greet, &dispatch)
103
109
  ```
104
110
 
105
111
  `compile` gates all three of its inputs. `method_name!`, `parameters!` and `source_location!` are public
106
- for a consumer that wants to fail earlier than the compile does.
112
+ for a consumer that wants to fail earlier than the compile does. `Candor::Signature::KINDS` is the frozen
113
+ list of the eight parameter kinds `Method#parameters` can emit, and the only ones `parameters!` and
114
+ `compile` accept.
107
115
 
108
116
  ## The contract
109
117
 
110
118
  **Body kinds.** A block, a `Proc`, a `Method` or an `UnboundMethod`, the three things `define_method`
111
- takes. A `#call` object is rejected, and no `source_location:` rescues it: the refusal is about the kind.
112
- So is any body whose `source_location` is `nil`: a curried proc, a `Symbol#to_proc`, a C-defined method.
113
- Ruby exposes no `curried?` predicate, and a nil `source_location` is the one reliable discriminator.
119
+ takes. A `#call` object raises `TypeError`, and no `source_location:` rescues it: the refusal is about the
120
+ kind. So does any body whose `source_location` is `nil`: a curried proc, a `Symbol#to_proc`, a C-defined
121
+ method. Ruby exposes no `curried?` predicate, and a nil `source_location` is the one reliable discriminator.
114
122
  Without it the honest-`source_location` guarantee cannot be kept. An explicit `source_location:` is the
115
123
  one way to fabricate from those three, and it is the caller taking responsibility for the honesty the gem
116
124
  otherwise derives. Inside a block body, `self` is the receiver.
@@ -138,24 +146,41 @@ to capture it and one to re-splat it into the body, on any wrapper you could wri
138
146
  none of its own, because past the branch limit the captured keyrest *is* the Hash the keywords accumulate
139
147
  into.
140
148
 
141
- Exactly as stated from **Ruby 3.4**. Below that, Ruby itself charges a `define_method`-created method for
142
- arguments crossing into it, and both the wrapper and the body are ones: on 3.3 the hashed path costs one
143
- Hash more, and on 3.2 a keyword-carrying call costs one Hash per hop. Nothing in the gem can reach that,
144
- and no call that carries no keyword ever allocates, on any supported Ruby.
149
+ Exactly as stated from **Ruby 3.4**. On Ruby 3.3, passing a splatted `**hash` into a
150
+ `define_method`-created method costs one extra Hash, so the hashed path allocates one more object.
151
+ Nothing in the gem can reach that, and no call that carries no keyword ever allocates, on any supported Ruby.
145
152
 
146
153
  **Thread safety.** Fabrication takes one global `Monitor`; concurrent `Candor.define` calls
147
154
  serialize. Call-time dispatch takes no lock at all, and never needs one: re-fabrication replaces a
148
155
  method in place rather than removing and reinstalling it, so a caller racing a `Candor.define` gets
149
156
  the old method or the new one, never a `NoMethodError`.
150
157
 
151
- **Failing fast.** A frozen target raises `FrozenError`, an `UnboundMethod` whose owner is not an
152
- ancestor of the target raises `TypeError`, and a malformed `parameters:`, a malformed `source_location:`
153
- or an uncallable `via:` raises `ArgumentError`, all *before* the target is touched. A `source_location:`
154
- is malformed unless it is a `[String, Integer]` pair whose line `eval` will take. A rejected fabrication
155
- leaves the target exactly as it was. A hand-written `parameters:` never passed Ruby's parser, so it is
156
- compiled before the first mutation: a shape whose *combination* is illegal (two rests, a duplicate
157
- keyword) is an `ArgumentError` too. Nothing ever surfaces as a `SyntaxError` from inside `eval`, which a
158
- `rescue` would not catch.
158
+ **Failing fast.** Every check runs *before* the target is touched, so a rejected fabrication leaves it
159
+ exactly as it was. A frozen target raises `FrozenError`. A non-Module target, a body that is none of the
160
+ three kinds or carries no location, and a `Method` or `UnboundMethod` whose owner is not an ancestor of
161
+ the target all raise `TypeError`. A name under the reserved prefix, a malformed `parameters:`, a malformed
162
+ `source_location:` or an uncallable `via:` raises `ArgumentError`. A `source_location:` is malformed
163
+ unless it is a `[String, Integer]` pair whose line `eval` will take. A hand-written `parameters:` never
164
+ passed Ruby's parser, so it is compiled before the first mutation: a shape whose *combination* is illegal
165
+ (two rests, a duplicate keyword) is an `ArgumentError` too. Nothing ever surfaces as a `SyntaxError` from
166
+ inside `eval`, which a `rescue` would not catch.
167
+
168
+ **The `eval`.** The one `eval` runs at definition time, never per call, and never on anything a caller
169
+ passes at runtime. Its source is rendered off the parameter *kinds*, not their names: every positional,
170
+ rest, keyrest and block name becomes a generated one, so the only user text that survives into the source
171
+ is a keyword name. That name is checked before it is rendered, and it cannot shadow the lambda's own
172
+ locals, which all carry a run-of-underscores prefix no keyword name starts with. The two call-site names,
173
+ the body's or `via:`, pass `method_name!` first, so a reserved word or anything `eval` would not call bare
174
+ raises `ArgumentError` before a character is compiled. You can read exactly what it will run: `Signature.render`
175
+ returns the source `compile` would `eval`, without evaluating it.
176
+
177
+ ```ruby
178
+ Candor::Signature.render([%i[req a]], name: :greet, via: :__call)
179
+ # => "__u = ::Object.new.freeze; ->(__p0) { __call(:greet, __p0) }"
180
+
181
+ Candor::Signature.render([[:req, :name], [:key, :greeting]], name: Candor.body_name(:greet))
182
+ # => "__u = ::Object.new.freeze; ->(__p0, greeting: __u) { __u.equal?(greeting) ? __candor_body_greet(__p0) : __candor_body_greet(__p0, greeting: greeting) }"
183
+ ```
159
184
 
160
185
  **A Ruby 3.4 wrinkle.** On 3.4 alone, a body written with the implicit `it` parameter receives its
161
186
  arguments packed into an Array when it is reached through `(name, ...)` forwarding, `send`, or a splat,
@@ -184,7 +209,7 @@ optional-argument rows carry a few percent of noise.
184
209
 
185
210
  - **hand-written wrapper** is the ceiling: a real `def` with the same signature forwarding to the same
186
211
  private body, with the defaults hard-coded. It is what you would write by hand if you knew the shape
187
- *and* the default expressions. Candor is within ~10–40% of it, and allocates the same nothing.
212
+ *and* the default expressions. Candor is within ~10-40% of it, and allocates the same nothing.
188
213
  - **bare method** is a single `def` doing the work inline. It is roughly twice as fast as any wrapper,
189
214
  because it is one method call rather than two. That is the price of wrapping at all, not of candor.
190
215
  - **variadic wrapper** is the `|*args, **kwargs, &block|` retreat: slower than candor on every shape
@@ -203,10 +228,21 @@ so the body defaults is the semantics that replaces it.
203
228
  Definition must happen on the main Ractor. Calling a fabricated method from a non-main Ractor raises, as
204
229
  it does for any `define_method`-installed `Proc`, unless both the dispatch and the body are shareable.
205
230
 
231
+ ## Status and support
232
+
233
+ Candor is maintained. It is pre-1.0, so the API can still change between minor versions, and only the
234
+ latest release gets fixes.
235
+
236
+ Ask a question or report a bug in [GitHub issues](https://github.com/svyatov/candor/issues). Report a
237
+ security problem privately through the
238
+ [advisory form](https://github.com/svyatov/candor/security/advisories/new) instead, as
239
+ [SECURITY.md](SECURITY.md) describes.
240
+
206
241
  ## Contributing
207
242
 
208
- Bug reports and pull requests are welcome on [GitHub](https://github.com/svyatov/candor). See
209
- [CONTRIBUTING.md](CONTRIBUTING.md).
243
+ Pull requests are welcome. [CONTRIBUTING.md](CONTRIBUTING.md) has the setup and test commands, and
244
+ states what an acceptable change has to satisfy. [CHANGELOG.md](CHANGELOG.md) records what changed in
245
+ each release, and the API docs are at [rubydoc.info/gems/candor](https://rubydoc.info/gems/candor).
210
246
 
211
247
  ## License
212
248
 
data/candor.gemspec CHANGED
@@ -8,14 +8,15 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Leonid Svyatov"]
9
9
  spec.email = ["leonid@svyatov.com"]
10
10
 
11
- spec.summary = "Turn a block or a callable into a real method with an honest signature."
12
- spec.description = "Ruby's missing functools.wraps. Candor fabricates real methods from blocks and " \
11
+ spec.summary = "Turn a block or a callable into a real Ruby method that reports the body's own " \
12
+ "arity, parameters and source location."
13
+ spec.description = "Candor fabricates real methods from blocks and " \
13
14
  "callables: same arity, same parameters, source_location pointing at your code, and " \
14
15
  "allocation-free dispatch. Zero runtime dependencies."
15
16
  spec.homepage = "https://github.com/svyatov/candor"
16
17
  spec.license = "MIT"
17
18
 
18
- spec.required_ruby_version = ">= 3.2.0"
19
+ spec.required_ruby_version = ">= 3.3.0"
19
20
 
20
21
  spec.require_paths = ["lib"]
21
22
  spec.files = Dir["lib/**/*.rb"] + Dir["sig/**/*"] +
@@ -75,9 +75,9 @@ module Candor
75
75
  LINE_RANGE = (-(2**31))...(2**31)
76
76
 
77
77
  # How the source is spelled, and what the two name gates happen to be spelled as. A consumer builds
78
- # against {compile}, {method_name!}, {parameters!} and {source_location!} — which raise — not against
79
- # the patterns and tables they are written in terms of. Only {KINDS} and {KEYWORD_BRANCH_LIMIT} name
80
- # something a caller has to know to use the compiler, so only those two stay public.
78
+ # against {compile}, {render}, {method_name!}, {parameters!} and {source_location!} — which raise — not
79
+ # against the patterns and tables they are written in terms of. Only {KINDS} and {KEYWORD_BRANCH_LIMIT}
80
+ # name something a caller has to know to use the compiler, so only those two stay public.
81
81
  private_constant :RESERVED_WORDS, :NAMED_KINDS, :OPTIONAL_KINDS, :SUFFIXES, :DECLARATIONS,
82
82
  :METHOD_NAME, :KEYWORD_NAME, :NUMBERED_PARAMETERS, :LINE_RANGE
83
83
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Candor
4
4
  # The gem version.
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: candor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leonid Svyatov
@@ -9,9 +9,9 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
- description: 'Ruby''s missing functools.wraps. Candor fabricates real methods from
13
- blocks and callables: same arity, same parameters, source_location pointing at your
14
- code, and allocation-free dispatch. Zero runtime dependencies.'
12
+ description: 'Candor fabricates real methods from blocks and callables: same arity,
13
+ same parameters, source_location pointing at your code, and allocation-free dispatch.
14
+ Zero runtime dependencies.'
15
15
  email:
16
16
  - leonid@svyatov.com
17
17
  executables: []
@@ -45,14 +45,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: 3.2.0
48
+ version: 3.3.0
49
49
  required_rubygems_version: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
54
  requirements: []
55
- rubygems_version: 4.0.12
55
+ rubygems_version: 4.0.20
56
56
  specification_version: 4
57
- summary: Turn a block or a callable into a real method with an honest signature.
57
+ summary: Turn a block or a callable into a real Ruby method that reports the body's
58
+ own arity, parameters and source location.
58
59
  test_files: []