sea_food 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 229c5e0090e1f77fe0603d6dd101c2a95a4b8b2ac6df8e3e6a4bfb2a33fe1dba
4
- data.tar.gz: a214594cb13e3f68a19780e89379396cc3555fe704d6aa5bd560c5d961b8592f
3
+ metadata.gz: '09caa9ace45be8850e8639249d6838094845be06718b0c70e384873a35612020'
4
+ data.tar.gz: 4b77831dc3d9decd91d67f735baea6bd3cfb27c0519d581d1e6988f6d8ff0194
5
5
  SHA512:
6
- metadata.gz: eccdcd9327f73be12b69603edf85868c24004a60e8e772682369fab85bc19404a6d7d59bf541b8481504577570ace291b4e816778bebed229bd71a66e71a328b
7
- data.tar.gz: 0d03a7f7a0ced6aa30bc611239863c2f4a38bad6a4869c641a3be80d49338ebf367098e14a1260b06c0ed75117a26b4071f22fcac5f382c4f1c8124ddd0b40fd
6
+ metadata.gz: 710db87b3d97c5cf54c3ad05599efd80a499a6d3610212a8c7289fa67d678eaf6213cf02f49801bf3fe86fb8713d2fed2d73d3a9b4b9eb6c8baa6d39b521c6b4
7
+ data.tar.gz: 49c68b7d88ef0526fa7f9762e0b5f264dd135a174287993b73e31e412dfc8ee225623c1c11bd4c966f50bb446459f83a604f31c46839c76368df51bff7b7ff83
data/.rubocop.yml CHANGED
@@ -42,7 +42,7 @@ Metrics/BlockLength:
42
42
  - 'sea_food.gemspec'
43
43
  - config/**/*
44
44
  - spec/**/*
45
- ExcludedMethods:
45
+ AllowedMethods:
46
46
  - class_methods
47
47
 
48
48
  Metrics/BlockNesting:
@@ -97,9 +97,14 @@ Style/MissingRespondToMissing:
97
97
  Exclude:
98
98
  - 'lib/sea_food/service.rb'
99
99
 
100
- Style/MethodMissingSuper:
100
+ Lint/MissingSuper:
101
101
  Exclude:
102
102
  - 'lib/sea_food/service.rb'
103
+ - spec/**/*
103
104
 
104
105
  Naming/PredicateName:
105
- Enabled: false
106
+ Enabled: false
107
+
108
+ Lint/ConstantDefinitionInBlock:
109
+ Exclude:
110
+ - 'spec/**/*'
data/README.md CHANGED
@@ -53,6 +53,197 @@ end
53
53
  ```
54
54
  It will raise an `ArgumentError`.
55
55
 
56
+
57
+ ### Handling Success and Failure
58
+ #### Using success and fail
59
+ `success(data):` Marks the service result as successful and optionally provides data.
60
+ `fail(data):` Marks the service result as a failure but continues executing the call method.
61
+ `fail!(data):` Marks the service result as a failure and immediately exits the call method.
62
+ #### Example: Using fail followed by success
63
+ ```ruby
64
+ class TestFailService < SeaFood::Service
65
+ def initialize(email:)
66
+ @email = email
67
+ end
68
+
69
+ def call
70
+ fail(email: 'hi@example.com')
71
+ success(email: @email)
72
+ end
73
+ end
74
+
75
+ result = TestFailService.call(email: 'service@example.com')
76
+
77
+ puts result.success? # => true
78
+ puts result.email # => 'service@example.com'
79
+ ```
80
+ In this example:
81
+
82
+ The fail method sets the result to failure but allows the method to continue.
83
+ The subsequent success call overrides the failure, resulting in a successful outcome.
84
+
85
+ #### Example: Using fail! to Exit Early
86
+ ```ruby
87
+ class TestFailBangService < SeaFood::Service
88
+ def initialize(email:)
89
+ @email = email
90
+ end
91
+
92
+ def call
93
+ fail!(email: 'hi@example.com')
94
+ success(email: @email) # This line is not executed
95
+ end
96
+ end
97
+
98
+ result = TestFailBangService.call(email: 'service@example.com')
99
+
100
+ puts result.success? # => false
101
+ puts result.email # => 'hi@example.com'
102
+ ```
103
+
104
+ The `fail!` method immediately exits the call method.
105
+ The service result is a failure, and subsequent code in call is not executed.
106
+ Nested Services
107
+ You can call other services within a service. The behavior depends on whether you use `call` or `call!`.
108
+ #### Summary of call vs. call!
109
+ `call`: Executes the service and returns the result. Does not raise an exception if the service fails.
110
+
111
+ `call!`: Executes the service and raises an exception if the service fails. Useful for propagating failures in nested services.
112
+
113
+ #### Using call (Non-Bang Method)
114
+ Failures in nested services do not automatically propagate to the parent service.
115
+
116
+
117
+ ```ruby
118
+ class InnerService < SeaFood::Service
119
+ def initialize(email:)
120
+ @email = email
121
+ end
122
+
123
+ def call
124
+ fail!(email: @email)
125
+ end
126
+ end
127
+
128
+ class OuterService < SeaFood::Service
129
+ def initialize(email:)
130
+ @email = email
131
+ end
132
+
133
+ def call
134
+ InnerService.call(email: 'inner@example.com')
135
+ success(email: @email)
136
+ end
137
+ end
138
+
139
+ result = OuterService.call(email: 'outer@example.com')
140
+
141
+ puts result.success? # => true
142
+ puts result.email # => 'outer@example.com'
143
+ ```
144
+ *Explanation:*
145
+
146
+ `InnerService` fails using `fail!`.
147
+ `OuterService` calls `InnerService` using `call`.
148
+ Since `call` does not raise an exception on failure, `OuterService` continues and succeeds.
149
+
150
+ #### Using `call!` (Bang Method)
151
+ Failures in nested services propagate to the parent service when using `call!`.
152
+
153
+ ```ruby
154
+ class InnerService < SeaFood::Service
155
+ def initialize(email:)
156
+ @email = email
157
+ end
158
+
159
+ def call
160
+ fail!(email: @email)
161
+ end
162
+ end
163
+
164
+ class OuterService < SeaFood::Service
165
+ def initialize(email:)
166
+ @email = email
167
+ end
168
+
169
+ def call
170
+ InnerService.call!(email: 'inner@example.com')
171
+ success(email: @email) # This line is not executed
172
+ end
173
+ end
174
+
175
+ result = OuterService.call(email: 'outer@example.com')
176
+
177
+ puts result.success? # => false
178
+ puts result.email # => 'inner@example.com'
179
+ ```
180
+ *Explanation:*
181
+
182
+ `InnerService` fails using `fail!`.
183
+ `OuterService` calls `InnerService` using call!.
184
+ The failure from `InnerService` propagates, causing `OuterService` to fail.
185
+ #### Handling Failures in Nested Services
186
+ You can handle failures from nested services by checking their result.
187
+
188
+ ```ruby
189
+ class InnerService < SeaFood::Service
190
+ def initialize(value:)
191
+ @value = value
192
+ end
193
+
194
+ def call
195
+ if @value < 0
196
+ fail!(error: 'Negative value')
197
+ else
198
+ success(value: @value)
199
+ end
200
+ end
201
+ end
202
+
203
+ class OuterService < SeaFood::Service
204
+ def initialize(value:)
205
+ @value = value
206
+ end
207
+
208
+ def call
209
+ result = InnerService.call(value: @value)
210
+
211
+ if result.fail?
212
+ fail!(error: result.error)
213
+ else
214
+ success(value: result.value * 2)
215
+ end
216
+ end
217
+ end
218
+
219
+ result = OuterService.call(value: -1)
220
+
221
+ puts result.success? # => false
222
+ puts result.error # => 'Negative value'
223
+ ```
224
+ *Explanation:*
225
+
226
+ `OuterService` checks the result of `InnerService`.
227
+ If `InnerService` fails, `OuterService` handles it accordingly.
228
+
229
+ #### Accessing Result Data
230
+ The result object allows you to access data provided in success or fail calls using method syntax.
231
+
232
+ ```ruby
233
+ class ExampleService < SeaFood::Service
234
+ def call
235
+ success(message: 'Operation successful', value: 42)
236
+ end
237
+ end
238
+
239
+ result = ExampleService.call
240
+
241
+ puts result.success? # => true
242
+ puts result.message # => 'Operation successful'
243
+ puts result.value # => 42
244
+ ```
245
+
246
+
56
247
  ## Development
57
248
 
58
249
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -21,12 +21,18 @@ module SeaFood
21
21
  # @param args [Hash] Arguments to pass to the service.
22
22
  # @return [ServiceResult] The result of the service call.
23
23
  def call(params = {})
24
- # debugger
25
24
  service = new(**params)
26
25
  service.call
27
26
  service.result || ServiceResult.new
28
27
  rescue ServiceError => e
29
- service.result
28
+ service.result || e.try(:result)
29
+ end
30
+
31
+ def call!(params = {})
32
+ result = call(params)
33
+ return result || ServiceResult.new unless result.fail?
34
+
35
+ raise ServiceError, result
30
36
  end
31
37
  end
32
38
 
@@ -113,7 +119,13 @@ module SeaFood
113
119
  end
114
120
  end
115
121
 
116
- class ServiceError < StandardError; end
122
+ class ServiceError < StandardError
123
+ attr_reader :result
124
+
125
+ def initialize(result)
126
+ @result = result
127
+ end
128
+ end
117
129
 
118
130
  private
119
131
 
@@ -1,3 +1,3 @@
1
1
  module SeaFood
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
data/sea_food.gemspec CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = 'A Ruby gem for seamlessly integrating form and service object patterns.'
13
13
  spec.homepage = 'https://github.com/eagerworks/sea_food'
14
14
  spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
15
16
 
16
17
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
18
  # to allow pushing to a single host or delete this section to allow pushing to any host.
@@ -43,6 +44,6 @@ Gem::Specification.new do |spec|
43
44
  spec.add_development_dependency 'debug'
44
45
  spec.add_development_dependency 'rake'
45
46
  spec.add_development_dependency 'rspec', '~> 3.0'
46
- spec.add_development_dependency 'rubocop', '~> 0.80.0'
47
+ spec.add_development_dependency 'rubocop', '~> 1.0'
47
48
  spec.add_development_dependency 'sqlite3', '~> 1.5.0'
48
49
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sea_food
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Federico Aldunate
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-01 00:00:00.000000000 Z
11
+ date: 2024-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.80.0
131
+ version: '1.0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.80.0
138
+ version: '1.0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: sqlite3
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -192,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
192
  requirements:
193
193
  - - ">="
194
194
  - !ruby/object:Gem::Version
195
- version: '0'
195
+ version: 2.7.0
196
196
  required_rubygems_version: !ruby/object:Gem::Requirement
197
197
  requirements:
198
198
  - - ">="