signal 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Nando Vieira
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # Signal
2
+
3
+ A simple observer implementation on POROs (Plain Old Ruby Object) and ActiveRecord objects.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem "signal"
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install signal
18
+
19
+ ## Usage
20
+
21
+ You can use Signal with PORO (Plain Old Ruby Object) and ActiveRecord.
22
+
23
+ ### Plain Ruby
24
+
25
+ All you have to do is including the `Signal` module. Then you can add listeners and trigger events.
26
+
27
+ ```ruby
28
+ class Status
29
+ include Signal
30
+
31
+ def ready!
32
+ emit(:ready)
33
+ end
34
+ end
35
+
36
+ status = Status.new
37
+ status.before(:ready) { puts "Before the ready event!" }
38
+ status.on(:ready) { puts "I'm ready!" }
39
+ status.after(:ready) { puts "After the ready event!" }
40
+ status.ready!
41
+ #=> Before the ready event!
42
+ #=> I'm ready!
43
+ #=> After the ready event!
44
+ ```
45
+
46
+ You can also pass objects that implement methods like `before_*`, `on_*` and `after_*`.
47
+
48
+ ```ruby
49
+ class MyListener
50
+ def before_ready
51
+ puts "Before the ready event!"
52
+ end
53
+
54
+ def on_ready
55
+ puts "I'm ready!"
56
+ end
57
+
58
+ def after_ready
59
+ puts "After the ready event!"
60
+ end
61
+ end
62
+
63
+ status = Status.new
64
+ status.listeners << MyListener.new
65
+ status.ready!
66
+ #=> Before the ready event!
67
+ #=> I'm ready!
68
+ #=> After the ready event!
69
+ ```
70
+
71
+ Blocks are executed in the context of the observable object.
72
+
73
+ ```ruby
74
+ class Contact
75
+ include Signal
76
+
77
+ attr_reader :name, :email
78
+
79
+ def initialize(name, email)
80
+ @name, @email = name, email
81
+ end
82
+
83
+ def output!
84
+ emit(:output)
85
+ end
86
+ end
87
+
88
+ contact = Contact.new("John Doe", "john@example.org")
89
+ contact.on(:output) { puts name, email }
90
+ contact.output!
91
+ #=> John Doe
92
+ #=> john@example.org
93
+ ```
94
+
95
+ You can provide arguments while emitting a signal:
96
+
97
+ ```ruby
98
+ class Arguments
99
+ include Signal
100
+ end
101
+
102
+ class MyListener
103
+ def on_args(a, b)
104
+ puts a, b
105
+ end
106
+ end
107
+
108
+ args = Arguments.new
109
+ args.on(:args) {|a, b| puts a, b }
110
+ args.listeners << MyListener.new
111
+ args.emit(:args, 1, 2)
112
+ ```
113
+
114
+ ### ActiveRecord
115
+
116
+ You can use Signal with ActiveRecord, which will give you some default events like `:create`, `:update`, `:remove` and `:validation`.
117
+
118
+ ```ruby
119
+ class Thing < ActiveRecord::Base
120
+ include Signal::ActiveRecord
121
+
122
+ validates_presence_of :name
123
+ end
124
+
125
+ thing = Thing.new(:name => "Stuff")
126
+ thing.on(:create) { puts updated_at, name }
127
+ thing.on(:update) { puts updated_at, name }
128
+ thing.on(:remove) { puts destroyed? }
129
+ thing.on(:validation) { p errors.full_messages }
130
+
131
+ thing.save!
132
+ #=> 2013-01-26 10:32:39 -0200
133
+ #=> Stuff
134
+
135
+ thing.update_attributes(:name => "Updated stuff")
136
+ #=> 2013-01-26 10:33:11 -0200
137
+ #=> Updated stuff
138
+
139
+ thing.update_attributes(:name => nil)
140
+ #=> ["Name can't be blank"]
141
+
142
+ thing.destroy
143
+ #=> true
144
+ ```
145
+
146
+ These are the available events:
147
+
148
+ * `before(:create)`: triggered before creating the record (record is valid).
149
+ * `on(:create)`: triggered after `before(:create)` event.
150
+ * `after(:create)`: triggered after the `on(:create)` event.
151
+ * `before(:update)`: triggered before updating the record (record is valid).
152
+ * `on(:update)`: triggered when the `before(:update)` event.
153
+ * `after(:update)`: triggered after the `on(:update)` event.
154
+ * `before(:remove)`: triggered before removing the record.
155
+ * `on(:remove)`: triggered after the `before(:remove)`.
156
+ * `after(:remove)`: triggered after the `on(:remove)` event.
157
+ * `before(:validation)`: triggered before validating record.
158
+ * `on(:validation)`: triggered when record is invalid.
159
+ * `after(:validation)`: triggered after validating record.
160
+
161
+ ## Contributing
162
+
163
+ 1. Fork it
164
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
165
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
166
+ 4. Push to the branch (`git push origin my-new-feature`)
167
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,41 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "signal"
3
+ require "active_record"
4
+
5
+ ActiveRecord::Base.establish_connection({
6
+ :adapter => "sqlite3",
7
+ :database => ":memory:"
8
+ })
9
+
10
+ ActiveRecord::Schema.define(:version => 0) do
11
+ create_table :things do |t|
12
+ t.string :name
13
+ t.timestamps
14
+ end
15
+ end
16
+
17
+ class Thing < ActiveRecord::Base
18
+ include Signal::ActiveRecord
19
+
20
+ validates_presence_of :name
21
+ end
22
+
23
+ thing = Thing.new(:name => "Stuff")
24
+ thing.on(:create) { puts updated_at, name }
25
+ thing.on(:update) { puts updated_at, name }
26
+ thing.on(:remove) { puts destroyed? }
27
+ thing.on(:validation) { p errors.full_messages }
28
+
29
+ thing.save!
30
+ #=> 2013-01-26 10:32:39 -0200
31
+ #=> Stuff
32
+
33
+ thing.update_attributes(:name => "Updated stuff")
34
+ #=> 2013-01-26 10:33:11 -0200
35
+ #=> Updated stuff
36
+
37
+ thing.update_attributes(:name => nil)
38
+ #=> ["Name can't be blank"]
39
+
40
+ thing.destroy
41
+ #=> true
@@ -0,0 +1,17 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "signal"
3
+
4
+ class Arguments
5
+ include Signal
6
+ end
7
+
8
+ class MyListener
9
+ def on_args(a, b)
10
+ puts a, b
11
+ end
12
+ end
13
+
14
+ args = Arguments.new
15
+ args.on(:args) {|a, b| puts a, b }
16
+ args.listeners << MyListener.new
17
+ args.emit(:args, 1, 2)
@@ -0,0 +1,20 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "signal"
3
+
4
+ class Contact
5
+ include Signal
6
+
7
+ attr_reader :name, :email
8
+
9
+ def initialize(name, email)
10
+ @name, @email = name, email
11
+ end
12
+
13
+ def output!
14
+ emit(:output)
15
+ end
16
+ end
17
+
18
+ contact = Contact.new("John Doe", "john@example.org")
19
+ contact.on(:output) { puts name, email }
20
+ contact.output!
@@ -0,0 +1,16 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "signal"
3
+
4
+ class Status
5
+ include Signal
6
+
7
+ def ready!
8
+ emit(:ready)
9
+ end
10
+ end
11
+
12
+ status = Status.new
13
+ status.before(:ready) { puts "Before the ready event!" }
14
+ status.on(:ready) { puts "I'm ready!" }
15
+ status.after(:ready) { puts "After the ready event!" }
16
+ status.ready!
data/examples/chain.rb ADDED
@@ -0,0 +1,56 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "signal"
3
+ require "active_record"
4
+
5
+ ActiveRecord::Base.establish_connection({
6
+ :adapter => "sqlite3",
7
+ :database => ":memory:"
8
+ })
9
+
10
+ ActiveRecord::Schema.define(:version => 0) do
11
+ create_table :things do |t|
12
+ t.string :name
13
+ t.timestamps
14
+ end
15
+ end
16
+
17
+ class Thing < ActiveRecord::Base
18
+ include Signal::ActiveRecord
19
+
20
+ validates_presence_of :name
21
+ end
22
+
23
+ class MyListener
24
+ [:validation, :update, :create, :remove].each do |type|
25
+ class_eval <<-RUBY
26
+ def before_#{type}; puts __method__; end
27
+ def on_#{type}; puts __method__; end
28
+ def after_#{type}; puts __method__; end
29
+ RUBY
30
+ end
31
+ end
32
+
33
+ puts "\n=== Creating valid record"
34
+ thing = Thing.new(:name => "Stuff")
35
+ thing.listeners << MyListener.new
36
+ thing.save
37
+
38
+ puts "\n=== Creating invalid record"
39
+ thing = Thing.new(:name => nil)
40
+ thing.listeners << MyListener.new
41
+ thing.save
42
+
43
+ puts "\n=== Updating valid record"
44
+ thing = Thing.create(:name => "Stuff")
45
+ thing.listeners << MyListener.new
46
+ thing.update_attributes(:name => "Updated stuff")
47
+
48
+ puts "\n=== Updating invalid record"
49
+ thing = Thing.create!(:name => "Stuff")
50
+ thing.listeners << MyListener.new
51
+ thing.update_attributes(:name => nil)
52
+
53
+ puts "\n=== Removing record"
54
+ thing = Thing.create(:name => "Stuff")
55
+ thing.listeners << MyListener.new
56
+ thing.destroy
@@ -0,0 +1,28 @@
1
+ $:.unshift File.expand_path("../../lib", __FILE__)
2
+ require "signal"
3
+
4
+ class Status
5
+ include Signal
6
+
7
+ def ready!
8
+ emit(:ready)
9
+ end
10
+ end
11
+
12
+ class MyListener
13
+ def before_ready
14
+ puts "Before the ready event!"
15
+ end
16
+
17
+ def on_ready
18
+ puts "I'm ready!"
19
+ end
20
+
21
+ def after_ready
22
+ puts "After the ready event!"
23
+ end
24
+ end
25
+
26
+ status = Status.new
27
+ status.listeners << MyListener.new
28
+ status.ready!
@@ -0,0 +1,55 @@
1
+ module Signal
2
+ module ActiveRecord
3
+ def self.included(base)
4
+ base.class_eval do
5
+ include Signal
6
+ include InstanceMethods
7
+
8
+ around_create :around_create_signal
9
+ around_save :around_save_signal
10
+ around_destroy :around_destroy_signal
11
+ before_validation :before_validation_signal
12
+ after_validation :after_validation_signal
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+ private
18
+ def around_create_signal
19
+ emit_signal(:before, :create)
20
+ yield
21
+ return unless persisted?
22
+ emit_signal(:on, :create)
23
+ emit_signal(:after, :create)
24
+ end
25
+
26
+ def around_save_signal
27
+ if new_record?
28
+ yield
29
+ return
30
+ end
31
+
32
+ emit_signal(:before, :update)
33
+ yield
34
+ emit_signal(:on, :update)
35
+ emit_signal(:after, :update)
36
+ end
37
+
38
+ def around_destroy_signal
39
+ emit_signal(:before, :remove)
40
+ yield
41
+ emit_signal(:on, :remove)
42
+ emit_signal(:after, :remove)
43
+ end
44
+
45
+ def before_validation_signal
46
+ emit_signal(:before, :validation)
47
+ end
48
+
49
+ def after_validation_signal
50
+ emit_signal(:on, :validation) if errors.any?
51
+ emit_signal(:after, :validation)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ module Signal
2
+ class Listener
3
+ def initialize(context, type, event, &block)
4
+ @context = context
5
+ @type = type
6
+ @event = event
7
+ @block = block
8
+ @event_method = :"#{@type}_#{@event}"
9
+ end
10
+
11
+ def method_missing(method, *args)
12
+ return super unless method == @event_method
13
+ @context.instance_exec(*args, &@block)
14
+ end
15
+
16
+ def to_s
17
+ "<#{self.class} event: #{@event_method}>"
18
+ end
19
+
20
+ def respond_to_missing?(method_name, include_private)
21
+ method_name == @event_method
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Signal
2
+ VERSION = "0.1.0"
3
+ end
data/lib/signal.rb ADDED
@@ -0,0 +1,42 @@
1
+ require "signal/active_record"
2
+ require "signal/listener"
3
+ require "signal/version"
4
+
5
+ module Signal
6
+ def on(event, &block)
7
+ listeners << Listener.new(self, __method__, event, &block)
8
+ self
9
+ end
10
+
11
+ def before(event, &block)
12
+ listeners << Listener.new(self, __method__, event, &block)
13
+ self
14
+ end
15
+
16
+ def after(event, &block)
17
+ listeners << Listener.new(self, __method__, event, &block)
18
+ self
19
+ end
20
+
21
+ def emit(event, *args)
22
+ emit_signal(:before, event, *args)
23
+ emit_signal(:on, event, *args)
24
+ emit_signal(:after, event, *args)
25
+ nil
26
+ end
27
+
28
+ def listeners
29
+ @listeners ||= []
30
+ end
31
+
32
+ private
33
+ def emit_signal(type, event, *args)
34
+ listeners.each do |listener|
35
+ method_name = "#{type}_#{event}"
36
+
37
+ if listener.respond_to?(method_name)
38
+ listener.public_send(method_name, *args)
39
+ end
40
+ end
41
+ end
42
+ end
data/signal.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require "./lib/signal/version"
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "signal"
6
+ gem.version = Signal::VERSION
7
+ gem.authors = ["Nando Vieira"]
8
+ gem.email = ["fnando.vieira@gmail.com"]
9
+ gem.description = "A simple observer implementation for POROs (Plain Old Ruby Object) and ActiveRecord objects."
10
+ gem.summary = gem.description
11
+ gem.homepage = "http://github.com/fnando/signal"
12
+
13
+ gem.files = `git ls-files`.split($/)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_development_dependency "activerecord"
19
+ gem.add_development_dependency "sqlite3"
20
+ gem.add_development_dependency "rspec"
21
+ end
@@ -0,0 +1,132 @@
1
+ require "spec_helper"
2
+
3
+ describe Signal::ActiveRecord do
4
+ let(:callable) { Callable.new }
5
+ let(:user) { User.new(:username => "johndoe") }
6
+
7
+ context "create event" do
8
+ it "triggers before event" do
9
+ user.before(:create, &callable)
10
+ callable.should_receive(:called).with(user)
11
+ user.save!
12
+ end
13
+
14
+ it "triggers event" do
15
+ user.on(:create, &callable)
16
+ callable.should_receive(:called).with(user)
17
+ user.save!
18
+ end
19
+
20
+ it "triggers after event" do
21
+ user.after(:create, &callable)
22
+ callable.should_receive(:called).with(user)
23
+ user.save!
24
+ end
25
+
26
+ it "doesn't trigger on/after events when record is invalid" do
27
+ user = User.new
28
+
29
+ on_callable = Callable.new
30
+ after_callable = Callable.new
31
+
32
+ user
33
+ .on(:create, &on_callable)
34
+ .after(:create, &after_callable)
35
+
36
+ on_callable.should_not_receive(:called)
37
+ after_callable.should_not_receive(:called)
38
+
39
+ user.save
40
+ end
41
+ end
42
+
43
+ context "validation event" do
44
+ it "triggers before event" do
45
+ user.before(:validation, &callable)
46
+ callable.should_receive(:called).with(user)
47
+ user.save!
48
+ end
49
+
50
+ it "triggers after event" do
51
+ user.after(:validation, &callable)
52
+ callable.should_receive(:called).with(user)
53
+ user.save!
54
+ end
55
+
56
+ it "triggers validation event when record is invalid" do
57
+ user.username = nil
58
+ user.on(:validation, &callable)
59
+ callable.should_receive(:called).with(user)
60
+ user.save
61
+ end
62
+
63
+ it "skips validation event when record is valid" do
64
+ user.on(:validation, &callable)
65
+ callable.should_not_receive(:called)
66
+ user.save!
67
+ end
68
+ end
69
+
70
+ context "update event" do
71
+ let(:user) { User.create!(:username => "johndoe") }
72
+
73
+ it "triggers before event" do
74
+ user.before(:update, &callable)
75
+ callable.should_receive(:called).with(user)
76
+ user.update_attributes!(:username => "johnd")
77
+ end
78
+
79
+ it "triggers on event" do
80
+ user.on(:update, &callable)
81
+ callable.should_receive(:called).with(user)
82
+ user.update_attributes!(:username => "johnd")
83
+ end
84
+
85
+ it "triggers after event" do
86
+ user.after(:update, &callable)
87
+ callable.should_receive(:called).with(user)
88
+ user.update_attributes!(:username => "johnd")
89
+ end
90
+
91
+ it "doesn't trigger on/after events when record is invalid" do
92
+ user.username = nil
93
+
94
+ on_callable = Callable.new
95
+ after_callable = Callable.new
96
+
97
+ user
98
+ .on(:update, &on_callable)
99
+ .after(:update, &after_callable)
100
+
101
+ on_callable.should_not_receive(:called)
102
+ after_callable.should_not_receive(:called)
103
+
104
+ user.save
105
+ end
106
+ end
107
+
108
+ context "remove event" do
109
+ let(:user) { User.create!(:username => "johndoe") }
110
+
111
+ it "triggers before event" do
112
+ user.before(:remove, &callable)
113
+ callable.should_receive(:called).with(user)
114
+
115
+ user.destroy
116
+ end
117
+
118
+ it "triggers on event" do
119
+ user.on(:remove, &callable)
120
+ callable.should_receive(:called).with(user)
121
+
122
+ user.destroy
123
+ end
124
+
125
+ it "triggers after event" do
126
+ user.after(:remove, &callable)
127
+ callable.should_receive(:called).with(user)
128
+
129
+ user.destroy
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,85 @@
1
+ require "spec_helper"
2
+
3
+ describe Signal do
4
+ let(:observable) { Observable.new }
5
+ let(:callable) { Callable.new }
6
+
7
+ context "using blocks" do
8
+ it "triggers event" do
9
+ observable.on(:ready, &callable)
10
+ callable.should_receive(:called).with(observable)
11
+
12
+ observable.emit(:ready)
13
+ end
14
+
15
+ it "triggers event with arguments" do
16
+ observable.on(:ready, &callable)
17
+ callable.should_receive(:called).with(observable, 1, 2, 3)
18
+
19
+ observable.emit(:ready, 1, 2, 3)
20
+ end
21
+
22
+ it "triggers before event" do
23
+ observable.before(:ready, &callable)
24
+ callable.should_receive(:called).with(observable)
25
+
26
+ observable.emit(:ready)
27
+ end
28
+
29
+ it "triggers before event with arguments" do
30
+ observable.before(:ready, &callable)
31
+ callable.should_receive(:called).with(observable, 1, 2, 3)
32
+
33
+ observable.emit(:ready, 1, 2, 3)
34
+ end
35
+
36
+ it "triggers after event" do
37
+ observable.after(:ready, &callable)
38
+ callable.should_receive(:called).with(observable)
39
+
40
+ observable.emit(:ready)
41
+ end
42
+
43
+ it "triggers after event with arguments" do
44
+ observable.after(:ready, &callable)
45
+ callable.should_receive(:called).with(observable, 1, 2, 3)
46
+
47
+ observable.emit(:ready, 1, 2, 3)
48
+ end
49
+
50
+ it "chains events" do
51
+ before_callable = Callable.new
52
+ on_callable = Callable.new
53
+ after_callable = Callable.new
54
+
55
+ observable
56
+ .before(:ready, &before_callable)
57
+ .on(:ready, &on_callable)
58
+ .after(:ready, &after_callable)
59
+
60
+ before_callable.should_receive(:called).with(observable).ordered
61
+ on_callable.should_receive(:called).with(observable).ordered
62
+ after_callable.should_receive(:called).with(observable).ordered
63
+
64
+ observable.emit(:ready)
65
+ end
66
+ end
67
+
68
+ context "using listeners" do
69
+ it "triggers event for listener" do
70
+ callable.respond_to(:on_ready)
71
+ observable.listeners << callable
72
+ callable.should_receive(:called).with(callable)
73
+
74
+ observable.emit(:ready)
75
+ end
76
+
77
+ it "triggers event for listener with arguments" do
78
+ callable.respond_to(:on_ready)
79
+ observable.listeners << callable
80
+ callable.should_receive(:called).with(callable, 1, 2, 3)
81
+
82
+ observable.emit(:ready, 1, 2, 3)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,20 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ require "active_record"
5
+
6
+ require "signal"
7
+ require "support/observable"
8
+ require "support/callable"
9
+ require "support/user"
10
+
11
+ ActiveRecord::Base.establish_connection({
12
+ :adapter => "sqlite3",
13
+ :database => ":memory:"
14
+ })
15
+
16
+ ActiveRecord::Schema.define(:version => 0) do
17
+ create_table :users do |t|
18
+ t.string :username
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ class Callable
2
+ def to_proc
3
+ callable = self
4
+ proc {|*args| callable.called(self, *args) }
5
+ end
6
+
7
+ def respond_to(method_name)
8
+ define_singleton_method(method_name, &to_proc)
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ class Observable
2
+ include Signal
3
+ end
@@ -0,0 +1,4 @@
1
+ class User < ActiveRecord::Base
2
+ include Signal::ActiveRecord
3
+ validates_presence_of :username
4
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: signal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nando Vieira
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: A simple observer implementation for POROs (Plain Old Ruby Object) and
63
+ ActiveRecord objects.
64
+ email:
65
+ - fnando.vieira@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - .rspec
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - examples/activerecord_model.rb
77
+ - examples/arguments.rb
78
+ - examples/block_context.rb
79
+ - examples/blocks.rb
80
+ - examples/chain.rb
81
+ - examples/listener.rb
82
+ - lib/signal.rb
83
+ - lib/signal/active_record.rb
84
+ - lib/signal/listener.rb
85
+ - lib/signal/version.rb
86
+ - signal.gemspec
87
+ - spec/activerecord_spec.rb
88
+ - spec/signal_spec.rb
89
+ - spec/spec_helper.rb
90
+ - spec/support/callable.rb
91
+ - spec/support/observable.rb
92
+ - spec/support/user.rb
93
+ homepage: http://github.com/fnando/signal
94
+ licenses: []
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.24
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: A simple observer implementation for POROs (Plain Old Ruby Object) and ActiveRecord
117
+ objects.
118
+ test_files:
119
+ - spec/activerecord_spec.rb
120
+ - spec/signal_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/support/callable.rb
123
+ - spec/support/observable.rb
124
+ - spec/support/user.rb