signal 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +1 -1
- data/README.md +58 -12
- data/Rakefile +1 -1
- data/examples/activerecord_model.rb +13 -13
- data/examples/arguments.rb +2 -2
- data/examples/block_context.rb +5 -5
- data/examples/blocks.rb +4 -4
- data/examples/chain.rb +14 -14
- data/examples/listener.rb +4 -4
- data/lib/signal/listener.rb +0 -1
- data/lib/signal/version.rb +1 -1
- data/lib/signal.rb +8 -3
- data/signal.gemspec +11 -11
- data/spec/signal/activerecord_spec.rb +132 -0
- data/spec/signal/listener_spec.rb +8 -0
- data/spec/signal/signal_spec.rb +108 -0
- data/spec/spec_helper.rb +12 -9
- metadata +35 -18
- data/Gemfile.lock +0 -51
- data/spec/activerecord_spec.rb +0 -132
- data/spec/signal_spec.rb +0 -105
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 203af304645a2f533a88161c89f11d777dfbdad5
|
4
|
+
data.tar.gz: 825a4bf9ac000f1f9625b1fcbac09bacb1ac8399
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3192bbb4d53667ae7c9acc5af81f34942f9a3ae23ec91f3913d86ce9c6739020446c84ad1f694192e981ec58e4c1a94763ba7b47df65c14824863e56d9772a39
|
7
|
+
data.tar.gz: 39d8e3725e312e8760684f3d4f93c3963b1caf3a1a81ac663f02855d16ded90eeb4797baf578a96eff9bdd23a4cc15c3aaa80ed86a422c6d44462e286464f9c7
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
sudo: false
|
4
|
+
script: bundle exec rspec
|
5
|
+
rvm:
|
6
|
+
- '2.2'
|
7
|
+
- '2.1'
|
8
|
+
- '2.0'
|
9
|
+
addons:
|
10
|
+
code_climate:
|
11
|
+
repo_token:
|
12
|
+
secure: "ASogQTLS/xYYczRtFwuo8DIkNdOl16mez4GHOw4RtdfTQ4BMROxE/CUemdPulMW1b/p7jsp5ghOtH2EJ4jN203s83HN4QjGC2wXhigkk6LzvxqjkmHxIWxJi2JS2sLq8nzOCcD0geO1pcbBFyuAzAdlwWa2g1WDP7O0L0fNjCtM="
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
gemspec
|
data/README.md
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
# Signal
|
2
2
|
|
3
|
+
[](https://travis-ci.org/fnando/signal)
|
4
|
+
[](https://codeclimate.com/github/fnando/signal)
|
5
|
+
[](https://codeclimate.com/github/fnando/signal)
|
6
|
+
|
3
7
|
A simple observer implementation on POROs (Plain Old Ruby Object) and ActiveRecord objects.
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
7
11
|
Add this line to your application's Gemfile:
|
8
12
|
|
9
|
-
|
13
|
+
```ruby
|
14
|
+
gem 'signal'
|
15
|
+
```
|
10
16
|
|
11
17
|
And then execute:
|
12
18
|
|
@@ -60,15 +66,15 @@ class MyListener
|
|
60
66
|
end
|
61
67
|
end
|
62
68
|
|
63
|
-
|
64
|
-
|
65
|
-
|
69
|
+
Status.new
|
70
|
+
.add_listener(MyListener.new)
|
71
|
+
.ready!
|
66
72
|
#=> Before the ready event!
|
67
73
|
#=> I'm ready!
|
68
74
|
#=> After the ready event!
|
69
75
|
```
|
70
76
|
|
71
|
-
|
77
|
+
Executed blocks don't switch context. You always have to emit the object you're interested in. The follow example uses `emit(:output, self)` to send the `Contact` instance to all listeners.
|
72
78
|
|
73
79
|
```ruby
|
74
80
|
class Contact
|
@@ -81,12 +87,12 @@ class Contact
|
|
81
87
|
end
|
82
88
|
|
83
89
|
def output!
|
84
|
-
emit(:output)
|
90
|
+
emit(:output, self)
|
85
91
|
end
|
86
92
|
end
|
87
93
|
|
88
|
-
contact = Contact.new(
|
89
|
-
contact.on(:output) { puts name, email }
|
94
|
+
contact = Contact.new('John Doe', 'john@example.org')
|
95
|
+
contact.on(:output) {|contact| puts contact.name, contact.email }
|
90
96
|
contact.output!
|
91
97
|
#=> John Doe
|
92
98
|
#=> john@example.org
|
@@ -105,10 +111,10 @@ class MyListener
|
|
105
111
|
end
|
106
112
|
end
|
107
113
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
114
|
+
Arguments.new
|
115
|
+
.on(:args) {|a, b| puts a, b }
|
116
|
+
.add_listener(MyListener.new)
|
117
|
+
.emit(:args, 1, 2)
|
112
118
|
```
|
113
119
|
|
114
120
|
### ActiveRecord
|
@@ -158,6 +164,21 @@ These are the available events:
|
|
158
164
|
* `on(:validation)`: triggered when record is invalid.
|
159
165
|
* `after(:validation)`: triggered after validating record.
|
160
166
|
|
167
|
+
### Inside Rails
|
168
|
+
|
169
|
+
Although there's no special code for Rails, here's just an example of how you can use it:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class UsersController < ApplicationController
|
173
|
+
def create
|
174
|
+
@user = User.new(user_params)
|
175
|
+
Signup.new(@user)
|
176
|
+
.on(:success) { redirect_to login_path, notice: 'Welcome to MyApp!' }
|
177
|
+
.on(:failure) { render :new }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
161
182
|
## Contributing
|
162
183
|
|
163
184
|
1. Fork it
|
@@ -165,3 +186,28 @@ These are the available events:
|
|
165
186
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
166
187
|
4. Push to the branch (`git push origin my-new-feature`)
|
167
188
|
5. Create new Pull Request
|
189
|
+
|
190
|
+
## License
|
191
|
+
|
192
|
+
Copyright (c) 2013-2015 Nando Vieira
|
193
|
+
|
194
|
+
MIT License
|
195
|
+
|
196
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
197
|
+
a copy of this software and associated documentation files (the
|
198
|
+
"Software"), to deal in the Software without restriction, including
|
199
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
200
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
201
|
+
permit persons to whom the Software is furnished to do so, subject to
|
202
|
+
the following conditions:
|
203
|
+
|
204
|
+
The above copyright notice and this permission notice shall be
|
205
|
+
included in all copies or substantial portions of the Software.
|
206
|
+
|
207
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
208
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
209
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
210
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
211
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
212
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
213
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -1,16 +1,16 @@
|
|
1
|
-
$:.unshift File.expand_path(
|
2
|
-
require
|
3
|
-
require
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'signal'
|
3
|
+
require 'active_record'
|
4
4
|
|
5
5
|
ActiveRecord::Base.establish_connection({
|
6
|
-
:adapter =>
|
7
|
-
:database =>
|
6
|
+
:adapter => 'sqlite3',
|
7
|
+
:database => ':memory:'
|
8
8
|
})
|
9
9
|
|
10
10
|
ActiveRecord::Schema.define(:version => 0) do
|
11
11
|
create_table :things do |t|
|
12
12
|
t.string :name
|
13
|
-
t.timestamps
|
13
|
+
t.timestamps null: false
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -20,22 +20,22 @@ class Thing < ActiveRecord::Base
|
|
20
20
|
validates_presence_of :name
|
21
21
|
end
|
22
22
|
|
23
|
-
thing = Thing.new(:name =>
|
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 }
|
23
|
+
thing = Thing.new(:name => 'Stuff')
|
24
|
+
thing.on(:create) {|model| puts model.updated_at, model.name }
|
25
|
+
thing.on(:update) {|model| puts model.updated_at, model.name }
|
26
|
+
thing.on(:remove) {|model| puts model.destroyed? }
|
27
|
+
thing.on(:validation) {|model| p model.errors.full_messages }
|
28
28
|
|
29
29
|
thing.save!
|
30
30
|
#=> 2013-01-26 10:32:39 -0200
|
31
31
|
#=> Stuff
|
32
32
|
|
33
|
-
thing.update_attributes(:name =>
|
33
|
+
thing.update_attributes(:name => 'Updated stuff')
|
34
34
|
#=> 2013-01-26 10:33:11 -0200
|
35
35
|
#=> Updated stuff
|
36
36
|
|
37
37
|
thing.update_attributes(:name => nil)
|
38
|
-
#=> [
|
38
|
+
#=> ['Name can't be blank']
|
39
39
|
|
40
40
|
thing.destroy
|
41
41
|
#=> true
|
data/examples/arguments.rb
CHANGED
data/examples/block_context.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
$:.unshift File.expand_path(
|
2
|
-
require
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'signal'
|
3
3
|
|
4
4
|
class Contact
|
5
5
|
include Signal
|
@@ -11,10 +11,10 @@ class Contact
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def output!
|
14
|
-
emit(:output)
|
14
|
+
emit(:output, self)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
contact = Contact.new(
|
19
|
-
contact.on(:output) { puts name, email }
|
18
|
+
contact = Contact.new('John Doe', 'john@example.org')
|
19
|
+
contact.on(:output) {|contact| puts contact.name, contact.email }
|
20
20
|
contact.output!
|
data/examples/blocks.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
$:.unshift File.expand_path(
|
2
|
-
require
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'signal'
|
3
3
|
|
4
4
|
class Status
|
5
5
|
include Signal
|
@@ -10,7 +10,7 @@ class Status
|
|
10
10
|
end
|
11
11
|
|
12
12
|
status = Status.new
|
13
|
-
status.before(:ready) { puts
|
13
|
+
status.before(:ready) { puts 'Before the ready event!' }
|
14
14
|
status.on(:ready) { puts "I'm ready!" }
|
15
|
-
status.after(:ready) { puts
|
15
|
+
status.after(:ready) { puts 'After the ready event!' }
|
16
16
|
status.ready!
|
data/examples/chain.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
$:.unshift File.expand_path(
|
2
|
-
require
|
3
|
-
require
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'signal'
|
3
|
+
require 'active_record'
|
4
4
|
|
5
5
|
ActiveRecord::Base.establish_connection({
|
6
|
-
:adapter =>
|
7
|
-
:database =>
|
6
|
+
:adapter => 'sqlite3',
|
7
|
+
:database => ':memory:'
|
8
8
|
})
|
9
9
|
|
10
10
|
ActiveRecord::Schema.define(:version => 0) do
|
11
11
|
create_table :things do |t|
|
12
12
|
t.string :name
|
13
|
-
t.timestamps
|
13
|
+
t.timestamps null: false
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -23,15 +23,15 @@ end
|
|
23
23
|
class MyListener
|
24
24
|
[:validation, :update, :create, :remove].each do |type|
|
25
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
|
26
|
+
def before_#{type}(thing); puts __method__; end
|
27
|
+
def on_#{type}(thing); puts __method__; end
|
28
|
+
def after_#{type}(thing); puts __method__; end
|
29
29
|
RUBY
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
puts "\n=== Creating valid record"
|
34
|
-
thing = Thing.new(:name =>
|
34
|
+
thing = Thing.new(:name => 'Stuff')
|
35
35
|
thing.listeners << MyListener.new
|
36
36
|
thing.save
|
37
37
|
|
@@ -41,16 +41,16 @@ thing.listeners << MyListener.new
|
|
41
41
|
thing.save
|
42
42
|
|
43
43
|
puts "\n=== Updating valid record"
|
44
|
-
thing = Thing.create(:name =>
|
44
|
+
thing = Thing.create(:name => 'Stuff')
|
45
45
|
thing.listeners << MyListener.new
|
46
|
-
thing.update_attributes(:name =>
|
46
|
+
thing.update_attributes(:name => 'Updated stuff')
|
47
47
|
|
48
48
|
puts "\n=== Updating invalid record"
|
49
|
-
thing = Thing.create!(:name =>
|
49
|
+
thing = Thing.create!(:name => 'Stuff')
|
50
50
|
thing.listeners << MyListener.new
|
51
51
|
thing.update_attributes(:name => nil)
|
52
52
|
|
53
53
|
puts "\n=== Removing record"
|
54
|
-
thing = Thing.create(:name =>
|
54
|
+
thing = Thing.create(:name => 'Stuff')
|
55
55
|
thing.listeners << MyListener.new
|
56
56
|
thing.destroy
|
data/examples/listener.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
$:.unshift File.expand_path(
|
2
|
-
require
|
1
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'signal'
|
3
3
|
|
4
4
|
class Status
|
5
5
|
include Signal
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
class MyListener
|
13
13
|
def before_ready
|
14
|
-
puts
|
14
|
+
puts 'Before the ready event!'
|
15
15
|
end
|
16
16
|
|
17
17
|
def on_ready
|
@@ -19,7 +19,7 @@ class MyListener
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def after_ready
|
22
|
-
puts
|
22
|
+
puts 'After the ready event!'
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
data/lib/signal/listener.rb
CHANGED
data/lib/signal/version.rb
CHANGED
data/lib/signal.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'signal/active_record'
|
2
|
+
require 'signal/listener'
|
3
|
+
require 'signal/version'
|
4
4
|
|
5
5
|
module Signal
|
6
6
|
def on(event, &block)
|
@@ -18,6 +18,11 @@ module Signal
|
|
18
18
|
self
|
19
19
|
end
|
20
20
|
|
21
|
+
def add_listener(listener)
|
22
|
+
listeners << listener
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
21
26
|
def emit(event, *args)
|
22
27
|
emit_signal(:before, event, *args)
|
23
28
|
emit_signal(:on, event, *args)
|
data/signal.gemspec
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
|
2
|
-
require "./lib/signal/version"
|
1
|
+
require './lib/signal/version'
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
5
|
-
gem.name =
|
4
|
+
gem.name = 'signal'
|
6
5
|
gem.version = Signal::VERSION
|
7
|
-
gem.authors = [
|
8
|
-
gem.email = [
|
9
|
-
gem.description =
|
6
|
+
gem.authors = ['Nando Vieira']
|
7
|
+
gem.email = ['fnando.vieira@gmail.com']
|
8
|
+
gem.description = 'A simple observer implementation for POROs (Plain Old Ruby Object) and ActiveRecord objects.'
|
10
9
|
gem.summary = gem.description
|
11
|
-
gem.homepage =
|
10
|
+
gem.homepage = 'http://github.com/fnando/signal'
|
12
11
|
|
13
12
|
gem.files = `git ls-files`.split($/)
|
14
13
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
14
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
-
gem.require_paths = [
|
15
|
+
gem.require_paths = ['lib']
|
17
16
|
|
18
|
-
gem.add_development_dependency
|
19
|
-
gem.add_development_dependency
|
20
|
-
gem.add_development_dependency
|
17
|
+
gem.add_development_dependency 'activerecord'
|
18
|
+
gem.add_development_dependency 'sqlite3'
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_development_dependency 'codeclimate-test-reporter'
|
21
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
|
+
expect(callable).to receive(:called).with(user)
|
11
|
+
user.save!
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'triggers event' do
|
15
|
+
user.on(:create, &callable)
|
16
|
+
expect(callable).to receive(:called).with(user)
|
17
|
+
user.save!
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'triggers after event' do
|
21
|
+
user.after(:create, &callable)
|
22
|
+
expect(callable).to receive(:called).with(user)
|
23
|
+
user.save!
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'does not 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
|
+
expect(on_callable).not_to receive(:called)
|
37
|
+
expect(after_callable).not_to 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
|
+
expect(callable).to receive(:called).with(user)
|
47
|
+
user.save!
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'triggers after event' do
|
51
|
+
user.after(:validation, &callable)
|
52
|
+
expect(callable).to 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
|
+
expect(callable).to 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
|
+
expect(callable).not_to 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
|
+
expect(callable).to 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
|
+
expect(callable).to 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
|
+
expect(callable).to receive(:called).with(user)
|
88
|
+
user.update_attributes!(:username => 'johnd')
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'does not 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
|
+
expect(on_callable).not_to receive(:called)
|
102
|
+
expect(after_callable).not_to 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
|
+
expect(callable).to receive(:called).with(user)
|
114
|
+
|
115
|
+
user.destroy
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'triggers on event' do
|
119
|
+
user.on(:remove, &callable)
|
120
|
+
expect(callable).to receive(:called).with(user)
|
121
|
+
|
122
|
+
user.destroy
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'triggers after event' do
|
126
|
+
user.after(:remove, &callable)
|
127
|
+
expect(callable).to receive(:called).with(user)
|
128
|
+
|
129
|
+
user.destroy
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Signal do
|
4
|
+
let(:observable) { Observable.new }
|
5
|
+
let(:callable) { Callable.new }
|
6
|
+
|
7
|
+
context 'add listener' do
|
8
|
+
it 'runs listener' do
|
9
|
+
callable.respond_to(:on_ready)
|
10
|
+
observable.add_listener(callable)
|
11
|
+
expect(callable).to receive(:called).with(no_args)
|
12
|
+
|
13
|
+
observable.emit(:ready)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns itself' do
|
17
|
+
expect(observable.add_listener(callable)).to eq(observable)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'using blocks' do
|
22
|
+
it 'triggers event' do
|
23
|
+
observable.on(:ready, &callable)
|
24
|
+
expect(callable).to receive(:called).with(no_args)
|
25
|
+
|
26
|
+
observable.emit(:ready)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'triggers event with arguments' do
|
30
|
+
observable.on(:ready, &callable)
|
31
|
+
expect(callable).to receive(:called).with(1, 2, 3)
|
32
|
+
|
33
|
+
observable.emit(:ready, 1, 2, 3)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'triggers before event' do
|
37
|
+
observable.before(:ready, &callable)
|
38
|
+
expect(callable).to receive(:called).with(no_args)
|
39
|
+
|
40
|
+
observable.emit(:ready)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'triggers before event with arguments' do
|
44
|
+
observable.before(:ready, &callable)
|
45
|
+
expect(callable).to receive(:called).with(1, 2, 3)
|
46
|
+
|
47
|
+
observable.emit(:ready, 1, 2, 3)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'triggers after event' do
|
51
|
+
observable.after(:ready, &callable)
|
52
|
+
expect(callable).to receive(:called).with(no_args)
|
53
|
+
|
54
|
+
observable.emit(:ready)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'triggers after event with arguments' do
|
58
|
+
observable.after(:ready, &callable)
|
59
|
+
expect(callable).to receive(:called).with(1, 2, 3)
|
60
|
+
|
61
|
+
observable.emit(:ready, 1, 2, 3)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'chains events' do
|
65
|
+
before_callable = Callable.new
|
66
|
+
on_callable = Callable.new
|
67
|
+
after_callable = Callable.new
|
68
|
+
|
69
|
+
observable
|
70
|
+
.before(:ready, &before_callable)
|
71
|
+
.on(:ready, &on_callable)
|
72
|
+
.after(:ready, &after_callable)
|
73
|
+
|
74
|
+
expect(before_callable).to receive(:called).with(no_args).ordered
|
75
|
+
expect(on_callable).to receive(:called).with(no_args).ordered
|
76
|
+
expect(after_callable).to receive(:called).with(no_args).ordered
|
77
|
+
|
78
|
+
observable.emit(:ready)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'keeps context' do
|
82
|
+
context = nil
|
83
|
+
callable = -> { context = self }
|
84
|
+
observable.on(:ready, &callable)
|
85
|
+
observable.emit(:ready)
|
86
|
+
|
87
|
+
expect(context).to eql(self)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'using listeners' do
|
92
|
+
it 'triggers event for listener' do
|
93
|
+
callable.respond_to(:on_ready)
|
94
|
+
observable.listeners << callable
|
95
|
+
expect(callable).to receive(:called).with(no_args)
|
96
|
+
|
97
|
+
observable.emit(:ready)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'triggers event for listener with arguments' do
|
101
|
+
callable.respond_to(:on_ready)
|
102
|
+
observable.listeners << callable
|
103
|
+
expect(callable).to receive(:called).with(1, 2, 3)
|
104
|
+
|
105
|
+
observable.emit(:ready, 1, 2, 3)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
require
|
2
|
-
|
1
|
+
require 'codeclimate-test-reporter'
|
2
|
+
CodeClimate::TestReporter.start
|
3
3
|
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'active_record'
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
require
|
9
|
-
require
|
7
|
+
I18n.enforce_available_locales = false
|
8
|
+
|
9
|
+
require 'signal'
|
10
|
+
require 'support/observable'
|
11
|
+
require 'support/callable'
|
12
|
+
require 'support/user'
|
10
13
|
|
11
14
|
ActiveRecord::Base.establish_connection({
|
12
|
-
:adapter =>
|
13
|
-
:database =>
|
15
|
+
:adapter => 'sqlite3',
|
16
|
+
:database => ':memory:'
|
14
17
|
})
|
15
18
|
|
16
19
|
ActiveRecord::Schema.define(:version => 0) do
|
metadata
CHANGED
@@ -1,55 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: signal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nando Vieira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sqlite3
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: codeclimate-test-reporter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
69
|
description: A simple observer implementation for POROs (Plain Old Ruby Object) and
|
@@ -60,10 +74,10 @@ executables: []
|
|
60
74
|
extensions: []
|
61
75
|
extra_rdoc_files: []
|
62
76
|
files:
|
63
|
-
- .gitignore
|
64
|
-
- .rspec
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
65
80
|
- Gemfile
|
66
|
-
- Gemfile.lock
|
67
81
|
- LICENSE.txt
|
68
82
|
- README.md
|
69
83
|
- Rakefile
|
@@ -78,8 +92,9 @@ files:
|
|
78
92
|
- lib/signal/listener.rb
|
79
93
|
- lib/signal/version.rb
|
80
94
|
- signal.gemspec
|
81
|
-
- spec/activerecord_spec.rb
|
82
|
-
- spec/
|
95
|
+
- spec/signal/activerecord_spec.rb
|
96
|
+
- spec/signal/listener_spec.rb
|
97
|
+
- spec/signal/signal_spec.rb
|
83
98
|
- spec/spec_helper.rb
|
84
99
|
- spec/support/callable.rb
|
85
100
|
- spec/support/observable.rb
|
@@ -93,25 +108,27 @@ require_paths:
|
|
93
108
|
- lib
|
94
109
|
required_ruby_version: !ruby/object:Gem::Requirement
|
95
110
|
requirements:
|
96
|
-
- -
|
111
|
+
- - ">="
|
97
112
|
- !ruby/object:Gem::Version
|
98
113
|
version: '0'
|
99
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
115
|
requirements:
|
101
|
-
- -
|
116
|
+
- - ">="
|
102
117
|
- !ruby/object:Gem::Version
|
103
118
|
version: '0'
|
104
119
|
requirements: []
|
105
120
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
121
|
+
rubygems_version: 2.4.5.1
|
107
122
|
signing_key:
|
108
123
|
specification_version: 4
|
109
124
|
summary: A simple observer implementation for POROs (Plain Old Ruby Object) and ActiveRecord
|
110
125
|
objects.
|
111
126
|
test_files:
|
112
|
-
- spec/activerecord_spec.rb
|
113
|
-
- spec/
|
127
|
+
- spec/signal/activerecord_spec.rb
|
128
|
+
- spec/signal/listener_spec.rb
|
129
|
+
- spec/signal/signal_spec.rb
|
114
130
|
- spec/spec_helper.rb
|
115
131
|
- spec/support/callable.rb
|
116
132
|
- spec/support/observable.rb
|
117
133
|
- spec/support/user.rb
|
134
|
+
has_rdoc:
|
data/Gemfile.lock
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
signal (0.1.1)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: http://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (4.0.0)
|
10
|
-
activesupport (= 4.0.0)
|
11
|
-
builder (~> 3.1.0)
|
12
|
-
activerecord (4.0.0)
|
13
|
-
activemodel (= 4.0.0)
|
14
|
-
activerecord-deprecated_finders (~> 1.0.2)
|
15
|
-
activesupport (= 4.0.0)
|
16
|
-
arel (~> 4.0.0)
|
17
|
-
activerecord-deprecated_finders (1.0.3)
|
18
|
-
activesupport (4.0.0)
|
19
|
-
i18n (~> 0.6, >= 0.6.4)
|
20
|
-
minitest (~> 4.2)
|
21
|
-
multi_json (~> 1.3)
|
22
|
-
thread_safe (~> 0.1)
|
23
|
-
tzinfo (~> 0.3.37)
|
24
|
-
arel (4.0.0)
|
25
|
-
atomic (1.1.10)
|
26
|
-
builder (3.1.4)
|
27
|
-
diff-lcs (1.2.4)
|
28
|
-
i18n (0.6.4)
|
29
|
-
minitest (4.7.5)
|
30
|
-
multi_json (1.7.7)
|
31
|
-
rspec (2.14.1)
|
32
|
-
rspec-core (~> 2.14.0)
|
33
|
-
rspec-expectations (~> 2.14.0)
|
34
|
-
rspec-mocks (~> 2.14.0)
|
35
|
-
rspec-core (2.14.3)
|
36
|
-
rspec-expectations (2.14.0)
|
37
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
38
|
-
rspec-mocks (2.14.1)
|
39
|
-
sqlite3 (1.3.7)
|
40
|
-
thread_safe (0.1.0)
|
41
|
-
atomic
|
42
|
-
tzinfo (0.3.37)
|
43
|
-
|
44
|
-
PLATFORMS
|
45
|
-
ruby
|
46
|
-
|
47
|
-
DEPENDENCIES
|
48
|
-
activerecord
|
49
|
-
rspec
|
50
|
-
signal!
|
51
|
-
sqlite3
|
data/spec/activerecord_spec.rb
DELETED
@@ -1,132 +0,0 @@
|
|
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
|
data/spec/signal_spec.rb
DELETED
@@ -1,105 +0,0 @@
|
|
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(no_args)
|
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(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(no_args)
|
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(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(no_args)
|
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(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
|
61
|
-
.should_receive(:called)
|
62
|
-
.with(no_args)
|
63
|
-
.ordered
|
64
|
-
|
65
|
-
on_callable
|
66
|
-
.should_receive(:called)
|
67
|
-
.with(no_args)
|
68
|
-
.ordered
|
69
|
-
|
70
|
-
after_callable
|
71
|
-
.should_receive(:called)
|
72
|
-
.with(no_args)
|
73
|
-
.ordered
|
74
|
-
|
75
|
-
observable.emit(:ready)
|
76
|
-
end
|
77
|
-
|
78
|
-
it "keeps context" do
|
79
|
-
context = nil
|
80
|
-
callable = -> { context = self }
|
81
|
-
observable.on(:ready, &callable)
|
82
|
-
observable.emit(:ready)
|
83
|
-
|
84
|
-
expect(context).to eql(self)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context "using listeners" do
|
89
|
-
it "triggers event for listener" do
|
90
|
-
callable.respond_to(:on_ready)
|
91
|
-
observable.listeners << callable
|
92
|
-
callable.should_receive(:called).with(no_args)
|
93
|
-
|
94
|
-
observable.emit(:ready)
|
95
|
-
end
|
96
|
-
|
97
|
-
it "triggers event for listener with arguments" do
|
98
|
-
callable.respond_to(:on_ready)
|
99
|
-
observable.listeners << callable
|
100
|
-
callable.should_receive(:called).with(1, 2, 3)
|
101
|
-
|
102
|
-
observable.emit(:ready, 1, 2, 3)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|