easy_monads 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +20 -0
- data/README.md +0 -0
- data/Rakefile +58 -0
- data/VERSION +1 -0
- data/easy_monads.gemspec +73 -0
- data/lib/easy_monads/monadic.rb +44 -0
- data/lib/easy_monads/option.rb +98 -0
- data/lib/easy_monads/option_functions.rb +15 -0
- data/lib/easy_monads.rb +11 -0
- data/test/helper.rb +20 -0
- data/test/test_easy_monads.rb +196 -0
- metadata +208 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "pry"
|
10
|
+
gem "shoulda", "~> 2.11.3"
|
11
|
+
gem "shared_should", "~> 0.8.1"
|
12
|
+
gem "always_execute", "~> 0.0.2"
|
13
|
+
gem "bundler", "~> 1.0.21"
|
14
|
+
gem "jeweler", "~> 1.6.4"
|
15
|
+
gem "rcov", "~> 0.9.11"
|
16
|
+
gem "rdoc", ">= 2.4.2"
|
17
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Stephen Sloan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "easy_monads"
|
18
|
+
gem.homepage = "https://github.com/bkr/easy_monads"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = "EasyMonads is a simple implementation of monads for Ruby"
|
21
|
+
gem.description = <<EOS
|
22
|
+
EasyMonads is a gem for Ruby that provides a simple implementation of monads. It also provides a useful example of
|
23
|
+
monads in the form of Option (similar to Scala's Option) which provides Some and None classes.
|
24
|
+
|
25
|
+
Developement for EasyMonads is sponsored by BookRenter.com and it is released under an MIT-style license
|
26
|
+
EOS
|
27
|
+
gem.email = "stephen.sloan@bookrenter.com"
|
28
|
+
gem.authors = ["Stephen Sloan"]
|
29
|
+
# dependencies defined in Gemfile
|
30
|
+
end
|
31
|
+
Jeweler::RubygemsDotOrgTasks.new
|
32
|
+
|
33
|
+
require 'rake/testtask'
|
34
|
+
Rake::TestTask.new(:test) do |test|
|
35
|
+
test.libs << 'lib' << 'test'
|
36
|
+
test.pattern = 'test/**/test_*.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
|
40
|
+
require 'rcov/rcovtask'
|
41
|
+
Rcov::RcovTask.new do |test|
|
42
|
+
test.libs << 'test'
|
43
|
+
test.pattern = 'test/**/test_*.rb'
|
44
|
+
test.verbose = true
|
45
|
+
test.rcov_opts << '--exclude "gems/*"'
|
46
|
+
end
|
47
|
+
|
48
|
+
task :default => :test
|
49
|
+
|
50
|
+
require 'rdoc/task'
|
51
|
+
Rake::RDocTask.new do |rdoc|
|
52
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
53
|
+
|
54
|
+
rdoc.rdoc_dir = 'rdoc'
|
55
|
+
rdoc.title = "easy_monads #{version}"
|
56
|
+
rdoc.rdoc_files.include('README*')
|
57
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
58
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
data/easy_monads.gemspec
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "easy_monads"
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Stephen Sloan"]
|
12
|
+
s.date = "2011-12-06"
|
13
|
+
s.description = "EasyMonads is a gem for Ruby that provides a simple implementation of monads. It also provides a useful example of\nmonads in the form of Option (similar to Scala's Option) which provides Some and None classes.\n\nDevelopement for EasyMonads is sponsored by BookRenter.com and it is released under an MIT-style license\n"
|
14
|
+
s.email = "stephen.sloan@bookrenter.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"easy_monads.gemspec",
|
27
|
+
"lib/easy_monads.rb",
|
28
|
+
"lib/easy_monads/monadic.rb",
|
29
|
+
"lib/easy_monads/option.rb",
|
30
|
+
"lib/easy_monads/option_functions.rb",
|
31
|
+
"test/helper.rb",
|
32
|
+
"test/test_easy_monads.rb"
|
33
|
+
]
|
34
|
+
s.homepage = "https://github.com/bkr/easy_monads"
|
35
|
+
s.licenses = ["MIT"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = "1.8.10"
|
38
|
+
s.summary = "EasyMonads is a simple implementation of monads for Ruby"
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_development_dependency(%q<pry>, [">= 0"])
|
45
|
+
s.add_development_dependency(%q<shoulda>, ["~> 2.11.3"])
|
46
|
+
s.add_development_dependency(%q<shared_should>, ["~> 0.8.1"])
|
47
|
+
s.add_development_dependency(%q<always_execute>, ["~> 0.0.2"])
|
48
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.21"])
|
49
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
50
|
+
s.add_development_dependency(%q<rcov>, ["~> 0.9.11"])
|
51
|
+
s.add_development_dependency(%q<rdoc>, [">= 2.4.2"])
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
54
|
+
s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
|
55
|
+
s.add_dependency(%q<shared_should>, ["~> 0.8.1"])
|
56
|
+
s.add_dependency(%q<always_execute>, ["~> 0.0.2"])
|
57
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.21"])
|
58
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
59
|
+
s.add_dependency(%q<rcov>, ["~> 0.9.11"])
|
60
|
+
s.add_dependency(%q<rdoc>, [">= 2.4.2"])
|
61
|
+
end
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
64
|
+
s.add_dependency(%q<shoulda>, ["~> 2.11.3"])
|
65
|
+
s.add_dependency(%q<shared_should>, ["~> 0.8.1"])
|
66
|
+
s.add_dependency(%q<always_execute>, ["~> 0.0.2"])
|
67
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.21"])
|
68
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
69
|
+
s.add_dependency(%q<rcov>, ["~> 0.9.11"])
|
70
|
+
s.add_dependency(%q<rdoc>, [">= 2.4.2"])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module EasyMonads
|
2
|
+
class Monadic
|
3
|
+
include Enumerable
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def unit(*args)
|
8
|
+
new(*args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def unit(to_wrap)
|
13
|
+
self.class.unit(to_wrap)
|
14
|
+
end
|
15
|
+
|
16
|
+
def bind(&func)
|
17
|
+
result = func.call(data) if defined? @data
|
18
|
+
raise RuntimeError.new("Result of .bind must be a Monadic but was #{result.class.name}") unless result.is_a? Monadic
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def bind_unit(&func)
|
23
|
+
self.bind { |*args| self.unit(func.call(*args)) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def data
|
27
|
+
@data
|
28
|
+
end
|
29
|
+
|
30
|
+
def each
|
31
|
+
yield data
|
32
|
+
end
|
33
|
+
|
34
|
+
def ==(other_monad)
|
35
|
+
return false unless other_monad.is_a? EasyMonads::Monadic
|
36
|
+
data == other_monad.data
|
37
|
+
end
|
38
|
+
|
39
|
+
def <=>(other_monad)
|
40
|
+
return RuntimeError.new("Can only compare with other Monadic objects") unless other_monad.is_a? EasyMonads::Monadic
|
41
|
+
data <=> other_monad.data
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
module EasyMonads
|
3
|
+
module Option
|
4
|
+
class Option < EasyMonads::Monadic
|
5
|
+
def initialize(*args)
|
6
|
+
raise RuntimeError.new("Attempt to initialize abstract #{self.class.name} class")
|
7
|
+
end
|
8
|
+
|
9
|
+
alias get data
|
10
|
+
alias or_nil data
|
11
|
+
end
|
12
|
+
|
13
|
+
class None < Option
|
14
|
+
def initialize(*args)
|
15
|
+
@data = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def bind
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def each
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(other_monad)
|
26
|
+
other_monad.is_a? self.class
|
27
|
+
end
|
28
|
+
|
29
|
+
def <=>(other_monad)
|
30
|
+
if self == other_monad
|
31
|
+
0
|
32
|
+
else
|
33
|
+
raise RuntimeError.new("#{self.class.name} is not comparable to other types") # nil <=> ... would raise NoMethodError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def size
|
38
|
+
0
|
39
|
+
end
|
40
|
+
|
41
|
+
def exists?(&pred)
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def defined?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_or_else(else_val=nil)
|
50
|
+
if block_given?
|
51
|
+
yield
|
52
|
+
else
|
53
|
+
else_val
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def empty?
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def or_else
|
62
|
+
yield
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
NONE = None.new.freeze
|
67
|
+
|
68
|
+
class Some < Option
|
69
|
+
def initialize(data)
|
70
|
+
@data = data
|
71
|
+
end
|
72
|
+
|
73
|
+
def size
|
74
|
+
1
|
75
|
+
end
|
76
|
+
|
77
|
+
def exists?(&pred)
|
78
|
+
pred.call(data) ? true : false
|
79
|
+
end
|
80
|
+
|
81
|
+
def defined?
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_or_else(ignored=nil)
|
86
|
+
data
|
87
|
+
end
|
88
|
+
|
89
|
+
def empty?
|
90
|
+
false
|
91
|
+
end
|
92
|
+
|
93
|
+
def or_else
|
94
|
+
self
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
module EasyMonads
|
3
|
+
module Option
|
4
|
+
module OptionFunctions
|
5
|
+
def self.sum_option_in_hash(hash, key, option)
|
6
|
+
if hash[key].is_a? Some
|
7
|
+
hash[key] = hash[key].bind { |value| Some.unit(value + option.get) }
|
8
|
+
else
|
9
|
+
hash[key] = option
|
10
|
+
end
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/easy_monads.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "easy_monads", "monadic")
|
2
|
+
require File.join(File.dirname(__FILE__), "easy_monads", "option")
|
3
|
+
require File.join(File.dirname(__FILE__), "easy_monads", "option_functions")
|
4
|
+
|
5
|
+
module EasyMonads
|
6
|
+
|
7
|
+
def self.option_everywhere!
|
8
|
+
Object.class_eval("include EasyMonads::Option")
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
require 'shared_should'
|
13
|
+
require 'always_execute'
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
16
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
|
+
require 'easy_monads'
|
18
|
+
|
19
|
+
class Test::Unit::TestCase
|
20
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestEasyMonads < Test::Unit::TestCase
|
4
|
+
# What the hell is a monad, you ask? Check out
|
5
|
+
# http://www.codecommit.com/blog/ruby/monads-are-not-metaphors
|
6
|
+
|
7
|
+
class TestMonadic < EasyMonads::Monadic
|
8
|
+
def initialize(data)
|
9
|
+
@data = data
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "A monadic Object" do
|
14
|
+
setup do
|
15
|
+
@monad = TestMonadic.new("test")
|
16
|
+
end
|
17
|
+
|
18
|
+
should "be enumerable" do
|
19
|
+
assert @monad.is_a? Enumerable
|
20
|
+
assert defined? @monad.each
|
21
|
+
end
|
22
|
+
|
23
|
+
should "be comparable" do
|
24
|
+
assert @monad.is_a? Comparable
|
25
|
+
assert defined? @monad.<=>
|
26
|
+
end
|
27
|
+
|
28
|
+
should "expose its contained data" do
|
29
|
+
assert_equal "test", @monad.data
|
30
|
+
end
|
31
|
+
|
32
|
+
should "have a fancy bind_unit method that does a bind and a unit in one" do
|
33
|
+
assert_equal TestMonadic.new("TEST"), @monad.bind_unit { |value| value.upcase }
|
34
|
+
end
|
35
|
+
|
36
|
+
# For all this monad identity business, checkout out
|
37
|
+
# http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/01identity
|
38
|
+
should "be true for identify law one" do
|
39
|
+
f = lambda { |value| TestMonadic.unit("#{value} foo") }
|
40
|
+
assert_equal "test foo", @monad.bind { |value| f.call(value) }.data
|
41
|
+
assert_equal f.call("test"), @monad.bind { |value| f.call(value) }
|
42
|
+
end
|
43
|
+
|
44
|
+
should "be true for identity law two" do
|
45
|
+
assert_equal @monad, @monad.bind { |value| TestMonadic.unit(value) }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "for identity law three" do
|
49
|
+
setup do
|
50
|
+
@f = lambda { |value| TestMonadic.unit(value * 2) }
|
51
|
+
@g = lambda { |value| TestMonadic.unit("#{value} foo") }
|
52
|
+
end
|
53
|
+
|
54
|
+
execute do
|
55
|
+
@monad.bind do |value_a|
|
56
|
+
@f.call(value_a)
|
57
|
+
end.bind do |value_b|
|
58
|
+
@g.call(value_b)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
should "be true" do
|
63
|
+
assert_equal "testtest foo", @execute_result.data
|
64
|
+
test_result = @monad.bind do |value_a|
|
65
|
+
@f.call(value_a).bind do |value_b|
|
66
|
+
@g.call(value_b)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
assert_equal @execute_result, test_result
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "An Option" do
|
75
|
+
|
76
|
+
should "raise an error if used directly" do
|
77
|
+
assert_raises(RuntimeError) { EasyMonads::Option::Option.new("foo") }
|
78
|
+
end
|
79
|
+
|
80
|
+
context "that is a None" do
|
81
|
+
setup do
|
82
|
+
@none = EasyMonads::Option::NONE
|
83
|
+
end
|
84
|
+
|
85
|
+
should "not bind to anything" do
|
86
|
+
assert_equal EasyMonads::Option::NONE, @none.bind { raise RuntimeError.new("Should not have entered block") }
|
87
|
+
end
|
88
|
+
|
89
|
+
should "not enumerate" do
|
90
|
+
count = 0
|
91
|
+
@none.each { count += 1 }
|
92
|
+
assert_equal 0, count
|
93
|
+
end
|
94
|
+
|
95
|
+
should "return nil for .get" do
|
96
|
+
assert_equal nil, @none.get
|
97
|
+
end
|
98
|
+
|
99
|
+
should "return true for .empty?" do
|
100
|
+
assert_equal true, @none.empty?
|
101
|
+
end
|
102
|
+
|
103
|
+
should "return 0 for .size" do
|
104
|
+
assert_equal 0, @none.size
|
105
|
+
end
|
106
|
+
|
107
|
+
should "return false always for .exists? and not call the predicate block" do
|
108
|
+
assert_equal false, @none.exists? { raise RuntimeError.new("Should not enter the block") }
|
109
|
+
end
|
110
|
+
|
111
|
+
should "return the else for .get_or_else" do
|
112
|
+
assert_equal "foo", @none.get_or_else("foo")
|
113
|
+
end
|
114
|
+
|
115
|
+
should "return the evaluated block for .get_or_else when passed a block" do
|
116
|
+
assert_equal "foo", @none.get_or_else { "foo" }
|
117
|
+
end
|
118
|
+
|
119
|
+
should "return false for .defined?" do
|
120
|
+
assert_equal false, @none.defined?
|
121
|
+
end
|
122
|
+
|
123
|
+
should "return nil for .or_nil" do
|
124
|
+
assert_equal nil, @none.or_nil
|
125
|
+
end
|
126
|
+
|
127
|
+
should "execute the block for .or_else" do
|
128
|
+
entered = "grouchy"
|
129
|
+
@none.or_else { entered = "happy" }
|
130
|
+
assert_equal "happy", entered
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "that is a Some" do
|
135
|
+
setup do
|
136
|
+
@some = EasyMonads::Option::Some.new("hello")
|
137
|
+
end
|
138
|
+
|
139
|
+
should "bind to another Some" do
|
140
|
+
assert_equal "hello world", @some.bind { |value| EasyMonads::Option::Some.new("#{value} world") }.data
|
141
|
+
end
|
142
|
+
|
143
|
+
should "enumerate" do
|
144
|
+
count = 0
|
145
|
+
@some.each { count += 1 }
|
146
|
+
assert_equal 1, count
|
147
|
+
end
|
148
|
+
|
149
|
+
should "return its data for .get" do
|
150
|
+
assert_equal "hello", @some.get
|
151
|
+
end
|
152
|
+
|
153
|
+
should "return false for .empty?" do
|
154
|
+
assert_equal false, @some.empty?
|
155
|
+
end
|
156
|
+
|
157
|
+
should "return 1 for its size" do
|
158
|
+
assert_equal 1, @some.size
|
159
|
+
another_some = EasyMonads::Option::Some.new(["hello", "world"])
|
160
|
+
assert_equal 1, another_some.size
|
161
|
+
end
|
162
|
+
|
163
|
+
should "return true when a predicate is true for .exists?" do
|
164
|
+
assert_equal true, @some.exists? { |value| value == "hello" }
|
165
|
+
end
|
166
|
+
|
167
|
+
should "return false when a predicate is false for .exists?" do
|
168
|
+
assert_equal false, @some.exists? { |value| value == "fooie" }
|
169
|
+
end
|
170
|
+
|
171
|
+
should "return its data for .get_or_else" do
|
172
|
+
assert_equal "hello", @some.get_or_else("goodbye")
|
173
|
+
end
|
174
|
+
|
175
|
+
should "return its data and ignore the block for .get_or_else when passed a block" do
|
176
|
+
assert_equal "hello", @some.get_or_else { raise RuntimeError.new("Should not enter the block") }
|
177
|
+
end
|
178
|
+
|
179
|
+
should "return true for .defined?" do
|
180
|
+
assert_equal true, @some.defined?
|
181
|
+
end
|
182
|
+
|
183
|
+
should "return its data for .or_nil" do
|
184
|
+
assert_equal "hello", @some.or_nil
|
185
|
+
end
|
186
|
+
|
187
|
+
should "not enter the block for .or_else" do
|
188
|
+
assert_nothing_raised { @some.or_else { raise RuntimeError.new("Should not enter the block") } }
|
189
|
+
end
|
190
|
+
|
191
|
+
should "return self for .or_else" do
|
192
|
+
assert_equal @some, @some.or_else {}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
metadata
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easy_monads
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Stephen Sloan
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-12-06 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
none: false
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
hash: 3
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
version_requirements: *id001
|
31
|
+
name: pry
|
32
|
+
prerelease: false
|
33
|
+
type: :development
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
hash: 37
|
41
|
+
segments:
|
42
|
+
- 2
|
43
|
+
- 11
|
44
|
+
- 3
|
45
|
+
version: 2.11.3
|
46
|
+
version_requirements: *id002
|
47
|
+
name: shoulda
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 61
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
- 8
|
60
|
+
- 1
|
61
|
+
version: 0.8.1
|
62
|
+
version_requirements: *id003
|
63
|
+
name: shared_should
|
64
|
+
prerelease: false
|
65
|
+
type: :development
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ~>
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 27
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
- 0
|
76
|
+
- 2
|
77
|
+
version: 0.0.2
|
78
|
+
version_requirements: *id004
|
79
|
+
name: always_execute
|
80
|
+
prerelease: false
|
81
|
+
type: :development
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 61
|
89
|
+
segments:
|
90
|
+
- 1
|
91
|
+
- 0
|
92
|
+
- 21
|
93
|
+
version: 1.0.21
|
94
|
+
version_requirements: *id005
|
95
|
+
name: bundler
|
96
|
+
prerelease: false
|
97
|
+
type: :development
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 7
|
105
|
+
segments:
|
106
|
+
- 1
|
107
|
+
- 6
|
108
|
+
- 4
|
109
|
+
version: 1.6.4
|
110
|
+
version_requirements: *id006
|
111
|
+
name: jeweler
|
112
|
+
prerelease: false
|
113
|
+
type: :development
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ~>
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
hash: 45
|
121
|
+
segments:
|
122
|
+
- 0
|
123
|
+
- 9
|
124
|
+
- 11
|
125
|
+
version: 0.9.11
|
126
|
+
version_requirements: *id007
|
127
|
+
name: rcov
|
128
|
+
prerelease: false
|
129
|
+
type: :development
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
hash: 27
|
137
|
+
segments:
|
138
|
+
- 2
|
139
|
+
- 4
|
140
|
+
- 2
|
141
|
+
version: 2.4.2
|
142
|
+
version_requirements: *id008
|
143
|
+
name: rdoc
|
144
|
+
prerelease: false
|
145
|
+
type: :development
|
146
|
+
description: |
|
147
|
+
EasyMonads is a gem for Ruby that provides a simple implementation of monads. It also provides a useful example of
|
148
|
+
monads in the form of Option (similar to Scala's Option) which provides Some and None classes.
|
149
|
+
|
150
|
+
Developement for EasyMonads is sponsored by BookRenter.com and it is released under an MIT-style license
|
151
|
+
|
152
|
+
email: stephen.sloan@bookrenter.com
|
153
|
+
executables: []
|
154
|
+
|
155
|
+
extensions: []
|
156
|
+
|
157
|
+
extra_rdoc_files:
|
158
|
+
- LICENSE.txt
|
159
|
+
- README.md
|
160
|
+
files:
|
161
|
+
- .document
|
162
|
+
- Gemfile
|
163
|
+
- LICENSE.txt
|
164
|
+
- README.md
|
165
|
+
- Rakefile
|
166
|
+
- VERSION
|
167
|
+
- easy_monads.gemspec
|
168
|
+
- lib/easy_monads.rb
|
169
|
+
- lib/easy_monads/monadic.rb
|
170
|
+
- lib/easy_monads/option.rb
|
171
|
+
- lib/easy_monads/option_functions.rb
|
172
|
+
- test/helper.rb
|
173
|
+
- test/test_easy_monads.rb
|
174
|
+
homepage: https://github.com/bkr/easy_monads
|
175
|
+
licenses:
|
176
|
+
- MIT
|
177
|
+
post_install_message:
|
178
|
+
rdoc_options: []
|
179
|
+
|
180
|
+
require_paths:
|
181
|
+
- lib
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
183
|
+
none: false
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
hash: 3
|
188
|
+
segments:
|
189
|
+
- 0
|
190
|
+
version: "0"
|
191
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
|
+
none: false
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
hash: 3
|
197
|
+
segments:
|
198
|
+
- 0
|
199
|
+
version: "0"
|
200
|
+
requirements: []
|
201
|
+
|
202
|
+
rubyforge_project:
|
203
|
+
rubygems_version: 1.8.10
|
204
|
+
signing_key:
|
205
|
+
specification_version: 3
|
206
|
+
summary: EasyMonads is a simple implementation of monads for Ruby
|
207
|
+
test_files: []
|
208
|
+
|