pymn 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ InstalledFiles
6
+ coverage
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p392
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - jruby-18mode
6
+ - jruby-19mode
7
+ - rbx-18mode
8
+ - rbx-19mode
9
+ - ruby-head
10
+ - jruby-head
11
+ - 1.8.7
12
+ - ree
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,8 @@
1
+ == 0.0.1
2
+
3
+ * Introduced Chain Of Command pattern
4
+ * Introduced Chain Of Command Factory Pattern
5
+
6
+ ==== Known Issues
7
+
8
+ * Does not work with rubinius.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pymn.gemspec
4
+ gemspec
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,9 @@
1
+ module Pymn
2
+ module ChainOfResponsibility
3
+ class CommandNotHandledError < Exception
4
+ def initialize(method)
5
+ super("'#{method}' could not be handled")
6
+ end
7
+ end
8
+ end
9
+ 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,9 @@
1
+ module Pymn
2
+ module ChainOfResponsibility
3
+ class ResponsibilityMethodUndefinedError < Exception
4
+ def initialize method
5
+ super("Responsibility must be called with an existing method. '#{method.to_s}' not defined.")
6
+ end
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,3 @@
1
+ module Pymn
2
+ VERSION = "0.0.1"
3
+ end
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
@@ -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