invokable 0.4.1 → 0.6.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: cefa41d32399484ad2204268eaecfbe2b60618c9eed79b327786dd10aae9e0a7
4
- data.tar.gz: 8ad5d706b553d62d244ee3e45c262c8f2c61a5b765fd2f55fa5be3243f00dda4
3
+ metadata.gz: b1c89f44b80135945cce3300f6f9b8e5b1210282d8c3d10256c2593ccf281948
4
+ data.tar.gz: 2a0e9ce82c10b9f57b1767087d56b5d53a67bdfeb139e5a642fb071a9bc6a8e6
5
5
  SHA512:
6
- metadata.gz: 416e5627985548c82477f61010368489ef9af9f134e15f4623a743bd36e50e0fbeb97cee5b82de99fc4db68f8d0f0e6a9890478c000ae4958d4d6119a0c55dd9
7
- data.tar.gz: 23a9d25e0ca3b92cad9177e07ea2e0e84266f97fd3a007c23a343e66e4e22002d97cf8d7aaa0a6b718e7d0c6da053516602f3e7ad8dca8f37323bc6c932a57da
6
+ metadata.gz: 20d8a431d84d973709f122211c8e606d4ac43e162c54a7bdf8e7507873c0235dede63a8e73a69d296152b6020ebd93a3001be8c73916dee7a7cfbcc6c600b0df
7
+ data.tar.gz: c1df682d8c7eed2525d7a2eaadce3e5dedb8114b18d64df3f7e323995b7c30c31827d2c6f2da94738094c06614a74bf4309dc20a1d3a2e9b66152c6e265b7035
@@ -0,0 +1,19 @@
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`
12
+
13
+ ## 0.5.2
14
+
15
+ - `Invokable::Command` deprecated in favor of `Invokable::Closure`.
16
+
17
+ ## 0.6.0
18
+
19
+ - `Invokable::Closure` deprecated comparable behavior has been added to `Invokable` itself.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- invokable (0.4.1)
4
+ invokable (0.6.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -8,40 +8,68 @@ Objects are functions! Treat any Object, Hashes, Arrays, and Sets as Procs (like
8
8
  ## Synopsis
9
9
 
10
10
  ```ruby
11
- require 'invokable/hash'
11
+ require 'invokable'
12
+ require 'invokable/hash'
12
13
 
13
- number_names = { 1 => "One", 2 => "Two", 3 => "Three" }
14
- [1, 2, 3, 4].map(&number_names) # => ["One", "Two", "Three", nil]
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
- require 'invokable/array'
19
+ require 'invokable'
20
+ require 'invokable/array'
19
21
 
20
- alpha = ('a'..'z').to_a
21
- [1, 2, 3, 4].map(&alpha) # => ["b", "c", "d", "e"]
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
- require 'invokable/set'
27
+ require 'invokable'
28
+ require 'invokable/set'
26
29
 
27
- favorite_numbers = Set[3, Math::PI]
28
- [1, 2, 3, 4].select(&favorite_numbers) # => [3]
30
+ favorite_numbers = Set[3, Math::PI]
31
+ [1, 2, 3, 4].select(&favorite_numbers) # => [3]
29
32
  ```
30
33
 
31
34
  ```ruby
32
- require 'invokable'
35
+ # service objects
36
+ require 'invokable'
33
37
 
34
- # service objects
35
- class GetDataFromSomeService
36
- include Invokable
38
+ class GetDataFromSomeService
39
+ include Invokable
37
40
 
38
- def call(user)
39
- # do the dirt
40
- end
41
+ def call(user)
42
+ # do the dirt
41
43
  end
44
+ end
42
45
 
43
- data_for_user = GetDataFromSomeService.new.memoize # 'memoize' makes a proc that caches results
44
- User.all.map(&data_for_user)
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
+
53
+ class TwitterPoster
54
+ include Invokable
55
+
56
+ def initialize(model)
57
+ @model = model
58
+ end
59
+
60
+ def call(user)
61
+ # do the dirt
62
+ ...
63
+ TwitterStatus.new(user, data)
64
+ end
65
+ end
66
+
67
+ TwitterPoster.call(Model.find(1)) # => #<TwitterPoster ...>
68
+ TwitterPoster.call(Model.find(1), current_user) # => #<TwitterStatus ...>
69
+
70
+ # both the class and it's instances can be used anywhere Procs are.
71
+
72
+ Model.where(created_at: Date.today).map(&TwitterPoster) # => [#<TwitterPoster ...>, ...]
45
73
  ```
46
74
 
47
75
  Use as much or a little as you need:
@@ -51,7 +79,7 @@ require 'invokable' # loads Invokable 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, array, and set patches
82
+ require 'invokable/data' # loads hash and set patches
55
83
  ```
56
84
 
57
85
  ## Why?
@@ -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
 
@@ -2,6 +2,7 @@ require 'invokable/version'
2
2
  require 'invokable/core'
3
3
  require 'invokable/compose'
4
4
 
5
+ # TODO: make use of Gem::Version
5
6
  if RUBY_VERSION.split('.').take(2).join('.').to_f < 2.6
6
7
  require 'invokable/proc'
7
8
  require 'invokable/method'
@@ -11,5 +12,46 @@ module Invokable
11
12
  def self.included(base)
12
13
  base.include(Invokable::Core)
13
14
  base.include(Invokable::Compose)
15
+ base.extend(Invokable::Core)
16
+ base.extend(Invokable::Compose)
17
+ base.extend(ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+ # Return the "total" arity of the class (i.e. the arity of the initializer and the arity of the call method)
22
+ #
23
+ # @version 0.6.0
24
+ # @see https://ruby-doc.org/core-2.7.1/Proc.html#method-i-arity Proc#arity
25
+ # @see initializer_arity
26
+ #
27
+ # @return [Integer]
28
+ def arity
29
+ initializer_arity + instance_method(:call).arity
30
+ end
31
+
32
+ # Handle automatic currying--will accept either the initializer arity or the total arity of the class. If
33
+ # the initializer arity is used return a class instance. If the total arity is used instantiate the class
34
+ # and return the results of the `call` method.
35
+ #
36
+ # @version 0.6.0
37
+ # @see arity
38
+ # @see initializer_arity
39
+ def call(*args)
40
+ if args.length == initializer_arity
41
+ new(*args)
42
+ elsif args.length == arity
43
+ init_args = args.slice(0, initializer_arity)
44
+ call_args = args.slice(initializer_arity, args.length)
45
+ new(*init_args).call(*call_args)
46
+ else
47
+ raise ArgumentError, "wrong number of arguments (given #{args.length}, expected #{initializer_arity} or #{arity})"
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def initializer_arity
54
+ instance_method(:initialize).arity
55
+ end
14
56
  end
15
57
  end
@@ -0,0 +1,115 @@
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
+ # @deprecated These features are included in the Invokable by default now.
8
+ module Closure
9
+ def self.included(klass)
10
+ klass.include(Invokable)
11
+ klass.extend(Invokable::Core)
12
+ klass.extend(Invokable::Compose)
13
+ klass.extend(ClassMethods)
14
+ end
15
+
16
+ module ClassMethods
17
+ # Return the "total" arity of the class (i.e. the arity of the initializer and the arity of the call method)
18
+ #
19
+ # @version 0.5.0
20
+ # @see https://ruby-doc.org/core-2.7.1/Proc.html#method-i-arity Proc#arity
21
+ # @see initializer_arity
22
+ #
23
+ # @return [Integer]
24
+ def arity
25
+ initializer_arity + instance_method(:call).arity
26
+ end
27
+
28
+ # Return the arity of the initializer
29
+ #
30
+ # @version 0.5.0
31
+ # @see arity
32
+ #
33
+ # @return [Integer]
34
+ def initializer_arity
35
+ instance_method(:initialize).arity
36
+ end
37
+
38
+ # Handle automatic currying--will accept either the initializer arity or the total arity of the class. If
39
+ # the initializer arity is used return a class instance. If the total arity is used instantiate the class
40
+ # and return the results of the `call` method.
41
+ #
42
+ # @version 0.5.0
43
+ # @see arity
44
+ # @see initializer_arity
45
+ def call(*args)
46
+ if args.length == initializer_arity
47
+ new(*args)
48
+ elsif args.length == arity
49
+ init_args = args.slice(0, initializer_arity)
50
+ call_args = args.slice(initializer_arity, args.length)
51
+ new(*init_args).call(*call_args)
52
+ else
53
+ raise ArgumentError, "wrong number of arguments (given #{args.length}, expected #{initializer_arity} or #{arity})"
54
+ end
55
+ end
56
+
57
+ # Specify any enclosed state with a block or named attributes
58
+ #
59
+ # @example
60
+ # class TwitterPater
61
+ # include Invokable::Command
62
+ #
63
+ # enclose :api_key
64
+ #
65
+ # def call(user)
66
+ # # interact with twitter, return results
67
+ # end
68
+ # end
69
+ #
70
+ # TwitterPater.new(API_KEY).call(User.find(1))
71
+ # TwitterPater.new(API_KEY).api_key == API_KEY # => true
72
+ #
73
+ # class TwitterPater
74
+ # include Invokable::Command
75
+ #
76
+ # enclose do |api_key|
77
+ # @api_key = api_key
78
+ # end
79
+ #
80
+ # def call(user)
81
+ # # interact with twitter, return results
82
+ # end
83
+ # end
84
+ #
85
+ # TwitterPater.new(API_KEY).call(User.find(1))
86
+ # TwitterPater.new(API_KEY).api_key # error 'method' missing
87
+ def enclose(*names, &block)
88
+ return define_initializer_with_block(block) unless block.nil?
89
+
90
+ define_initializer_with_names(names)
91
+ end
92
+
93
+ private
94
+
95
+ def define_initializer_with_block(block)
96
+ @initializer = block
97
+ define_method :initialize, &block
98
+ end
99
+
100
+ def define_initializer_with_names(names)
101
+ @initializer_arity = names.length
102
+
103
+ names.each do |name|
104
+ attr_reader name
105
+ end
106
+
107
+ define_method :initialize do |*args|
108
+ names.each_with_index do |name, i|
109
+ instance_variable_set(:"@#{name}", args[i])
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,18 @@
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
+ # @deprecated These features are included in the Invokable by default now.
10
+ module Command
11
+ def self.included(klass)
12
+ klass.include(Invokable)
13
+ klass.extend(Invokable::Core)
14
+ klass.extend(Invokable::Compose)
15
+ klass.extend(Invokable::Closure::ClassMethods)
16
+ end
17
+ end
18
+ end
@@ -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
@@ -1,4 +1,2 @@
1
- require_relative 'core'
2
1
  require_relative 'hash'
3
2
  require_relative 'set'
4
- require_relative 'array'
@@ -1,3 +1,3 @@
1
1
  module Invokable
2
- VERSION = "0.4.1"
2
+ VERSION = "0.6.0"
3
3
  end
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.1
4
+ version: 0.6.0
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-03-02 00:00:00.000000000 Z
11
+ date: 2020-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -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)