invokable 0.4.0 → 0.5.2
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 +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +3 -3
- data/README.md +49 -20
- data/invokable.gemspec +1 -1
- data/lib/invokable.rb +1 -0
- data/lib/invokable/closure.rb +116 -0
- data/lib/invokable/command.rb +17 -0
- data/lib/invokable/core.rb +9 -0
- data/lib/invokable/data.rb +0 -2
- data/lib/invokable/version.rb +1 -1
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b107ca53f8d89104fa38152d27141d24ae62dbec10e8e313b1428b5e711f61e9
|
4
|
+
data.tar.gz: b17e3b4207c4262637a08975772063f8d99583c6ef472220e18598885c272860
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c036b555078552a8902b83ccb7800ce878c23844a3ac6c7586d510622a56ba9ef0e4da985773662d5a605566308bb1c835b28eb988b417cc5a42a1c92aa95464
|
7
|
+
data.tar.gz: 900fab835907e7a8af2f8284629361ed0fbe1db81e6d05d8a2a98152fc223e4a44de352eb1eba538a9e53d406e95d97bcf4ad82f133a96e91c282626999175a7
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## 0.4.2
|
4
|
+
|
5
|
+
- `invokable/array` is no longer loaded with `invokable/data`.
|
6
|
+
This created a bit of havok in a few places. Including breaking
|
7
|
+
puma bootup in Rails 5.2.4.1.
|
8
|
+
|
9
|
+
## 0.5.0
|
10
|
+
|
11
|
+
- Added `Invokable::Command` and `Invokable::Core#arity`
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
invokable (0.
|
4
|
+
invokable (0.5.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -20,7 +20,7 @@ GEM
|
|
20
20
|
pry (0.12.2)
|
21
21
|
coderay (~> 1.1.0)
|
22
22
|
method_source (~> 0.9.0)
|
23
|
-
rake (
|
23
|
+
rake (13.0.1)
|
24
24
|
regexp-examples (1.5.1)
|
25
25
|
rspec (3.9.0)
|
26
26
|
rspec-core (~> 3.9.0)
|
@@ -45,7 +45,7 @@ DEPENDENCIES
|
|
45
45
|
gen-test
|
46
46
|
invokable!
|
47
47
|
pry
|
48
|
-
rake (~>
|
48
|
+
rake (~> 13.0)
|
49
49
|
rspec (~> 3.0)
|
50
50
|
yard
|
51
51
|
|
data/README.md
CHANGED
@@ -8,50 +8,78 @@ Objects are functions! Treat any Object, Hashes, Arrays, and Sets as Procs (like
|
|
8
8
|
## Synopsis
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
|
11
|
+
require 'invokable'
|
12
|
+
require 'invokable/hash'
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
number_names = { 1 => "One", 2 => "Two", 3 => "Three" }
|
15
|
+
[1, 2, 3, 4].map(&number_names) # => ["One", "Two", "Three", nil]
|
15
16
|
```
|
16
17
|
|
17
18
|
```ruby
|
18
|
-
|
19
|
+
require 'invokable'
|
20
|
+
require 'invokable/array'
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
alpha = ('a'..'z').to_a
|
23
|
+
[1, 2, 3, 4].map(&alpha) # => ["b", "c", "d", "e"]
|
22
24
|
```
|
23
25
|
|
24
26
|
```ruby
|
25
|
-
|
27
|
+
require 'invokable'
|
28
|
+
require 'invokable/set'
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
favorite_numbers = Set[3, Math::PI]
|
31
|
+
[1, 2, 3, 4].select(&favorite_numbers) # => [3]
|
29
32
|
```
|
30
33
|
|
31
34
|
```ruby
|
32
|
-
|
35
|
+
# service objects
|
36
|
+
require 'invokable'
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
include Invokable
|
38
|
+
class GetDataFromSomeService
|
39
|
+
include Invokable
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
+
def call(user)
|
42
|
+
# do the dirt
|
41
43
|
end
|
44
|
+
end
|
42
45
|
|
43
|
-
|
44
|
-
|
46
|
+
data_for_user = GetDataFromSomeService.new.memoize # 'memoize' makes a proc that caches results
|
47
|
+
User.all.map(&data_for_user)
|
48
|
+
```
|
49
|
+
```ruby
|
50
|
+
# command objects that enclose state, can be treated as automatically curried functions.
|
51
|
+
require 'invokable'
|
52
|
+
require 'invokable/closure'
|
53
|
+
|
54
|
+
class TwitterPoster
|
55
|
+
include Invokable::Closure
|
56
|
+
|
57
|
+
enclose :model
|
58
|
+
|
59
|
+
def call(user)
|
60
|
+
# do the dirt
|
61
|
+
...
|
62
|
+
TwitterStatus.new(user, data)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
TwitterPoster.call(Model.find(1)) # => #<TwitterPoster ...>
|
67
|
+
TwitterPoster.call(Model.find(1), current_user) # => #<TwitterStatus ...>
|
68
|
+
|
69
|
+
# both the class and it's instances can be used any where Procs are.
|
70
|
+
|
71
|
+
Model.where(created_at: Date.today).map(&:TwitterPoster) # => [#<TwitterPoster ...>, ...]
|
45
72
|
```
|
46
73
|
|
47
74
|
Use as much or a little as you need:
|
48
75
|
|
49
76
|
```ruby
|
50
77
|
require 'invokable' # loads Invokable module
|
78
|
+
require 'invokable/closure' # loads Invokable::Closure module
|
51
79
|
require 'invokable/hash' # loads hash patch
|
52
80
|
require 'invokable/array' # loads array patch
|
53
81
|
require 'invokable/set' # loads set patch
|
54
|
-
require 'invokable/data' # loads hash
|
82
|
+
require 'invokable/data' # loads hash and set patches
|
55
83
|
```
|
56
84
|
|
57
85
|
## Why?
|
@@ -99,7 +127,7 @@ Returns a curried proc. If the `arity` is given, it determines the number of arg
|
|
99
127
|
|
100
128
|
### `memoize => Proc`
|
101
129
|
|
102
|
-
Returns a memoized proc, that is, a proc that caches it return values by it's arguments.
|
130
|
+
Returns a memoized proc, that is, a proc that caches it's return values by it's arguments.
|
103
131
|
|
104
132
|
### `<<(invokable) => Proc`
|
105
133
|
|
@@ -111,6 +139,7 @@ Returns a proc that is a composition of this invokable and the given invokable.
|
|
111
139
|
|
112
140
|
## See Also
|
113
141
|
|
142
|
+
- [Closures and Objects are Equivalent](http://wiki.c2.com/?ClosuresAndObjectsAreEquivalent)
|
114
143
|
- [Clojure](https://clojure.org)
|
115
144
|
- [Arc](http://www.arclanguage.org)
|
116
145
|
|
data/invokable.gemspec
CHANGED
@@ -37,6 +37,6 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.require_paths = ["lib"]
|
38
38
|
|
39
39
|
spec.add_development_dependency "bundler", "~> 1.17"
|
40
|
-
spec.add_development_dependency "rake", "~>
|
40
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
41
41
|
spec.add_development_dependency "rspec", "~> 3.0"
|
42
42
|
end
|
data/lib/invokable.rb
CHANGED
@@ -0,0 +1,116 @@
|
|
1
|
+
module Invokable
|
2
|
+
# Treat classes as curried functions
|
3
|
+
#
|
4
|
+
# @see https://ruby-doc.org/core-2.7.0/Proc.html#method-i-curry Proc#curry
|
5
|
+
#
|
6
|
+
# @version 0.5.2
|
7
|
+
module Closure
|
8
|
+
def self.included(klass)
|
9
|
+
klass.include(Invokable)
|
10
|
+
klass.extend(Invokable::Core)
|
11
|
+
klass.extend(Invokable::Compose)
|
12
|
+
klass.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# Return the "total" arity of the class (i.e. the arity of the initializer and the arity of the call method)
|
17
|
+
#
|
18
|
+
# @version 0.5.0
|
19
|
+
# @see https://ruby-doc.org/core-2.7.1/Proc.html#method-i-arity Proc#arity
|
20
|
+
# @see initializer_arity
|
21
|
+
#
|
22
|
+
# @return [Integer]
|
23
|
+
def arity
|
24
|
+
initializer_arity + instance_method(:call).arity
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the arity of the initializer
|
28
|
+
#
|
29
|
+
# @version 0.5.0
|
30
|
+
# @see arity
|
31
|
+
#
|
32
|
+
# @return [Integer]
|
33
|
+
def initializer_arity
|
34
|
+
return @initializer_arity if @initializer_arity
|
35
|
+
|
36
|
+
@initializer ? @initializer.arity : 0
|
37
|
+
end
|
38
|
+
|
39
|
+
# Handle automatic currying--will accept either the initializer arity or the total arity of the class. If
|
40
|
+
# the initializer arity is used return a class instance. If the total arity is used instantiate the class
|
41
|
+
# and return the results of the `call` method.
|
42
|
+
#
|
43
|
+
# @version 0.5.0
|
44
|
+
# @see arity
|
45
|
+
# @see initializer_arity
|
46
|
+
def call(*args)
|
47
|
+
if args.length == initializer_arity
|
48
|
+
new(*args)
|
49
|
+
elsif args.length == arity
|
50
|
+
init_args = args.slice(0, initializer_arity)
|
51
|
+
call_args = args.slice(initializer_arity, args.length)
|
52
|
+
new(*init_args).call(*call_args)
|
53
|
+
else
|
54
|
+
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected #{initializer_arity} or #{arity})"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Specify any enclosed state with a block or named attributes
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# class TwitterPater
|
62
|
+
# include Invokable::Command
|
63
|
+
#
|
64
|
+
# enclose :api_key
|
65
|
+
#
|
66
|
+
# def call(user)
|
67
|
+
# # interact with twitter, return results
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# TwitterPater.new(API_KEY).call(User.find(1))
|
72
|
+
# TwitterPater.new(API_KEY).api_key == API_KEY # => true
|
73
|
+
#
|
74
|
+
# class TwitterPater
|
75
|
+
# include Invokable::Command
|
76
|
+
#
|
77
|
+
# enclose do |api_key|
|
78
|
+
# @api_key = api_key
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# def call(user)
|
82
|
+
# # interact with twitter, return results
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# TwitterPater.new(API_KEY).call(User.find(1))
|
87
|
+
# TwitterPater.new(API_KEY).api_key # error 'method' missing
|
88
|
+
def enclose(*names, &block)
|
89
|
+
return define_initializer_with_block(block) unless block.nil?
|
90
|
+
|
91
|
+
define_initializer_with_names(names)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def define_initializer_with_block(block)
|
97
|
+
@initializer = block
|
98
|
+
define_method :initialize, &block
|
99
|
+
end
|
100
|
+
|
101
|
+
def define_initializer_with_names(names)
|
102
|
+
@initializer_arity = names.length
|
103
|
+
|
104
|
+
names.each do |name|
|
105
|
+
attr_reader name
|
106
|
+
end
|
107
|
+
|
108
|
+
define_method :initialize do |*args|
|
109
|
+
names.each_with_index do |name, i|
|
110
|
+
instance_variable_set(:"@#{name}", args[i])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'closure'
|
2
|
+
|
3
|
+
module Invokable
|
4
|
+
# Treat "Command Objects" as curried functions
|
5
|
+
#
|
6
|
+
# @see https://ruby-doc.org/core-2.7.0/Proc.html#method-i-curry Proc#curry
|
7
|
+
#
|
8
|
+
# @version 0.5.0
|
9
|
+
module Command
|
10
|
+
def self.included(klass)
|
11
|
+
klass.include(Invokable)
|
12
|
+
klass.extend(Invokable::Core)
|
13
|
+
klass.extend(Invokable::Compose)
|
14
|
+
klass.extend(Invokable::Closure::ClassMethods)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/invokable/core.rb
CHANGED
@@ -36,5 +36,14 @@ module Invokable
|
|
36
36
|
@memo[args.hash] ||= call(*args)
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
# Return the arity (i.e. the number of arguments) of the `call` method.
|
41
|
+
#
|
42
|
+
# @version 0.5.0
|
43
|
+
# @see https://ruby-doc.org/core-2.7.1/Proc.html#method-i-arity Proc#arity
|
44
|
+
# @return [Integer]
|
45
|
+
def arity
|
46
|
+
method(:call).arity
|
47
|
+
end
|
39
48
|
end
|
40
49
|
end
|
data/lib/invokable/data.rb
CHANGED
data/lib/invokable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: invokable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delon Newman
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- ".github/workflows/ruby.yml"
|
64
64
|
- ".gitignore"
|
65
65
|
- ".rspec"
|
66
|
+
- CHANGELOG.md
|
66
67
|
- Gemfile
|
67
68
|
- Gemfile.lock
|
68
69
|
- LICENSE.txt
|
@@ -71,6 +72,8 @@ files:
|
|
71
72
|
- invokable.gemspec
|
72
73
|
- lib/invokable.rb
|
73
74
|
- lib/invokable/array.rb
|
75
|
+
- lib/invokable/closure.rb
|
76
|
+
- lib/invokable/command.rb
|
74
77
|
- lib/invokable/compose.rb
|
75
78
|
- lib/invokable/core.rb
|
76
79
|
- lib/invokable/data.rb
|
@@ -88,7 +91,7 @@ metadata:
|
|
88
91
|
source_code_uri: https://github.com/delonnewman/invokable
|
89
92
|
changelog_uri: https://github.com/delonnewman/invokable#changelog
|
90
93
|
documentation_uri: https://www.rubydoc.info/gems/invokable
|
91
|
-
post_install_message:
|
94
|
+
post_install_message:
|
92
95
|
rdoc_options: []
|
93
96
|
require_paths:
|
94
97
|
- lib
|
@@ -104,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
107
|
version: '0'
|
105
108
|
requirements: []
|
106
109
|
rubygems_version: 3.0.6
|
107
|
-
signing_key:
|
110
|
+
signing_key:
|
108
111
|
specification_version: 4
|
109
112
|
summary: Objects are functions! Treat any Object, Hashes, Arrays and Sets as Procs
|
110
113
|
(like Enumerable but for Proc-like objects)
|