tron 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -23
  3. data/lib/tron/version.rb +4 -2
  4. data/lib/tron.rb +9 -12
  5. metadata +11 -94
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3d033d6fa697cd4da7d443028e7ca891676266f8e41ecf00be057d52e84e0e0
4
- data.tar.gz: 222f4a27b2acd1f887ee5deeb6e41b475f45c027c82663174129d7d83db6e5f5
3
+ metadata.gz: dc919787c5b549b14e26fc8d2d2a1cfd601bfbf6320751e0e4862d23856ec604
4
+ data.tar.gz: 74e32cc0cd310b830bb58bb5a92c4e44f4a966d9271557ad7482337051d8dcf5
5
5
  SHA512:
6
- metadata.gz: cbb6fe573460da64aac5a59da8148fc766dfc73152cb8f887950fd4b99e90c7e2f9c0ebabed249d44f6e5b28dc912e48506866f29d0b44a65e84a7318f9339c8
7
- data.tar.gz: 497c6f228706f96d9157a9600de35af4bd2e432177ed7c5e66c6c37e10f6dc74a874467a1b8ca235066619e36a3db8bea51c390bd5e540a2ab641e1dfe5f2617
6
+ metadata.gz: 82a40a2046b62244b66cf7dbc52210215359b9f61112bd4836363b65491f7aec939be457d9a67de6bc7093cd9bdfc7676074a4cc791ba14a64389d18891c429f
7
+ data.tar.gz: 51149e095d5bf173eafeb4a99f46b4890bc47f6dcee8b8c8cbe4337ca59f5c94df436073b263aa2d1b152330a3e50d5654f15d0193728d174164e715f00e2923
data/README.md CHANGED
@@ -1,21 +1,18 @@
1
1
  [![Gem Version](https://img.shields.io/gem/v/tron.svg)](https://rubygems.org/gems/tron)
2
- [![Build Status](https://travis-ci.org/halo/tron.svg?branch=master)](https://travis-ci.org/halo/tron)
2
+ [![Build Status](https://github.com/halo/tron/actions/workflows/main.yml/badge.svg)](https://github.com/halo/tron/actions)
3
3
  [![License](http://img.shields.io/badge/license-MIT-blue.svg)](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/failed. That returns an immutable Struct (value object) that responds to `result.success?` and `result.failure?`.
10
-
11
- The reason is accessible in `result.success #=> :it_worked`. You can add more metadata as a second argument: `Tron.failure(:nopes, error_code: 404)` which you can access like a Struct: `result.error_code #=> 404`.
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 :deletion_failed, id: id
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 even take it a step further and write it like this:
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
- ## So what are the benefits?
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
- ### 1. It will give you robust and predictable code
88
+ result.with(code: :could_not_delete_user)
89
+ # => "#<data failure=:could_not_delete_user, reason=:password_not_accepted>"
90
+ ```
89
91
 
90
- Tron will give you this consistent, implementation-unaware, programming convention:
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 a Struct:
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 # => "#<struct failure=:alright, user_id=42, message='...'>"
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 the `false` as expected return value because it could mean anything. Tron helps you to check the response objects for every case.
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 documenation. You see immediately what each line is doing.
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.5.0
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 2015-2019 halo. See [MIT-LICENSE](http://github.com/halo/tron/blob/master/LICENSE.md).
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 Struct, so you cannot overwrite the metadata. The values are also frozen, so you don't accidentally modify the attributes in-place. However, they are not deep-frozen, so an object may still be modified if you're ignorant.
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
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tron
2
- module VERSION #:nodoc:
3
- MAJOR = 2
4
+ module VERSION # :nodoc:
5
+ MAJOR = 3
4
6
  MINOR = 0
5
7
  TINY = 0
6
8
  PRE = nil
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, Metrics/AbcSize
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, 'The second argument (metadata) for Tron.success must respond to #values')
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, Metrics/AbcSize
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, 'The second argument (metadata) for Tron.failure must respond to #values')
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: 2.0.0
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: 2021-10-30 00:00:00.000000000 Z
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
- post_install_message:
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.5.0
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.1.2
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: []