option 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.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in option.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Rob Ares
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,62 @@
1
+ # Option
2
+
3
+ A Ruby port os Scala's Option monad. Tries to be faithful
4
+ but also pragmatic in RE: to ducktyping.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'option'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install option
19
+
20
+ ## Usage
21
+
22
+ Generally, you want to use the Option(A) wrapper method to box
23
+ your value. This will make the right decision as to what your initial
24
+ value should be:
25
+
26
+ ```ruby
27
+ foo = Option("bar")
28
+ ```
29
+
30
+ This will allow you to now manipulate the value in the box via various means:
31
+
32
+ ```ruby
33
+
34
+ # get the value
35
+ foo.get #=> "bar"
36
+
37
+ # return a default if the box is None
38
+ None.get_or_else { "default" } #=> "default"
39
+
40
+ # map the value to another option
41
+ foo.map { |v| v.upcase } #=> Some("BAR")
42
+
43
+ # does the value meet a requirement?
44
+ foo.exists? { |v| v == "bar" } #=> true
45
+
46
+ # return the value or nil depending on the state
47
+ foo.or_nil #=> "bar"
48
+
49
+ # chain values
50
+ foo.map { |v| v * 2 }.map { |v| v.upcase }.get_or_else { "missing" } #=> BARBAR
51
+
52
+ # attempt to extract a value but default if None
53
+ None.fold(-> { "missing" }) { |v| v.upcase } #=> missing
54
+ ```
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it
59
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
61
+ 4. Push to the branch (`git push origin my-new-feature`)
62
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:spec) do |test|
7
+ test.libs << "lib" << "spec"
8
+ test.pattern = "spec/**/*_spec.rb"
9
+ end
data/lib/option.rb ADDED
@@ -0,0 +1,115 @@
1
+ class Option
2
+
3
+ def or_nil
4
+ end
5
+
6
+ def ==(that)
7
+ or_nil == that.or_nil
8
+ end
9
+ end
10
+
11
+ class Some < Option
12
+
13
+ def initialize(value)
14
+ @value = value
15
+ end
16
+
17
+ def to_a
18
+ [get]
19
+ end
20
+
21
+ def get
22
+ @value
23
+ end
24
+
25
+ def get_or_else(&blk)
26
+ get
27
+ end
28
+
29
+ def foreach(&blk)
30
+ blk.call(get)
31
+
32
+ nil
33
+ end
34
+
35
+ def or_nil
36
+ get
37
+ end
38
+
39
+ def empty?
40
+ false
41
+ end
42
+
43
+ def map(&blk)
44
+ Option(blk.call(get))
45
+ end
46
+
47
+ def flat_map(&blk)
48
+ result = blk.call(get)
49
+ case result
50
+ when Option then return result
51
+ else raise TypeError, "Must be Option"
52
+ end
53
+ end
54
+
55
+ def fold(if_empty, &blk)
56
+ blk.call(get)
57
+ end
58
+
59
+ def exists?(&blk)
60
+ !! blk.call(get)
61
+ end
62
+ end
63
+
64
+ class NoneClass < Option
65
+
66
+ def to_a
67
+ []
68
+ end
69
+
70
+ def get
71
+ raise IndexError, "None.get"
72
+ end
73
+
74
+ def get_or_else(&blk)
75
+ blk.call
76
+ end
77
+
78
+ def foreach(&blk)
79
+ nil
80
+ end
81
+
82
+ def or_nil
83
+ nil
84
+ end
85
+
86
+ def empty?
87
+ true
88
+ end
89
+
90
+ def map(&blk)
91
+ flat_map(&blk)
92
+ end
93
+
94
+ def flat_map(&blk)
95
+ self
96
+ end
97
+
98
+ def fold(if_empty, &blk)
99
+ if_empty.call
100
+ end
101
+
102
+ def exists?(&blk)
103
+ false
104
+ end
105
+ end
106
+
107
+ None = NoneClass.new
108
+
109
+ def Some(value)
110
+ Some.new(value)
111
+ end
112
+
113
+ def Option(value)
114
+ value.nil? ? None : Some(value)
115
+ end
@@ -0,0 +1,3 @@
1
+ module Option
2
+ VERSION = "0.0.1"
3
+ end
data/option.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/option/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Rob Ares"]
6
+ gem.email = ["rob.ares@gmail.com"]
7
+ gem.description = %q{Ruby port of Scala's Option Monad}
8
+ gem.summary = %q{Option attempts to be faithful to the useful parts of the scala api. We lose the type safety but still is quite useful when dealing with optional values.}
9
+ gem.homepage = "http://www.robares.com/"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(spec)/})
14
+ gem.name = "option"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Option::VERSION
17
+
18
+ gem.add_development_dependency "rake", "= 0.9.2.2"
19
+ gem.add_development_dependency "rr", "= 1.0.4"
20
+ gem.add_development_dependency "minitest", "= 3.4.0"
21
+ end
@@ -0,0 +1,157 @@
1
+ require "minitest/autorun"
2
+ require "minitest/spec"
3
+
4
+ require "rr"
5
+ require "rr/adapters/rr_methods"
6
+
7
+ require "option"
8
+
9
+ include RR::Adapters::RRMethods
10
+
11
+ def value
12
+ 12
13
+ end
14
+
15
+ describe NoneClass do
16
+
17
+ it "#to_a returns an empty array" do
18
+ None.to_a.must_equal([])
19
+ end
20
+
21
+ it "#get raises IndexError" do
22
+ lambda { None.get }.must_raise IndexError
23
+ end
24
+
25
+ it "#get_or_else executes the block" do
26
+ None.get_or_else { "Some" }.must_equal "Some"
27
+ end
28
+
29
+ it "#foreach does not execute the block" do
30
+ blk = proc {}
31
+ dont_allow(blk).call
32
+
33
+ None.foreach(&blk)
34
+
35
+ RR.verify
36
+ end
37
+
38
+ it "#or_nil should return nil" do
39
+ None.or_nil.must_be_nil
40
+ end
41
+
42
+ it "#empty? should be true" do
43
+ None.empty?.must_equal(true)
44
+ end
45
+
46
+ it "#map should return itself" do
47
+ None.map {}.must_equal(None)
48
+ end
49
+
50
+ it "#flat_map should return itself" do
51
+ None.flat_map {}.must_equal(None)
52
+ end
53
+
54
+ it "#exists? should return false" do
55
+ None.exists? {}.must_equal(false)
56
+ end
57
+
58
+ it "#fold should invoke the default proc" do
59
+ None.fold(proc { value }) { |v| v.to_f }.must_equal(value)
60
+ end
61
+
62
+ it "should be aliased to None" do
63
+ None.must_be_instance_of(NoneClass)
64
+ end
65
+ end
66
+
67
+ describe Some do
68
+
69
+ it "#to_a returns the value wrapped in an array" do
70
+ Some(value).to_a.must_equal([value])
71
+ end
72
+
73
+ it "#get returns the inner value" do
74
+ Some(value).get.must_equal(value)
75
+ end
76
+
77
+ it "#get_or_else does not execute the block;" do
78
+ blk = proc { value }
79
+ dont_allow(blk).call
80
+
81
+ Some(value).get_or_else(&blk)
82
+
83
+ RR.verify
84
+ end
85
+
86
+ it "#get_or_else returns the value" do
87
+ Some(value).get_or_else { }.must_equal(value)
88
+ end
89
+
90
+ it "#foreach executes the block passing the inner value" do
91
+ blk = proc {}
92
+ mock(blk).call(value)
93
+
94
+ Some(value).foreach(&blk)
95
+
96
+ RR.verify
97
+ end
98
+
99
+ it "#or_nil should return the inner value" do
100
+ Some(value).or_nil.must_equal(value)
101
+ end
102
+
103
+ it "#empty? should be false" do
104
+ Some(value).empty?.must_equal(false)
105
+ end
106
+
107
+ it "#map should return the result of the proc over the value in an Option" do
108
+ Some(value).map { |v| v * 2 }.must_equal(Some(24))
109
+ end
110
+
111
+ it "#flat_map should raise TypeError if the returned value is not an Option" do
112
+ lambda { Some(value).flat_map { |v| v * 2 } }.must_raise TypeError
113
+ end
114
+
115
+ it "#flat_map should return an Option value from the block" do
116
+ Some(value).flat_map { |v| Option(v * 2) }.must_equal(Some(24))
117
+ end
118
+
119
+ it "#flat_map can return None from the block" do
120
+ Some(value).flat_map { |_| None }.must_equal(None)
121
+ end
122
+
123
+ it "#exists? should return true when the block evaluates true" do
124
+ Some(value).exists? { |v| v % 2 == 0 }.must_equal(true)
125
+ end
126
+
127
+ it "#exists? should return false when the block evaluates false" do
128
+ Some(value).exists? { |v| v % 2 != 0 }.must_equal(false)
129
+ end
130
+
131
+ it "#fold should map the proc over the value and return it" do
132
+ Some(value).fold(proc { value * 2 }) { |v| v * 3 }.must_equal(36)
133
+ end
134
+
135
+ it "should be aliased to Some" do
136
+ Some.must_equal(Some)
137
+ end
138
+
139
+ it "should wrap the creation of a Some" do
140
+ mock(Some).new(value)
141
+
142
+ Some(value)
143
+
144
+ RR.verify
145
+ end
146
+ end
147
+
148
+ describe Option do
149
+
150
+ it "must return a some if the passed value is not nil" do
151
+ Option(value).must_equal(Some(value))
152
+ end
153
+
154
+ it "must return a None if the passed value is nil" do
155
+ Option(nil).must_equal(None)
156
+ end
157
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: option
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Rob Ares
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70150970015480 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.2.2
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70150970015480
25
+ - !ruby/object:Gem::Dependency
26
+ name: rr
27
+ requirement: &70150970014980 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - =
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.4
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70150970014980
36
+ - !ruby/object:Gem::Dependency
37
+ name: minitest
38
+ requirement: &70150970014520 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
43
+ version: 3.4.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70150970014520
47
+ description: Ruby port of Scala's Option Monad
48
+ email:
49
+ - rob.ares@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - LICENSE
57
+ - README.md
58
+ - Rakefile
59
+ - lib/option.rb
60
+ - lib/option/version.rb
61
+ - option.gemspec
62
+ - spec/option_spec.rb
63
+ homepage: http://www.robares.com/
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.10
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Option attempts to be faithful to the useful parts of the scala api. We lose
87
+ the type safety but still is quite useful when dealing with optional values.
88
+ test_files:
89
+ - spec/option_spec.rb