callbacks 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/Manifest.txt +1 -0
- data/README.txt +1 -1
- data/Rakefile +3 -0
- data/Version.txt +1 -1
- data/lib/callback.rb +8 -7
- data/lib/callbacks.rb +18 -4
- data/lib/classmethods.rb +40 -15
- data/lib/instancemethods.rb +23 -31
- data/test/test_callbacks.rb +21 -25
- data/test/test_singleton_callbacks.rb +85 -0
- data/test/tester_class.rb +2 -2
- metadata +5 -3
data/History.txt
CHANGED
@@ -10,3 +10,11 @@
|
|
10
10
|
* API still not stable
|
11
11
|
* Callbacks now picks up "before#{callback}" and "after_#{callback}" instance methods automatically
|
12
12
|
* Some documentation added
|
13
|
+
|
14
|
+
== 0.0.3 / 2008-10-14
|
15
|
+
|
16
|
+
* Callbacks per object instance (singleton callbacks)
|
17
|
+
* Shuffled some code between instancemethods and classmethods
|
18
|
+
* Some more tests
|
19
|
+
* API still not stable
|
20
|
+
* Some documentation added
|
data/Manifest.txt
CHANGED
data/README.txt
CHANGED
@@ -22,7 +22,7 @@ This package makes it simple to add callbacks a.k.a. "hooks" to ruby classes
|
|
22
22
|
Object.send(:include, Callbacks)
|
23
23
|
Object.add_callback_methods :inspect
|
24
24
|
Object.before_inspect do
|
25
|
-
|
25
|
+
print "Going to inspect #{self.class}\n"
|
26
26
|
end
|
27
27
|
|
28
28
|
o = Object.new
|
data/Rakefile
CHANGED
data/Version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/lib/callback.rb
CHANGED
@@ -2,14 +2,14 @@ class Callback
|
|
2
2
|
attr_accessor :method, :input
|
3
3
|
attr_writer :proc
|
4
4
|
ACCEPTED = [Symbol, Proc, String, Method]
|
5
|
+
ACCEPTANCE_ERROR = "Callbacks must be a symbol denoting the method to call, a string to be evaluated, a block to be invoked, or an object responding to the callback method. %s is none of those."
|
5
6
|
|
6
7
|
def initialize(method, input, &block)
|
7
|
-
#self.method = method
|
8
8
|
self.input = input
|
9
9
|
self.input = block if block_given?
|
10
10
|
|
11
11
|
if not ACCEPTED.include? self.input.class
|
12
|
-
raise
|
12
|
+
raise ACCEPTANCE_ERROR % self.input.class
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -25,19 +25,20 @@ class Callback
|
|
25
25
|
case self.input
|
26
26
|
when String
|
27
27
|
Proc.new { eval(self.input) }
|
28
|
-
|
29
|
-
|
30
|
-
# end
|
28
|
+
else
|
29
|
+
nil
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
33
|
def generate_block
|
35
34
|
case self.input
|
36
35
|
when Symbol
|
37
|
-
|
38
|
-
Proc.new { self.send(
|
36
|
+
instance_method = self.input.to_sym
|
37
|
+
Proc.new { self.send(instance_method) }
|
39
38
|
when Proc, Method
|
40
39
|
self.input
|
40
|
+
else
|
41
|
+
nil
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
data/lib/callbacks.rb
CHANGED
@@ -1,20 +1,34 @@
|
|
1
1
|
#Idea stolen from rails/activerecord
|
2
2
|
module Callbacks
|
3
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
4
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
5
|
+
|
3
6
|
require 'observer'
|
4
|
-
require
|
7
|
+
require "#{PATH}/ext/metaid.rb"
|
5
8
|
require 'callbackchain.rb'
|
6
9
|
require 'instancemethods.rb'
|
7
10
|
require 'classmethods.rb'
|
8
11
|
require 'callback.rb'
|
9
|
-
|
12
|
+
|
10
13
|
#Sets all things right
|
11
14
|
def self.included(base) #:nodoc:
|
12
|
-
base.extend Observable #why?
|
13
15
|
base.extend Callbacks::ClassMethods
|
14
16
|
base.send(:include, Callbacks::InstanceMethods)
|
15
17
|
end
|
18
|
+
|
19
|
+
def self.version
|
20
|
+
VERSION
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.libpath( *args )
|
24
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.path( *args )
|
28
|
+
args.empty? ? PATH : ::File.join(PATH, *args)
|
29
|
+
end
|
30
|
+
|
16
31
|
end
|
17
32
|
|
18
33
|
#TODO: add aliases like add_hook(), callbacks(), et cetera
|
19
|
-
#TODO: feature to add hooks/callbacks to instances instead of only classes
|
20
34
|
#TODO: make all of the activesupport features/tests work
|
data/lib/classmethods.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Callbacks
|
2
2
|
module ClassMethods
|
3
3
|
|
4
|
-
def callback_methods
|
4
|
+
def callback_methods
|
5
5
|
#Use one @, else it gets stored in the module and then it will be avaiable in every class that uses callback
|
6
6
|
@callback_methods ||= []
|
7
7
|
end
|
@@ -30,15 +30,38 @@ module Callbacks
|
|
30
30
|
self.callback_methods.delete(method.to_sym)
|
31
31
|
end
|
32
32
|
|
33
|
+
#TODO: make this nicer
|
34
|
+
def callback_actions_for(method, type)
|
35
|
+
if self.callback_actions[method].nil?
|
36
|
+
callback_actions = []
|
37
|
+
else
|
38
|
+
callback_actions = self.callback_actions[method][type] ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
#Removed this because this didn't work
|
42
|
+
#callback_actions_for is called four times with every callback method:
|
43
|
+
# before, before metaclass, after, after metaclass
|
44
|
+
# And a class and metaclass both now the #{type}_#{method} method
|
45
|
+
# So it got called twice
|
46
|
+
# if self.instance_methods.include?("#{type}_#{method}")
|
47
|
+
# if not callback_actions.include? "#{type}_#{method}".to_sym
|
48
|
+
# callback = self.add_callback_action(type, method, "#{type}_#{method}".to_sym)
|
49
|
+
# callback_actions << callback
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
|
53
|
+
return callback_actions
|
54
|
+
end
|
55
|
+
|
33
56
|
def build_callback_methods(method)
|
34
57
|
build_before_callback_method(method)
|
35
58
|
build_after_callback_method(method)
|
36
59
|
|
37
60
|
class_eval <<-"end_eval"
|
38
61
|
def #{method}_with_callbacks
|
39
|
-
trigger_callback_actions(:#{method}, :before)
|
62
|
+
self.trigger_callback_actions(:#{method}, :before)
|
40
63
|
retval = self.send("#{method}_without_callbacks")
|
41
|
-
trigger_callback_actions(:#{method}, :after)
|
64
|
+
self.trigger_callback_actions(:#{method}, :after)
|
42
65
|
return retval
|
43
66
|
end
|
44
67
|
end_eval
|
@@ -63,26 +86,28 @@ module Callbacks
|
|
63
86
|
ca[method][type] << callback
|
64
87
|
return callback
|
65
88
|
end
|
66
|
-
|
67
|
-
private
|
89
|
+
|
68
90
|
def build_before_callback_method(method)
|
69
|
-
|
70
|
-
|
71
|
-
def before_#{method}(*callbacks, &block)
|
72
|
-
add_callback_action :before, :#{method}, *callbacks, &block
|
73
|
-
end
|
74
|
-
|
75
|
-
end_eval
|
91
|
+
build_callback_method(:before, method)
|
76
92
|
end
|
77
93
|
|
78
94
|
def build_after_callback_method(method)
|
79
|
-
|
95
|
+
build_callback_method(:after, method)
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_callback_method(type, method)
|
99
|
+
method = <<-"end_eval"
|
100
|
+
|
101
|
+
# def #{type}_#{method}(*callbacks, &block)
|
102
|
+
# self.class.add_callback_action(:#{type}, :#{method}, *callbacks, &block)
|
103
|
+
# end
|
80
104
|
|
81
|
-
def
|
82
|
-
add_callback_action
|
105
|
+
def self.#{type}_#{method}(*callbacks, &block)
|
106
|
+
add_callback_action(:#{type}, :#{method}, *callbacks, &block)
|
83
107
|
end
|
84
108
|
|
85
109
|
end_eval
|
110
|
+
module_eval(method)
|
86
111
|
end
|
87
112
|
|
88
113
|
end
|
data/lib/instancemethods.rb
CHANGED
@@ -1,49 +1,41 @@
|
|
1
1
|
module Callbacks
|
2
2
|
module InstanceMethods
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
#
|
4
|
+
def trigger_callback_actions(method, type)
|
5
|
+
trigger_class_callback_actions(method, type) if self.class.respond_to?(:callback_actions_for)
|
6
|
+
trigger_metaclass_callback_actions(method, type) if self.metaclass.respond_to?(:callback_actions_for)
|
7
|
+
#Should I return something?
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
#TODO: do something with a block or proc or something :p
|
11
|
+
#Instead of self.class/self.metaclass
|
12
|
+
def trigger_class_callback_actions(method, type)
|
13
|
+
self.class.callback_actions_for(method, type).each do |callback|
|
14
|
+
|
15
|
+
if callback.block
|
16
|
+
self.instance_eval(&callback.block)
|
17
|
+
else
|
18
|
+
callback.proc.call
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
|
-
#
|
19
|
-
# add it!
|
20
|
-
#Dit kan mooier!
|
22
|
+
#I'm not happy with this...
|
21
23
|
if self.respond_to?("#{type}_#{method}")
|
22
|
-
|
23
|
-
#callback_actions << Callback.new(method, "#{type}_#{method}".to_sym)
|
24
|
-
callback = self.class.add_callback_action(type, method, "#{type}_#{method}".to_sym)
|
25
|
-
callback_actions << callback
|
26
|
-
end
|
24
|
+
self.send("#{type}_#{method}")
|
27
25
|
end
|
28
|
-
|
29
|
-
return callback_actions
|
30
26
|
end
|
31
27
|
|
32
|
-
def
|
33
|
-
self.
|
34
|
-
|
35
|
-
|
36
|
-
def trigger_callback_actions(method, type)
|
37
|
-
|
38
|
-
self.callback_actions_for(method, type).each do |callback|
|
28
|
+
def trigger_metaclass_callback_actions(method, type)
|
29
|
+
self.metaclass.callback_actions_for(method, type).each do |callback|
|
30
|
+
|
39
31
|
if callback.block
|
40
|
-
return instance_eval(&callback.block)
|
32
|
+
return self.instance_eval(&callback.block)
|
41
33
|
else
|
42
34
|
callback.proc.call
|
43
35
|
end
|
44
36
|
end
|
45
|
-
|
46
37
|
#Should I return something?
|
47
38
|
end
|
48
|
-
|
49
|
-
end
|
39
|
+
|
40
|
+
end #InstanceMethods
|
41
|
+
end #Callbacks
|
data/test/test_callbacks.rb
CHANGED
@@ -153,21 +153,6 @@ class CallbacksTest < Test::Unit::TestCase
|
|
153
153
|
assert_equal ['before_exit'], $tests_run
|
154
154
|
end
|
155
155
|
|
156
|
-
# def test_should_not_raise_error_when_method_not_exist
|
157
|
-
# assert_nothing_raised do
|
158
|
-
# Tester.add_callback_methods :doesnotexist
|
159
|
-
# end
|
160
|
-
# end
|
161
|
-
|
162
|
-
# def test_no_method_callback_should_not_add_method
|
163
|
-
# Tester.add_callback_methods :nomethodcallback
|
164
|
-
# t = Tester.new
|
165
|
-
#
|
166
|
-
# assert_raise NameError do
|
167
|
-
# t.nomethodcallback
|
168
|
-
# end
|
169
|
-
# end
|
170
|
-
|
171
156
|
def test_should_use_defined_methods_in_class_as_callback
|
172
157
|
Tester.add_callback_methods :callback_with_defined_method
|
173
158
|
t = Tester.new
|
@@ -185,16 +170,27 @@ class CallbacksTest < Test::Unit::TestCase
|
|
185
170
|
end
|
186
171
|
end
|
187
172
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
173
|
+
def test_callbacks_created_in_class_should_be_vissible_in_instance
|
174
|
+
Tester.add_callback_methods :boot, :exit
|
175
|
+
Tester.new
|
176
|
+
assert_equal [:boot, :exit], Tester.callback_methods
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_predefined_callback_methods_should_run_once
|
180
|
+
Tester.add_callback_methods :callback_with_defined_method
|
181
|
+
t = Tester.new
|
182
|
+
t.callback_with_defined_method
|
183
|
+
assert $tests_run.length == 1
|
184
|
+
end
|
193
185
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
186
|
+
def test_method_defined_after_include_should_work
|
187
|
+
Tester.send(:define_method, :after_include) do
|
188
|
+
$tests_run << 'after_include'
|
189
|
+
end
|
190
|
+
Tester.add_callback_methods :after_include
|
191
|
+
t = Tester.new
|
192
|
+
t.after_include
|
193
|
+
assert $tests_run.length == 1
|
194
|
+
end
|
199
195
|
|
200
196
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class SingletonCallbacksTest < Test::Unit::TestCase
|
2
|
+
attr_accessor :tester
|
3
|
+
|
4
|
+
def setup
|
5
|
+
Object.send(:remove_const, :Tester) if defined? Tester
|
6
|
+
load 'test/tester_class.rb'
|
7
|
+
self.tester = Tester.new
|
8
|
+
$tests_run = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_should_create_instance_methods
|
12
|
+
tester.metaclass.add_callback_methods :boot
|
13
|
+
|
14
|
+
assert_nothing_raised { tester.boot }
|
15
|
+
assert_nothing_raised { tester.boot_without_callbacks }
|
16
|
+
assert_nothing_raised { tester.metaclass.before_boot('p "ehlo"') }
|
17
|
+
assert_nothing_raised { tester.metaclass.after_boot('p "ehlo"') }
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_class_should_create_before_and_after_method
|
21
|
+
tester.metaclass.add_callback_methods :boot
|
22
|
+
methods = tester.metaclass.methods.grep(/(^before_.+$|^after_.+$)/)
|
23
|
+
|
24
|
+
assert methods.include?('before_boot')
|
25
|
+
assert methods.include?('after_boot')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_callback_created_in_instance_should_not_be_vissible_in_class
|
29
|
+
tester.metaclass.add_callback_methods :boot
|
30
|
+
assert_equal [], Tester.callback_methods
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_callback_created_in_class_should_be_vissible_in_instance
|
34
|
+
#This ain't gonna work...
|
35
|
+
#I don't know how to get the variables
|
36
|
+
Tester.add_callback_methods :boot
|
37
|
+
t = Tester.new
|
38
|
+
assert_equal [:boot], t.metaclass.callback_methods
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_callbacks_created_in_class_and_instance_should_both_be_run
|
42
|
+
Tester.add_callback_methods :boot
|
43
|
+
Tester.before_boot do
|
44
|
+
$tests_run << 'before_boot'
|
45
|
+
end
|
46
|
+
|
47
|
+
tester.metaclass.after_boot do
|
48
|
+
$tests_run << 'after_boot'
|
49
|
+
end
|
50
|
+
|
51
|
+
tester.boot
|
52
|
+
|
53
|
+
assert $tests_run.include?('before_boot')
|
54
|
+
assert $tests_run.include?('after_boot')
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_callbacks_created_in_class_and_instance_should_both_be_run_2
|
58
|
+
Tester.add_callback_methods :boot
|
59
|
+
Tester.before_boot do
|
60
|
+
$tests_run << 'before_boot'
|
61
|
+
end
|
62
|
+
|
63
|
+
tester.metaclass.before_boot do
|
64
|
+
$tests_run << 'before_boot_2'
|
65
|
+
end
|
66
|
+
|
67
|
+
tester.boot
|
68
|
+
|
69
|
+
assert $tests_run.include?('before_boot')
|
70
|
+
assert $tests_run.include?('before_boot_2')
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_singleton_callbacks_on_clean_object
|
74
|
+
a = Object.new
|
75
|
+
a.metaclass.send(:include, Callbacks)
|
76
|
+
a.metaclass.add_callback_methods :to_s
|
77
|
+
a.metaclass.before_to_s do
|
78
|
+
$tests_run << 'clean!'
|
79
|
+
end
|
80
|
+
a.to_s #and see the magic happen
|
81
|
+
|
82
|
+
assert $tests_run.length == 1
|
83
|
+
assert $tests_run[0] == 'clean!'
|
84
|
+
end
|
85
|
+
end
|
data/test/tester_class.rb
CHANGED
@@ -2,6 +2,7 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
|
|
2
2
|
require 'callbacks'
|
3
3
|
|
4
4
|
class Tester
|
5
|
+
include Callbacks
|
5
6
|
|
6
7
|
def boot
|
7
8
|
return "booting"
|
@@ -27,6 +28,5 @@ class Tester
|
|
27
28
|
def fill_globalvar_tests_run
|
28
29
|
$tests_run << 'fill_globalvar_tests_run'
|
29
30
|
end
|
30
|
-
|
31
|
-
include Callbacks
|
31
|
+
|
32
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: callbacks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leon Bogaert
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-10-14 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- test/profile.rb
|
52
52
|
- test/test_callbacks.rb
|
53
53
|
- test/test_helper.rb
|
54
|
+
- test/test_singleton_callbacks.rb
|
54
55
|
- test/tester_class.rb
|
55
56
|
has_rdoc: true
|
56
57
|
homepage: www.vanutsteen.nl
|
@@ -76,10 +77,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
77
|
requirements: []
|
77
78
|
|
78
79
|
rubyforge_project: callbacks
|
79
|
-
rubygems_version: 1.
|
80
|
+
rubygems_version: 1.3.0
|
80
81
|
signing_key:
|
81
82
|
specification_version: 2
|
82
83
|
summary: This package makes it simple to add callbacks a
|
83
84
|
test_files:
|
84
85
|
- test/test_helper.rb
|
86
|
+
- test/test_singleton_callbacks.rb
|
85
87
|
- test/test_callbacks.rb
|