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 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