functional-ruby 0.7.0 → 0.7.1
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/README.md +4 -3
- data/lib/functional/behavior.rb +38 -6
- data/lib/functional/utilities.rb +58 -26
- data/lib/functional/version.rb +1 -1
- data/md/behavior.md +50 -9
- data/spec/functional/behavior_spec.rb +215 -62
- data/spec/functional/utilities_spec.rb +55 -21
- data/spec/spec_helper.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bc4db6eba8d3f68f626e27415bb5e5b20e69fc3
|
4
|
+
data.tar.gz: fa353eb6d4d4fc0d2557e7340d2874d68159050d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d482b7d25a1066ef058ca13cc5e8b7b5b0d7e249a7356d4b7cb815288b18daff9c3f5fb789fdbe2ef4c47e0a3e26f9f3437b244bed244b69cbd16d72f415c2e
|
7
|
+
data.tar.gz: 693b09f4e460522ff1aad1db7098414138ec076d90674c0303f699c476cd2fc4b5f745c032508aa93559ea4ebbf37e2c4ebb509965a104e531b7b50d822b3e37
|
data/README.md
CHANGED
@@ -120,7 +120,7 @@ Documentation: [Behavior](https://github.com/jdantonio/functional-ruby/blob/mast
|
|
120
120
|
```ruby
|
121
121
|
require 'functional/behavior'
|
122
122
|
|
123
|
-
behaviour_info(:gen_foo, foo: 0,
|
123
|
+
behaviour_info(:gen_foo, foo: 0, self_bar: 1)
|
124
124
|
|
125
125
|
class Foo
|
126
126
|
behavior(:gen_foo)
|
@@ -129,14 +129,15 @@ class Foo
|
|
129
129
|
return 'foo/0'
|
130
130
|
end
|
131
131
|
|
132
|
-
def bar(one, &block)
|
132
|
+
def self.bar(one, &block)
|
133
133
|
return 'bar/1'
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
137
|
foo = Foo.new
|
138
138
|
|
139
|
-
|
139
|
+
Foo.behaves_as? :gen_foo #=> true
|
140
|
+
foo.behaves_as?(:gen_foo) #=> true
|
140
141
|
foo.behaves_as?(:bogus) #=> false
|
141
142
|
'foo'.behaves_as? :gen_foo #=> false
|
142
143
|
```
|
data/lib/functional/behavior.rb
CHANGED
@@ -38,15 +38,29 @@ module Kernel
|
|
38
38
|
|
39
39
|
clazz.behaviors << name
|
40
40
|
|
41
|
+
if self.class == Module
|
42
|
+
(class << self; self; end).class_eval do
|
43
|
+
define_method(:included) do |base|
|
44
|
+
base.class_eval do
|
45
|
+
behavior(name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
41
51
|
class << clazz
|
42
52
|
def new(*args, &block)
|
43
|
-
name = self.behaviors.first
|
44
53
|
obj = super
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
54
|
+
self.ancestors.each do |clazz|
|
55
|
+
if clazz.respond_to?(:behaviors)
|
56
|
+
clazz.behaviors.each do |behavior|
|
57
|
+
unless obj.behaves_as?(behavior)
|
58
|
+
raise BehaviorError.new("undefined callback functions in #{self} (behavior '#{behavior}')")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
49
62
|
end
|
63
|
+
return obj
|
50
64
|
end
|
51
65
|
end
|
52
66
|
end
|
@@ -79,9 +93,27 @@ class Object
|
|
79
93
|
bi = $__behavior_info__[name]
|
80
94
|
return false if bi.nil?
|
81
95
|
|
96
|
+
validator = proc do |obj, method, arity|
|
97
|
+
(obj.respond_to?(method) && arity == :any) || obj.method(method).arity == arity
|
98
|
+
end
|
99
|
+
|
100
|
+
if self.is_a?(Class) || self.is_a?(Module)
|
101
|
+
bi = bi.select{|method, arity| method.to_s =~ /^self_/ }
|
102
|
+
end
|
103
|
+
|
82
104
|
bi.each do |method, arity|
|
83
105
|
begin
|
84
|
-
|
106
|
+
method = method.to_s
|
107
|
+
obj = self
|
108
|
+
|
109
|
+
if (self.is_a?(Class) || self.is_a?(Module)) && method =~ /^self_/
|
110
|
+
method = method.gsub(/^self_/, '')
|
111
|
+
elsif method =~ /^self_/
|
112
|
+
method = method.gsub(/^self_/, '')
|
113
|
+
obj = self.class
|
114
|
+
end
|
115
|
+
|
116
|
+
return false unless validator.call(obj, method, arity)
|
85
117
|
rescue NameError
|
86
118
|
return false
|
87
119
|
end
|
data/lib/functional/utilities.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'pp'
|
2
2
|
require 'stringio'
|
3
3
|
require 'erb'
|
4
|
+
require 'rbconfig'
|
4
5
|
|
5
6
|
Infinity = 1/0.0 unless defined?(Infinity)
|
6
7
|
NaN = 0/0.0 unless defined?(NaN)
|
@@ -79,24 +80,28 @@ module Kernel
|
|
79
80
|
# Sandbox the given operation at a high $SAFE level.
|
80
81
|
#
|
81
82
|
# @param args [Array] zero or more arguments to pass to the block
|
82
|
-
# @param block [Proc] the block to isolate
|
83
83
|
#
|
84
84
|
# @return [Object] the result of the block operation
|
85
85
|
def safe(*args)
|
86
86
|
raise ArgumentError.new('no block given') unless block_given?
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
if RbConfig::CONFIG['ruby_install_name'] =~ /^ruby$/i
|
88
|
+
result = nil
|
89
|
+
t = Thread.new do
|
90
|
+
$SAFE = 3
|
91
|
+
result = yield(*args)
|
92
|
+
end
|
93
|
+
t.join
|
94
|
+
return result
|
95
|
+
else
|
96
|
+
return yield(*args)
|
91
97
|
end
|
92
|
-
t.join
|
93
|
-
return result
|
94
98
|
end
|
95
99
|
module_function :safe
|
96
100
|
|
97
101
|
# Open a file, read it, close the file, and return its contents.
|
98
102
|
#
|
99
103
|
# @param file [String] path to and name of the file to open
|
104
|
+
#
|
100
105
|
# @return [String] file contents
|
101
106
|
#
|
102
107
|
# @see slurpee
|
@@ -110,6 +115,7 @@ module Kernel
|
|
110
115
|
#
|
111
116
|
# @param file [String] path to and name of the file to open
|
112
117
|
# @param safe_level [Integer] when not nil, ERB will $SAFE set to this
|
118
|
+
#
|
113
119
|
# @return [String] file contents
|
114
120
|
#
|
115
121
|
# @see slurpee
|
@@ -118,33 +124,36 @@ module Kernel
|
|
118
124
|
end
|
119
125
|
module_function :slurpee
|
120
126
|
|
121
|
-
|
122
|
-
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
#
|
130
|
-
def
|
131
|
-
return
|
132
|
-
end
|
133
|
-
|
134
|
-
# @private
|
135
|
-
def timer(*args) # :nodoc:
|
127
|
+
# Run the given block and time how long it takes in seconds. All arguments
|
128
|
+
# will be passed to the block. The function will return two values. The
|
129
|
+
# first value will be the duration of the timer in seconds. The second
|
130
|
+
# return value will be the result of the block.
|
131
|
+
#
|
132
|
+
# @param args [Array] zero or more arguments to pass to the block
|
133
|
+
#
|
134
|
+
# @return [Integer, Object] the duration of the operation in seconds and
|
135
|
+
# the result of the block operation
|
136
|
+
def timer(*args)
|
137
|
+
return 0,nil unless block_given?
|
136
138
|
t1 = Time.now
|
137
139
|
result = yield(*args)
|
138
140
|
t2 = Time.now
|
139
|
-
return (t2 - t1)
|
141
|
+
return (t2 - t1), result
|
140
142
|
end
|
141
143
|
module_function :timer
|
142
144
|
|
145
|
+
#############################################################################
|
146
|
+
|
143
147
|
# @private
|
144
|
-
|
145
|
-
|
148
|
+
# @see http://cirw.in/blog/find-references
|
149
|
+
def object_counts # :nodoc:
|
150
|
+
counts = Hash.new{ 0 }
|
151
|
+
ObjectSpace.each_object do |obj|
|
152
|
+
counts[obj.class] += 1
|
153
|
+
end
|
154
|
+
return counts
|
146
155
|
end
|
147
|
-
module_function :
|
156
|
+
module_function :object_counts
|
148
157
|
|
149
158
|
# @private
|
150
159
|
# @see http://rhaseventh.blogspot.com/2008/07/ruby-and-rails-how-to-get-pp-pretty.html
|
@@ -157,4 +166,27 @@ module Kernel
|
|
157
166
|
s.read
|
158
167
|
end
|
159
168
|
module_function :pp_s
|
169
|
+
|
170
|
+
# @private
|
171
|
+
def repl? # :nodoc:
|
172
|
+
return ($0 == 'irb' || $0 == 'pry' || $0 == 'script/rails' || !!($0 =~ /bin\/bundle$/))
|
173
|
+
end
|
174
|
+
module_function :repl?
|
175
|
+
|
176
|
+
# @private
|
177
|
+
def strftimer(seconds) # :nodoc:
|
178
|
+
Time.at(seconds).gmtime.strftime('%R:%S.%L')
|
179
|
+
end
|
180
|
+
module_function :strftimer
|
181
|
+
|
182
|
+
# @private
|
183
|
+
def timestamp # :nodoc:
|
184
|
+
return Time.now.getutc.to_i
|
185
|
+
end
|
186
|
+
|
187
|
+
def write_object_counts(name = 'ruby')
|
188
|
+
file = "#{name}_#{Time.now.to_i}.txt"
|
189
|
+
File.open(file, 'w') {|f| f.write(pp_s(object_counts)) }
|
190
|
+
end
|
191
|
+
module_function :write_object_counts
|
160
192
|
end
|
data/lib/functional/version.rb
CHANGED
data/md/behavior.md
CHANGED
@@ -11,14 +11,10 @@ Forget to implement a required method and Ruby will let you know. See the exampl
|
|
11
11
|
|
12
12
|
## Usage
|
13
13
|
|
14
|
-
|
14
|
+
Require the gem
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
require 'functional
|
18
|
-
|
19
|
-
# -or-
|
20
|
-
|
21
|
-
require 'functional/behaviour'
|
17
|
+
require 'functional'
|
22
18
|
```
|
23
19
|
|
24
20
|
### behavior_info
|
@@ -34,7 +30,6 @@ behaviour_info(:gen_foo, foo: 0, bar: 1, baz: 2)
|
|
34
30
|
# -or (for the Java/C# crowd)
|
35
31
|
|
36
32
|
interface(:gen_foo, foo: 0, bar: 1, baz: 2)
|
37
|
-
|
38
33
|
```
|
39
34
|
|
40
35
|
Each function name can be listed only once and the arity must follow the rules of the
|
@@ -43,6 +38,12 @@ Though not explicitly documented, block arguments do not count toward a method's
|
|
43
38
|
methods defined using this gem's `defn` function will always have an arity of -1,
|
44
39
|
regardless of how many overloads are defined.
|
45
40
|
|
41
|
+
To specify class/module methods prepend the methid name with 'self_'
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
behaviour_info(:gen_foo, self_foo: 0, self_bar: 1, baz: 2)
|
45
|
+
```
|
46
|
+
|
46
47
|
### behavior
|
47
48
|
|
48
49
|
To enforce a behavior on a class simply call the `behavior` function within the class,
|
@@ -74,6 +75,45 @@ raise an exception when you try to create an object from the class:
|
|
74
75
|
Baz.new #=> ArgumentError: undefined callback functions in Baz (behavior 'gen_foo')
|
75
76
|
```
|
76
77
|
|
78
|
+
A class may support multiple behaviors:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
behavior_info(:gen_foo, foo: 0)
|
82
|
+
behavior_info(:gen_bar, bar: 1)
|
83
|
+
|
84
|
+
class FooBar
|
85
|
+
behavior(:gen_foo)
|
86
|
+
behavior(:gen_bar)
|
87
|
+
...
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
Inheritance and module inclusion are supported as well:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
behavior_info(:gen_foo, foo: 0)
|
95
|
+
behavior_info(:gen_bar, bar: 0)
|
96
|
+
|
97
|
+
class Foo
|
98
|
+
behavior(:gen_foo)
|
99
|
+
def foo() nil; end
|
100
|
+
end
|
101
|
+
|
102
|
+
module Bar
|
103
|
+
behavior(:gen_bar)
|
104
|
+
def bar() nil; end
|
105
|
+
end
|
106
|
+
|
107
|
+
class FooBar < Foo
|
108
|
+
include Bar
|
109
|
+
end
|
110
|
+
|
111
|
+
foobar = FooBar.new
|
112
|
+
|
113
|
+
foobar.behaves_as?(:gen_foo) #=> true
|
114
|
+
foobar.behaves_as?(:gen_bar) #=> true
|
115
|
+
```
|
116
|
+
|
77
117
|
### behaves_as?
|
78
118
|
|
79
119
|
As an added bonus, Ruby [Object](http://ruby-doc.org/core-1.9.3/Object.html) will be
|
@@ -84,12 +124,12 @@ monkey-patched with a `behaves_as?` predicate method.
|
|
84
124
|
A complete example:
|
85
125
|
|
86
126
|
```ruby
|
87
|
-
behaviour_info(:gen_foo,
|
127
|
+
behaviour_info(:gen_foo, self_foo: 0, bar: 1, baz: 2, boom: -1, bam: :any)
|
88
128
|
|
89
129
|
class Foo
|
90
130
|
behavior(:gen_foo)
|
91
131
|
|
92
|
-
def foo
|
132
|
+
def self.foo
|
93
133
|
return 'foo/0'
|
94
134
|
end
|
95
135
|
|
@@ -112,6 +152,7 @@ end
|
|
112
152
|
|
113
153
|
foo = Foo.new
|
114
154
|
|
155
|
+
Foo.behaves_as? :gen_foo #=> true
|
115
156
|
foo.behaves_as? :gen_foo #=> true
|
116
157
|
foo.behaves_as?(:bogus) #=> false
|
117
158
|
'foo'.behaves_as? :gen_foo #=> false
|
@@ -74,93 +74,166 @@ describe '-behavior' do
|
|
74
74
|
|
75
75
|
context 'object creation' do
|
76
76
|
|
77
|
-
it '
|
78
|
-
behavior_info(:gen_foo, foo: 0
|
77
|
+
it 'checks all required behaviors' do
|
78
|
+
behavior_info(:gen_foo, foo: 0)
|
79
|
+
behavior_info(:gen_bar, bar: 1)
|
80
|
+
|
79
81
|
clazz = Class.new {
|
80
82
|
behavior(:gen_foo)
|
83
|
+
behavior(:gen_bar)
|
81
84
|
def foo() nil; end
|
82
85
|
}
|
86
|
+
lambda{ clazz.new }.should raise_error(BehaviorError)
|
83
87
|
|
84
|
-
lambda {
|
85
|
-
clazz.new
|
86
|
-
}.should raise_error(BehaviorError)
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'raises an exception when one or more functions do not have proper arity' do
|
90
|
-
behavior_info(:gen_foo, foo: 0)
|
91
88
|
clazz = Class.new {
|
92
89
|
behavior(:gen_foo)
|
93
|
-
|
90
|
+
behavior(:gen_bar)
|
91
|
+
def bar() nil; end
|
94
92
|
}
|
93
|
+
lambda{ clazz.new }.should raise_error(BehaviorError)
|
95
94
|
|
96
|
-
lambda {
|
97
|
-
clazz.new
|
98
|
-
}.should raise_error(BehaviorError)
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'accepts any arity when function arity is set to :any' do
|
102
|
-
behavior_info(:gen_foo, foo: :any)
|
103
95
|
clazz = Class.new {
|
104
96
|
behavior(:gen_foo)
|
105
|
-
|
97
|
+
behavior(:gen_bar)
|
106
98
|
}
|
107
|
-
|
108
|
-
lambda {
|
109
|
-
clazz.new
|
110
|
-
}.should_not raise_error
|
99
|
+
lambda{ clazz.new }.should raise_error(BehaviorError)
|
111
100
|
end
|
112
101
|
|
113
|
-
|
114
|
-
behavior_info(:gen_foo, foo: 0, bar: 1)
|
115
|
-
clazz = Class.new {
|
116
|
-
behavior(:gen_foo)
|
117
|
-
def foo() nil; end
|
118
|
-
def bar(first) nil; end
|
119
|
-
}
|
102
|
+
context 'instance methods' do
|
120
103
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
104
|
+
it 'raises an exception when one or more function definitions are missing' do
|
105
|
+
behavior_info(:gen_foo, foo: 0, bar: 1)
|
106
|
+
clazz = Class.new {
|
107
|
+
behavior(:gen_foo)
|
108
|
+
def foo() nil; end
|
109
|
+
}
|
126
110
|
|
127
|
-
|
111
|
+
lambda {
|
112
|
+
clazz.new
|
113
|
+
}.should raise_error(BehaviorError)
|
114
|
+
end
|
128
115
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
}
|
116
|
+
it 'raises an exception when one or more functions do not have proper arity' do
|
117
|
+
behavior_info(:gen_foo, foo: 0)
|
118
|
+
clazz = Class.new {
|
119
|
+
behavior(:gen_foo)
|
120
|
+
def foo(broken) nil; end
|
121
|
+
}
|
136
122
|
|
137
|
-
|
138
|
-
|
123
|
+
lambda {
|
124
|
+
clazz.new
|
125
|
+
}.should raise_error(BehaviorError)
|
126
|
+
end
|
139
127
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
128
|
+
it 'accepts any arity when function arity is set to :any' do
|
129
|
+
behavior_info(:gen_foo, foo: :any)
|
130
|
+
clazz = Class.new {
|
131
|
+
behavior(:gen_foo)
|
132
|
+
def foo(first) nil; end
|
133
|
+
}
|
145
134
|
|
146
|
-
|
135
|
+
lambda {
|
136
|
+
clazz.new
|
137
|
+
}.should_not raise_error
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'creates the object when function definitions match' do
|
141
|
+
behavior_info(:gen_foo, foo: 0, bar: 1)
|
142
|
+
clazz = Class.new {
|
143
|
+
behavior(:gen_foo)
|
144
|
+
def foo() nil; end
|
145
|
+
def bar(first) nil; end
|
146
|
+
}
|
147
|
+
|
148
|
+
lambda {
|
149
|
+
clazz.new
|
150
|
+
}.should_not raise_error
|
151
|
+
end
|
147
152
|
end
|
148
153
|
|
149
|
-
|
150
|
-
behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
|
151
|
-
clazz = Class.new {
|
152
|
-
def foo() nil; end
|
153
|
-
def bar(first) nil; end
|
154
|
-
}
|
154
|
+
context 'class methods' do
|
155
155
|
|
156
|
-
|
156
|
+
it 'raises an exception when one or more function definitions are missing' do
|
157
|
+
behavior_info(:gen_foo, self_foo: 0, self_bar: 1)
|
158
|
+
clazz = Class.new {
|
159
|
+
behavior(:gen_foo)
|
160
|
+
def self.foo() nil; end
|
161
|
+
}
|
162
|
+
|
163
|
+
lambda {
|
164
|
+
clazz.new
|
165
|
+
}.should raise_error(BehaviorError)
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'raises an exception when one or more functions do not have proper arity' do
|
169
|
+
behavior_info(:gen_foo, self_foo: 0)
|
170
|
+
clazz = Class.new {
|
171
|
+
behavior(:gen_foo)
|
172
|
+
def self.foo(broken) nil; end
|
173
|
+
}
|
174
|
+
|
175
|
+
lambda {
|
176
|
+
clazz.new
|
177
|
+
}.should raise_error(BehaviorError)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'accepts any arity when function arity is set to :any' do
|
181
|
+
behavior_info(:gen_foo, self_foo: :any)
|
182
|
+
clazz = Class.new {
|
183
|
+
behavior(:gen_foo)
|
184
|
+
def self.foo(first) nil; end
|
185
|
+
}
|
186
|
+
|
187
|
+
lambda {
|
188
|
+
clazz.new
|
189
|
+
}.should_not raise_error
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'creates the object when function definitions match' do
|
193
|
+
behavior_info(:gen_foo, self_foo: 0, self_bar: 1)
|
194
|
+
clazz = Class.new {
|
195
|
+
behavior(:gen_foo)
|
196
|
+
def self.foo() nil; end
|
197
|
+
def self.bar(first) nil; end
|
198
|
+
}
|
199
|
+
|
200
|
+
lambda {
|
201
|
+
clazz.new
|
202
|
+
}.should_not raise_error
|
203
|
+
end
|
157
204
|
end
|
158
205
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
206
|
+
context 'inheritance' do
|
207
|
+
|
208
|
+
it 'raises an exception if a superclass includes a behavior the subclass does not support' do
|
209
|
+
behavior_info(:gen_foo, foo: 0)
|
210
|
+
superclass = Class.new{
|
211
|
+
behavior(:gen_foo)
|
212
|
+
}
|
213
|
+
subclass = Class.new(superclass)
|
214
|
+
|
215
|
+
lambda {
|
216
|
+
subclass.new
|
217
|
+
}.should raise_error(BehaviorError)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'raises an exception if a module includes a behavior the containing class does not support' do
|
221
|
+
behavior_info(:gen_foo, foo: 0)
|
222
|
+
mod = Module.new{
|
223
|
+
behavior(:gen_foo)
|
224
|
+
}
|
225
|
+
subclass = Class.new{
|
226
|
+
include mod
|
227
|
+
}
|
228
|
+
|
229
|
+
lambda {
|
230
|
+
subclass.new
|
231
|
+
}.should raise_error(BehaviorError)
|
232
|
+
end
|
163
233
|
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context '#behaves_as?' do
|
164
237
|
|
165
238
|
it 'returns false when the behavior does not exist' do
|
166
239
|
clazz = Class.new { }
|
@@ -178,6 +251,87 @@ describe '-behavior' do
|
|
178
251
|
clazz = Class.new { }
|
179
252
|
clazz.new.behaves_as?('gen_foo').should be_true
|
180
253
|
end
|
254
|
+
|
255
|
+
context 'Object' do
|
256
|
+
|
257
|
+
it 'returns true when the behavior is fully suported' do
|
258
|
+
behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
|
259
|
+
clazz = Class.new {
|
260
|
+
def foo() nil; end
|
261
|
+
def bar(first) nil; end
|
262
|
+
def baz(first, second) nil; end
|
263
|
+
}
|
264
|
+
|
265
|
+
clazz.new.behaves_as?(:gen_foo).should be_true
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'accepts any arity when function arity is set to :any' do
|
269
|
+
behavior_info(:gen_foo, foo: :any)
|
270
|
+
clazz = Class.new {
|
271
|
+
def foo(*args, &block) nil; end
|
272
|
+
}
|
273
|
+
|
274
|
+
clazz.new.behaves_as?(:gen_foo).should be_true
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'returns false when the behavior is partially supported' do
|
278
|
+
behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
|
279
|
+
clazz = Class.new {
|
280
|
+
def foo() nil; end
|
281
|
+
def bar(first) nil; end
|
282
|
+
}
|
283
|
+
|
284
|
+
clazz.new.behaves_as?(:gen_foo).should be_false
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'returns false when the behavior is not supported at all' do
|
288
|
+
behavior_info(:gen_foo, foo: 0, bar: 1, baz: 2)
|
289
|
+
clazz = Class.new { }
|
290
|
+
clazz.new.behaves_as?(:gen_foo).should be_false
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context 'Class' do
|
295
|
+
|
296
|
+
it 'returns true when the behavior is fully suported' do
|
297
|
+
behavior_info(:gen_foo, self_foo: 0, self_bar: 1, baz: 2)
|
298
|
+
clazz = Class.new {
|
299
|
+
def self.foo() nil; end
|
300
|
+
def self.bar(first) nil; end
|
301
|
+
def baz(first, second) nil; end
|
302
|
+
}
|
303
|
+
|
304
|
+
clazz.behaves_as?(:gen_foo).should be_true
|
305
|
+
clazz.new.behaves_as?(:gen_foo).should be_true
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'accepts any arity when function arity is set to :any' do
|
309
|
+
behavior_info(:gen_foo, self_foo: :any)
|
310
|
+
clazz = Class.new {
|
311
|
+
def self.foo(*args, &block) nil; end
|
312
|
+
}
|
313
|
+
|
314
|
+
clazz.behaves_as?(:gen_foo).should be_true
|
315
|
+
clazz.new.behaves_as?(:gen_foo).should be_true
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'returns false when the behavior is partially supported' do
|
319
|
+
behavior_info(:gen_foo, self_foo: 0, bar: 1, self_baz: 2)
|
320
|
+
clazz = Class.new {
|
321
|
+
def self.foo() nil; end
|
322
|
+
def self(first) nil; end
|
323
|
+
}
|
324
|
+
|
325
|
+
clazz.behaves_as?(:gen_foo).should be_false
|
326
|
+
clazz.new.behaves_as?(:gen_foo).should be_false
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'returns false when the behavior is not supported at all' do
|
330
|
+
behavior_info(:gen_foo, self_foo: 0, self_bar: 1, self_baz: 2)
|
331
|
+
clazz = Class.new { }
|
332
|
+
clazz.new.behaves_as?(:gen_foo).should be_false
|
333
|
+
end
|
334
|
+
end
|
181
335
|
end
|
182
336
|
|
183
337
|
context 'aliases' do
|
@@ -212,5 +366,4 @@ describe '-behavior' do
|
|
212
366
|
clazz.new.behaves_as?(:gen_foo).should be_true
|
213
367
|
end
|
214
368
|
end
|
215
|
-
|
216
369
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'fakefs/safe'
|
3
|
+
require 'rbconfig'
|
3
4
|
|
4
5
|
describe 'utilities' do
|
5
6
|
|
@@ -125,32 +126,34 @@ describe 'utilities' do
|
|
125
126
|
end
|
126
127
|
end
|
127
128
|
|
128
|
-
|
129
|
+
if RbConfig::CONFIG['ruby_install_name'] =~ /^ruby$/i
|
130
|
+
context '#safe' do
|
129
131
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
it 'allows safe operations' do
|
133
|
+
lambda {
|
134
|
+
safe{ 1 + 1 }
|
135
|
+
}.should_not raise_error
|
136
|
+
end
|
135
137
|
|
136
|
-
|
137
|
-
|
138
|
-
|
138
|
+
it 'returns the value of the block when safe' do
|
139
|
+
safe{ 1 + 1 }.should eq 2
|
140
|
+
end
|
139
141
|
|
140
|
-
|
141
|
-
|
142
|
-
|
142
|
+
it 'passes all arguments to the block' do
|
143
|
+
safe(1, 2, 3){|x, y, z| x + y + z }.should eq 6
|
144
|
+
end
|
143
145
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
146
|
+
it 'rejects unsafe operations on tainted objects' do
|
147
|
+
lambda {
|
148
|
+
safe{ Signal.trap('INT'.taint) }
|
149
|
+
}.should raise_error(SecurityError)
|
150
|
+
end
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
152
|
+
it 'rejects the use of #eval' do
|
153
|
+
lambda {
|
154
|
+
safe{ eval 'puts 1' }
|
155
|
+
}.should raise_error(SecurityError)
|
156
|
+
end
|
154
157
|
end
|
155
158
|
end
|
156
159
|
|
@@ -234,4 +237,35 @@ describe 'utilities' do
|
|
234
237
|
repl?.should be_false
|
235
238
|
end
|
236
239
|
end
|
240
|
+
|
241
|
+
context '#timer' do
|
242
|
+
|
243
|
+
it 'returns [0, nil] if no block is given' do
|
244
|
+
duration, result = timer()
|
245
|
+
duration.should eq 0
|
246
|
+
result.should be_nil
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'yields to the block' do
|
250
|
+
@expected = false
|
251
|
+
duration, result = timer{ @expected = true }
|
252
|
+
@expected.should be_true
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'passes all arguments to the block' do
|
256
|
+
@expected = nil
|
257
|
+
duration, result = timer(1,2,3){|a,b,c| @expected = [a,b,c]}
|
258
|
+
@expected.should eq [1,2,3]
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'returns the duration as the first return value' do
|
262
|
+
duration, result = timer{ sleep(0.1) }
|
263
|
+
duration.should > 0
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'returns the block result as the second return value' do
|
267
|
+
duration, result = timer{ 42 }
|
268
|
+
result.should eq 42
|
269
|
+
end
|
270
|
+
end
|
237
271
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: functional-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|