pymn 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +9 -0
- data/integration/chain_of_responsibility_factory_spec.rb +38 -0
- data/integration/chain_of_responsibility_spec.rb +30 -0
- data/integration/fixtures/chain_of_responsibility.rb +43 -0
- data/integration/fixtures/chain_of_responsibility_factory.rb +116 -0
- data/lib/pymn/chain_of_responsibility/command_not_handled_error.rb +9 -0
- data/lib/pymn/chain_of_responsibility/factory.rb +63 -0
- data/lib/pymn/chain_of_responsibility/has_handlers.rb +14 -0
- data/lib/pymn/chain_of_responsibility/responsibility_method_undefined_error.rb +9 -0
- data/lib/pymn/chain_of_responsibility.rb +39 -0
- data/lib/pymn/version.rb +3 -0
- data/lib/pymn.rb +1 -0
- data/pymn.gemspec +25 -0
- data/spec/chain_of_responsibility/command_not_handled_error_spec.rb +13 -0
- data/spec/chain_of_responsibility/factory_spec.rb +114 -0
- data/spec/chain_of_responsibility/responsibility_method_undefined_error_spec.rb +12 -0
- data/spec/chain_of_responsibility_spec.rb +109 -0
- data/spec/fixtures/message_handler.rb +15 -0
- data/spec/spec_helper.rb +14 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZTE1ZDQyY2NjNDAwOTRhN2U4M2Y2NGI5NmY5OWZmZGQ5YTRjNDBjNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZGRiOTkxNWVkNGY2OWIwYjA1YjI3NzEzMTY5ZDMzOWFkODk1NjFkZQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OThmNjA2MDhkOWZjNTg4OWNmNjk3MmYyNzY4YWQ2MGY3Yjk2NWM5MmQ5MWYz
|
10
|
+
YmQzNWY0MTVhZWY2ZTdhZmQxNDg3MjNkZmJmZWE2ZWUzNjM5YjVlMThkNWU4
|
11
|
+
N2U3ZTllNzMwYzU0MTMyYjhhMzliZTU3MGEyMjUwMzEwNzRiOGQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MGIwYWYzZjRkNTA1ZmRhMjc5Nzc1ZTQ1MzM2YWVhMTZlOTg4ZDI4ZWY1OWNi
|
14
|
+
OTIxNTVmMDdkNzczNTdjNzU5ZjhjN2IxZGZkM2IyOTM5Y2UzZWE0ZDk0MzIw
|
15
|
+
YmZlNzI4YzUwMDAxY2ZmYTIxNGQyMTdhMzdhZWJmMzg3MmIxNGU=
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p392
|
data/.travis.yml
ADDED
data/CHANGELOG.rdoc
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pymn (0.0.1)
|
5
|
+
activesupport
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (3.2.8)
|
11
|
+
i18n (~> 0.6)
|
12
|
+
multi_json (~> 1.0)
|
13
|
+
coderay (1.0.9)
|
14
|
+
diff-lcs (1.2.1)
|
15
|
+
i18n (0.6.1)
|
16
|
+
method_source (0.8.1)
|
17
|
+
multi_json (1.3.6)
|
18
|
+
pry (0.9.12)
|
19
|
+
coderay (~> 1.0.5)
|
20
|
+
method_source (~> 0.8)
|
21
|
+
slop (~> 3.4)
|
22
|
+
rake (0.9.2.2)
|
23
|
+
rspec (2.13.0)
|
24
|
+
rspec-core (~> 2.13.0)
|
25
|
+
rspec-expectations (~> 2.13.0)
|
26
|
+
rspec-mocks (~> 2.13.0)
|
27
|
+
rspec-core (2.13.0)
|
28
|
+
rspec-expectations (2.13.0)
|
29
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
30
|
+
rspec-mocks (2.13.0)
|
31
|
+
slop (3.4.3)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
ruby
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
pry
|
38
|
+
pymn!
|
39
|
+
rake
|
40
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Rasheed Abdul-Aziz
|
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,34 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/squeedee/pymn.png?branch=master)](https://travis-ci.org/squeedee/pymn)
|
2
|
+
|
3
|
+
Patterns You May Need
|
4
|
+
=======
|
5
|
+
|
6
|
+
Other patterns, not just the one your framework provides, are quite useful. Especially as your app gets bigger.
|
7
|
+
|
8
|
+
Here are some (one so far) patterns that you may need.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'pymn'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install pymn
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
### Chain Of Responsibility
|
27
|
+
|
28
|
+
TODO: example usage
|
29
|
+
|
30
|
+
For now, take a look at:
|
31
|
+
|
32
|
+
https://github.com/squeedee/pymn/blob/master/integrations/fixtures/chain_of_responsibility.rb
|
33
|
+
https://github.com/squeedee/pymn/blob/master/integrations/fixtures/chain_of_responsibility_factory.rb
|
34
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
RSpec::Core::RakeTask.new(:integration) do |integration_task|
|
6
|
+
integration_task.pattern = "integration/**/*_spec.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
task :default => [:spec, :integration]
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/chain_of_responsibility_factory'
|
3
|
+
|
4
|
+
describe "Chain Of Responsibility as a class method" do
|
5
|
+
let(:items) {
|
6
|
+
[
|
7
|
+
Product.new(
|
8
|
+
:price => 5.0,
|
9
|
+
:description => "Hat with wide brim"
|
10
|
+
),
|
11
|
+
Product.new(
|
12
|
+
:price => 10.20,
|
13
|
+
:description => "Office chair",
|
14
|
+
:discount => 50
|
15
|
+
),
|
16
|
+
Promotion.new(
|
17
|
+
:description => "Add our after-sales care and receive a further 10% off your order"
|
18
|
+
)
|
19
|
+
]
|
20
|
+
}
|
21
|
+
|
22
|
+
subject(:products) { ProductsPresenter.new(items).products }
|
23
|
+
|
24
|
+
it "builds a ProductPresenter for a normal product" do
|
25
|
+
products[0].description.should == "Hat with wide brim"
|
26
|
+
products[0].price.should == "$5.00"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "builds a SpecialsPresenter for a product on sale" do
|
30
|
+
products[1].description.should == "On Sale! - Office chair"
|
31
|
+
products[1].price.should == "$5.10"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "builds a PromotionPresenter for a promotion" do
|
35
|
+
products[2].description.should == "Add our after-sales care and receive a further 10% off your order"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/chain_of_responsibility'
|
3
|
+
|
4
|
+
describe "Chain Of Responsibility" do
|
5
|
+
let(:logger) { InfoLogger.new(buffer) }
|
6
|
+
let(:error_logger) { ErrorLogger.new(buffer) }
|
7
|
+
let(:warn_logger) { WarnLogger.new(buffer) }
|
8
|
+
|
9
|
+
let(:buffer) { double(:buffer) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
logger.add_handler(error_logger)
|
13
|
+
logger.add_handler(warn_logger)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "logs info prepended with 'Info:'" do
|
17
|
+
buffer.should_receive(:<<).with("Info: you look nice today")
|
18
|
+
logger.log(:info, "you look nice today")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "logs warnings prepended with 'Warning:'" do
|
22
|
+
buffer.should_receive(:<<).with("Warning: things look grim")
|
23
|
+
logger.log(:warn, "things look grim")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "logs errors in all caps" do
|
27
|
+
buffer.should_receive(:<<).with("ERROR: OH NO, IT WENT WRONG")
|
28
|
+
logger.log(:error, "oh no, it went wrong")
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'pymn/chain_of_responsibility'
|
2
|
+
|
3
|
+
class ErrorLogger
|
4
|
+
include Pymn::ChainOfResponsibility
|
5
|
+
|
6
|
+
def initialize(buffer)
|
7
|
+
@buffer = buffer
|
8
|
+
end
|
9
|
+
|
10
|
+
def log(type, message)
|
11
|
+
@buffer << "ERROR: #{message.upcase}"
|
12
|
+
end
|
13
|
+
|
14
|
+
responsibility(:log) { |type, message| type == :error }
|
15
|
+
end
|
16
|
+
|
17
|
+
class WarnLogger
|
18
|
+
include Pymn::ChainOfResponsibility
|
19
|
+
|
20
|
+
def initialize(buffer)
|
21
|
+
@buffer = buffer
|
22
|
+
end
|
23
|
+
|
24
|
+
def log(type, message)
|
25
|
+
@buffer << "Warning: #{message}"
|
26
|
+
end
|
27
|
+
|
28
|
+
responsibility(:log) { |type, message| type == :warn }
|
29
|
+
end
|
30
|
+
|
31
|
+
class InfoLogger
|
32
|
+
include Pymn::ChainOfResponsibility
|
33
|
+
|
34
|
+
def initialize(buffer)
|
35
|
+
@buffer = buffer
|
36
|
+
end
|
37
|
+
|
38
|
+
def log(type, message)
|
39
|
+
@buffer << "Info: #{message}"
|
40
|
+
end
|
41
|
+
|
42
|
+
responsibility(:log) { |type, message| type == :info }
|
43
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'pymn/chain_of_responsibility/factory'
|
2
|
+
|
3
|
+
class Promotion
|
4
|
+
attr_reader :description
|
5
|
+
|
6
|
+
def initialize(attributes={})
|
7
|
+
@description = attributes[:description]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Product
|
12
|
+
attr_reader :price, :description, :discount
|
13
|
+
|
14
|
+
def initialize(attributes={})
|
15
|
+
@price = attributes[:price]
|
16
|
+
@discount = attributes[:discount]
|
17
|
+
@description = attributes[:description]
|
18
|
+
end
|
19
|
+
|
20
|
+
def discounted?
|
21
|
+
!@discount.nil? && @discount > 0.0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ProductPresenter
|
26
|
+
include Pymn::ChainOfResponsibility::Factory
|
27
|
+
|
28
|
+
def self.build(product)
|
29
|
+
new(product)
|
30
|
+
end
|
31
|
+
|
32
|
+
responsibility :build do |model|
|
33
|
+
model.is_a?(Product)
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(product)
|
37
|
+
@product = product
|
38
|
+
end
|
39
|
+
|
40
|
+
def description
|
41
|
+
@product.description
|
42
|
+
end
|
43
|
+
|
44
|
+
def price
|
45
|
+
"$%.2f" % @product.price
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class SpecialsPresenter
|
50
|
+
include Pymn::ChainOfResponsibility::Factory
|
51
|
+
|
52
|
+
def self.build(product)
|
53
|
+
new(product)
|
54
|
+
end
|
55
|
+
|
56
|
+
responsibility :build do |model|
|
57
|
+
model.is_a?(Product) &&
|
58
|
+
model.discounted?
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(product)
|
62
|
+
@product = product
|
63
|
+
end
|
64
|
+
|
65
|
+
def description
|
66
|
+
"On Sale! - #{@product.description}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def price
|
70
|
+
"$%.2f" % (@product.price * @product.discount / 100)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class PromotionPresenter
|
75
|
+
include Pymn::ChainOfResponsibility::Factory
|
76
|
+
|
77
|
+
def self.build(promotion)
|
78
|
+
new(promotion)
|
79
|
+
end
|
80
|
+
|
81
|
+
responsibility :build do |model|
|
82
|
+
model.is_a?(Promotion)
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(product)
|
86
|
+
@product = product
|
87
|
+
end
|
88
|
+
|
89
|
+
def description
|
90
|
+
@product.description
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class ProductsPresenter
|
95
|
+
attr_accessor :products
|
96
|
+
|
97
|
+
def self.build_chain
|
98
|
+
return @chain if @chain
|
99
|
+
|
100
|
+
@chain = SpecialsPresenter.create_factory.
|
101
|
+
add_handler(ProductPresenter.create_factory).
|
102
|
+
add_handler(PromotionPresenter.create_factory)
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize(product_list)
|
106
|
+
@products = build_products(product_list)
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def build_products(product_list)
|
112
|
+
product_list.map do |item|
|
113
|
+
self.class.build_chain.build(item)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'pymn/chain_of_responsibility'
|
2
|
+
require 'pymn/chain_of_responsibility/command_not_handled_error'
|
3
|
+
require 'pymn/chain_of_responsibility/responsibility_method_undefined_error'
|
4
|
+
require 'pymn/chain_of_responsibility/has_handlers'
|
5
|
+
|
6
|
+
module Pymn
|
7
|
+
module ChainOfResponsibility
|
8
|
+
module Factory
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def responsibility class_method, &block
|
13
|
+
singleton_class = class << self; self; end
|
14
|
+
|
15
|
+
unless singleton_class.method_defined?(class_method)
|
16
|
+
raise ResponsibilityMethodUndefinedError.new(class_method)
|
17
|
+
end
|
18
|
+
|
19
|
+
singleton_class.instance_eval do
|
20
|
+
define_method(:create_factory) do
|
21
|
+
FactoryCommand.new(self, class_method, block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class FactoryCommand
|
28
|
+
include HasHandlers
|
29
|
+
|
30
|
+
def initialize(target, factory_method, can_handle_block)
|
31
|
+
create_method(factory_method)
|
32
|
+
@factory_method = factory_method
|
33
|
+
@target = target
|
34
|
+
@can_handle_block = can_handle_block
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def call_target(*args)
|
40
|
+
@target.send(@factory_method, *args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_method(factory_method)
|
44
|
+
singleton_class = class << self; self; end
|
45
|
+
singleton_class.define_method(factory_method) do |*args|
|
46
|
+
if @target.instance_exec(*args, &@can_handle_block)
|
47
|
+
return call_target(*args)
|
48
|
+
end
|
49
|
+
|
50
|
+
if @next_handler_in_chain
|
51
|
+
return @next_handler_in_chain.send(factory_method, *args)
|
52
|
+
end
|
53
|
+
|
54
|
+
raise CommandNotHandledError.new(@factory_method)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Pymn
|
2
|
+
module ChainOfResponsibility
|
3
|
+
module HasHandlers
|
4
|
+
def add_handler(next_handler)
|
5
|
+
if (@next_handler_in_chain)
|
6
|
+
@next_handler_in_chain.add_handler(next_handler)
|
7
|
+
else
|
8
|
+
@next_handler_in_chain = next_handler
|
9
|
+
end
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'pymn/chain_of_responsibility/command_not_handled_error'
|
3
|
+
require 'pymn/chain_of_responsibility/responsibility_method_undefined_error'
|
4
|
+
require 'pymn/chain_of_responsibility/has_handlers'
|
5
|
+
|
6
|
+
module Pymn
|
7
|
+
module ChainOfResponsibility
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
include HasHandlers
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def responsibility method, &block
|
17
|
+
unless method_defined?(method)
|
18
|
+
raise ResponsibilityMethodUndefinedError.new(method)
|
19
|
+
end
|
20
|
+
|
21
|
+
command_method = "__command_#{method}".to_sym
|
22
|
+
alias_method command_method, method
|
23
|
+
|
24
|
+
define_method(method) do |*args|
|
25
|
+
if instance_exec(*args, &block)
|
26
|
+
return send(command_method, *args)
|
27
|
+
end
|
28
|
+
|
29
|
+
if @next_handler_in_chain
|
30
|
+
return @next_handler_in_chain.send(method, *args)
|
31
|
+
end
|
32
|
+
|
33
|
+
raise CommandNotHandledError.new(method)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/pymn/version.rb
ADDED
data/lib/pymn.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "pymn/version"
|
data/pymn.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pymn/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "pymn"
|
8
|
+
gem.version = Pymn::VERSION
|
9
|
+
gem.authors = ["Rasheed Abdul-Aziz"]
|
10
|
+
gem.email = ["squeedee@gmail.com"]
|
11
|
+
gem.description = %q{Sometimes, there are Patterns You May Need.}
|
12
|
+
gem.summary = %q{Sometimes, there are Patterns You May Need.}
|
13
|
+
gem.homepage = "https://github.com/pymn"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(integraton|spec)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "activesupport"
|
21
|
+
|
22
|
+
gem.add_development_dependency "rake"
|
23
|
+
gem.add_development_dependency "pry"
|
24
|
+
gem.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pymn/chain_of_responsibility'
|
3
|
+
|
4
|
+
module Pymn
|
5
|
+
module ChainOfResponsibility
|
6
|
+
describe CommandNotHandledError do
|
7
|
+
subject { CommandNotHandledError.new(:the_command) }
|
8
|
+
|
9
|
+
its(:message) { should include "'the_command' could not be handled" }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "pymn/chain_of_responsibility/factory"
|
3
|
+
|
4
|
+
module Pymn
|
5
|
+
module ChainOfResponsibility
|
6
|
+
describe Factory do
|
7
|
+
describe "dsl" do
|
8
|
+
context "without a matching method" do
|
9
|
+
subject do
|
10
|
+
Class.new do
|
11
|
+
include Pymn::ChainOfResponsibility::Factory
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "fails to add the responsibility" do
|
16
|
+
expect {
|
17
|
+
subject.responsibility(:run_command) { true }
|
18
|
+
}.to raise_error(Pymn::ChainOfResponsibility::ResponsibilityMethodUndefinedError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
describe "#add_handler" do
|
25
|
+
let(:test_class) {
|
26
|
+
Class.new do
|
27
|
+
include Pymn::ChainOfResponsibility::Factory
|
28
|
+
def self.build
|
29
|
+
return new
|
30
|
+
end
|
31
|
+
|
32
|
+
responsibility(:build) { true }
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
let(:next_handler) { double(:next_handler) }
|
37
|
+
|
38
|
+
subject(:factory) { test_class.create_factory }
|
39
|
+
|
40
|
+
it "provides a fluent interface for add_handler" do
|
41
|
+
result = factory.add_handler(next_handler)
|
42
|
+
result.should == factory
|
43
|
+
end
|
44
|
+
|
45
|
+
it "adds handlers to the leaf node" do
|
46
|
+
factory.add_handler(next_handler)
|
47
|
+
last_handler = double(:last_handler)
|
48
|
+
next_handler.should_receive(:add_handler).with(last_handler)
|
49
|
+
factory.add_handler(last_handler)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "calling the handler" do
|
55
|
+
let(:test_class) do
|
56
|
+
Class.new do
|
57
|
+
include Pymn::ChainOfResponsibility::Factory
|
58
|
+
|
59
|
+
def self.build *args
|
60
|
+
args
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
before do
|
66
|
+
if can_handle
|
67
|
+
test_class.responsibility(:build) { true }
|
68
|
+
else
|
69
|
+
test_class.responsibility(:build) { false }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
subject(:build_handler) { test_class.create_factory }
|
74
|
+
|
75
|
+
context "the factory handles the command" do
|
76
|
+
let(:can_handle) { true }
|
77
|
+
|
78
|
+
it "passes and return no args" do
|
79
|
+
build_handler.build.should == []
|
80
|
+
end
|
81
|
+
|
82
|
+
it "passes and return any args" do
|
83
|
+
build_handler.build(1,2,3).should == [1,2,3]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "the factory does not handle the command" do
|
88
|
+
let(:can_handle) { false }
|
89
|
+
|
90
|
+
context "singleton chain" do
|
91
|
+
it "raises an exception" do
|
92
|
+
expect { build_handler.build }.to raise_error(Pymn::ChainOfResponsibility::CommandNotHandledError)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "has another handler in chain" do
|
97
|
+
let(:next_handler) { double(:next_handler) }
|
98
|
+
|
99
|
+
before do
|
100
|
+
build_handler.add_handler(next_handler)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "calls the next handler" do
|
104
|
+
next_handler.should_receive(:build).with([1,2,3])
|
105
|
+
build_handler.build([1,2,3])
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pymn/chain_of_responsibility'
|
3
|
+
|
4
|
+
module Pymn
|
5
|
+
module ChainOfResponsibility
|
6
|
+
describe ResponsibilityMethodUndefinedError do
|
7
|
+
subject { ResponsibilityMethodUndefinedError.new(:my_method) }
|
8
|
+
|
9
|
+
its(:message) { should include "'my_method' not defined" }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "pymn/chain_of_responsibility"
|
3
|
+
|
4
|
+
module Pymn
|
5
|
+
describe ChainOfResponsibility do
|
6
|
+
describe "dsl" do
|
7
|
+
context "without a matching method" do
|
8
|
+
subject do
|
9
|
+
Class.new do
|
10
|
+
include Pymn::ChainOfResponsibility
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "fails to add the responsibility" do
|
15
|
+
expect {
|
16
|
+
subject.responsibility(:run_command) { true }
|
17
|
+
}.to raise_error(Pymn::ChainOfResponsibility::ResponsibilityMethodUndefinedError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
describe "#add_handler" do
|
24
|
+
let(:test_class) {
|
25
|
+
Class.new do
|
26
|
+
include Pymn::ChainOfResponsibility
|
27
|
+
def action
|
28
|
+
end
|
29
|
+
|
30
|
+
responsibility(:action) { true }
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
let(:next_handler) { double(:next_handler) }
|
35
|
+
subject(:instance) { test_class.new }
|
36
|
+
|
37
|
+
it "provides a fluent interface for add_handler" do
|
38
|
+
result = instance.add_handler(next_handler)
|
39
|
+
result.should == instance
|
40
|
+
end
|
41
|
+
|
42
|
+
it "adds handlers to the leaf node" do
|
43
|
+
instance.add_handler(next_handler)
|
44
|
+
last_handler = double(:last_handler)
|
45
|
+
next_handler.should_receive(:add_handler).with(last_handler)
|
46
|
+
instance.add_handler(last_handler)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "calling the handler" do
|
51
|
+
let(:test_class) do
|
52
|
+
Class.new do
|
53
|
+
include Pymn::ChainOfResponsibility
|
54
|
+
|
55
|
+
def run_command *args
|
56
|
+
args
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
before do
|
63
|
+
if can_handle
|
64
|
+
test_class.responsibility(:run_command) { true }
|
65
|
+
else
|
66
|
+
test_class.responsibility(:run_command) { false }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
subject(:command_handler) { test_class.new }
|
71
|
+
|
72
|
+
context "the class handles the command" do
|
73
|
+
let(:can_handle) { true }
|
74
|
+
|
75
|
+
it "passes and return no args" do
|
76
|
+
command_handler.run_command.should == []
|
77
|
+
end
|
78
|
+
|
79
|
+
it "passes and return any args" do
|
80
|
+
command_handler.run_command(1,2,3).should == [1,2,3]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "the class does not handle the command" do
|
85
|
+
let(:can_handle) { false }
|
86
|
+
|
87
|
+
context "singleton chain" do
|
88
|
+
it "raises an exception" do
|
89
|
+
expect { command_handler.run_command }.to raise_error(Pymn::ChainOfResponsibility::CommandNotHandledError)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "has another handler in chain" do
|
94
|
+
let(:next_handler) { double(:next_handler) }
|
95
|
+
|
96
|
+
before do
|
97
|
+
command_handler.add_handler(next_handler)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "calls the next handler" do
|
101
|
+
next_handler.should_receive(:run_command).with([1,2,3])
|
102
|
+
command_handler.run_command([1,2,3])
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'pymn/chain_of_responsibility'
|
2
|
+
|
3
|
+
class
|
4
|
+
include Pymn::ChainOfResponsibility
|
5
|
+
|
6
|
+
def initialize(supports_type)
|
7
|
+
@supports_type = supports_type
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_message message, type
|
11
|
+
message
|
12
|
+
end
|
13
|
+
|
14
|
+
responsibility (:handle_message) { |message, type| type == @supports_type }
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "pry"
|
3
|
+
|
4
|
+
require "pymn"
|
5
|
+
$:.unshift File.expand_path('..', __FILE__)
|
6
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
7
|
+
$:.unshift File.expand_path('../../integration', __FILE__)
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.color_enabled = true
|
11
|
+
config.before(:each) do
|
12
|
+
@lib_dir = File.expand_path('../../lib', __FILE__)
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pymn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rasheed Abdul-Aziz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
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
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Sometimes, there are Patterns You May Need.
|
70
|
+
email:
|
71
|
+
- squeedee@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .ruby-version
|
78
|
+
- .travis.yml
|
79
|
+
- CHANGELOG.rdoc
|
80
|
+
- Gemfile
|
81
|
+
- Gemfile.lock
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- integration/chain_of_responsibility_factory_spec.rb
|
86
|
+
- integration/chain_of_responsibility_spec.rb
|
87
|
+
- integration/fixtures/chain_of_responsibility.rb
|
88
|
+
- integration/fixtures/chain_of_responsibility_factory.rb
|
89
|
+
- lib/pymn.rb
|
90
|
+
- lib/pymn/chain_of_responsibility.rb
|
91
|
+
- lib/pymn/chain_of_responsibility/command_not_handled_error.rb
|
92
|
+
- lib/pymn/chain_of_responsibility/factory.rb
|
93
|
+
- lib/pymn/chain_of_responsibility/has_handlers.rb
|
94
|
+
- lib/pymn/chain_of_responsibility/responsibility_method_undefined_error.rb
|
95
|
+
- lib/pymn/version.rb
|
96
|
+
- pymn.gemspec
|
97
|
+
- spec/chain_of_responsibility/command_not_handled_error_spec.rb
|
98
|
+
- spec/chain_of_responsibility/factory_spec.rb
|
99
|
+
- spec/chain_of_responsibility/responsibility_method_undefined_error_spec.rb
|
100
|
+
- spec/chain_of_responsibility_spec.rb
|
101
|
+
- spec/fixtures/message_handler.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
homepage: https://github.com/pymn
|
104
|
+
licenses: []
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.0.3
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: Sometimes, there are Patterns You May Need.
|
126
|
+
test_files:
|
127
|
+
- spec/chain_of_responsibility/command_not_handled_error_spec.rb
|
128
|
+
- spec/chain_of_responsibility/factory_spec.rb
|
129
|
+
- spec/chain_of_responsibility/responsibility_method_undefined_error_spec.rb
|
130
|
+
- spec/chain_of_responsibility_spec.rb
|
131
|
+
- spec/fixtures/message_handler.rb
|
132
|
+
- spec/spec_helper.rb
|