invocations 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +57 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.org +128 -0
- data/invocations.gemspec +23 -0
- data/lib/invocations.rb +17 -0
- data/lib/invocations/invocation.rb +253 -0
- data/tests/invocations.rb +24 -0
- data/trust/certificates/colstrom.pem +25 -0
- metadata +78 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 212878a412f9d0078de6d2a13192a8d4867d72a3ec64c1a5680dd1e4bfd03acf
|
4
|
+
data.tar.gz: e9bf132d50b08da294099cb995ede79dadd9fc7304d2ab6fb8ab11839dfd49d4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da1fbe8a35ece0b67dbaebb87e300c970f4319f52532b922e3813ffb917f996f353632d43244e8278c4ff3894a8148bd855c80242a97f424945acc681117d99c
|
7
|
+
data.tar.gz: dae0dcfe98e1653f5e068ace7dd986ceb43eaaf61857f8e4139e7b7c878f47c0ad8e5e2faf0ff85faa01b8d1c561af204aeca3c701868928791d2735f28857a4
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/.gitignore
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
# Created by https://www.gitignore.io/api/ruby
|
3
|
+
|
4
|
+
### Ruby ###
|
5
|
+
*.gem
|
6
|
+
*.rbc
|
7
|
+
/.config
|
8
|
+
/coverage/
|
9
|
+
/InstalledFiles
|
10
|
+
/pkg/
|
11
|
+
/spec/reports/
|
12
|
+
/spec/examples.txt
|
13
|
+
/test/tmp/
|
14
|
+
/test/version_tmp/
|
15
|
+
/tmp/
|
16
|
+
|
17
|
+
# Used by dotenv library to load environment variables.
|
18
|
+
# .env
|
19
|
+
|
20
|
+
## Specific to RubyMotion:
|
21
|
+
.dat*
|
22
|
+
.repl_history
|
23
|
+
build/
|
24
|
+
*.bridgesupport
|
25
|
+
build-iPhoneOS/
|
26
|
+
build-iPhoneSimulator/
|
27
|
+
|
28
|
+
## Specific to RubyMotion (use of CocoaPods):
|
29
|
+
#
|
30
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
31
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
32
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
33
|
+
#
|
34
|
+
# vendor/Pods/
|
35
|
+
|
36
|
+
## Documentation cache and generated files:
|
37
|
+
/.yardoc/
|
38
|
+
/_yardoc/
|
39
|
+
/doc/
|
40
|
+
/rdoc/
|
41
|
+
|
42
|
+
## Environment normalization:
|
43
|
+
/.bundle/
|
44
|
+
/vendor/bundle
|
45
|
+
/lib/bundler/man/
|
46
|
+
|
47
|
+
# for a library or gem, you might want to ignore these files since the code is
|
48
|
+
# intended to run in multiple environments; otherwise, check them in:
|
49
|
+
# Gemfile.lock
|
50
|
+
# .ruby-version
|
51
|
+
# .ruby-gemset
|
52
|
+
|
53
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
54
|
+
.rvmrc
|
55
|
+
|
56
|
+
|
57
|
+
# End of https://www.gitignore.io/api/ruby
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
The MIT License (MIT)
|
3
|
+
Copyright © 2018 Chris Olstrom <chris@olstrom.com>
|
4
|
+
Copyright © 2018 SUSE LLC
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the “Software”), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
data/README.org
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
#+TITLE: Invocations
|
2
|
+
#+LATEX: \pagebreak
|
3
|
+
|
4
|
+
* Overview
|
5
|
+
|
6
|
+
~Invocations~ are better partial functions for Ruby, because sometimes
|
7
|
+
=Proc#curry= just isn't enough.
|
8
|
+
|
9
|
+
* What problem does this solve?
|
10
|
+
|
11
|
+
Partial function evaluation is a very useful tool, but understanding the state
|
12
|
+
carried by a curried =Proc= is often cumbersome and unintuitive.
|
13
|
+
|
14
|
+
* How does Invocations address this problem?
|
15
|
+
|
16
|
+
~Invocations~ provides a single class: the =Invocation=. It functions as a
|
17
|
+
drop-in alternative to a =Proc=, with a few notable improvements (none of
|
18
|
+
which break compatibility):
|
19
|
+
|
20
|
+
- An =Invocation= is implicitly self-currying. Which is to say that if you
|
21
|
+
call it without all the parameters it requires, it simply returns an
|
22
|
+
=Invocation= that requires the missing parameters.
|
23
|
+
- An =Invocation= allows non-keyword arguments to be given as keywords.
|
24
|
+
- An =Invocation= allows arguments to be given out of order, as keyword
|
25
|
+
arguments.
|
26
|
+
- An =Invocation= has several methods for inspection, including ones for
|
27
|
+
listing the missing arguments, identifying keyword inferences, explaining
|
28
|
+
how the underlying function will be called, and reporting internal state.
|
29
|
+
|
30
|
+
* Installation
|
31
|
+
|
32
|
+
#+BEGIN_SRC shell
|
33
|
+
gem install invocations
|
34
|
+
#+END_SRC
|
35
|
+
|
36
|
+
* How can I start using this majestic tool?
|
37
|
+
|
38
|
+
An =Invocation= is a drop-in alternative to =Proc=, or =lambda=. You can use
|
39
|
+
it as an explicit =&block=, etc. As a result, it's very easy to adapt existing
|
40
|
+
code to use it.
|
41
|
+
|
42
|
+
Let's lay out a simple function that will serve as our example, going forward.
|
43
|
+
|
44
|
+
This =power= function takes two arguments, =n= (a number) and =e= (an
|
45
|
+
exponent) and returns the result of raising =n= to =e=:
|
46
|
+
|
47
|
+
#+BEGIN_SRC ruby
|
48
|
+
lambda_power = lambda { |n, e| n ** e }
|
49
|
+
#+END_SRC
|
50
|
+
|
51
|
+
Now, this is somewhat contrived, because I've deliberately defined the
|
52
|
+
arguments in the least convenient order, for illustrative purposes.
|
53
|
+
|
54
|
+
The equivalent =Invocation= would be:
|
55
|
+
|
56
|
+
#+BEGIN_SRC ruby
|
57
|
+
invoke_power = Invocation.new { |n, e| n ** e }
|
58
|
+
#+END_SRC
|
59
|
+
|
60
|
+
~Invocations~ includes an optional =Refinement= for that brings the syntax
|
61
|
+
more in line with =proc= and =lambda=:
|
62
|
+
|
63
|
+
#+BEGIN_SRC ruby
|
64
|
+
using Invocations
|
65
|
+
invoke_power = invocation { |n, e| n ** e }
|
66
|
+
#+END_SRC
|
67
|
+
|
68
|
+
Calling either of these is the same:
|
69
|
+
|
70
|
+
#+BEGIN_SRC ruby
|
71
|
+
lambda_power.(5, 2) #=> 25
|
72
|
+
invoke_power.(5, 2) #=> 25
|
73
|
+
#+END_SRC
|
74
|
+
|
75
|
+
Let's say we wanted to define =lambda_square= and =lambda_cube= functions,
|
76
|
+
that do what their names imply:
|
77
|
+
|
78
|
+
#+BEGIN_SRC ruby
|
79
|
+
lambda_square = lambda { |n| lambda_power.(n, 2) }
|
80
|
+
lambda_cube = lambda { |n| lambda_power.(n, 3) }
|
81
|
+
#+END_SRC
|
82
|
+
|
83
|
+
The order of the arguments to =lambda_power= makes these definitions more
|
84
|
+
awkward. If instead, we had defined it like so:
|
85
|
+
|
86
|
+
#+BEGIN_SRC ruby
|
87
|
+
lambda_power = lambda { |e, n| n ** e }.curry
|
88
|
+
#+END_SRC
|
89
|
+
|
90
|
+
Then we could have done this:
|
91
|
+
|
92
|
+
#+BEGIN_SRC ruby
|
93
|
+
lambda_square = lambda_power.(2)
|
94
|
+
lambda_cube = lambda_power.(3)
|
95
|
+
#+END_SRC
|
96
|
+
|
97
|
+
That said, we don't define every function we use. Often we use the functions
|
98
|
+
provided by a library, and if those have inconvenient argument ordering, too
|
99
|
+
bad.
|
100
|
+
|
101
|
+
If we had been using an =Invocation=, we could have done this:
|
102
|
+
|
103
|
+
#+BEGIN_SRC ruby
|
104
|
+
invoke_square = invoke_power.(e: 2)
|
105
|
+
invoke_cube = invoke_power.(e: 3)
|
106
|
+
#+END_SRC
|
107
|
+
|
108
|
+
** Wait what? Those weren't keyword arguments.
|
109
|
+
|
110
|
+
True, but the block parameters have names. Since it is a =SyntaxError= for a
|
111
|
+
block to have two parameters with the same name, an =Invocation= can Do The
|
112
|
+
Right Thing.
|
113
|
+
|
114
|
+
* Explore It!
|
115
|
+
|
116
|
+
~Invocations~ really shines when used with a great REPL like [[https://github.com/pry/pry][pry]].
|
117
|
+
|
118
|
+
I've uploaded a short screencast [[https://asciinema.org/a/DW4ctct8Nkx1qdwjmOF9Eyw4O][here]] that demonstrates the sort of
|
119
|
+
information an =Invocation= provides (using the example scenario above).
|
120
|
+
|
121
|
+
* License
|
122
|
+
|
123
|
+
~Invocations~ is available under the [[https://tldrlegal.com/license/mit-license][MIT License]]. See ~LICENSE.txt~ for the
|
124
|
+
full text.
|
125
|
+
|
126
|
+
* Contributors
|
127
|
+
|
128
|
+
- [[https://colstrom.github.io/][Chris Olstrom]] | [[mailto:chris@olstrom.com][e-mail]] | [[https://twitter.com/ChrisOlstrom][Twitter]]
|
data/invocations.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
tag = `git describe --tags --abbrev=0`.chomp
|
3
|
+
|
4
|
+
gem.name = 'invocations'
|
5
|
+
gem.homepage = 'https://github.com/colstrom/invocations'
|
6
|
+
gem.summary = 'Drop-in alternative to procs and lambdas.'
|
7
|
+
|
8
|
+
gem.version = "#{tag}"
|
9
|
+
gem.licenses = ['MIT']
|
10
|
+
gem.authors = ['Chris Olstrom']
|
11
|
+
gem.email = 'chris@olstrom.com'
|
12
|
+
|
13
|
+
gem.cert_chain = ['trust/certificates/colstrom.pem']
|
14
|
+
gem.signing_key = File.expand_path ENV.fetch 'GEM_SIGNING_KEY'
|
15
|
+
|
16
|
+
gem.files = `git ls-files -z`.split("\x0")
|
17
|
+
gem.test_files = `git ls-files -z -- {test,spec,features}/*`.split("\x0")
|
18
|
+
gem.executables = `git ls-files -z -- bin/*`.split("\x0").map { |f| File.basename(f) }
|
19
|
+
|
20
|
+
gem.require_paths = ['lib']
|
21
|
+
|
22
|
+
gem.required_ruby_version = '~> 2.3.0' # Explicit Non-Support of Unsupported Ruby Versions
|
23
|
+
end
|
data/lib/invocations.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require_relative 'invocations/invocation'
|
5
|
+
|
6
|
+
# This module refines Kernel, adding "invocation" and "Invocation" as methods.
|
7
|
+
module Invocations
|
8
|
+
refine Kernel do
|
9
|
+
# Creates a new Invocation with the provided parameters
|
10
|
+
def invocation(*rest, **keyrest, &block)
|
11
|
+
::Invocation.new(*rest, **keyrest, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :Invocation, :invocation
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,253 @@
|
|
1
|
+
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
# Invocations are drop-in replacements for other functions (such as
|
5
|
+
# procs/blocks, lambdas, methods, etc).
|
6
|
+
#
|
7
|
+
# They differ in that they are self-currying, allow partial evaluation with
|
8
|
+
# arbitrary argument ordering, and allow non-keyword arguments to be given as
|
9
|
+
# keywords.
|
10
|
+
#
|
11
|
+
class Invocation
|
12
|
+
%i(call yield []).each { |name| singleton_class.alias_method name, :new }
|
13
|
+
|
14
|
+
# Creates a new Invocation.
|
15
|
+
#
|
16
|
+
# @param callable [#call] a proc-like object
|
17
|
+
#
|
18
|
+
# @raise [ArgumentError] if neither a callable object nor a block is provided.
|
19
|
+
#
|
20
|
+
# @return [Invocation] a new instance of Invocation
|
21
|
+
#
|
22
|
+
def initialize(callable = nil, *rest, **state, &block)
|
23
|
+
raise ::ArgumentError, "#{self.class}##{__callee__} requires a callable object or a block" unless (callable.respond_to?(:call) || block)
|
24
|
+
|
25
|
+
if callable.respond_to? :call
|
26
|
+
@function = callable
|
27
|
+
@block = block
|
28
|
+
else
|
29
|
+
@function = block
|
30
|
+
end
|
31
|
+
|
32
|
+
@state = state
|
33
|
+
@rest = rest
|
34
|
+
|
35
|
+
%i(required optional inferences unassigned arguments keywords).each { |method| send method }
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :function, :state
|
41
|
+
|
42
|
+
# Which parameters are required?
|
43
|
+
#
|
44
|
+
# @return [Array<Symbol>] the required parameters of the function
|
45
|
+
#
|
46
|
+
def required
|
47
|
+
@required ||= (
|
48
|
+
required_arguments = function_parameters(:req)
|
49
|
+
required_keywords = function_parameters(:keyreq)
|
50
|
+
needed = function_arity - (required_arguments.length + (required_keywords.length > 0 ? 1 : 0))
|
51
|
+
|
52
|
+
@required = function_parameters(:opt, :key).take(needed) + required_arguments + required_keywords
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Which parameters are optional?
|
57
|
+
#
|
58
|
+
# @return [Array<Symbol>] the optional parameters of the function
|
59
|
+
#
|
60
|
+
def optional
|
61
|
+
@optional ||= function_parameters(:opt, :key)
|
62
|
+
.drop(function_arity - function_parameters(:req).length)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Which parameters can be inferred from arguments?
|
66
|
+
#
|
67
|
+
# @return [Hash<Symbol, Object>] the inferred association of non-keyword
|
68
|
+
# arguments to parameter names.
|
69
|
+
#
|
70
|
+
def inferences
|
71
|
+
@inferences ||= if @rest.empty?
|
72
|
+
{}
|
73
|
+
else
|
74
|
+
(function_parameters(:req, :opt) - @state.keys)
|
75
|
+
.map
|
76
|
+
.with_index { |argument, index| [argument, @rest[index]] if index < @rest.length }
|
77
|
+
.compact
|
78
|
+
.to_h
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Which arguments are not assigned to known parameters?
|
83
|
+
#
|
84
|
+
# @return [Array] the arguments that are not assigned to parameters.
|
85
|
+
#
|
86
|
+
def unassigned
|
87
|
+
@unassigned ||= @rest.drop(inferences.length)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Which parameters have been provided?
|
91
|
+
#
|
92
|
+
# @return [Hash<Symbol, Object>] all known parameters provided for the function.
|
93
|
+
#
|
94
|
+
def known
|
95
|
+
@known ||= @state.merge(inferences)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Which parameters are missing?
|
99
|
+
#
|
100
|
+
# @return [Array<Symbol>] the names of any missing parameters.
|
101
|
+
def missing
|
102
|
+
@missing ||= required - known.keys
|
103
|
+
end
|
104
|
+
|
105
|
+
# What are the arguments?
|
106
|
+
#
|
107
|
+
# @return [Array] the provided arguments for the function.
|
108
|
+
def arguments
|
109
|
+
@arguments ||= function_parameters(:req, :opt, :rest)
|
110
|
+
.map { |argument| known[argument] }
|
111
|
+
end
|
112
|
+
|
113
|
+
# What are the keywords?
|
114
|
+
#
|
115
|
+
# @return [Hash<Symbol, Object>] the provided keywords for the functino.
|
116
|
+
#
|
117
|
+
def keywords
|
118
|
+
@keywords ||= function_parameters(:keyreq, :key, :keyrest)
|
119
|
+
.map { |keyword| [keyword, known[keyword]] if known.key?(keyword) }
|
120
|
+
.compact
|
121
|
+
.to_h
|
122
|
+
end
|
123
|
+
|
124
|
+
# How will the function be called?
|
125
|
+
#
|
126
|
+
# @return Array the list of arguments that will be used to call the function.
|
127
|
+
#
|
128
|
+
def invocation(*rest, **keyrest)
|
129
|
+
@invocation ||= [*[*arguments, *unassigned].compact, *rest, *[**keywords.merge(keyrest)].reject(&:empty?)]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Is the function ready to be called?
|
133
|
+
#
|
134
|
+
# @return [Boolean] if this Invocation has all required parameters specified.
|
135
|
+
#
|
136
|
+
def prepared?
|
137
|
+
missing.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
# Prepares an Invocation, without calling it.
|
141
|
+
#
|
142
|
+
# @return [Invocation] a new Invocation populated with the parameters given.
|
143
|
+
#
|
144
|
+
def prepare(*rest, **keyrest, &block)
|
145
|
+
self.class.new(@function, *[*unassigned, *rest], **known.merge(keyrest), &(block || @block))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Prepares an Invocation, and invokes it if able.
|
149
|
+
#
|
150
|
+
# If the provided parameters produce a properly prepared Invocation, it will
|
151
|
+
# be invoked. Otherwise, it will be returned.
|
152
|
+
#
|
153
|
+
# @note This is very similar to how #call works with a curried Proc.
|
154
|
+
#
|
155
|
+
def call(*rest, **keyrest, &block)
|
156
|
+
if block || [rest, keyrest].all?(&:empty?)
|
157
|
+
prepared? ? invoke : self
|
158
|
+
else
|
159
|
+
function = prepare(*rest, **keyrest, &block)
|
160
|
+
function.prepared? ? function.send(:invoke) : function
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
alias [] call
|
165
|
+
alias yield call
|
166
|
+
|
167
|
+
# How many additional parameters are needed?
|
168
|
+
#
|
169
|
+
# @return [Integer] the number of required parameters.
|
170
|
+
#
|
171
|
+
# @note when multiple keyword parameters are required, they count as one
|
172
|
+
# parameter. This is consistent with other Ruby functions (Proc, etc).
|
173
|
+
#
|
174
|
+
def arity
|
175
|
+
@arity ||= (
|
176
|
+
required_keywords = function_parameters(:keyreq)
|
177
|
+
missing_keywords = required_keywords - known.keys
|
178
|
+
(missing - required_keywords).length + (missing_keywords.length > 0 ? 1 : 0)
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Converts the Invocation into a Proc
|
183
|
+
#
|
184
|
+
# @return [Proc] a Proc that calls the Invocation with any parameters given.
|
185
|
+
#
|
186
|
+
def to_proc
|
187
|
+
proc { |*rest, **keyrest, &block| self.(*rest, **keyrest, &block) }
|
188
|
+
end
|
189
|
+
|
190
|
+
# Converts the Invocation into a curried Proc.
|
191
|
+
#
|
192
|
+
# @return [Proc] a Proc, curried with the arity of the Invocation.
|
193
|
+
#
|
194
|
+
def curry(n = arity)
|
195
|
+
to_proc.curry(n)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Is the Invocation a lambda?
|
199
|
+
#
|
200
|
+
# @return [false] false, always.
|
201
|
+
#
|
202
|
+
# @note An Invocation is not a lambda, as it does not handle arguments
|
203
|
+
# strictly. It is semantically much more proc-like.
|
204
|
+
#
|
205
|
+
def lambda?
|
206
|
+
false
|
207
|
+
end
|
208
|
+
|
209
|
+
# Which parameters have not been provided?
|
210
|
+
#
|
211
|
+
# @return [Array<Symbol, Symbol>] the remaining parameters of the function.
|
212
|
+
#
|
213
|
+
def parameters
|
214
|
+
@function.parameters.reject { |_, name| known.keys.include? name }
|
215
|
+
end
|
216
|
+
|
217
|
+
####################
|
218
|
+
# Internal Methods #
|
219
|
+
####################
|
220
|
+
|
221
|
+
private
|
222
|
+
|
223
|
+
# Invokes the function.
|
224
|
+
#
|
225
|
+
# @note This is used internally to call the function. A return cannot be
|
226
|
+
# specified, because it depends entirely on the function this Invocation was
|
227
|
+
# created with.
|
228
|
+
#
|
229
|
+
def invoke(*rest, **keyrest, &block)
|
230
|
+
@function.(*invocation(*rest, **keyrest), &(block || @block))
|
231
|
+
end
|
232
|
+
|
233
|
+
# How many parameters does the function require?
|
234
|
+
#
|
235
|
+
# @return [Integer] The arity of the initial function.
|
236
|
+
#
|
237
|
+
# @note this is for internal use, and is *not* strictly equivalent to
|
238
|
+
# function.arity. For example, it always returns a non-negative value.
|
239
|
+
#
|
240
|
+
def function_arity
|
241
|
+
@function.arity.positive? ? @function.arity : @function.arity.succ.abs
|
242
|
+
end
|
243
|
+
|
244
|
+
# What are the names of the parameters of certain types?
|
245
|
+
#
|
246
|
+
# @return [Array<Symbol>] the names of parameters matching the given types.
|
247
|
+
#
|
248
|
+
def function_parameters(*types)
|
249
|
+
@function.parameters
|
250
|
+
.select { |type, _| types.include? type }
|
251
|
+
.flat_map(&:last)
|
252
|
+
end
|
253
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require_relative '../lib/invocations'
|
5
|
+
|
6
|
+
class Invocation
|
7
|
+
def self.test
|
8
|
+
{
|
9
|
+
'&lambda' => (self.new(&lambda { |am1, am2, ao = nil, *ar, km1:, km2:, ko: nil, **kr| [am1, am2, ao, ar, km1, km2, ko, kr] })),
|
10
|
+
'lambda' => (self.new(lambda { |am1, am2, ao = nil, *ar, km1:, km2:, ko: nil, **kr| [am1, am2, ao, ar, km1, km2, ko, kr] })),
|
11
|
+
'&proc' => (self.new(&proc { |am1, am2, ao = nil, *ar, km1:, km2:, ko: nil, **kr| [am1, am2, ao, ar, km1, km2, ko, kr] })),
|
12
|
+
'proc' => (self.new(proc { |am1, am2, ao = nil, *ar, km1:, km2:, ko: nil, **kr| [am1, am2, ao, ar, km1, km2, ko, kr] })),
|
13
|
+
'&block' => (self.new { |am1, am2, ao = nil, *ar, km1:, km2:, ko: nil, **kr| [am1, am2, ao, ar, km1, km2, ko, kr] }),
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
abort unless 1 == Invocation
|
19
|
+
.test
|
20
|
+
.map { |style, function| [style, function.(1).(2).(3).(4, 5).(km1: 6).(km2: 7)] }
|
21
|
+
.to_h
|
22
|
+
.values
|
23
|
+
.uniq
|
24
|
+
.length
|
@@ -0,0 +1,25 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIENDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdjaHJp
|
3
|
+
cy9EQz1vbHN0cm9tL0RDPWNvbTAeFw0xODAzMTUxODMxMTdaFw0xOTAzMTUxODMx
|
4
|
+
MTdaMCIxIDAeBgNVBAMMF2NocmlzL0RDPW9sc3Ryb20vREM9Y29tMIIBojANBgkq
|
5
|
+
hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAp31YmQvpMuQSlgX22B++/rxl4p4LYyaq
|
6
|
+
cDDbi8DBro9cm2H60lbpCuAUALiED2CagZEK0vel5W8AnZhhns0OEYAlpQtBSJtN
|
7
|
+
8P/jlNYruuY26aVhfHfyA5j1n7tVecJz3i/awEPGC3zuTfvUq7Ahn5czOy+hIm4M
|
8
|
+
epee881dqnJlXjzTX/TKFYQa9tYj4bhsjfJOV+EDMcao/DE3vmNcBKH8XFVv/wQe
|
9
|
+
MGC7VY5zBwow00AkCicNmIr0Psy5hLvqphJ/E3Eiu4UpXhiBfM0z7xiBPoPMBqOx
|
10
|
+
r1RzgfKm/JbDO7leFmrEi8hLofyMmbuGvrSTE274vS4EnKaW6OtK7QM5R+jOJZbd
|
11
|
+
67KUgSw+LdHNwu8xCuuQOdKPeSfWdNz94KAdczjzHdXUl/SpfmTuN/D+BCZjTxSo
|
12
|
+
F1kACSU6uGTBFKZy35XK+yqeny/1l6xRs6j+cON+LSRMKYSt7jdLcKQVk5wH2xLo
|
13
|
+
83njwnumFxKhiWu0oaT5dlDCtyYM85j9AgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYD
|
14
|
+
VR0PBAQDAgSwMB0GA1UdDgQWBBQEd3/D0MMj9FHhMZk0QJDlrUtKaTAcBgNVHREE
|
15
|
+
FTATgRFjaHJpc0BvbHN0cm9tLmNvbTAcBgNVHRIEFTATgRFjaHJpc0BvbHN0cm9t
|
16
|
+
LmNvbTANBgkqhkiG9w0BAQsFAAOCAYEALritM5RkGNZ7cs8hlljSEyuwJrbJYOSX
|
17
|
+
6p1S0D83GlfGZ/5XABy1p4EGQjxiAYuDrnnIw6GLHpgxFEtUNvyNYVfAa6u6yz4Y
|
18
|
+
nEjbEF76zAAxoRfivDApGJ3G9wuZ14cHZswFJppf2N4RG14F8bfLtU1OMYDLw8eK
|
19
|
+
QJOpynqHtrSj+FfsyNb6d93K8rlNCEd4UHkdRH1m7VnG6M18HvkbQCRMJtOFg/3j
|
20
|
+
c66TgdClDMJJXXiktVinfsmpTwxe2IzjGvwo2CZ/S53WPU/jb4uQMUzY0tMw48rl
|
21
|
+
S07/1DQNogstTnLYueqkUS1PYEwtavKVnpAtnaOdf0rJ/Rk4hA36BRgAVyQrp0uu
|
22
|
+
mSbo3NCvepJNYsTOUM+Df421VuPq713JV0aJDqltyfPptTM7fmNMcukbRh0aRuMT
|
23
|
+
EIKh6yDoB+oCRuiTV0uw/lKE2PtbONhJb7uN1qhZqla/iBpmUjiEu8+skI+ygv9n
|
24
|
+
7Krw8FJrV3+VRCiZTPKHeshAfL9yeIZh
|
25
|
+
-----END CERTIFICATE-----
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: invocations
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Olstrom
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIENDCCApygAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdjaHJp
|
14
|
+
cy9EQz1vbHN0cm9tL0RDPWNvbTAeFw0xODAzMTUxODMxMTdaFw0xOTAzMTUxODMx
|
15
|
+
MTdaMCIxIDAeBgNVBAMMF2NocmlzL0RDPW9sc3Ryb20vREM9Y29tMIIBojANBgkq
|
16
|
+
hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAp31YmQvpMuQSlgX22B++/rxl4p4LYyaq
|
17
|
+
cDDbi8DBro9cm2H60lbpCuAUALiED2CagZEK0vel5W8AnZhhns0OEYAlpQtBSJtN
|
18
|
+
8P/jlNYruuY26aVhfHfyA5j1n7tVecJz3i/awEPGC3zuTfvUq7Ahn5czOy+hIm4M
|
19
|
+
epee881dqnJlXjzTX/TKFYQa9tYj4bhsjfJOV+EDMcao/DE3vmNcBKH8XFVv/wQe
|
20
|
+
MGC7VY5zBwow00AkCicNmIr0Psy5hLvqphJ/E3Eiu4UpXhiBfM0z7xiBPoPMBqOx
|
21
|
+
r1RzgfKm/JbDO7leFmrEi8hLofyMmbuGvrSTE274vS4EnKaW6OtK7QM5R+jOJZbd
|
22
|
+
67KUgSw+LdHNwu8xCuuQOdKPeSfWdNz94KAdczjzHdXUl/SpfmTuN/D+BCZjTxSo
|
23
|
+
F1kACSU6uGTBFKZy35XK+yqeny/1l6xRs6j+cON+LSRMKYSt7jdLcKQVk5wH2xLo
|
24
|
+
83njwnumFxKhiWu0oaT5dlDCtyYM85j9AgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYD
|
25
|
+
VR0PBAQDAgSwMB0GA1UdDgQWBBQEd3/D0MMj9FHhMZk0QJDlrUtKaTAcBgNVHREE
|
26
|
+
FTATgRFjaHJpc0BvbHN0cm9tLmNvbTAcBgNVHRIEFTATgRFjaHJpc0BvbHN0cm9t
|
27
|
+
LmNvbTANBgkqhkiG9w0BAQsFAAOCAYEALritM5RkGNZ7cs8hlljSEyuwJrbJYOSX
|
28
|
+
6p1S0D83GlfGZ/5XABy1p4EGQjxiAYuDrnnIw6GLHpgxFEtUNvyNYVfAa6u6yz4Y
|
29
|
+
nEjbEF76zAAxoRfivDApGJ3G9wuZ14cHZswFJppf2N4RG14F8bfLtU1OMYDLw8eK
|
30
|
+
QJOpynqHtrSj+FfsyNb6d93K8rlNCEd4UHkdRH1m7VnG6M18HvkbQCRMJtOFg/3j
|
31
|
+
c66TgdClDMJJXXiktVinfsmpTwxe2IzjGvwo2CZ/S53WPU/jb4uQMUzY0tMw48rl
|
32
|
+
S07/1DQNogstTnLYueqkUS1PYEwtavKVnpAtnaOdf0rJ/Rk4hA36BRgAVyQrp0uu
|
33
|
+
mSbo3NCvepJNYsTOUM+Df421VuPq713JV0aJDqltyfPptTM7fmNMcukbRh0aRuMT
|
34
|
+
EIKh6yDoB+oCRuiTV0uw/lKE2PtbONhJb7uN1qhZqla/iBpmUjiEu8+skI+ygv9n
|
35
|
+
7Krw8FJrV3+VRCiZTPKHeshAfL9yeIZh
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
date: 2018-05-10 00:00:00.000000000 Z
|
38
|
+
dependencies: []
|
39
|
+
description:
|
40
|
+
email: chris@olstrom.com
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- ".gitignore"
|
46
|
+
- Gemfile
|
47
|
+
- LICENSE.txt
|
48
|
+
- README.org
|
49
|
+
- invocations.gemspec
|
50
|
+
- lib/invocations.rb
|
51
|
+
- lib/invocations/invocation.rb
|
52
|
+
- tests/invocations.rb
|
53
|
+
- trust/certificates/colstrom.pem
|
54
|
+
homepage: https://github.com/colstrom/invocations
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.3.0
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.7.6
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Drop-in alternative to procs and lambdas.
|
78
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|