callbacks 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -26,4 +26,5 @@ tasks/test.rake
26
26
  test/profile.rb
27
27
  test/test_callbacks.rb
28
28
  test/test_helper.rb
29
+ test/test_singleton_callbacks.rb
29
30
  test/tester_class.rb
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
- print "Going to inspect #{self.class}\n"
25
+ print "Going to inspect #{self.class}\n"
26
26
  end
27
27
 
28
28
  o = Object.new
data/Rakefile CHANGED
@@ -9,6 +9,9 @@ require 'callbacks'
9
9
 
10
10
  task :default => 'spec:run'
11
11
 
12
+ SUDO = ''
13
+ HAVE_GIT = true
14
+
12
15
  PROJ.name = 'callbacks'
13
16
  PROJ.authors = 'Leon Bogaert'
14
17
  PROJ.email = 'leon@vanutsteen.nl'
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
@@ -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 "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. #{self.input} is none of those."
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
- #else if self.input.respond_to?(self.method)
29
- # Proc.new { callback.send(method, self) }
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
- symbol = self.input.to_sym
38
- Proc.new { self.send(symbol) }
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
@@ -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 'ext/metaid.rb'
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
@@ -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
- instance_eval <<-"end_eval"
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
- instance_eval <<-"end_eval"
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 after_#{method}(*callbacks, &block)
82
- add_callback_action :after, :#{method}, *callbacks, &block
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
@@ -1,49 +1,41 @@
1
1
  module Callbacks
2
2
  module InstanceMethods
3
3
 
4
- def callback_actions(show_classvars = true)
5
- callback_actions = self.class_callback_actions
6
- #return self.instance_callbacks if show_classvars == false
7
- #return self.class_callback_actions + self.instance_callback_actions if show_classvars == true
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
- def callback_actions_for(method, type)
11
- #Do the rescue if [method] does not exist (nil), [type] will fail
12
- begin
13
- callback_actions = self.callback_actions[method][type] ||= []
14
- rescue NoMethodError
15
- callback_actions = []
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
- #If the before/after_ method exists, and it is not already added,
19
- # add it!
20
- #Dit kan mooier!
22
+ #I'm not happy with this...
21
23
  if self.respond_to?("#{type}_#{method}")
22
- if not callback_actions.include? "#{type}_#{method}".to_sym
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 class_callback_actions
33
- self.class.callback_actions
34
- end
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
- end
49
- end
39
+
40
+ end #InstanceMethods
41
+ end #Callbacks
@@ -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
- # def test_callbacks_created_in_class_should_be_vissible_in_instance
189
- # Tester.add_callback_methods :boot, :exit
190
- # t = Tester.new
191
- # assert_equal [:boot, :exit], t.callbacks
192
- # end
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
- # def test_callback_created_in_instance_should_not_be_vissible_in_class
195
- # t = Tester.new
196
- # t.add_callback :boot
197
- # assert_equal [], Tester.callbacks
198
- # end
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
@@ -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.2
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-09-28 00:00:00 +02:00
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.2.0
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