invokable 0.4.1 → 0.6.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: 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)