on_event 0.0.1
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +81 -0
- data/Rakefile +11 -0
- data/lib/on_event/version.rb +3 -0
- data/lib/on_event.rb +72 -0
- data/on_event.gemspec +16 -0
- data/test/test_on_event.rb +73 -0
- metadata +76 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Brendon Murphy
|
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,81 @@
|
|
1
|
+
# OnEvent
|
2
|
+
|
3
|
+
Build callback chains for named events.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'on_event'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install on_event
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# Regular Style:
|
23
|
+
on_event = OnEvent.new(:success, :failure)
|
24
|
+
on_event.on_success { |a| a << "A success" }
|
25
|
+
on_event.on_failure { |a| a << "A failure" }
|
26
|
+
|
27
|
+
# Block Style:
|
28
|
+
on_event = OnEvent.new(:foo, :bar) do |oe|
|
29
|
+
oe.on_foo { |a| a << "foo" }
|
30
|
+
oe.on_bar { |a| a << "bar" }
|
31
|
+
end
|
32
|
+
|
33
|
+
a = []
|
34
|
+
on_event.foo(a)
|
35
|
+
a # => ["foo",]
|
36
|
+
on_event.bar(a)
|
37
|
+
a # => ["foo", "bar"]
|
38
|
+
```
|
39
|
+
|
40
|
+
## Why is this useful?
|
41
|
+
|
42
|
+
You could just put event calls inline in a code block to get a similar effect.
|
43
|
+
However, in the case you want a repeatable and reusable chain of events with
|
44
|
+
shared rescue handling for firing, then this pattern helps.
|
45
|
+
|
46
|
+
An example might be you are tracking multiple metric statistics in Rails controller
|
47
|
+
actions (or via filters). Perhaps the metrics are important, but in the case of a
|
48
|
+
new user signup, not so important that you should fail the action should any of the
|
49
|
+
metrics tracking or other notifications fail.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
on_event = OnEvent.new(:signup_success) do |oe|
|
53
|
+
oe.on_signup_success do |new_user|
|
54
|
+
Mailer.notify_admins(new_user)
|
55
|
+
end
|
56
|
+
|
57
|
+
oe.on_signup_success do |new_user|
|
58
|
+
Metrics.increment(new_user)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
If the admin doesn't get the email that somebody signed up, or Redis is unreachable and
|
64
|
+
your metrics are temporarily unavailable, your user still signs up.
|
65
|
+
|
66
|
+
By overriding the `#rescue_handler` in your `OnEvent` class, you can get shared exception
|
67
|
+
handling should any callback fail. This could be as simple as call to `Rails.logger.error`,
|
68
|
+
or triggering Airbrake but still swallowing the exception.
|
69
|
+
|
70
|
+
Often these callbacks are packaged into lifecycle on a model; however, it is sometimes
|
71
|
+
the case where you only want them firing in the specific context of a controller. For
|
72
|
+
instance, if I create a user on the console, I don't need to receive a mail message
|
73
|
+
about it.
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it
|
78
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/on_event.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "on_event/version"
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
class OnEvent
|
5
|
+
def initialize(*events)
|
6
|
+
establish_events(*events)
|
7
|
+
yield self if block_given?
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# This defines an #event_name and #on_event_name method for
|
12
|
+
# each given event. #on_event_name takes a block stored
|
13
|
+
# as a callback, which is passed the args from corresponding
|
14
|
+
# calls to #event_name
|
15
|
+
#
|
16
|
+
# # Regular Style:
|
17
|
+
# on_event = OnEvent.new(:success, :failure)
|
18
|
+
# on_event.on_success { |a| a << "A success" }
|
19
|
+
# on_event.on_failure { |a| a << "A failure" }
|
20
|
+
#
|
21
|
+
# # Block Style:
|
22
|
+
# on_event = OnEvent.new(:foo, :bar) do |oe|
|
23
|
+
# oe.on_foo { |a| a << "foo" }
|
24
|
+
# oe.on_bar { |a| a << "bar" }
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# a = []
|
28
|
+
# on_event.foo(a)
|
29
|
+
# a # => ["foo",]
|
30
|
+
# on_event.bar(a)
|
31
|
+
# a # => ["foo", "bar"]
|
32
|
+
#
|
33
|
+
def establish_events(*events)
|
34
|
+
(class << self; self; end).instance_eval do
|
35
|
+
Array(events).each do |event_name|
|
36
|
+
define_method "on_#{event_name}" do |&block|
|
37
|
+
event_blocks[event_name.to_sym] << block
|
38
|
+
end
|
39
|
+
|
40
|
+
define_method event_name do |*args|
|
41
|
+
event_blocks[event_name.to_sym].each do |block|
|
42
|
+
with_rescue { block.call *args }
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
alias :establish_event :establish_events
|
50
|
+
|
51
|
+
def logger
|
52
|
+
@logger ||= Logger.new(STDERR)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def event_blocks
|
58
|
+
@event_blocks ||= Hash.new {|h, k| h[k] = []}
|
59
|
+
end
|
60
|
+
|
61
|
+
def with_rescue
|
62
|
+
begin
|
63
|
+
yield
|
64
|
+
rescue => e
|
65
|
+
rescue_handler(e)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def rescue_handler(exception)
|
70
|
+
logger.error exception.message
|
71
|
+
end
|
72
|
+
end
|
data/on_event.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/on_event/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Brendon Murphy"]
|
6
|
+
gem.email = ["xternal1+github@gmail.com"]
|
7
|
+
gem.description = %q{Build callback chains for named events.}
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
|
+
gem.name = "on_event"
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
gem.version = OnEvent::VERSION
|
16
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require File.expand_path("../../lib/on_event", __FILE__)
|
3
|
+
|
4
|
+
class TestOnEvent < Test::Unit::TestCase
|
5
|
+
def test_setup_with_no_block
|
6
|
+
subject = OnEvent.new(:foo, :bar)
|
7
|
+
assert subject.respond_to?(:on_foo)
|
8
|
+
assert subject.respond_to?(:foo)
|
9
|
+
assert subject.respond_to?(:on_bar)
|
10
|
+
assert subject.respond_to?(:bar)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_adding_event_callbacks
|
14
|
+
subject = OnEvent.new(:foo, :bar)
|
15
|
+
subject.on_foo { |a| a << "f1" }
|
16
|
+
subject.on_bar { |a| a << "b1" }
|
17
|
+
subject.on_foo { |a| a << "f2" }
|
18
|
+
subject.on_bar { |a| a << "b2" }
|
19
|
+
a = []
|
20
|
+
subject.foo(a)
|
21
|
+
subject.bar(a)
|
22
|
+
assert_equal %w[f1 f2 b1 b2], a
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_callback_events_returns_true
|
26
|
+
subject = OnEvent.new(:foo)
|
27
|
+
subject.on_foo { "f1" }
|
28
|
+
assert_instance_of TrueClass, subject.foo()
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_adding_establish_event_alias
|
32
|
+
subject = OnEvent.new
|
33
|
+
subject.establish_event(:foo)
|
34
|
+
assert subject.respond_to?(:on_foo)
|
35
|
+
assert subject.respond_to?(:foo)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_setup_with_block
|
39
|
+
subject = OnEvent.new(:foo, :bar) do |oe|
|
40
|
+
oe.on_foo { |a| a << "foo" }
|
41
|
+
oe.on_bar { |a| a << "bar" }
|
42
|
+
end
|
43
|
+
a = []
|
44
|
+
subject.foo(a)
|
45
|
+
subject.bar(a)
|
46
|
+
assert_equal %w[foo bar], a
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_rescue_handler
|
50
|
+
subject = OnEvent.new(:foo, :bar) do |oe|
|
51
|
+
oe.on_foo { |a| a << "foo" }
|
52
|
+
oe.on_bar { |a| a << oops_missing }
|
53
|
+
oe.on_bar { |a| a << oops_another }
|
54
|
+
end
|
55
|
+
|
56
|
+
$handledExceptions = []
|
57
|
+
def subject.rescue_handler(exception)
|
58
|
+
$handledExceptions << exception.message
|
59
|
+
end
|
60
|
+
|
61
|
+
a = []
|
62
|
+
subject.foo(a)
|
63
|
+
subject.bar(a)
|
64
|
+
assert_equal ["foo"], a
|
65
|
+
assert_match /oops_missing/, $handledExceptions[0]
|
66
|
+
assert_match /oops_another/, $handledExceptions[1]
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_logger
|
70
|
+
subject = OnEvent.new
|
71
|
+
assert_kind_of Logger, subject.logger
|
72
|
+
end
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: on_event
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Brendon Murphy
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-08-12 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Build callback chains for named events.
|
23
|
+
email:
|
24
|
+
- xternal1+github@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- lib/on_event.rb
|
38
|
+
- lib/on_event/version.rb
|
39
|
+
- on_event.gemspec
|
40
|
+
- test/test_on_event.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: ""
|
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: Build callback chains for named events.
|
75
|
+
test_files:
|
76
|
+
- test/test_on_event.rb
|