resonad 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7eee55274773363f0220a61e2d4714d11a129869
4
- data.tar.gz: 05873de655e1cc85fe147e7b247788ad273f10d9
2
+ SHA256:
3
+ metadata.gz: 2751182e01f6cf2c97cdc99d46cb716ec1e517d52680bc75c92fd0f5c1bd693f
4
+ data.tar.gz: 2d1a5a21e81f7da804fa099d16a8b3a2032472e6f89112e4284942d050087293
5
5
  SHA512:
6
- metadata.gz: 34f5b90502c5737493195d5e44ed8b6686f1c9cb3145c240c09609db89deb5e577196e01ba55e3bdf3a9511d4107f996d8a26bbbcc7c4e55fc01f645956e312b
7
- data.tar.gz: a1a80de205c720d7f2ba54e799b97ad7cb0da4edac82b5dfba6aba8ab4b1fa87d7133fc03f71d452b4c834cf9c399ee85f076696290bcccbc6e81e3ac9cda482
6
+ metadata.gz: 6571a2f2e4e2ae98dee8c40efbf0bccf0aed09b6bc18cce47a5fb3fc83cc77c32141b31807d9b64b2842c62dfc737025ac24234dc22a1285f0e9910dae97cced
7
+ data.tar.gz: a000acabecf552daebeff7f10b1e57ab44f7fba224e8e85deb25acb7904b0c97981453931f008b68547b2fdade0e3ebec8d8b868af6757f4271a4a434f075cdb
data/.rspec CHANGED
@@ -1,2 +1,6 @@
1
+ --require spec_helper
2
+ <% if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.7') %>
3
+ --exclude-pattern spec/pattern_matching_spec.rb
4
+ <% end %>
1
5
  --format documentation
2
6
  --color
@@ -0,0 +1 @@
1
+ 2.7
@@ -1,13 +1,25 @@
1
1
  language: ruby
2
+ script: bundle exec rspec
3
+
4
+ # test old rubies
2
5
  rvm:
3
- - 2.2.7
4
- - 2.3.4
5
- - 2.4.1
6
- cache: bundler
6
+ - 2.2.10
7
+ - 2.3.8
8
+ - 2.4.10
9
+ - 2.5.8
10
+ - 2.6.6
11
+
12
+ # test on latest ruby
13
+ matrix:
14
+ include:
15
+ - rvm: 2.7.1
16
+ env: LATEST_RUBY=true
17
+
18
+ # Rubygems deployment
7
19
  deploy:
8
20
  provider: rubygems
9
21
  on:
10
22
  tags: true
11
- rvm: 2.4.1
23
+ condition: $LATEST_RUBY = true
12
24
  api_key:
13
25
  secure: 0+R2SaUaKOZE0U4FwHiC/0DLepizJ1anjfvFEWk5pYVkaZl6HuaSYq50g8ff4VqXBH955Y5W7tFI8gfg4ZY9jrivHyEZT9Yoz3PFFPxcqSdVbDsV12RQt7ZjzW0HbvUhFu9nlrVACfFsLt4WFG61pyhXvewghp1p4JBp2UxeTk1kyL7U+wfWsp1RpcKiHkaLBeWJ0N87j4QkhTfcWlModLqN/19ATigvfyDjrwerkTescVmQi4TzfAiwkeAiDgUB32FkwJjbX9RfIko33CsuctuDRU/HT+RWiXcGAxdHZx4dtQpP9pAiNTVxXdIq+QAvitekIah70pdCTNKrOh3tDj3kglkUK23MqU6kdeXjmUn9r4SuzHCX0sVf16UpfnwuryDDPlG1ISY+mf7BARr/wNQWuAD4MA4kWiPGMqT/0uoysbY7dt44lkO9NV7HBbqs2shqqMtmgPgDoJ+SGTXo8LvrjuL0jHB2/MoHziiqWDKLQ9PS2Fcqp/06d5u8GcSRt7dcgo2rvwnMwRdUW6iCV0zQgzrNccWn/SsJROtgzEIkuLJYO0GIOCgNBJ0euorWqQBEEPniltwh5StSgH2bL5khdPxiI+LhsL7UDhWGiNFl5tlQp8Ob98WmmQ39ZyVAGKlJoe2rdE/IaDVfysVvQV5XzYUVRn4ZKftwubo5Zvw=
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [1.3.0] - 2020-07-12
8
+ ### Added
9
+ - more documentation
10
+ - support for Ruby 2.7 pattern matching
11
+ - `#otherwise` alias for `#or_else`
12
+ - `#map_value` alias for `#map`
13
+ - alternate constructor methods
14
+ - aliases for `#on_success` and `#on_failure`
15
+ - `Success` and `Failure` class constants to `Resonad::Mixin`
16
+ - `Resonad::PublicMixin` for people who want the previous behaviour of
17
+ `Resonad::Mixin`
18
+ ### Changed
19
+ - The methods provided by `Resonad::Mixin` are now private. Replace with
20
+ `Resonad::PublicMixin` to revert them back to being public.
21
+
22
+ ## [1.2.0] - 2017-05-22
23
+ ### Added
24
+ - `Resonad.Success()` and `Resonad.Failure()` arguments are optional, and
25
+ default to nil.
26
+ - `#successful?` and `#ok?` as new aliases for `#success?`
27
+ - `#failed?` and `#bad?` as new aliases for `#failure?`
28
+
29
+ ## [1.1.1] - 2017-05-09
30
+ ### Fixed
31
+ - Aliased methods `#and_then` and `#or_else` were not aliased properly.
32
+
33
+ ## [1.1.0] - 2017-05-01
34
+ ### Added
35
+ - `Resonad::Mixin`
36
+ ### Changed
37
+ - `Resonad` is now a class. `Resonad::Success` and `Resonad::Failure` now
38
+ inherit from `Resonad`.
39
+
40
+ ## [1.0.2] - 2017-04-22
41
+ ### Fixed
42
+ - Typo in class names
43
+
44
+ ## [1.0.1] - 2017-04-22
45
+ ### Changed
46
+ - Nothing (bumped to force a deploy)
47
+
48
+ ## [1.0.0] - 2017-04-22
49
+ ### Added
50
+ - Everything (initial release)
data/README.md CHANGED
@@ -1,15 +1,26 @@
1
+ [![Build Status](https://travis-ci.org/tomdalling/resonad.svg?branch=master)](https://travis-ci.org/tomdalling/resonad)
2
+
1
3
  # Resonad
2
4
 
3
- Usage example (assume each method returns a `Resonad`):
5
+ Lightweight, functional "result" objects that can be used instead of exceptions.
6
+
7
+ Read: [Result Objects - Errors Without Exceptions](https://www.rubypigeon.com/posts/result-objects-errors-without-exceptions/)
8
+
9
+ ## Typical Usage Example
10
+
11
+ Assuming each method returns a `Resonad` (Ruby 2.7 syntax):
4
12
 
5
13
  ```ruby
6
14
  find_widget(widget_id)
7
- .and_then { |widget| update_widget(widget) }
8
- .on_success { |widget| logger.info("Updated #{widget}" }
9
- .on_failure { |error| logger.warn("Widget update failed because #{error}") }
15
+ .and_then { update_widget(_1) }
16
+ .on_success { logger.info("Updated #{_1}" }
17
+ .on_failure { logger.warn("Widget update failed because #{_1}") }
10
18
  ```
11
19
 
12
- Success type:
20
+ ## Success Type
21
+
22
+ A value that represents success. Wraps a `value` that can be any arbitrary
23
+ object.
13
24
 
14
25
  ```ruby
15
26
  result = Resonad.Success(5)
@@ -19,7 +30,10 @@ result.value #=> 5
19
30
  result.error #=> raises an exception
20
31
  ```
21
32
 
22
- Failure type:
33
+ ## Failure Type
34
+
35
+ A value that represents a failure. Wraps an `error` that can be any arbitrary
36
+ object.
23
37
 
24
38
  ```ruby
25
39
  result = Resonad.Failure(:buzz)
@@ -29,39 +43,199 @@ result.value #=> raises an exception
29
43
  result.error #=> :buzz
30
44
  ```
31
45
 
32
- Mapping monads:
46
+ ## Mapping
47
+
48
+ Non-destructive update for the `value` of a `Success` object. Does nothing to
49
+ `Failure` objects.
50
+
51
+ The block takes the `value` as an argument, and returns the new `value`.
33
52
 
34
53
  ```ruby
35
54
  result = Resonad.Success(5)
36
- .map { |i| i + 1 }
37
- .map { |i| i + 1 }
38
- .map { |i| i + 1 }
55
+ .map { _1 + 1 } # 5 + 1 -> 6
56
+ .map { _1 + 1 } # 6 + 1 -> 7
57
+ .map { _1 + 1 } # 7 + 1 -> 8
39
58
  result.success? #=> true
40
59
  result.value #=> 8
41
60
 
42
61
  result = Resonad.Failure(:buzz)
43
- .map { |i| i + 1 }
44
- .map { |i| i + 1 }
45
- .map { |i| i + 1 }
62
+ .map { _1 + 1 } # not run
63
+ .map { _1 + 1 } # not run
64
+ .map { _1 + 1 } # not run
46
65
  result.success? #=> false
47
66
  result.error #=> :buzz
48
67
  ```
49
68
 
50
- Flat mapping monads (a.k.a. `and_then`):
69
+
70
+ ## Aliases
71
+
72
+ Lots of the Resonad methods have aliases.
73
+
74
+ Personally, I can never remember if it's `success?` or `successful?` or `ok?`,
75
+ so let's just do it the Ruby way and allow all of them.
76
+
77
+ ```ruby
78
+ # >>> object creation aliases (same for failure) <<<
79
+ result = Resonad.Success(5)
80
+ result = Resonad.success(5) # lowercase, for those offended by capital letters
81
+ result = Resonad::Success[5] # class constructor method
82
+
83
+ # >>> success aliases <<<
84
+ result.success? #=> true
85
+ result.successful? #=> true
86
+ result.ok? #=> true
87
+
88
+ # >>> failure aliases <<<
89
+ result.failure? #=> false
90
+ result.failed? #=> false
91
+ result.bad? #=> false
92
+
93
+ # >>> mapping aliases <<<
94
+ result.map { _1 + 1 } #=> Success(6)
95
+ result.map_value { _1 + 1 } #=> Success(6)
96
+
97
+ # >>> flat mapping aliases <<<
98
+ result.and_then { Resonad.Success(_1 + 1) } #=> Success(6)
99
+ result.flat_map { Resonad.Success(_1 + 1) } #=> Success(6)
100
+
101
+ # >>> error flat mapping aliases <<<
102
+ result.or_else { Resonad.Failure(_1 + 1) } # not run
103
+ result.otherwise { Resonad.Failure(_1 + 1) } # not run
104
+ result.flat_map_error { Resonad.Success(_1 + 1) } # not run
105
+
106
+ # >>> conditional tap aliases <<<
107
+ # pattern: (on_|if_|when_)(success_alias|failure_alias)
108
+ result.on_success { puts "hi" } # outputs "hi"
109
+ result.if_success { puts "hi" } # outputs "hi"
110
+ result.when_success { puts "hi" } # outputs "hi"
111
+ result.on_ok { puts "hi" } # outputs "hi"
112
+ result.if_ok { puts "hi" } # outputs "hi"
113
+ result.when_ok { puts "hi" } # outputs "hi"
114
+ result.on_successful { puts "hi" } # outputs "hi"
115
+ result.if_successful { puts "hi" } # outputs "hi"
116
+ result.when_successful { puts "hi" } # outputs "hi"
117
+ result.on_failure { puts "hi" } # not run
118
+ result.if_failure { puts "hi" } # not run
119
+ result.when_failure { puts "hi" } # not run
120
+ result.on_bad { puts "hi" } # not run
121
+ result.if_bad { puts "hi" } # not run
122
+ result.when_bad { puts "hi" } # not run
123
+ result.on_failed { puts "hi" } # not run
124
+ result.if_failed { puts "hi" } # not run
125
+ result.when_failed { puts "hi" } # not run
126
+ ```
127
+
128
+
129
+ ## Flat Mapping (a.k.a. `and_then`)
130
+
131
+ Non-destructive update for a `Success` object. Either turns it into another
132
+ `Success` (can have a different `value`), or turns it into a `Failure`. Does
133
+ nothing to `Failure` objects.
134
+
135
+ The block takes the `value` as an argument, and returns a `Resonad` (either
136
+ `Success` or `Failure`).
51
137
 
52
138
  ```ruby
53
139
  result = Resonad.Success(5)
54
- .and_then { |i| Resonad.Success(i + 1) }
55
- .and_then { |i| Resonad.Failure("buzz #{i}") }
56
- .and_then { |i| Resonad.Success(i + 1) }
140
+ .and_then { Resonad.Success(_1 + 1) } # updates to Success(6)
141
+ .and_then { Resonad.Failure("buzz #{_1}") } # updates to Failure("buzz 6")
142
+ .and_then { Resonad.Success(_1 + 1) } # not run (because it's a failure)
57
143
  .error #=> "buzz 6"
58
144
 
59
- # can also use the less-nice `flat_map` method
60
- result
61
- .flat_map { |i| Resonad.Success(i + 1) }
145
+ # also has a less-friendly but more-technically-descriptive alias: `flat_map`
146
+ result.flat_map { Resonad.Success(_1 + 1) }
62
147
  ```
63
148
 
64
- Automatic exception rescuing:
149
+ This is different to Ruby's `#then` method added in 2.6. The block for `#then`
150
+ would take a Resonad argument, regardless of whether it's `Success` or
151
+ `Failure`. The block for `#and_then` takes a _`Success` object's value_, and
152
+ only runs on `Success` objects, not `Failure` objects.
153
+
154
+
155
+ ## Error Mapping
156
+
157
+ Just as `Success` objects can be chained with `#map` and `#and_then`, so can
158
+ `Failure` objects with `#map_error` and `#or_else`. This isn't used as often,
159
+ but has a few use cases such as:
160
+
161
+ ```ruby
162
+ # Use Case: convert an error value into another error value
163
+ make_http_request #=> Failure(404)
164
+ .map_error { |status_code| "HTTP #{status_code} Error" }
165
+ .error #=> "HTTP 404 Error"
166
+
167
+ # Use Case: recover from error, turning into Success
168
+ load_config_file #=> Failure(:config_file_missing)
169
+ .or_else { try_recover_from(_1) }
170
+ .value #=> { :setting => 'default' }
171
+
172
+ def try_recover_from(error)
173
+ if error == :config_file_missing
174
+ Resonad.Success({ setting: 'default' })
175
+ else
176
+ Resonad.Failure(error)
177
+ end
178
+ end
179
+ ```
180
+
181
+
182
+ ## Conditional Tap
183
+
184
+ If you're in the middle of a long chain of methods, and you don't want to break
185
+ the chain to run some kind of side effect, you can use the `#on_success` and
186
+ `#on_failure` methods. These run an arbitrary block code, but do not affect the
187
+ result object in any way. They work like Ruby's `#tap` method, but `Failure`
188
+ objects will not run `on_success` blocks, and `Success` objects will not run
189
+ `on_failure` blocks.
190
+
191
+ ```ruby
192
+ do_step_1
193
+ .and_then { do_step_2(_1) }
194
+ .and_then { do_step_3(_1) }
195
+ .on_success { puts "Successful step 3 result: #{_1}" }
196
+ .and_then { do_step_4(_1) }
197
+ .and_then { do_step_5(_1) }
198
+ .on_failure { puts "Uh oh! Step 5 failed: #{_1} }
199
+ .and_then { do_step_6(_1) }
200
+ .and_then { do_step_7(_1) }
201
+ ```
202
+
203
+ There are lots of aliases for these methods. See the "Aliases" section above.
204
+
205
+
206
+ ## Pattern Matching Support
207
+
208
+ If you are using Ruby 2.7 or later, you can pattern match on Resonad objects.
209
+ For example:
210
+
211
+ ```ruby
212
+ case result
213
+ in { value: } # match any Success
214
+ puts value
215
+ in { error: :not_found } # match Failure(:not_found)
216
+ puts "Thing not found"
217
+ in { error: String => msg } # match any Failure with a String error
218
+ puts "Failed to fetch thing because #{msg}"
219
+ in { error: } # match any Failure
220
+ raise "Unhandled error: #{error.inspect}"
221
+ end
222
+ ```
223
+
224
+ `Resonad.Success(5)` deconstructs to:
225
+
226
+ - Hash: `{ value: 5 }`
227
+ - Array: `[:success, 5]`
228
+
229
+ And `Resonad.Failure('yikes')` deconstructs to:
230
+
231
+ - Hash: `{ error: 'yikes' }`
232
+ - Array: `[:failure, 'yikes']`
233
+
234
+
235
+ ## Automatic Exception Rescuing
236
+
237
+ If no exception is raised, wraps the block's return value in `Success`. If an
238
+ exception is raised, wraps the exception object in `Failure`.
65
239
 
66
240
  ```ruby
67
241
  def try_divide(top, bottom)
@@ -76,3 +250,55 @@ nope = try_divide(6, 0)
76
250
  nope.success? #=> false
77
251
  node.error #=> #<ZeroDivisionError: ZeroDivisionError>
78
252
  ```
253
+
254
+
255
+ ## Convenience Mixin
256
+
257
+ If you're tired of typing "Resonad." in front of everything, you can include
258
+ the `Resonad::Mixin` mixin.
259
+
260
+ ```ruby
261
+ class RobotFortuneTeller
262
+ include Resonad::Mixin
263
+
264
+ def next_fortune
265
+ case rand(0..100)
266
+ when 0..70
267
+ # title-case constructor from Resonad::Mixin
268
+ Success("today is auspicious")
269
+ when 71..95
270
+ # lower-case constructor from Resonad::Mixin
271
+ success("ill omens abound")
272
+ else
273
+ # direct access to classes from Resonad::Mixin
274
+ Failure.new("MALFUNCTION")
275
+ end
276
+ end
277
+ end
278
+ ```
279
+
280
+ Note that `Resonad::Mixin` provides private methods, and private constants, so
281
+ you can't do this:
282
+
283
+ ```ruby
284
+ RobotFortuneTeller.new.Success(5)
285
+ #=> NoMethodError: private method `Success' called for #<RobotFortuneTeller:0x00007fe7fc0ff0c8>
286
+
287
+ RobotFortuneTeller::Success
288
+ #=> NameError: private constant Resonad::Mixin::Success referenced
289
+ ```
290
+
291
+ If you want the methods/constants to be public, then use `Resonad::PublicMixin`
292
+ instead.
293
+
294
+
295
+ ## Contributing
296
+
297
+ Bug reports and pull requests are welcome on GitHub at:
298
+ https://github.com/tomdalling/resonad
299
+
300
+ I'm open to PRs that make the gem more convenient, or that makes calling code
301
+ read better.
302
+
303
+ Make sure your PR has full test coverage.
304
+
@@ -2,28 +2,17 @@ class Resonad
2
2
  class NonExistentError < StandardError; end
3
3
  class NonExistentValue < StandardError; end
4
4
 
5
- module Mixin
6
- def Success(value=nil)
5
+ class Success < Resonad
6
+ attr_accessor :value
7
+
8
+ def self.[](value = nil)
7
9
  if nil == value
8
10
  NIL_SUCCESS
9
11
  else
10
- Success.new(value)
12
+ new(value)
11
13
  end
12
14
  end
13
15
 
14
- def Failure(error=nil)
15
- if nil == error
16
- NIL_FAILURE
17
- else
18
- Failure.new(error)
19
- end
20
- end
21
- end
22
- extend Mixin
23
-
24
- class Success < Resonad
25
- attr_accessor :value
26
-
27
16
  def initialize(value)
28
17
  @value = value
29
18
  freeze
@@ -66,11 +55,27 @@ class Resonad
66
55
  def flat_map_error
67
56
  self
68
57
  end
58
+
59
+ def deconstruct
60
+ [:success, value]
61
+ end
62
+
63
+ def deconstruct_keys(_)
64
+ { value: value }
65
+ end
69
66
  end
70
67
 
71
68
  class Failure < Resonad
72
69
  attr_accessor :error
73
70
 
71
+ def self.[](error = nil)
72
+ if nil == error
73
+ NIL_FAILURE
74
+ else
75
+ new(error)
76
+ end
77
+ end
78
+
74
79
  def initialize(error)
75
80
  @error = error
76
81
  freeze
@@ -113,8 +118,35 @@ class Resonad
113
118
  def flat_map_error
114
119
  yield error
115
120
  end
121
+
122
+ def deconstruct
123
+ [:failure, error]
124
+ end
125
+
126
+ def deconstruct_keys(_)
127
+ { error: error }
128
+ end
116
129
  end
117
130
 
131
+ module PublicMixin
132
+ Success = ::Resonad::Success
133
+ Failure = ::Resonad::Failure
134
+
135
+ def Success(*args); Success[*args]; end
136
+ def success(*args); Success[*args]; end
137
+ def Failure(*args); Failure[*args]; end
138
+ def failure(*args); Failure[*args]; end
139
+ end
140
+
141
+ Mixin = PublicMixin.dup.tap do |mixin|
142
+ mixin.module_eval do
143
+ private(*public_instance_methods)
144
+ private_constant(*constants)
145
+ end
146
+ end
147
+
148
+ extend PublicMixin
149
+
118
150
  def self.rescuing_from(*exception_classes)
119
151
  Success(yield)
120
152
  rescue Exception => e
@@ -143,6 +175,11 @@ class Resonad
143
175
  def failed?; failure?; end
144
176
  def bad?; failure?; end
145
177
 
178
+ def map(&block)
179
+ raise NotImplementedError, "should be implemented in subclass"
180
+ end
181
+ def map_value(&block); map(&block); end
182
+
146
183
  def flat_map
147
184
  raise NotImplementedError, "should be implemented in subclass"
148
185
  end
@@ -152,6 +189,31 @@ class Resonad
152
189
  raise NotImplementedError, "should be implemented in subclass"
153
190
  end
154
191
  def or_else(&block); flat_map_error(&block); end
192
+ def otherwise(&block); flat_map_error(&block); end
193
+
194
+ def on_success(&block)
195
+ raise NotImplementedError, "should be implemented in subclass"
196
+ end
197
+ def if_success(&block); on_success(&block); end
198
+ def when_success(&block); on_success(&block); end
199
+ def on_ok(&block); on_success(&block); end
200
+ def if_ok(&block); on_success(&block); end
201
+ def when_ok(&block); on_success(&block); end
202
+ def on_successful(&block); on_success(&block); end
203
+ def if_successful(&block); on_success(&block); end
204
+ def when_successful(&block); on_success(&block); end
205
+
206
+ def on_failure(&block)
207
+ raise NotImplementedError, "should be implemented in subclass"
208
+ end
209
+ def if_failure(&block); on_failure(&block); end
210
+ def when_failure(&block); on_failure(&block); end
211
+ def on_bad(&block); on_failure(&block); end
212
+ def if_bad(&block); on_failure(&block); end
213
+ def when_bad(&block); on_failure(&block); end
214
+ def on_failed(&block); on_failure(&block); end
215
+ def if_failed(&block); on_failure(&block); end
216
+ def when_failed(&block); on_failure(&block); end
155
217
 
156
218
  NIL_SUCCESS = Success.new(nil)
157
219
  NIL_FAILURE = Failure.new(nil)
@@ -1,3 +1,3 @@
1
1
  class Resonad
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -20,8 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.14"
24
- spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "bundler", ">= 1.15"
25
24
  spec.add_development_dependency "rspec", "~> 3.0"
26
- spec.add_development_dependency "gem-release", "~> 0.7"
25
+ spec.add_development_dependency "gem-release", "~> 2.1"
27
26
  end
metadata CHANGED
@@ -1,43 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resonad
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Dalling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-22 00:00:00.000000000 Z
11
+ date: 2020-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.14'
19
+ version: '1.15'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.14'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
24
+ - - ">="
39
25
  - !ruby/object:Gem::Version
40
- version: '10.0'
26
+ version: '1.15'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rspec
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +44,14 @@ dependencies:
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '0.7'
47
+ version: '2.1'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '0.7'
54
+ version: '2.1'
69
55
  description: Objects that represent success or failure
70
56
  email:
71
57
  - tom@tomdalling.com
@@ -75,12 +61,13 @@ extra_rdoc_files: []
75
61
  files:
76
62
  - ".gitignore"
77
63
  - ".rspec"
64
+ - ".ruby-version"
78
65
  - ".travis.yml"
66
+ - CHANGELOG.md
79
67
  - CODE_OF_CONDUCT.md
80
68
  - Gemfile
81
69
  - LICENSE.txt
82
70
  - README.md
83
- - Rakefile
84
71
  - bin/console
85
72
  - bin/setup
86
73
  - lib/resonad.rb
@@ -106,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
93
  version: '0'
107
94
  requirements: []
108
95
  rubyforge_project:
109
- rubygems_version: 2.4.5
96
+ rubygems_version: 2.7.7
110
97
  signing_key:
111
98
  specification_version: 4
112
99
  summary: Objects that represent success or failure
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec