From cde00cf90c6f71d4b5236ed81fe95a3791bf6fb2 Mon Sep 17 00:00:00 2001 From: Sergey Dolganov Date: Sat, 20 Feb 2016 15:59:54 +0500 Subject: [PATCH 1/3] Fix Struct inheritance error See details here: https://github.com/tomstuart/monads/issues/4 --- lib/monads/eventually.rb | 5 +++-- lib/monads/many.rb | 7 ++++++- lib/monads/optional.rb | 7 ++++++- spec/monads/eventually_spec.rb | 11 +++++++++++ spec/monads/many_spec.rb | 11 +++++++++++ spec/monads/optional_spec.rb | 11 +++++++++++ 6 files changed, 48 insertions(+), 4 deletions(-) diff --git a/lib/monads/eventually.rb b/lib/monads/eventually.rb index 8bb203e..32047fc 100644 --- a/lib/monads/eventually.rb +++ b/lib/monads/eventually.rb @@ -1,11 +1,12 @@ require 'monads/monad' module Monads - Eventually = Struct.new(:block) do + class Eventually include Monad + attr_reader :block def initialize(&block) - super(block) + @block = block end def run(&success) diff --git a/lib/monads/many.rb b/lib/monads/many.rb index 1fbf06b..8823ee9 100644 --- a/lib/monads/many.rb +++ b/lib/monads/many.rb @@ -1,8 +1,13 @@ require 'monads/monad' module Monads - Many = Struct.new(:values) do + class Many include Monad + attr_reader :values + + def initialize(values) + @values = values + end def and_then(&block) block = ensure_monadic_result(&block) diff --git a/lib/monads/optional.rb b/lib/monads/optional.rb index 9ce77b3..c44da9a 100644 --- a/lib/monads/optional.rb +++ b/lib/monads/optional.rb @@ -1,8 +1,13 @@ require 'monads/monad' module Monads - Optional = Struct.new(:value) do + class Optional include Monad + attr_reader :value + + def initialize(value) + @value = value + end def and_then(&block) block = ensure_monadic_result(&block) diff --git a/spec/monads/eventually_spec.rb b/spec/monads/eventually_spec.rb index 2f6405a..248301f 100644 --- a/spec/monads/eventually_spec.rb +++ b/spec/monads/eventually_spec.rb @@ -109,6 +109,17 @@ module Monads Eventually.new { |success| success.call(value) }.challenge.run { |result| @result = result } expect(@result).to eq response end + + context 'when value is Enumerable' do + let(:value) { [1, 2, 3] } + + it 'forwards any unrecognised message to the value' do + expect(Eventually.new { |success| success.call(value) }.first).to be_a(Eventually) + expect(Eventually.new { |success| success.call(value) }.first.run { |value| value }).to eq 1 + expect(Eventually.new { |success| success.call(value) }.last).to be_a(Eventually) + expect(Eventually.new { |success| success.call(value) }.last.run { |value| value }).to eq 3 + end + end end end end diff --git a/spec/monads/many_spec.rb b/spec/monads/many_spec.rb index e5bda34..289963c 100644 --- a/spec/monads/many_spec.rb +++ b/spec/monads/many_spec.rb @@ -92,6 +92,17 @@ module Monads it 'returns the messages’ results wrapped in a Many' do expect(many.challenge.values).to eq responses end + + context 'when values are Enumerable' do + let(:values) { [[1, 2], [3, 5]] } + + it 'forwards any unrecognised message to the value' do + expect(many.first).to be_a(Many) + expect(many.first.values).to eq [1, 3] + expect(many.last).to be_a(Many) + expect(many.last.values).to eq [2, 5] + end + end end end end diff --git a/spec/monads/optional_spec.rb b/spec/monads/optional_spec.rb index 2ae6e46..1ac0688 100644 --- a/spec/monads/optional_spec.rb +++ b/spec/monads/optional_spec.rb @@ -94,6 +94,17 @@ module Monads it 'returns the message’s result wrapped in an Optional' do expect(optional.challenge.value).to eq response end + + context 'when value is Enumerable' do + let(:value) { [1, 2, 3] } + + it 'forwards any unrecognised message to the value' do + expect(optional.first).to be_a(Optional) + expect(optional.first.value).to eq 1 + expect(optional.last).to be_a(Optional) + expect(optional.last.value).to eq 3 + end + end end end end From 8d6ade8200e729cdf2958861751a56450f82789a Mon Sep 17 00:00:00 2001 From: Sergey Dolganov Date: Sat, 20 Feb 2016 17:48:41 +0500 Subject: [PATCH 2/3] Chore travis.yml, force installing bundler --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5fc2b04..5718ab1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,5 @@ rvm: - 2.0.0 - 2.1.2 script: bundle exec rspec +before_install: + - gem install bundler From 8aeb332559078ad67a0935509cf190542dde13ea Mon Sep 17 00:00:00 2001 From: Sergey Dolganov Date: Sat, 20 Feb 2016 17:47:02 +0500 Subject: [PATCH 3/3] Implement `respond_to?` in module Monad Resolves #2, as previous had no tests. See details in #2 PR, breifly: Prompted by @tomstuart statement: "If this was production code, we should remember to implement #respond_to? as well." --- lib/monads/monad.rb | 6 ++++++ spec/monads/eventually_spec.rb | 2 ++ spec/monads/many_spec.rb | 2 ++ spec/monads/optional_spec.rb | 2 ++ 4 files changed, 12 insertions(+) diff --git a/lib/monads/monad.rb b/lib/monads/monad.rb index 26e0bbd..cc19c90 100644 --- a/lib/monads/monad.rb +++ b/lib/monads/monad.rb @@ -12,6 +12,12 @@ def method_missing(*args, &block) end end + def respond_to_missing?(method_name, include_private=false) + within do |value| + value.respond_to?(method_name, include_private) + end || super + end + private def ensure_monadic_result(&block) diff --git a/spec/monads/eventually_spec.rb b/spec/monads/eventually_spec.rb index 248301f..7353aee 100644 --- a/spec/monads/eventually_spec.rb +++ b/spec/monads/eventually_spec.rb @@ -102,6 +102,8 @@ module Monads it 'forwards any unrecognised message to the block’s value' do expect(value).to receive(:challenge) Eventually.new { |success| success.call(value) }.challenge.run {} + expect { Eventually.new { |success| success.call(value) }.method(:challenge) }.not_to raise_error + expect(Eventually.new { |success| success.call(value) }).to respond_to(:challenge) end it 'returns the message’s result wrapped in an Eventually' do diff --git a/spec/monads/many_spec.rb b/spec/monads/many_spec.rb index 289963c..58e3489 100644 --- a/spec/monads/many_spec.rb +++ b/spec/monads/many_spec.rb @@ -87,6 +87,8 @@ module Monads expect(value).to receive(:challenge) end many.challenge + expect { many.method(:challenge) }.not_to raise_error + expect(many).to respond_to(:challenge) end it 'returns the messages’ results wrapped in a Many' do diff --git a/spec/monads/optional_spec.rb b/spec/monads/optional_spec.rb index 1ac0688..120483f 100644 --- a/spec/monads/optional_spec.rb +++ b/spec/monads/optional_spec.rb @@ -89,6 +89,8 @@ module Monads it 'forwards any unrecognised message to the value' do expect(value).to receive(:challenge) optional.challenge + expect { optional.method(:challenge) }.not_to raise_error + expect(optional).to respond_to(:challenge) end it 'returns the message’s result wrapped in an Optional' do