resultr 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1651637e66e98a6a7001ee31ec00314f2a64c42ddb1520d20d4f407271b383ab
4
+ data.tar.gz: 4aca80aa9cc55ec641d255a3c05984ecea4f8cdc75a334179a20f813900c9f74
5
+ SHA512:
6
+ metadata.gz: 1843722ea0e26a7a67c8b693c613e567f269a12fb62a765452bab23e7a54a414753a76886dc539a39d545688d824f06a85e8d1914364248a833aade06104276c
7
+ data.tar.gz: 31ec642597a4a10651b25234b321e1518e184fef7eb43e290f4e23a7462157a0940a9d10d3dd8de857536e2ecfa41da51aa8775d0ad298b4d3b2b07a20936440
@@ -0,0 +1,7 @@
1
+ .ruby-version
2
+ .ruby-gemset
3
+ .bundle
4
+ .DS_Store
5
+ Gemfile.lock
6
+ tags
7
+ resultr-*.gem
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5.0
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Metrics/BlockLength:
8
+ Exclude: test/**/*.rb
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.5.0
6
+ before_install:
7
+ - gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Leonardo Camelo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,169 @@
1
+ # Resultr
2
+
3
+ [![Build Status](https://travis-ci.org/leocamelo/resultr.svg?branch=master)](https://travis-ci.org/leocamelo/resultr)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/d59916bca76b37153273/maintainability)](https://codeclimate.com/github/leocamelo/resultr/maintainability)
5
+
6
+ Ruby beautiful results.
7
+
8
+ Resultr provides a simple interface to work with computation results, highly
9
+ inspired by [Rust results](https://doc.rust-lang.org/std/result) for handling
10
+ errors on function returns.
11
+
12
+ ## Installation
13
+
14
+ Add Resultr to your `Gemfile`:
15
+
16
+ ```ruby
17
+ gem 'resultr'
18
+ ```
19
+
20
+ and run `bundle install` from your shell.
21
+
22
+ ## Getting Started
23
+
24
+ ### Good and bad results
25
+
26
+ Resultr works with two kinds of results, good results (`Resultr.ok`) and bad
27
+ results (`Resultr.err`). You can store any kind of data on any kind of result.
28
+
29
+ ```ruby
30
+ good_result = Resultr.ok(42)
31
+ # => <Resultr::Result @kind=:ok @value=42>
32
+
33
+ good_result.ok?
34
+ # => true
35
+
36
+ good_result.value
37
+ # => 42
38
+
39
+ bad_result = Resultr.err('foo')
40
+ # => <Resultr::Result @kind=:err @value="foo">
41
+
42
+ bad_result.err?
43
+ # => true
44
+
45
+ bad_result.reason
46
+ # => "foo"
47
+ ```
48
+
49
+ *`#reason` is an alias of `#value`, but is a common practice
50
+ to use `#value` for good results and `#reason` for bad results.*
51
+
52
+ ### Chaining results
53
+
54
+ You can chain results with `#and_then` and `#or_else` methods,
55
+ both will receive a block using result's value / reason and returns
56
+ the block return or itself, depending on result kind.
57
+
58
+ ```ruby
59
+ def shout(word)
60
+ if word == 'marco'
61
+ Resultr.ok('polo')
62
+ else
63
+ Resultr.err('unknown word')
64
+ end
65
+ end
66
+
67
+ # =========================================
68
+ # Using #and_then to chaining good results.
69
+ # =========================================
70
+
71
+ shout('marco').and_then { |value| "#{value}!" }
72
+ # => "polo!"
73
+
74
+ shout('foo').and_then { |value| "#{value}!" }
75
+ # => <Resultr::Result @kind=:err @value="unknown word">
76
+
77
+ # =======================================
78
+ # Using #or_else to chaining bad results.
79
+ # =======================================
80
+
81
+ shout('marco').or_else { |reason| "#{reason}, try 'marco'" }
82
+ # => <Resultr::Result @kind=:ok @value="polo">
83
+
84
+ shout('foo').or_else { |reason| "#{reason}, try 'marco'" }
85
+ # => "unknown word, try 'marco'"
86
+
87
+ # ================================================
88
+ # Using both to chaining the two kinds of results.
89
+ # ================================================
90
+
91
+ shout('marco').and_then { |v| "#{v}!" }.or_else { |r| "#{r}, try 'marco'" }
92
+ # => "polo!"
93
+
94
+ shout('foo').and_then { |v| "#{v}!" }.or_else { |r| "#{r}, try 'marco'" }
95
+ # => "unknown word, try 'marco'"
96
+ ```
97
+
98
+ ### Elegant result branching
99
+
100
+ Resultr provides a sugar syntax for branching results by kind,
101
+ its called `#thus` and works like a flavor of case statement.
102
+
103
+ ```ruby
104
+ def get_posts
105
+ response = get('/posts')
106
+
107
+ if response.status == 200
108
+ Resultr.ok(response.body)
109
+ else
110
+ Resultr.err(response.body)
111
+ end
112
+ end
113
+
114
+ # ==================================
115
+ # Using #thus for branching actions.
116
+ # ==================================
117
+
118
+ get_posts.thus do |result|
119
+ result.ok do |value|
120
+ render json: { posts: value }
121
+ end
122
+ result.err do |reason|
123
+ render json: { error: reason }
124
+ end
125
+ end
126
+ # => ["{\"posts\":[{\"title\":\"The Free Lunch Is Over\"}]}"]
127
+
128
+ # =====================================
129
+ # Using #thus for branching assignment.
130
+ # =====================================
131
+
132
+ posts = get_posts.thus do |result|
133
+ result.ok # if you omit the block, it returns value
134
+ result.err { |_reason| [{ title: 'The Placeholder Post' }] }
135
+ end
136
+ # => [{ title: "The Free Lunch Is Over" }]
137
+ ```
138
+
139
+ ### Raising exceptions for bad results
140
+
141
+ If you don't want to handle possible result errors, you can use
142
+ `#expect!`, that returns the result value when successful or raises
143
+ an exception with the error reason, you can also provides a custom
144
+ message for the exception.
145
+
146
+ ```ruby
147
+ def write_on(file, text)
148
+ if File.exist?(file)
149
+ File.open(file, 'w') { |f| f.write(text) }
150
+ Resultr.ok(text)
151
+ else
152
+ Resultr.err('File not found')
153
+ end
154
+ end
155
+
156
+ write_on('diary.txt', 'Dear diary').expect!
157
+ # => "Dear diary"
158
+
159
+ write_on('wrong.txt', 'Dear diary').expect!
160
+ # => Resultr::ExpectationError: File not found
161
+
162
+ write_on('wrong.txt', 'Dear diary').expect!('Failed to write text')
163
+ # => Resultr::ExpectationError: Failed to write text
164
+ ```
165
+
166
+ ## License
167
+
168
+ Resultr is freely distributable under the
169
+ [MIT license](https://github.com/leocamelo/resultr/blob/master/LICENSE)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new :test do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ task default: :test
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resultr/version'
4
+ require 'resultr/expectation_error'
5
+ require 'resultr/result'
6
+ require 'resultr/result_proxy'
7
+
8
+ module Resultr
9
+ def self.ok(value)
10
+ ::Resultr::Result.new(:ok, value)
11
+ end
12
+
13
+ def self.err(reason)
14
+ ::Resultr::Result.new(:err, reason)
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resultr
4
+ class ExpectationError < StandardError; end
5
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resultr
4
+ class Result
5
+ attr_reader :value
6
+ alias reason value
7
+
8
+ def initialize(kind, value)
9
+ @kind = kind
10
+ @value = value
11
+ end
12
+
13
+ def ok?
14
+ @kind == :ok
15
+ end
16
+
17
+ def err?
18
+ @kind == :err
19
+ end
20
+
21
+ def and_then
22
+ if ok?
23
+ yield @value
24
+ else
25
+ self
26
+ end
27
+ end
28
+
29
+ def or_else
30
+ if err?
31
+ yield @value
32
+ else
33
+ self
34
+ end
35
+ end
36
+
37
+ def expect!(message = @value)
38
+ if ok?
39
+ @value
40
+ else
41
+ raise ::Resultr::ExpectationError, message
42
+ end
43
+ end
44
+
45
+ def thus
46
+ result_proxy = ::Resultr::ResultProxy.new(self)
47
+ yield result_proxy
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resultr
4
+ class ResultProxy
5
+ def initialize(result)
6
+ @result = result
7
+ @resolved = false
8
+ end
9
+
10
+ def ok
11
+ resolve_result_if :ok? do |value|
12
+ if block_given?
13
+ yield value
14
+ else
15
+ value
16
+ end
17
+ end
18
+ end
19
+
20
+ def err
21
+ resolve_result_if :err? do |reason|
22
+ if block_given?
23
+ yield reason
24
+ else
25
+ reason
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def resolve_result_if(condition)
33
+ if @resolved
34
+ @result.value
35
+ elsif @result.send(condition)
36
+ @resolved = true
37
+ yield @result.value
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resultr
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'resultr/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'resultr'
9
+ spec.version = Resultr::VERSION
10
+ spec.authors = ['@leocamelo']
11
+ spec.email = ['leonardocamelo.nave@gmail.com']
12
+ spec.summary = 'Ruby beatiful results'
13
+ spec.homepage = 'https://github.com/leocamelo/resultr'
14
+ spec.license = 'MIT'
15
+ spec.require_paths = ['lib']
16
+
17
+ spec.description = <<~DESCRIPTION
18
+ Resultr provides a simple interface to work with
19
+ computation results, highly inspired by Rust results
20
+ for handling errors on function returns.
21
+ DESCRIPTION
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
24
+ f.match(%r{^(test)/})
25
+ end
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.16'
28
+ spec.add_development_dependency 'minitest', '~> 5.0'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resultr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - "@leocamelo"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: |
56
+ Resultr provides a simple interface to work with
57
+ computation results, highly inspired by Rust results
58
+ for handling errors on function returns.
59
+ email:
60
+ - leonardocamelo.nave@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - ".rubocop.yml"
67
+ - ".travis.yml"
68
+ - Gemfile
69
+ - LICENSE
70
+ - README.md
71
+ - Rakefile
72
+ - lib/resultr.rb
73
+ - lib/resultr/expectation_error.rb
74
+ - lib/resultr/result.rb
75
+ - lib/resultr/result_proxy.rb
76
+ - lib/resultr/version.rb
77
+ - resultr.gemspec
78
+ homepage: https://github.com/leocamelo/resultr
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.7.3
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Ruby beatiful results
102
+ test_files: []