pymn 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.
- 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
|
+
[](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
|