central_notifications 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,98 @@
1
+ == Overview
2
+
3
+ Based on the idea of notifications in objective-C.
4
+ Register an object method for notifications.
5
+ When registered method is called, all objects which have registered will be notified and will be able to know the result of the registered method.
6
+ Can act as Rails observers, by registering on setters methods.
7
+ You can register both class or instance methods.
8
+ Several different objects, with different class can register for same object method.
9
+
10
+ See tests units for more examples of usage.
11
+
12
+ == Install
13
+
14
+ gem install central_notifications
15
+
16
+ == Dependencies
17
+
18
+ none
19
+
20
+ == Usage
21
+
22
+
23
+ === Declaring a notifier
24
+ ==== In the model
25
+ You can declare a notifier inside the model by including the module CentralNotifications and then declare in you model :
26
+ register_for_notification do |registration, notification|
27
+ registration.klass = Order
28
+ registration.method = :payment
29
+ notification.method = :one_order_has_been_payed
30
+ end
31
+ In this way you don't have to have to declare the notification.klass which is automatically set to self.
32
+
33
+ ==== In an initializer
34
+ You can register your notification in an initializer (for exemple, in Rails, in a file under config/initializers).
35
+ The analog as previous example will be in this initializer :
36
+ CentralNotifications.notify do |registration, notification|
37
+ registration.klass = Order
38
+ registration.method = :payment
39
+ notification.klass = User
40
+ notification.method = :one_order_has_been_payed
41
+ end
42
+
43
+ == Example
44
+ Suppose you have classes User and Order, and, you have registered for notification on instance method :payment (as previous)
45
+
46
+ class User
47
+ def one_order_has_been_payed
48
+ puts "Hey! one user know that one order has been paid!"
49
+ end
50
+ end
51
+
52
+ def Order
53
+ def payment(amount)
54
+ @amount = amount
55
+ end
56
+ end
57
+
58
+ order = Order.new
59
+ order.payment(100)
60
+
61
+ # => "Hey! one user know that one order has been paid!"
62
+
63
+ If you register notification for another class objects :
64
+
65
+ class Acounting
66
+ include CentralNotification
67
+
68
+ def one_order_has_been_payed
69
+ "Hey ! an accounting object know that one order has been payed"
70
+ end
71
+
72
+ register_for_notification do |registration, notification|
73
+ registration.klass = Order
74
+ registration.method = :payment
75
+ notification.method = :one_order_has_been_payed
76
+ end
77
+ end
78
+
79
+ then :
80
+ order = Order.new
81
+ order.payment(100)
82
+
83
+ # => "Hey! one user know that one order has been paid!"
84
+ # => "Hey ! an accounting object know that one order has been payed"
85
+
86
+ == Retrieve the result of the registered method
87
+
88
+ You can get in User class the result of Order#payment in the instance variable @registration_result.
89
+
90
+ def one_order_has_been_payed
91
+ puts "Payment is : " + @registration_result.to_s
92
+ end
93
+
94
+ order = Order.new
95
+ order.payment(100)
96
+
97
+ # => "Payment is : 100"
98
+
@@ -0,0 +1,25 @@
1
+ require 'notifier'
2
+
3
+ module CentralNotifications
4
+
5
+ def self.notify
6
+ notifier = Notifier.instance
7
+ notifier.register do |registration, notification|
8
+ yield registration, notification
9
+ end
10
+ end
11
+
12
+ def self.included(klass)
13
+ class << klass
14
+ def register_for_notification
15
+ notifier = Notifier.instance
16
+ notifier.register do |registration, notification|
17
+ notification.klass = self
18
+ yield registration, notification
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+
data/lib/notifier.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'registration'
2
+
3
+ module CentralNotifications
4
+ class Notifier
5
+ attr_accessor :registrations, :klass, :method
6
+
7
+ def initialize args={}
8
+ @registrations = {}
9
+ end
10
+
11
+ def self.instance
12
+ return @@instance ||= Notifier.new
13
+ end
14
+
15
+ def register
16
+ registration = Registration.new(:notifier => self)
17
+ yield registration, self
18
+
19
+ registration = registration_from_stack(registration)
20
+ registrations[registration] ||= []
21
+ registrations[registration] << {:klass => klass, :method => method}
22
+ registration.fork
23
+ end
24
+
25
+ def alert(registration)
26
+ registrations[registration].each do |notified|
27
+ ObjectSpace.each_object(notified[:klass]) do |object|
28
+ object.send(:instance_variable_set, :@registration_result, registration.result)
29
+ object.send(notified[:method])
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def registration_from_stack registration
37
+ reg = registrations.select {|registered, | registered.klass == registration.klass && registered.method == registration.method}
38
+ reg.empty? ? registration : reg.first.first
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,57 @@
1
+ module CentralNotifications
2
+ class Registration
3
+ NOTIFIER_CLASS_VARIABLE = :@@_____notifier
4
+ attr_accessor :klass, :method, :result
5
+
6
+ def initialize(args={})
7
+ @notifier = args[:notifier]
8
+ end
9
+
10
+ def fork
11
+ @real_klass = singleton_method? ? (class << klass; self end) : klass
12
+ @original_alias_symbol = original_alias_symbol
13
+ return if already_registered?
14
+ set_notifier_in_notifier_class
15
+ redefine_orinal_method
16
+ end
17
+
18
+ private
19
+
20
+ def original_alias_symbol
21
+ (method.to_s + '_original___#central_notifications_gem').to_sym
22
+ end
23
+
24
+ def already_registered?
25
+ @real_klass.instance_methods.include?(@original_alias_symbol.to_s)
26
+ end
27
+
28
+ def set_notifier_in_notifier_class
29
+ @real_klass.send(:class_variable_set, NOTIFIER_CLASS_VARIABLE, @notifier)
30
+ end
31
+
32
+ def redefine_orinal_method
33
+ original = @original_alias_symbol
34
+ @real_klass.send(:alias_method, original, @method)
35
+ redefine_method
36
+ end
37
+
38
+ def redefine_method
39
+ registration, eigenclass, original = self, on_eigenclass?, @original_alias_symbol
40
+ @real_klass.send(:define_method, method) do |*params|
41
+ registration.result = send(original, *params)
42
+ notifier = (eigenclass ? self : self.class).send(:class_variable_get, NOTIFIER_CLASS_VARIABLE)
43
+ notifier.alert(registration)
44
+ registration.result
45
+ end
46
+ end
47
+
48
+ def singleton_method?
49
+ klass.send(:singleton_methods).include?(method.to_s)
50
+ end
51
+
52
+ def on_eigenclass?
53
+ @real_klass.ancestors.first != @real_klass
54
+ end
55
+
56
+ end
57
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'central_notifications'
4
+ require 'models/user'
5
+ require 'models/order'
6
+ require 'models/accounting'
7
+
8
+ require 'mocha'
@@ -0,0 +1,17 @@
1
+ class Accounting
2
+
3
+ def initialize args={}
4
+
5
+ end
6
+
7
+ def one_order_has_been_payed
8
+
9
+ end
10
+
11
+ def all_orders_has_been_asked
12
+
13
+ end
14
+
15
+
16
+
17
+ end
@@ -0,0 +1,13 @@
1
+ CentralNotifications.notify do |registration, notification|
2
+ registration.klass = Order
3
+ registration.method = :payment
4
+ notification.klass = Accounting
5
+ notification.method = :one_order_has_been_payed
6
+ end
7
+
8
+ CentralNotifications.notify do |registration, notification|
9
+ registration.klass = Order
10
+ registration.method = :all
11
+ notification.klass = Accounting
12
+ notification.method = :all_orders_has_been_asked
13
+ end
@@ -0,0 +1,19 @@
1
+ class Order
2
+ attr_accessor :amount, :currency
3
+
4
+ def initialize args={}
5
+
6
+ end
7
+
8
+ def payment amount, currency=:euro
9
+ @amount = amount
10
+ @currency = currency
11
+ "payment done"
12
+ end
13
+
14
+ def self.all
15
+
16
+ end
17
+
18
+
19
+ end
@@ -0,0 +1,43 @@
1
+ require 'central_notifications'
2
+ require 'models/order'
3
+
4
+ class User
5
+ include CentralNotifications
6
+
7
+ attr_accessor :new_amount
8
+
9
+ def initialize args={}
10
+
11
+ end
12
+
13
+ def one_order_has_been_payed
14
+
15
+ end
16
+
17
+ def all_orders_has_been_asked
18
+
19
+ end
20
+
21
+ def amount_has_changed
22
+ @new_amount = @registration_result
23
+ end
24
+
25
+ register_for_notification do |registration, notification|
26
+ registration.klass = Order
27
+ registration.method = :payment
28
+ notification.method = :one_order_has_been_payed
29
+ end
30
+
31
+ register_for_notification do |registration, notification|
32
+ registration.klass = Order
33
+ registration.method = :all
34
+ notification.method = :all_orders_has_been_asked
35
+ end
36
+
37
+ register_for_notification do |registration, notification|
38
+ registration.klass = Order
39
+ registration.method = :amount=
40
+ notification.method = :amount_has_changed
41
+ end
42
+
43
+ end
@@ -0,0 +1,66 @@
1
+ # User use central notifications by including module, Accounting by initializer
2
+
3
+ require 'helper'
4
+ require 'models/central_notifications_initializer'
5
+
6
+ class TestNotifier < Test::Unit::TestCase
7
+
8
+ def test_notifier_should_have_singleton_instance
9
+ assert_equal CentralNotifications::Notifier.instance , CentralNotifications::Notifier.instance
10
+ end
11
+
12
+ def test_when_registered_method_is_called_method_triggered_of_registering_objects_should_be_called
13
+ user, admin, order = User.new, User.new, Order.new
14
+
15
+ user.expects(:one_order_has_been_payed)
16
+ admin.expects(:one_order_has_been_payed)
17
+
18
+ order.payment(100, :usd)
19
+ end
20
+
21
+ def test_should_call_orinal_method_with_original_parameters
22
+ user, order = User.new, Order.new
23
+
24
+ order.payment(100, :usd)
25
+
26
+ assert_equal 100, order.amount
27
+ assert_equal :usd, order.currency
28
+ end
29
+
30
+ def test_aliased_method_should_return_orginal_method_result
31
+ assert_equal "payment done", Order.new.payment(100)
32
+ end
33
+
34
+ def test_notified_method_should_be_able_to_know_the_return_of_notfied_method
35
+ user, order = User.new, Order.new
36
+
37
+ result = order.payment(100, :usd)
38
+
39
+ assert_equal result, user.instance_variable_get(:@registration_result)
40
+ end
41
+
42
+ def test_should_notify_class_method
43
+ user = User.new
44
+
45
+ user.expects(:all_orders_has_been_asked)
46
+ Order.all
47
+ end
48
+
49
+ def test_should_be_able_to_act_as_observer_on_attributes_change
50
+ user, order = User.new, Order.new
51
+
52
+ user.expects(:amount_has_changed)
53
+ order.amount = 200
54
+ assert_equal 200, order.amount
55
+ end
56
+
57
+ def test_notifications_on_same_klass_method_for_many_objects_should_be_able
58
+ user, accounting, order = User.new, Accounting.new, Order.new
59
+
60
+ user.expects(:one_order_has_been_payed)
61
+ accounting.expects(:one_order_has_been_payed)
62
+
63
+ order.payment(100)
64
+ end
65
+
66
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: central_notifications
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Philippe Cantin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-19 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: "\n Based on the idea of notifications in objective-C.\n Register an object method for notifications.\n When registered method is called, all objects which have registered will be notified and\n will be able to know the result of the registered method.\n Can replace Rails observers.\n "
23
+ email:
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ files:
31
+ - lib/central_notifications.rb
32
+ - lib/notifier.rb
33
+ - lib/registration.rb
34
+ - README.rdoc
35
+ - test/helper.rb
36
+ - test/models/accounting.rb
37
+ - test/models/central_notifications_initializer.rb
38
+ - test/models/order.rb
39
+ - test/models/user.rb
40
+ - test/test_notifier.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/anoiaque/central_notifications
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.7
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Register an object method for notifications
75
+ test_files:
76
+ - test/helper.rb
77
+ - test/models/accounting.rb
78
+ - test/models/central_notifications_initializer.rb
79
+ - test/models/order.rb
80
+ - test/models/user.rb
81
+ - test/test_notifier.rb