From cad21af42eff923235b740b453917c081f52d788 Mon Sep 17 00:00:00 2001 From: Mikko Koski Date: Sat, 23 Aug 2014 22:56:36 +0300 Subject: [PATCH 1/2] Breaking change: Rename or_else to get_or_else --- README.md | 24 ++++++++++++------------ lib/possibly.rb | 4 ++-- spec/spec.rb | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 2e1fcc1..5956896 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Maybe monad implementation for Ruby ```ruby -puts Maybe(User.find_by_id("123")).username.downcase.or_else { "N/A" } +puts Maybe(User.find_by_id("123")).username.downcase.get_or_else { "N/A" } => # puts downcased username if user "123" can be found, otherwise puts "N/A" ``` @@ -21,7 +21,7 @@ gem install possibly ``` require 'possibly' -first_name = Maybe(deep_hash)[:account][:profile][:first_name].or_else { "No first name available" } +first_name = Maybe(deep_hash)[:account][:profile][:first_name].get_or_else { "No first name available" } ``` ## Documentation @@ -38,14 +38,14 @@ Maybe(nil) => # Both `Some` and `None` implement four trivial methods: `is_some?`, `is_none?`, `get` and `or_else` ```ruby -Maybe("I'm a value").is_some? => true -Maybe("I'm a value").is_none? => false -Maybe(nil).is_some? => false -Maybe(nil).is_none? => true -Maybe("I'm a value").get => "I'm a value" -Maybe("I'm a value").or_else { "No value" } => "I'm a value" -Maybe(nil).get => RuntimeError: No such element -Maybe(nil).or_else { "No value" } => "No value" +Maybe("I'm a value").is_some? => true +Maybe("I'm a value").is_none? => false +Maybe(nil).is_some? => false +Maybe(nil).is_none? => true +Maybe("I'm a value").get => "I'm a value" +Maybe("I'm a value").get_or_else { "No value" } => "I'm a value" +Maybe(nil).get => RuntimeError: No such element +Maybe(nil).get_or_else { "No value" } => "No value" ``` In addition, `Some` and `None` implement `Enumerable`, so all methods available for `Enumerable` are available for `Some` and `None`: @@ -134,7 +134,7 @@ end With Maybe(): ```ruby -number_of_friends = Maybe(User.find_by_id(user_id)).friends.count.or_else { 0 } +number_of_friends = Maybe(User.find_by_id(user_id)).friends.count.get_or_else { 0 } ``` Same in HAML view, without Maybe(): @@ -147,7 +147,7 @@ Same in HAML view, without Maybe(): ``` ```haml -= Maybe(@user).friends.count.or_else { 0 } += Maybe(@user).friends.count.get_or_else { 0 } ``` ## Tests diff --git a/lib/possibly.rb b/lib/possibly.rb index a0287a6..b52bdb6 100644 --- a/lib/possibly.rb +++ b/lib/possibly.rb @@ -27,7 +27,7 @@ def get @value end - def or_else(*) + def get_or_else(*) @value end @@ -67,7 +67,7 @@ def get fail 'No such element' end - def or_else(els = nil) + def get_or_else(els = nil) block_given? ? yield : els end diff --git a/spec/spec.rb b/spec/spec.rb index 4c5c86b..198c5dd 100644 --- a/spec/spec.rb +++ b/spec/spec.rb @@ -136,17 +136,17 @@ def test_case_when(case_value, match_value, non_match_value) end end - describe "get and or_else" do + describe "get and get_or_else" do it "get" do expect { None.get }.to raise_error expect(Some(1).get).to eql(1) end - it "or_else" do - expect(None().or_else(true)).to eql(true) - expect(None().or_else { false }).to eql(false) - expect(Some(1).or_else(2)).to eql(1) - expect(Some(1).or_else { 2 }).to eql(1) + it "get_or_else" do + expect(None().get_or_else(true)).to eql(true) + expect(None().get_or_else { false }).to eql(false) + expect(Some(1).get_or_else(2)).to eql(1) + expect(Some(1).get_or_else { 2 }).to eql(1) end end @@ -156,4 +156,4 @@ def test_case_when(case_value, match_value, non_match_value) expect(Some([1, 2, 3]).map { |arr| arr.map { |v| v * v } }.get).to eql([1, 4, 9]) end end -end \ No newline at end of file +end From cef5b0e0fa4987262b1b20ce48feddd45e799c9d Mon Sep 17 00:00:00 2001 From: Mikko Koski Date: Sat, 23 Aug 2014 23:41:39 +0300 Subject: [PATCH 2/2] or_else examples --- README.md | 20 ++++++++++++++++++++ lib/possibly.rb | 8 ++++++++ spec/spec.rb | 23 +++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/README.md b/README.md index 5956896..5fbe933 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,26 @@ when None end ``` +## or_else + +`or_else` returns the current `Maybe` if it's a `Some`, but if it's a `None`, it returns the parameter that was given to it (which should be a `Maybe`). + +Here's an example: Show "title", which is person's job title or degree if she doesn't have a job or "Unknown" if both are missing. + +```ruby +maybe_person = Maybe(person) + +title = maybe_person.job.title.or_else { maybe_person.degree }.get_or_else { "Unknown" } + +title = if person && person.job && person.job.title.present? + person.job.title +elsif person && person.degree.present? + person.degree +else + "Unknown" +end +``` + ## Examples Instead of using if-clauses to define whether a value is a `nil`, you can wrap the value with `Maybe()` and threat it the same way whether or not it is a `nil` diff --git a/lib/possibly.rb b/lib/possibly.rb index b52bdb6..ba19b49 100644 --- a/lib/possibly.rb +++ b/lib/possibly.rb @@ -31,6 +31,10 @@ def get_or_else(*) @value end + def or_else(*) + self + end + # rubocop:disable PredicateName def is_some? true @@ -71,6 +75,10 @@ def get_or_else(els = nil) block_given? ? yield : els end + def or_else(els = nil, &block) + block ? block.call : els + end + # rubocop:disable PredicateName def is_some? false diff --git a/spec/spec.rb b/spec/spec.rb index 198c5dd..2d8b2cb 100644 --- a/spec/spec.rb +++ b/spec/spec.rb @@ -150,6 +150,29 @@ def test_case_when(case_value, match_value, non_match_value) end end + describe "or_else" do + it "returns self if it's a Some" do + current = Maybe(true) + other = Maybe(true) + + expect(current.or_else(other)).to equal current + end + + it "returns other if it's a Some" do + current = Maybe(nil) + other = Maybe(true) + + expect(current.or_else(other)).to equal other + end + + it "takes also a block" do + current = Maybe(true) + other = Maybe(true) + + expect(current.or_else { other }).to equal current + end + end + describe "forward" do it "forwards methods" do expect(Some("maybe").upcase.get).to eql("MAYBE")