callable 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +81 -44
- data/callable.gemspec +2 -1
- data/lib/callable.rb +19 -1
- data/lib/callable/version.rb +1 -1
- data/spec/callable_spec.rb +78 -0
- data/spec/spec_helper.rb +5 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e85b170016fdbc135bebf0884c38e5637907d77a
|
4
|
+
data.tar.gz: 040b7e0d547142f84b52b547594171f3fcaa29f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ff80b6c79dd75efe33e43c156ef738354470e1a2ad61c67b05cef612e9abeb339900dce8c2f193bf69ed772d28bdb7902150f6fc9c1a77ee1f4a7e3867b24ab
|
7
|
+
data.tar.gz: 72ecb0cf755932c829ceeefc659b5960770836ed2fcdb377910c0283abf555cd0ca776d96de7aaba410e5a533a7357733ad58bc6464d99d13d6216563dbb88ce
|
data/README.md
CHANGED
@@ -26,71 +26,108 @@ in one of two ways (don't forget to install the gem first).
|
|
26
26
|
The first way is by invoking the callable method:
|
27
27
|
|
28
28
|
```ruby
|
29
|
-
c = Callable( :ret_val )
|
30
|
-
c.call
|
31
|
-
=> ret_val
|
29
|
+
c = Callable( :ret_val )
|
30
|
+
c.call
|
31
|
+
=> ret_val
|
32
32
|
```
|
33
33
|
|
34
34
|
Take into account that if you pass a callable object (such as a
|
35
35
|
lambda), you'll get it back as the return value:
|
36
36
|
|
37
37
|
```ruby
|
38
|
-
c = Callable( ->{ :ret_val } )
|
39
|
-
c.call
|
40
|
-
=> ret_val
|
38
|
+
c = Callable( ->{ :ret_val } )
|
39
|
+
c.call
|
40
|
+
=> ret_val
|
41
41
|
```
|
42
42
|
|
43
|
-
The
|
44
|
-
|
43
|
+
The gem also ships with a #callable? method thar returns true if the
|
44
|
+
object is callable and false if it's not.
|
45
45
|
|
46
46
|
```ruby
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
:not_callable.callable?
|
48
|
+
=> false
|
49
|
+
|
50
|
+
->{ :not_callable }.callable?
|
51
|
+
=> true
|
50
52
|
```
|
51
53
|
|
52
|
-
|
54
|
+
This is the same as saying
|
53
55
|
|
54
56
|
```ruby
|
55
|
-
|
56
|
-
c.call
|
57
|
-
=> ret_val
|
57
|
+
xxx.respond_to? :call
|
58
58
|
```
|
59
59
|
|
60
|
-
|
61
|
-
|
60
|
+
But I felt it would be more illustrative of it's purpose.
|
61
|
+
|
62
|
+
## Where to use it?
|
63
|
+
|
64
|
+
I think the main use for this library is handling actions as options.
|
65
|
+
|
66
|
+
For example, imagine we have a very reduced authorization library that provides a method called `do_if`.
|
67
|
+
This method receives:
|
68
|
+
- a symbol representing a permission name
|
69
|
+
- a Hash that represents the available authorization policies
|
70
|
+
- a block with the actions to perform
|
71
|
+
|
72
|
+
The premise is that the method will execute the block if the selected policy returns true when we send the `call` message.
|
73
|
+
|
74
|
+
Our first approach is:
|
62
75
|
|
63
76
|
```ruby
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
=> true
|
77
|
+
def do_if(permission, policies=POLICIES)
|
78
|
+
yield if policies[permission].call
|
79
|
+
end
|
68
80
|
```
|
69
81
|
|
70
|
-
|
82
|
+
So, if our POLICIES hash is:
|
71
83
|
|
72
84
|
```ruby
|
73
|
-
|
85
|
+
POLICIES = {
|
86
|
+
development: -> { true }
|
87
|
+
}
|
88
|
+
|
89
|
+
do_if(:development) do
|
90
|
+
puts "Debugging"
|
91
|
+
end
|
92
|
+
|
93
|
+
# >> Debugging
|
74
94
|
```
|
75
95
|
|
76
|
-
|
96
|
+
And if we switch the policy value:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
POLICIES = {
|
100
|
+
development: -> { false }
|
101
|
+
}
|
102
|
+
|
103
|
+
do_if(:development) do
|
104
|
+
puts "Debugging"
|
105
|
+
end
|
106
|
+
|
107
|
+
# >>
|
108
|
+
```
|
109
|
+
|
110
|
+
This allows us to have a lot of flexibility. But we could provide the user a way to say the same with less code:
|
111
|
+
|
112
|
+
|
113
|
+
|
77
114
|
|
78
|
-
## Where to use it?
|
79
115
|
|
80
|
-
|
81
|
-
|
116
|
+
*******************************
|
117
|
+
Let me say where to use this gem with a very
|
118
|
+
trivial example.
|
82
119
|
|
83
120
|
Imagine we have some class that admits an informer object that
|
84
121
|
responds to the get_info method and returns a some information on a
|
85
122
|
String.
|
86
123
|
|
87
124
|
```ruby
|
88
|
-
class SomeClass
|
89
|
-
|
90
|
-
|
91
|
-
|
125
|
+
class SomeClass
|
126
|
+
attr_writer :informer
|
127
|
+
def info
|
128
|
+
@informer.get_info
|
129
|
+
end
|
92
130
|
end
|
93
|
-
end
|
94
131
|
```
|
95
132
|
|
96
133
|
If we want to use this "informer" object, we must define a new class
|
@@ -101,25 +138,25 @@ method "call", instead of "get_info", because we now can toss a simple
|
|
101
138
|
lambda to substitute it. We can rewrite the code above like this:
|
102
139
|
|
103
140
|
```ruby
|
104
|
-
class SomeClass
|
105
|
-
|
106
|
-
|
107
|
-
|
141
|
+
class SomeClass
|
142
|
+
attr_writer :informer
|
143
|
+
def info
|
144
|
+
@informer.call
|
145
|
+
end
|
108
146
|
end
|
109
|
-
end
|
110
147
|
```
|
111
148
|
|
112
149
|
And now we can define a class or module that responds to the call
|
113
150
|
method. In that call method, we can get as fancy as we want:
|
114
151
|
|
115
152
|
```ruby
|
116
|
-
module Informer
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
153
|
+
module Informer
|
154
|
+
def call
|
155
|
+
# retrieve the information we need from wherever we want
|
156
|
+
# maybe a web service
|
157
|
+
# maybe a local file
|
158
|
+
end
|
121
159
|
end
|
122
|
-
end
|
123
160
|
```
|
124
161
|
|
125
162
|
So, when we do:
|
@@ -149,7 +186,7 @@ thing like this:
|
|
149
186
|
|
150
187
|
```ruby
|
151
188
|
something = SomeClass.new
|
152
|
-
something.informer = Callable
|
189
|
+
something.informer = Callable("No info available" )
|
153
190
|
something.info
|
154
191
|
```
|
155
192
|
|
data/callable.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'callable/version'
|
@@ -22,3 +21,5 @@ Gem::Specification.new do |spec|
|
|
22
21
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
22
|
spec.add_development_dependency "matest", "~> 1.5"
|
24
23
|
end
|
24
|
+
|
25
|
+
|
data/lib/callable.rb
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
require "callable/version"
|
2
2
|
|
3
3
|
module Callable
|
4
|
-
|
4
|
+
def Callable( callable_or_not )
|
5
|
+
if callable_or_not.respond_to?(:call)
|
6
|
+
callable_or_not
|
7
|
+
else
|
8
|
+
proc { |*args| callable_or_not }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def callable
|
13
|
+
Callable(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def callable?
|
17
|
+
self.respond_to?(:call)
|
18
|
+
end
|
5
19
|
end
|
20
|
+
|
21
|
+
::Object.include(Callable)
|
22
|
+
|
23
|
+
puts "X" * 100
|
data/lib/callable/version.rb
CHANGED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
scope Callable do
|
4
|
+
spec "creates a callable object" do
|
5
|
+
@obj = :not_callable
|
6
|
+
@c = Callable(@obj)
|
7
|
+
|
8
|
+
@c.call == @obj
|
9
|
+
end
|
10
|
+
|
11
|
+
spec "leaves a callable object intact" do
|
12
|
+
@obj = -> { :callable }
|
13
|
+
@c = Callable(@obj)
|
14
|
+
|
15
|
+
@c == @obj
|
16
|
+
end
|
17
|
+
|
18
|
+
scope "#callable" do
|
19
|
+
spec "creates a callable object" do
|
20
|
+
@obj = :not_callable
|
21
|
+
@c = @obj.callable
|
22
|
+
|
23
|
+
@c.call == @obj
|
24
|
+
end
|
25
|
+
|
26
|
+
spec "leaves a callable object intact" do
|
27
|
+
@obj = -> { :callable }
|
28
|
+
@c = @obj.callable
|
29
|
+
|
30
|
+
@c == @obj
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
scope "#callable?" do
|
36
|
+
spec "returns true if the object responds to #call" do
|
37
|
+
@obj = -> { :callable }
|
38
|
+
|
39
|
+
@obj.callable?
|
40
|
+
end
|
41
|
+
|
42
|
+
spec "returns false if the object doesn't respond to #call" do
|
43
|
+
@obj = :not_callable
|
44
|
+
|
45
|
+
! @obj.callable?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
scope "arguments" do
|
50
|
+
spec "accepts arguments arguments" do
|
51
|
+
@obj = :not_callable
|
52
|
+
@c = Callable(@obj)
|
53
|
+
|
54
|
+
@c.call(1, 2, 3) == @obj
|
55
|
+
end
|
56
|
+
|
57
|
+
spec "passes the arguments on" do
|
58
|
+
@obj = -> (a, b) { a + " " + b }
|
59
|
+
@c = Callable(@obj)
|
60
|
+
|
61
|
+
@c.call("Call", "me") == "Call me"
|
62
|
+
end
|
63
|
+
|
64
|
+
spec "can pass any number of arguments to a proc" do
|
65
|
+
@obj = proc { |a, b| a + " " + b }
|
66
|
+
@c = Callable(@obj)
|
67
|
+
|
68
|
+
@c.call("Call", "me", "now") == "Call me"
|
69
|
+
end
|
70
|
+
|
71
|
+
spec "passes the arguments on" do
|
72
|
+
@obj = -> (*args) { args.join(" ") }
|
73
|
+
@c = Callable(@obj)
|
74
|
+
|
75
|
+
@c.call("Call", "me", "now") == "Call me now"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: callable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Federico Iachetti
|
@@ -68,6 +68,8 @@ files:
|
|
68
68
|
- callable.gemspec
|
69
69
|
- lib/callable.rb
|
70
70
|
- lib/callable/version.rb
|
71
|
+
- spec/callable_spec.rb
|
72
|
+
- spec/spec_helper.rb
|
71
73
|
homepage: ''
|
72
74
|
licenses:
|
73
75
|
- MIT
|
@@ -92,4 +94,6 @@ rubygems_version: 2.4.5
|
|
92
94
|
signing_key:
|
93
95
|
specification_version: 4
|
94
96
|
summary: It allows you to define callable objects.
|
95
|
-
test_files:
|
97
|
+
test_files:
|
98
|
+
- spec/callable_spec.rb
|
99
|
+
- spec/spec_helper.rb
|