invokable 0.4.0 → 0.5.2

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: b8be1208734fdbbf1e11e1974834bfb6a65e294c7814a7df1f65775b4a898ae9
4
- data.tar.gz: 2693e344b7eb7c1e9e12615c1c6831b6c842219adf39e70aa924bbd65c7edaee
3
+ metadata.gz: b107ca53f8d89104fa38152d27141d24ae62dbec10e8e313b1428b5e711f61e9
4
+ data.tar.gz: b17e3b4207c4262637a08975772063f8d99583c6ef472220e18598885c272860
5
5
  SHA512:
6
- metadata.gz: 2bc791de5268235f8f7f2715e14f7d14bd6d6155f38aafa85f5a976e037a81b0df57e03def253fb9d55d3881e9845db243a6fffc723cc306d2536b0daa15c931
7
- data.tar.gz: e36ab920d191d24022954f4cd4d055db571390a7e7e0252a8ad38b456283b344678d534bebf58cbe96b0653af2c10e745ca96de0969a10d8371da4b54c361d48
6
+ metadata.gz: c036b555078552a8902b83ccb7800ce878c23844a3ac6c7586d510622a56ba9ef0e4da985773662d5a605566308bb1c835b28eb988b417cc5a42a1c92aa95464
7
+ data.tar.gz: 900fab835907e7a8af2f8284629361ed0fbe1db81e6d05d8a2a98152fc223e4a44de352eb1eba538a9e53d406e95d97bcf4ad82f133a96e91c282626999175a7
@@ -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`
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- invokable (0.4.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 (10.5.0)
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 (~> 10.0)
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
- 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
+ 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, array, and set patches
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
 
@@ -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", "~> 10.0"
40
+ spec.add_development_dependency "rake", "~> 13.0"
41
41
  spec.add_development_dependency "rspec", "~> 3.0"
42
42
  end
@@ -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'
@@ -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
@@ -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.0"
2
+ VERSION = "0.5.2"
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.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-02-11 00:00:00.000000000 Z
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: '10.0'
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: '10.0'
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)