tron 2.0.0 → 3.0.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.
- checksums.yaml +4 -4
- data/README.md +36 -23
- data/lib/tron/version.rb +4 -2
- data/lib/tron.rb +9 -12
- metadata +11 -94
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc919787c5b549b14e26fc8d2d2a1cfd601bfbf6320751e0e4862d23856ec604
|
|
4
|
+
data.tar.gz: 74e32cc0cd310b830bb58bb5a92c4e44f4a966d9271557ad7482337051d8dcf5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 82a40a2046b62244b66cf7dbc52210215359b9f61112bd4836363b65491f7aec939be457d9a67de6bc7093cd9bdfc7676074a4cc791ba14a64389d18891c429f
|
|
7
|
+
data.tar.gz: 51149e095d5bf173eafeb4a99f46b4890bc47f6dcee8b8c8cbe4337ca59f5c94df436073b263aa2d1b152330a3e50d5654f15d0193728d174164e715f00e2923
|
data/README.md
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
[](https://rubygems.org/gems/tron)
|
|
2
|
-
[](https://github.com/halo/tron/actions)
|
|
3
3
|
[](http://github.com/halo/tron/blob/master/LICENSE.md)
|
|
4
4
|
|
|
5
5
|
## TL;DR
|
|
6
6
|
|
|
7
7
|
Tron is a minimalistic combination of a [monad](https://www.morozov.is/2018/09/08/monad-laws-in-ruby.html) and [value object](https://madeintandem.com/blog/creating-value-objects-in-ruby/), implemented in [a few lines](https://github.com/halo/tron/blob/master/lib/tron.rb) of code.
|
|
8
8
|
|
|
9
|
-
Return `Tron.success(:it_worked)` or `Tron.failure(:aww_too_bad)` from a method to explain why and how it succeded
|
|
10
|
-
|
|
11
|
-
The
|
|
12
|
-
|
|
13
|
-
Chaining can make your code cleaner: `result.on_success { download }.on_failure { show_message }`
|
|
9
|
+
* Return `Tron.success(:it_worked)` or `Tron.failure(:aww_too_bad)` from a method, to explain why and how it succeded or failed. That returns an immutable Data (value object) that responds to `result.success?` and `result.failure?`.
|
|
10
|
+
* Add metadata as a second argument: `Tron.failure(:nopes, error_code: 404)` which you then can access: `result.error_code #=> 404`.
|
|
11
|
+
* The result can also be queried with `result.success #=> :it_worked` and `result.failure #=> nil`.
|
|
12
|
+
* Chaining can make your code cleaner: `result.on_success { download }.on_failure { show_message }`
|
|
14
13
|
|
|
15
14
|
## Introduction
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
16
|
Imagine you have a class like this:
|
|
20
17
|
|
|
21
18
|
```ruby
|
|
@@ -42,7 +39,7 @@ class User
|
|
|
42
39
|
if @users.delete id
|
|
43
40
|
Tron.success :user_deleted, user: user
|
|
44
41
|
else
|
|
45
|
-
Tron.success :
|
|
42
|
+
Tron.success :already_deleted, id: id # Notice the success here
|
|
46
43
|
end
|
|
47
44
|
|
|
48
45
|
rescue ConnectionError
|
|
@@ -51,7 +48,7 @@ class User
|
|
|
51
48
|
end
|
|
52
49
|
```
|
|
53
50
|
|
|
54
|
-
One could
|
|
51
|
+
One could break the functionality apart into smaller pieces:
|
|
55
52
|
|
|
56
53
|
```ruby
|
|
57
54
|
class User
|
|
@@ -83,11 +80,20 @@ class User
|
|
|
83
80
|
end
|
|
84
81
|
```
|
|
85
82
|
|
|
86
|
-
|
|
83
|
+
On a side-note, the data object can be passed on further with modifications, that's due to the way `Data` object work.
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
result = Tron.success(:api_not_responding, reason: :password_not_accepted)
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
result.with(code: :could_not_delete_user)
|
|
89
|
+
# => "#<data failure=:could_not_delete_user, reason=:password_not_accepted>"
|
|
90
|
+
```
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
## So, what are the benefits?
|
|
93
|
+
|
|
94
|
+
### 1. An internal API that doesn't change over time
|
|
95
|
+
|
|
96
|
+
Tron will give you a consistent, implementation-unaware, programming convention. That means that you can decide later, what constitutes a success or a failure, without changing the way the result is handled. You could also add metadata after-the-fact and the following code would still work fine:
|
|
91
97
|
|
|
92
98
|
```ruby
|
|
93
99
|
result = User.delete 42
|
|
@@ -99,7 +105,7 @@ else
|
|
|
99
105
|
end
|
|
100
106
|
```
|
|
101
107
|
|
|
102
|
-
The result is just
|
|
108
|
+
The result is just an instance of Data:
|
|
103
109
|
|
|
104
110
|
```ruby
|
|
105
111
|
result = User.delete 42
|
|
@@ -114,9 +120,7 @@ result.failure # => :deletion_failed_badly
|
|
|
114
120
|
|
|
115
121
|
# Access immutable metadata
|
|
116
122
|
result.message # => "..."
|
|
117
|
-
result.inspect # => "#<
|
|
118
|
-
|
|
119
|
-
result.message.upcase! # => modification raises an exception
|
|
123
|
+
result.inspect # => "#<data failure=:alright, user_id=42, message='...'>"
|
|
120
124
|
```
|
|
121
125
|
|
|
122
126
|
### 2. If will give you better tests
|
|
@@ -138,15 +142,20 @@ class Product
|
|
|
138
142
|
end
|
|
139
143
|
```
|
|
140
144
|
|
|
141
|
-
You cannot simply test for
|
|
145
|
+
You cannot simply test for `false` as expected return value, because it could mean anything. Tron helps you to check the response objects for every case. Data objects even support deconstruction for `case` statements.
|
|
142
146
|
|
|
143
147
|
### 3. It gives you documentation
|
|
144
148
|
|
|
145
|
-
While the code you're writing becomes slightly more verbose, that verbosity translates directly into
|
|
149
|
+
While the code you're writing becomes slightly more verbose, that verbosity translates directly into documentation. You see immediately what each line is doing.
|
|
150
|
+
|
|
151
|
+
## Upgrading from 2.0.0 to 3.0.0
|
|
152
|
+
|
|
153
|
+
* You will need to use at least Ruby `3.2`
|
|
154
|
+
* The result object doesn't respond to collection methods any more, such as `result[:some_key]` or `result.to_a`, but it's unlikely that you relied on them in the first place.
|
|
146
155
|
|
|
147
156
|
## Upgrading from 1.x.x to 2.0.0
|
|
148
157
|
|
|
149
|
-
* 1.2.0 and 2.0.0 are identical, except that all deprecations have been removed and don't work any more.
|
|
158
|
+
* `1.2.0` and `2.0.0` are identical, except that all deprecations have been removed and don't work any more.
|
|
150
159
|
|
|
151
160
|
## Upgrading from 0.x.x to 1.x.x
|
|
152
161
|
|
|
@@ -161,12 +170,16 @@ Tron is a complete rewrite of its predecessor [operation](https://github.com/hal
|
|
|
161
170
|
|
|
162
171
|
## Requirements
|
|
163
172
|
|
|
164
|
-
* Ruby >= 2.
|
|
173
|
+
* Ruby >= 3.2.0
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
Clone the repository, run `bundle install` and run the tests with `bundle exec rake`.
|
|
165
178
|
|
|
166
179
|
## Copyright
|
|
167
180
|
|
|
168
|
-
MIT
|
|
181
|
+
MIT halo. See [MIT-LICENSE](http://github.com/halo/tron/blob/master/LICENSE.txt).
|
|
169
182
|
|
|
170
183
|
## Caveats
|
|
171
184
|
|
|
172
|
-
* There are no setter methods in the returned
|
|
185
|
+
* There are no setter methods in the returned Data, so you cannot overwrite the metadata. But you can use `Data#with` to essentially clone the object and change values.
|
data/lib/tron/version.rb
CHANGED
data/lib/tron.rb
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require 'tron/version'
|
|
4
4
|
|
|
5
|
+
# Return data objects that can indicate success or failure.
|
|
5
6
|
module Tron
|
|
6
|
-
def self.success(code, attributes = {}) # rubocop:disable Metrics/MethodLength
|
|
7
|
+
def self.success(code, attributes = {}) # rubocop:disable Metrics/MethodLength
|
|
7
8
|
code.respond_to?(:to_sym) ||
|
|
8
9
|
raise(ArgumentError, 'Tron.success must be called with a Symbol as first argument')
|
|
9
10
|
|
|
@@ -11,12 +12,10 @@ module Tron
|
|
|
11
12
|
raise(ArgumentError, 'The second argument (metadata) for Tron.success must respond to #keys')
|
|
12
13
|
|
|
13
14
|
attributes.respond_to?(:values) ||
|
|
14
|
-
raise(ArgumentError,
|
|
15
|
-
|
|
16
|
-
Struct.new(:success, *attributes.keys) do
|
|
17
|
-
undef_method :[]=
|
|
18
|
-
members.each { |member| undef_method :"#{member}=" }
|
|
15
|
+
raise(ArgumentError,
|
|
16
|
+
'The second argument (metadata) for Tron.success must respond to #values')
|
|
19
17
|
|
|
18
|
+
Data.define(:success, *attributes.keys) do
|
|
20
19
|
def success?
|
|
21
20
|
true
|
|
22
21
|
end
|
|
@@ -39,7 +38,7 @@ module Tron
|
|
|
39
38
|
end.new code.to_sym, *attributes.values
|
|
40
39
|
end
|
|
41
40
|
|
|
42
|
-
def self.failure(code, attributes = {}) # rubocop:disable Metrics/MethodLength
|
|
41
|
+
def self.failure(code, attributes = {}) # rubocop:disable Metrics/MethodLength
|
|
43
42
|
code.respond_to?(:to_sym) ||
|
|
44
43
|
raise(ArgumentError, 'Tron.failure must be called with a Symbol as first argument')
|
|
45
44
|
|
|
@@ -47,12 +46,10 @@ module Tron
|
|
|
47
46
|
raise(ArgumentError, 'The second argument (metadata) for Tron.failure must respond to #keys')
|
|
48
47
|
|
|
49
48
|
attributes.respond_to?(:values) ||
|
|
50
|
-
raise(ArgumentError,
|
|
51
|
-
|
|
52
|
-
Struct.new(:failure, *attributes.keys) do
|
|
53
|
-
undef_method :[]=
|
|
54
|
-
members.each { |member| undef_method :"#{member}=" }
|
|
49
|
+
raise(ArgumentError,
|
|
50
|
+
'The second argument (metadata) for Tron.failure must respond to #values')
|
|
55
51
|
|
|
52
|
+
Data.define(:failure, *attributes.keys) do
|
|
56
53
|
def success?
|
|
57
54
|
false
|
|
58
55
|
end
|
metadata
CHANGED
|
@@ -1,103 +1,19 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tron
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- halo
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: guard-rspec
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
20
|
-
type: :development
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: hashie
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: rb-fsevent
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - ">="
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
48
|
-
type: :development
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - ">="
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rspec
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ">="
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - ">="
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: rubocop
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - ">="
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rubocop-rspec
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
11
|
+
date: 2023-08-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
97
13
|
description: General-purpose method return objects that can be chained. Think minimalistic
|
|
98
14
|
value object monads. Heavily inspired by the `deterministic` gem, but much much
|
|
99
15
|
more light-weight.
|
|
100
|
-
email:
|
|
16
|
+
email:
|
|
101
17
|
executables: []
|
|
102
18
|
extensions: []
|
|
103
19
|
extra_rdoc_files: []
|
|
@@ -108,8 +24,9 @@ files:
|
|
|
108
24
|
homepage: https://github.com/halo/tron
|
|
109
25
|
licenses:
|
|
110
26
|
- MIT
|
|
111
|
-
metadata:
|
|
112
|
-
|
|
27
|
+
metadata:
|
|
28
|
+
rubygems_mfa_required: 'true'
|
|
29
|
+
post_install_message:
|
|
113
30
|
rdoc_options: []
|
|
114
31
|
require_paths:
|
|
115
32
|
- lib
|
|
@@ -117,15 +34,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
117
34
|
requirements:
|
|
118
35
|
- - ">="
|
|
119
36
|
- !ruby/object:Gem::Version
|
|
120
|
-
version: 2.
|
|
37
|
+
version: 3.2.0
|
|
121
38
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
39
|
requirements:
|
|
123
40
|
- - ">="
|
|
124
41
|
- !ruby/object:Gem::Version
|
|
125
42
|
version: '0'
|
|
126
43
|
requirements: []
|
|
127
|
-
rubygems_version: 3.
|
|
128
|
-
signing_key:
|
|
44
|
+
rubygems_version: 3.4.18
|
|
45
|
+
signing_key:
|
|
129
46
|
specification_version: 4
|
|
130
47
|
summary: General-purpose method return objects that can be chained.
|
|
131
48
|
test_files: []
|