has-guarded-handlers 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ spec/reports
7
+ .yardoc
8
+ doc
9
+ .*.swp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --colour
3
+ --tty
@@ -0,0 +1,2 @@
1
+ # 0.0.1
2
+ * Feature: Some code that works!
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in has-guarded-handlers.gemspec
4
+ gemspec
5
+
6
+ if RUBY_PLATFORM =~ /darwin/
7
+ gem 'growl_notify'
8
+ gem 'rb-fsevent'
9
+ end
@@ -0,0 +1,5 @@
1
+ guard 'rspec', :version => 2, :cli => '--format documentation' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec/" }
5
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Ben Langfeld, Jeff Smick
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # HasGuardedHandlers
2
+ HasGuardedHandlers allows an object's API to provide flexible handler registration, storage and matching to arbitrary events.
3
+
4
+ ## Installation
5
+ gem install has-guarded-handlers
6
+
7
+ ## Usage
8
+
9
+ ```ruby
10
+ require 'has_guarded_handlers'
11
+
12
+ class A
13
+ include HasGuardedHandlers
14
+
15
+ def receive_event(event)
16
+ trigger_handler :event, event
17
+ end
18
+ end
19
+
20
+ a = A.new
21
+ a.register_handler :event, :type => :foo do
22
+ puts "Handled the event"
23
+ end
24
+
25
+ class Event
26
+ attr_accessor :type
27
+ end
28
+
29
+ event = Event.new.tap { |e| e.type = :foo }
30
+ a.receive_event event
31
+ ```
32
+
33
+ ## Links:
34
+ * [Source](https://github.com/adhearsion/has-guarded-handlers)
35
+ * [Documentation](http://rdoc.info/github/adhearsion/has-guarded-handlers/master/frames)
36
+ * [Bug Tracker](https://github.com/adhearsion/has-guarded-handlers/issues)
37
+
38
+ ## Note on Patches/Pull Requests
39
+
40
+ * Fork the project.
41
+ * Make your feature addition or bug fix.
42
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
43
+ * Commit, do not mess with rakefile, version, or history.
44
+ * If you want to have your own version, that is fine but bump version in a commit by itself so I can ignore when I pull
45
+ * Send me a pull request. Bonus points for topic branches.
46
+
47
+ ## Copyright
48
+
49
+ Copyright (c) 2011 Ben Langfeld, Jeff Smick. MIT licence (see LICENSE for details).
@@ -0,0 +1,22 @@
1
+ require 'bundler/gem_tasks'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+ require 'ci/reporter/rake/rspec'
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = 'spec/**/*_spec.rb'
9
+ spec.rspec_opts = '--color'
10
+ end
11
+
12
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
13
+ spec.pattern = 'spec/**/*_spec.rb'
14
+ spec.rcov = true
15
+ spec.rspec_opts = '--color'
16
+ end
17
+
18
+ task :default => :spec
19
+ task :ci => ['ci:setup:rspec', :spec]
20
+
21
+ require 'yard'
22
+ YARD::Rake::YardocTask.new
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "has_guarded_handlers/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "has-guarded-handlers"
7
+ s.version = HasGuardedHandlers::VERSION
8
+ s.authors = ["Ben Langfeld", "Jeff Smick"]
9
+ s.email = ["ben@langfeld.me"]
10
+ s.homepage = "http://github.com/adhearsion/has-guarded-handlers"
11
+ s.summary = %q{A library for associating a set of event handlers, complete with guards, with a Ruby object}
12
+ s.description = %q{Allow an object's API to provide flexible handler registration, storage and matching to arbitrary events.}
13
+
14
+ s.rubyforge_project = "has-guarded-handlers"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency 'bundler', ["~> 1.0.0"]
22
+ s.add_development_dependency 'rspec', [">= 2.5.0"]
23
+ s.add_development_dependency 'mocha', [">= 0"]
24
+ s.add_development_dependency 'ci_reporter', [">= 1.6.3"]
25
+ s.add_development_dependency 'yard', ["~> 0.7.0"]
26
+ s.add_development_dependency 'rake', [">= 0"]
27
+ s.add_development_dependency 'guard-rspec'
28
+ end
@@ -0,0 +1,86 @@
1
+ require "has_guarded_handlers/version"
2
+
3
+ module HasGuardedHandlers
4
+ def initialize(*args)
5
+ @handlers = {}
6
+ end
7
+
8
+ # Register a handler
9
+ #
10
+ # @param [Symbol, nil] type set the filter on a specific handler
11
+ # @param [guards] guards take a look at the guards documentation
12
+ # @yield [Object] stanza the incoming event
13
+ def register_handler(type, *guards, &handler)
14
+ check_guards guards
15
+ @handlers[type] ||= []
16
+ @handlers[type] << [guards, handler]
17
+ end
18
+
19
+ # Clear handlers with given guards
20
+ #
21
+ # @param [Symbol, nil] type remove filters for a specific handler
22
+ # @param [guards] guards take a look at the guards documentation
23
+ def clear_handlers(type, *guards)
24
+ @handlers[type].delete_if { |g, _| g == guards }
25
+ end
26
+
27
+ def trigger_handler(type, event)
28
+ return unless handler = @handlers[type]
29
+ catch :halt do
30
+ handler.find do |guards, handler|
31
+ catch(:pass) { call_handler handler, guards, event }
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def call_handler(handler, guards, event)
39
+ handler.call event unless guarded?(guards, event)
40
+ end
41
+
42
+ # If any of the guards returns FALSE this returns true
43
+ # the logic is reversed to allow short circuiting
44
+ # (why would anyone want to loop over more values than necessary?)
45
+ #
46
+ # @private
47
+ def guarded?(guards, event)
48
+ guards.find do |guard|
49
+ case guard
50
+ when Symbol
51
+ !event.__send__ guard
52
+ when Array
53
+ # return FALSE if any item is TRUE
54
+ !guard.detect { |condition| !guarded? [condition], event }
55
+ when Hash
56
+ # return FALSE unless any inequality is found
57
+ guard.find do |method, test|
58
+ value = event.__send__(method)
59
+ # last_match is the only method found unique to Regexp classes
60
+ if test.class.respond_to?(:last_match)
61
+ !(test =~ value.to_s)
62
+ elsif test.is_a?(Array)
63
+ !test.include? value
64
+ else
65
+ test != value
66
+ end
67
+ end
68
+ when Proc
69
+ !guard.call event
70
+ end
71
+ end
72
+ end
73
+
74
+ def check_guards(guards)
75
+ guards.each do |guard|
76
+ case guard
77
+ when Array
78
+ guard.each { |g| check_guards [g] }
79
+ when Symbol, Proc, Hash, String
80
+ nil
81
+ else
82
+ raise "Bad guard: #{guard.inspect}"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ module HasGuardedHandlers
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ describe TestObject do
4
+ subject { TestObject.new :bar }
5
+
6
+ it { should be_a TestObject }
7
+ its(:foo) { should == :bar }
8
+
9
+ let(:event) { mock 'Event' }
10
+ let(:response) { mock 'Response' }
11
+
12
+ it 'can register a handler' do
13
+ response.expects(:call).twice.with(event)
14
+ subject.register_handler(:event) { |e| response.call e }
15
+ subject.trigger_handler :event, event
16
+ subject.trigger_handler :event, event
17
+ end
18
+
19
+ it 'allows for breaking out of handlers' do
20
+ response.expects(:handle).once
21
+ response.expects(:fail).never
22
+ subject.register_handler :event do |_|
23
+ response.handle
24
+ throw :halt
25
+ response.fail
26
+ end
27
+ subject.trigger_handler :event, event
28
+ end
29
+
30
+ it 'allows for passing to the next handler of the same type' do
31
+ response.expects(:handle1).once
32
+ response.expects(:handle2).once
33
+ response.expects(:fail).never
34
+ subject.register_handler :event do |_|
35
+ response.handle1
36
+ throw :pass
37
+ response.fail
38
+ end
39
+ subject.register_handler :event do |_|
40
+ response.handle2
41
+ end
42
+ subject.trigger_handler :event, event
43
+ end
44
+
45
+ it 'can clear handlers' do
46
+ response.expects(:call).once
47
+
48
+ subject.register_handler(:event) { |_| response.call }
49
+ subject.trigger_handler :event, event
50
+
51
+ subject.clear_handlers :event
52
+ subject.trigger_handler :event, event
53
+ end
54
+
55
+ describe 'guards' do
56
+ it 'can be a symbol' do
57
+ response.expects(:call).once
58
+ subject.register_handler(:event, :chat?) { |_| response.call }
59
+
60
+ event.expects(:chat?).returns true
61
+ subject.trigger_handler :event, event
62
+
63
+ event.expects(:chat?).returns false
64
+ subject.trigger_handler :event, event
65
+ end
66
+
67
+ it 'can be a hash with string match' do
68
+ response.expects(:call).once
69
+ subject.register_handler(:event, :body => 'exit') { |_| response.call }
70
+
71
+ event.expects(:body).returns 'exit'
72
+ subject.trigger_handler :event, event
73
+
74
+ event.expects(:body).returns 'not-exit'
75
+ subject.trigger_handler :event, event
76
+ end
77
+
78
+ it 'can be a hash with a value' do
79
+ response.expects(:call).once
80
+ subject.register_handler(:event, :number => 0) { |_| response.call }
81
+
82
+ event.expects(:number).returns 0
83
+ subject.trigger_handler :event, event
84
+
85
+ event.expects(:number).returns 1
86
+ subject.trigger_handler :event, event
87
+ end
88
+
89
+ it 'can be a hash with a regexp' do
90
+ response.expects(:call).once
91
+ subject.register_handler(:event, :body => /exit/) { |_| response.call }
92
+
93
+ event.expects(:body).returns 'more than just exit, but exit still'
94
+ subject.trigger_handler :event, event
95
+
96
+ event.expects(:body).returns 'keyword not found'
97
+ subject.trigger_handler :event, event
98
+
99
+ event.expects(:body).returns nil
100
+ subject.trigger_handler :event, event
101
+ end
102
+
103
+ it 'can be a hash with an array' do
104
+ response.expects(:call).twice
105
+ subject.register_handler(:event, :type => [:result, :error]) { |_| response.call }
106
+
107
+ event = mock 'Event'
108
+ event.expects(:type).at_least_once.returns :result
109
+ subject.trigger_handler :event, event
110
+
111
+ event = mock 'Event'
112
+ event.expects(:type).at_least_once.returns :error
113
+ subject.trigger_handler :event, event
114
+
115
+ event = mock 'Event'
116
+ event.expects(:type).at_least_once.returns :get
117
+ subject.trigger_handler :event, event
118
+ end
119
+
120
+ it 'chained are treated like andand (short circuited)' do
121
+ response.expects(:call).once
122
+ subject.register_handler(:event, :type => :get, :body => 'test') { |_| response.call }
123
+
124
+ event = mock 'Event'
125
+ event.expects(:type).at_least_once.returns :get
126
+ event.expects(:body).returns 'test'
127
+ subject.trigger_handler :event, event
128
+
129
+ event = mock 'Event'
130
+ event.expects(:type).at_least_once.returns :set
131
+ event.expects(:body).never
132
+ subject.trigger_handler :event, event
133
+ end
134
+
135
+ it 'within an Array are treated as oror (short circuited)' do
136
+ response.expects(:call).twice
137
+ subject.register_handler(:event, [{:type => :get}, {:body => 'test'}]) { |_| response.call }
138
+
139
+ event = mock 'Event'
140
+ event.expects(:type).at_least_once.returns :set
141
+ event.expects(:body).returns 'test'
142
+ subject.trigger_handler :event, event
143
+
144
+ event = mock 'Event'
145
+ event.stubs(:type).at_least_once.returns :get
146
+ event.expects(:body).never
147
+ subject.trigger_handler :event, event
148
+ end
149
+
150
+ it 'can be a lambda' do
151
+ response.expects(:call).once
152
+ subject.register_handler(:event, lambda { |e| e.number % 3 == 0 }) { |_| response.call }
153
+
154
+ event.expects(:number).at_least_once.returns 3
155
+ subject.trigger_handler :event, event
156
+
157
+ event.expects(:number).at_least_once.returns 2
158
+ subject.trigger_handler :event, event
159
+ end
160
+
161
+ it 'raises an error when a bad guard is tried' do
162
+ lambda {
163
+ subject.register_handler(:event, 0) {}
164
+ }.should raise_error RuntimeError
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'has_guarded_handlers'
3
+ require 'mocha'
4
+
5
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :mocha
9
+ config.filter_run :focus => true
10
+ config.run_all_when_everything_filtered = true
11
+ end
12
+
13
+ class TestObject
14
+ include HasGuardedHandlers
15
+
16
+ attr_reader :foo
17
+
18
+ def initialize(foo)
19
+ @foo = foo
20
+ super
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has-guarded-handlers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Langfeld
9
+ - Jeff Smick
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-09-21 00:00:00.000000000 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ requirement: &2157593120 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.0
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: *2157593120
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: &2157592500 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: 2.5.0
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *2157592500
38
+ - !ruby/object:Gem::Dependency
39
+ name: mocha
40
+ requirement: &2157591880 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *2157591880
49
+ - !ruby/object:Gem::Dependency
50
+ name: ci_reporter
51
+ requirement: &2157591320 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: 1.6.3
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *2157591320
60
+ - !ruby/object:Gem::Dependency
61
+ name: yard
62
+ requirement: &2157590820 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 0.7.0
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *2157590820
71
+ - !ruby/object:Gem::Dependency
72
+ name: rake
73
+ requirement: &2157590320 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: *2157590320
82
+ - !ruby/object:Gem::Dependency
83
+ name: guard-rspec
84
+ requirement: &2157589900 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: *2157589900
93
+ description: Allow an object's API to provide flexible handler registration, storage
94
+ and matching to arbitrary events.
95
+ email:
96
+ - ben@langfeld.me
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - .rspec
103
+ - CHANGELOG.md
104
+ - Gemfile
105
+ - Guardfile
106
+ - LICENSE.md
107
+ - README.md
108
+ - Rakefile
109
+ - has-guarded-handlers.gemspec
110
+ - lib/has_guarded_handlers.rb
111
+ - lib/has_guarded_handlers/version.rb
112
+ - spec/has_guarded_handlers_spec.rb
113
+ - spec/spec_helper.rb
114
+ has_rdoc: true
115
+ homepage: http://github.com/adhearsion/has-guarded-handlers
116
+ licenses: []
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project: has-guarded-handlers
135
+ rubygems_version: 1.6.2
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: A library for associating a set of event handlers, complete with guards,
139
+ with a Ruby object
140
+ test_files:
141
+ - spec/has_guarded_handlers_spec.rb
142
+ - spec/spec_helper.rb