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 +98 -0
- data/lib/central_notifications.rb +25 -0
- data/lib/notifier.rb +42 -0
- data/lib/registration.rb +57 -0
- data/test/helper.rb +8 -0
- data/test/models/accounting.rb +17 -0
- data/test/models/central_notifications_initializer.rb +13 -0
- data/test/models/order.rb +19 -0
- data/test/models/user.rb +43 -0
- data/test/test_notifier.rb +66 -0
- metadata +81 -0
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
|
data/lib/registration.rb
ADDED
@@ -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,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
|
data/test/models/user.rb
ADDED
@@ -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
|