tron 1.2.0 → 3.0.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
2
  SHA256:
3
- metadata.gz: 0231e5a13e707acc3ec83ffc50af2cb846b01c31ba8e2bb9fc105e78d30bd60e
4
- data.tar.gz: b3ab4cd46c20a71bfc2673345f5da04ca0a388e2141c259387976952ddd7c983
3
+ metadata.gz: dc919787c5b549b14e26fc8d2d2a1cfd601bfbf6320751e0e4862d23856ec604
4
+ data.tar.gz: 74e32cc0cd310b830bb58bb5a92c4e44f4a966d9271557ad7482337051d8dcf5
5
5
  SHA512:
6
- metadata.gz: 187817f794d517f5c176f2c719344485df1afaca69cd32caf4e94b271f38a6a80e9dd0f328e2368bc0762985e7acf711b1f77c47fb77621e77e65080101a084f
7
- data.tar.gz: 80811f5605325a75668bdbe9e8de95f18eb481ccd094e2f4b10f6a772b4fb483c876d34c06906b42e89ad8fafffea375d1620d4a0d111e4a1d40f067f34eed04
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
@@ -64,13 +61,13 @@ class User
64
61
  def self.check_id_syntax(id)
65
62
  return Tron.failure(:id_missing) unless id
66
63
  return Tron.failure(:invalid_id, id: id) unless id.match /[a-f]{8}/
67
-
64
+
68
65
  Tron.success :id_looks_good
69
66
  end
70
67
 
71
68
  def self.delete_user(id)
72
69
  user = @users[id]
73
-
70
+
74
71
  if @users.delete id
75
72
  Tron.success :user_deleted, user: user
76
73
  else
@@ -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.
87
84
 
88
- ### 1. It will give you robust and predictable code
85
+ ```ruby
86
+ result = Tron.success(:api_not_responding, reason: :password_not_accepted)
87
+
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,11 +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.
155
+
156
+ ## Upgrading from 1.x.x to 2.0.0
157
+
158
+ * `1.2.0` and `2.0.0` are identical, except that all deprecations have been removed and don't work any more.
146
159
 
147
160
  ## Upgrading from 0.x.x to 1.x.x
148
161
 
@@ -157,12 +170,16 @@ Tron is a complete rewrite of its predecessor [operation](https://github.com/hal
157
170
 
158
171
  ## Requirements
159
172
 
160
- * Ruby >= 2.3.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`.
161
178
 
162
179
  ## Copyright
163
180
 
164
- 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).
165
182
 
166
183
  ## Caveats
167
184
 
168
- * 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,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Tron
2
- module VERSION #:nodoc:
3
- MAJOR = 1
4
- MINOR = 2
4
+ module VERSION # :nodoc:
5
+ MAJOR = 3
6
+ MINOR = 0
5
7
  TINY = 0
6
8
  PRE = nil
7
9
 
data/lib/tron.rb CHANGED
@@ -2,12 +2,9 @@
2
2
 
3
3
  require 'tron/version'
4
4
 
5
- require 'tron/resultable' # Legacy
6
- require 'tron/success' # Legacy
7
- require 'tron/failure' # Legacy
8
-
5
+ # Return data objects that can indicate success or failure.
9
6
  module Tron
10
- def self.success(code, attributes = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
7
+ def self.success(code, attributes = {}) # rubocop:disable Metrics/MethodLength
11
8
  code.respond_to?(:to_sym) ||
12
9
  raise(ArgumentError, 'Tron.success must be called with a Symbol as first argument')
13
10
 
@@ -15,12 +12,10 @@ module Tron
15
12
  raise(ArgumentError, 'The second argument (metadata) for Tron.success must respond to #keys')
16
13
 
17
14
  attributes.respond_to?(:values) ||
18
- raise(ArgumentError, 'The second argument (metadata) for Tron.success must respond to #values')
19
-
20
- Struct.new(:success, *attributes.keys) do
21
- undef_method :[]=
22
- members.each { |member| undef_method :"#{member}=" }
15
+ raise(ArgumentError,
16
+ 'The second argument (metadata) for Tron.success must respond to #values')
23
17
 
18
+ Data.define(:success, *attributes.keys) do
24
19
  def success?
25
20
  true
26
21
  end
@@ -33,13 +28,6 @@ module Tron
33
28
  nil
34
29
  end
35
30
 
36
- def code
37
- warn 'DEPRECATION WARNING: Calling `#code` on a Tron object is deprecated and will be removed in Tron 2.0.0. ' \
38
- "Please use `#success` instead. Called from `#{caller.first}`"
39
-
40
- success
41
- end
42
-
43
31
  def on_success(proc = nil, &block)
44
32
  (proc || block).call self
45
33
  end
@@ -50,7 +38,7 @@ module Tron
50
38
  end.new code.to_sym, *attributes.values
51
39
  end
52
40
 
53
- def self.failure(code, attributes = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
41
+ def self.failure(code, attributes = {}) # rubocop:disable Metrics/MethodLength
54
42
  code.respond_to?(:to_sym) ||
55
43
  raise(ArgumentError, 'Tron.failure must be called with a Symbol as first argument')
56
44
 
@@ -58,12 +46,10 @@ module Tron
58
46
  raise(ArgumentError, 'The second argument (metadata) for Tron.failure must respond to #keys')
59
47
 
60
48
  attributes.respond_to?(:values) ||
61
- raise(ArgumentError, 'The second argument (metadata) for Tron.failure must respond to #values')
62
-
63
- Struct.new(:failure, *attributes.keys) do
64
- undef_method :[]=
65
- members.each { |member| undef_method :"#{member}=" }
49
+ raise(ArgumentError,
50
+ 'The second argument (metadata) for Tron.failure must respond to #values')
66
51
 
52
+ Data.define(:failure, *attributes.keys) do
67
53
  def success?
68
54
  false
69
55
  end
@@ -76,13 +62,6 @@ module Tron
76
62
  nil
77
63
  end
78
64
 
79
- def code
80
- warn 'DEPRECATION WARNING: Calling `#code` on a Tron object is deprecated and will be removed in Tron 2.0.0. ' \
81
- "Please use `#failure` instead. Called from `#{caller.first}`"
82
-
83
- failure
84
- end
85
-
86
65
  def on_success(_ = nil)
87
66
  self
88
67
  end
metadata CHANGED
@@ -1,90 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tron
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.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: 2016-11-29 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'
11
+ date: 2023-08-25 00:00:00.000000000 Z
12
+ dependencies: []
69
13
  description: General-purpose method return objects that can be chained. Think minimalistic
70
14
  value object monads. Heavily inspired by the `deterministic` gem, but much much
71
15
  more light-weight.
72
- email:
16
+ email:
73
17
  executables: []
74
18
  extensions: []
75
19
  extra_rdoc_files: []
76
20
  files:
77
21
  - README.md
78
22
  - lib/tron.rb
79
- - lib/tron/failure.rb
80
- - lib/tron/resultable.rb
81
- - lib/tron/success.rb
82
23
  - lib/tron/version.rb
83
24
  homepage: https://github.com/halo/tron
84
25
  licenses:
85
26
  - MIT
86
- metadata: {}
87
- post_install_message:
27
+ metadata:
28
+ rubygems_mfa_required: 'true'
29
+ post_install_message:
88
30
  rdoc_options: []
89
31
  require_paths:
90
32
  - lib
@@ -92,15 +34,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
34
  requirements:
93
35
  - - ">="
94
36
  - !ruby/object:Gem::Version
95
- version: 2.3.0
37
+ version: 3.2.0
96
38
  required_rubygems_version: !ruby/object:Gem::Requirement
97
39
  requirements:
98
40
  - - ">="
99
41
  - !ruby/object:Gem::Version
100
42
  version: '0'
101
43
  requirements: []
102
- rubygems_version: 3.1.2
103
- signing_key:
44
+ rubygems_version: 3.4.18
45
+ signing_key:
104
46
  specification_version: 4
105
47
  summary: General-purpose method return objects that can be chained.
106
48
  test_files: []
data/lib/tron/failure.rb DELETED
@@ -1,13 +0,0 @@
1
- module Tron
2
- class Failure
3
- include Resultable
4
-
5
- def on_success(_ = nil)
6
- self
7
- end
8
-
9
- def on_failure(proc = nil, &block)
10
- (proc || block).call
11
- end
12
- end
13
- end
@@ -1,65 +0,0 @@
1
- module Tron
2
- module Resultable
3
- attr_reader :metadata
4
-
5
- def self.included(receiver)
6
- receiver.extend ::Tron::Resultable::ClassMethods
7
- end
8
-
9
- module ClassMethods
10
- # Convenience wrapper
11
- def call(code, metadata = nil)
12
- new code: code, metadata: metadata
13
- end
14
- end
15
-
16
- def initialize(code: nil, metadata: nil)
17
- @code = code
18
- @metadata = metadata
19
- warn 'DEPRECATION WARNING: As of Tron 1.0.0 calls to `Tron::Success.call` and `Tron::Failure.call` are deprecated. ' \
20
- 'They will be removed in Tron 2.0.0. Please migrate using `Tron.success` and `Tron.failure`. ' \
21
- "See github.com/halo/tron Called in:: `#{caller[2]}`"
22
- end
23
-
24
- def success?
25
- is_a? ::Tron::Success
26
- end
27
-
28
- def failure?
29
- is_a? ::Tron::Failure
30
- end
31
-
32
- def code
33
- return if @code.to_s == ''
34
-
35
- @code.to_s.to_sym
36
- end
37
-
38
- # Convenience Wrapper
39
- def object
40
- metadata[:object] || metadata['object']
41
- rescue StandardError
42
- nil
43
- end
44
-
45
- def meta
46
- if defined? ::Hashie::Mash
47
- metamash
48
- else
49
- metadata
50
- end
51
- end
52
-
53
- private
54
-
55
- def metamash
56
- if metadata.respond_to? :each_pair
57
- ::Hashie::Mash.new metadata
58
- elsif metadata
59
- metadata
60
- else
61
- ::Hashie::Mash.new
62
- end
63
- end
64
- end
65
- end
data/lib/tron/success.rb DELETED
@@ -1,13 +0,0 @@
1
- module Tron
2
- class Success
3
- include Resultable
4
-
5
- def on_success(proc = nil, &block)
6
- (proc || block).call
7
- end
8
-
9
- def on_failure(_ = nil)
10
- self
11
- end
12
- end
13
- end