callbacks 0.0.2 → 0.0.3

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.
@@ -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