f_service 0.3.1 → 0.4.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: 4997e65a2e3054de3de7a252a3e85143d41701f44046982ffc583c486755aa1d
4
- data.tar.gz: ea5212762e5529ec315dac3437d29ac75a5c20058d30fdc382fe31b6f18288a6
3
+ metadata.gz: 1e6e4ea7905315820d4149138a6d0acfbcb013cde481b34cb0cbd95247aef439
4
+ data.tar.gz: 7abcb86eaf3080a9c1e8d6bfaca8b5c8a70a932ba0e57fd55e9bd88f479d538c
5
5
  SHA512:
6
- metadata.gz: f3c51bf4006bb0b037361690fabb7e0af7895b393394561ed9a784d89ffe063bd48e573406fbee6675e5d3ef5f9ca3f9085240c6855ece5a7a50259dd6264e98
7
- data.tar.gz: 7af0dfcf8f92fb8ac39b43efc044c5f623c9c52084b0b1a9542a9d6f1902dbe7444eb5b3b00ec043302dfe9b6e78eb879bc1cb335c2e078930bb15c49a9fe176
6
+ metadata.gz: 36ec32dab3e5b223996963426298949403bf606fccd1d58c26362d1c38de8e46a5717f4639264709aee03d11b78b960f270e4db3b003f9688b57b2e0456bb958
7
+ data.tar.gz: 42d233650b876ca35f68b99d2985c4044b1e2989779e9817c9ea20677ecd3bf696e2d22bf7c9c0238b1803ccf74501af7e65ff1ccd70c4878b11be941218fba1
data/CHANGELOG.md CHANGED
@@ -4,13 +4,18 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## Unreleased (master)
8
- <!-- ### Added -->
9
- <!-- ### Changed -->
10
- <!-- ### Removed -->
11
- ---
7
+ ## [0.4.0](https://github.com/Fretadao/f_service/compare/v0.3.1...v0.4.0) (2026-08-19)
12
8
 
13
- ## 0.3.0
9
+
10
+ ### ⚠ BREAKING CHANGES
11
+
12
+ * Failure#then and Success#then were removed; use #and_then, which has always been their alias. Base#success, Base#failure and Base#result were removed; use #Success, #Failure and #Check. Result#type was removed; use #types. The mock_service `type:` argument was removed; use `types:` with an array.
13
+
14
+ ### Features
15
+
16
+ * remove deprecated Failure#then, Success#then and the 0.2.0 leftovers ([#63](https://github.com/Fretadao/f_service/issues/63)) ([69b4e80](https://github.com/Fretadao/f_service/commit/69b4e8099cfdb9850ecab656779436ac9cf16d09))
17
+
18
+ ## 0.3.1
14
19
  ### Added
15
20
  - Drop Support to Ruby 2.6 and 2.7
16
21
  - Add Support to Ruby 3.2 and 3.3
data/README.md CHANGED
@@ -23,9 +23,14 @@ It uses the Result monad for handling operations.
23
23
 
24
24
  Add this line to your application's Gemfile:
25
25
 
26
+ <!-- x-release-please-start-version -->
26
27
  ```ruby
27
- gem 'f_service'
28
+ gem 'f_service', '~> 0.4.0'
28
29
  ```
30
+ <!-- x-release-please-end-version -->
31
+
32
+ > The version above is kept current automatically on every release; pin to
33
+ > whichever version you prefer.
29
34
 
30
35
  And then execute:
31
36
 
@@ -64,11 +69,12 @@ You can optionally specify a list of types which represents that result and a va
64
69
  class User::Create < FService::Base
65
70
  # ...
66
71
  def run
67
- return Failure(:no_name, :invalid_attribute) if @name.nil?
72
+ return Failure(:invalid_name, data: { name: ["can't be blank"] }) if @name.nil?
68
73
 
69
74
  user = UserRepository.create(name: @name)
75
+
70
76
  if user.save
71
- Success(:success, :created, data: user)
77
+ Success(:created, data: user)
72
78
  else
73
79
  Failure(:creation_failed, data: user.errors)
74
80
  end
@@ -78,6 +84,11 @@ end
78
84
 
79
85
  > Remember, you **have** to return an `FService::Result` at the end of your services.
80
86
 
87
+ > Always give your results a type. It says what happened, not just whether it worked, so
88
+ > callers can branch on the reason and a failure is readable in a log without opening the
89
+ > service. Pass the payload in `data:`, including on failures — otherwise `#error` is `nil`
90
+ > and whoever serializes it has nothing to show.
91
+
81
92
  ### Using your service
82
93
 
83
94
  To run your service, use the method `#call` provided by `FService::Base`. We like to use the [implicit call](https://stackoverflow.com/a/19108981/8650655), but you can use it in the form you like most.
@@ -112,7 +123,7 @@ class UsersController < BaseController
112
123
  end
113
124
  ```
114
125
 
115
- > Note that you're not limited to using services inside controllers. They're just PORO's (Play Old Ruby Objects), so you can use in controllers, models, etc. (even other services!).
126
+ > Note that you're not limited to using services inside controllers. They're just PORO's (Plain Old Ruby Objects), so you can use in controllers, models, etc. (even other services!).
116
127
 
117
128
  ### Pattern matching
118
129
 
@@ -121,70 +132,65 @@ The code above could be rewritten using the `#on_success` and `#on_failure` hook
121
132
  ```ruby
122
133
  class UsersController < BaseController
123
134
  def create
124
- User::Create.(user_params)
125
- .on_success { |value| return json_success(value) }
126
- .on_failure { |error| return json_error(error) }
135
+ User::Create
136
+ .call(user_params)
137
+ .on_success { |user| return json_success(user) }
138
+ .on_failure { |errors| return json_error(errors) }
127
139
  end
128
140
  end
129
141
  ```
130
142
 
131
- Or else it is possible to specify an unhandled option to ensure that the callback will process that message anyway the
132
- error.
143
+ > You can ignore any of the callbacks, if you want to.
133
144
 
134
- ```ruby
135
- class UsersController < BaseController
136
- def create
137
- User::Create.(user_params)
138
- .on_success(unhandled: true) { |value| return json_success(value) }
139
- .on_failure(unhandled: true) { |error| return json_error(error) }
140
- end
141
- end
142
- ```
145
+ Once you start matching specific types (below), a result whose type none of the hooks
146
+ mention falls through untouched. Pass `unhandled: true` to run a callback for exactly those
147
+ leftovers:
143
148
 
144
149
  ```ruby
145
150
  class UsersController < BaseController
146
151
  def create
147
- User::Create.(user_params)
148
- .on_success { |value| return json_success(value) }
149
- .on_failure { |error| return json_error(error) }
152
+ User::Create
153
+ .call(user_params)
154
+ .on_success(:created) { |user| return json_success(user) }
155
+ .on_failure(unhandled: true) { |errors| return json_error(errors) }
150
156
  end
151
157
  end
152
158
  ```
153
159
 
154
- > You can ignore any of the callbacks, if you want to.
155
-
156
160
  Going further, you can match the Result type, in case you want to handle them differently:
157
161
 
158
162
  ```ruby
159
163
  class UsersController < BaseController
160
164
  def create
161
- User::Create.(user_params)
162
- .on_success(:user_created) { |value| return json_success(value) }
163
- .on_success(:user_already_exists) { |value| return json_success(value) }
164
- .on_failure(:invalid_data) { |error| return json_error(error) }
165
- .on_failure(:critical_error) do |error|
166
- MyLogger.report_failure(error)
167
-
168
- return json_error(error)
169
- end
165
+ User::Create
166
+ .call(user_params)
167
+ .on_success(:created) { |user| return json_success(user) }
168
+ .on_failure(:invalid_name) { |errors| return json_error(errors) }
169
+ .on_failure(:creation_failed) do |errors|
170
+ MyLogger.report_failure(errors)
171
+
172
+ return json_error(errors)
173
+ end
170
174
  end
171
175
  end
172
176
  ```
173
177
 
174
178
  It's possible to provide multiple types to the hooks too. If the result type matches any of the given types,
175
- the hook will run.
179
+ the hook will run. Say the service also answers `Success(:already_exists, data: user)` when the
180
+ name is taken — both outcomes are fine for the caller:
176
181
 
177
182
  ```ruby
178
183
  class UsersController < BaseController
179
184
  def create
180
- User::Create.(user_params)
181
- .on_success(:user_created, :user_already_exists) { |value| return json_success(value) }
182
- .on_failure(:invalid_data) { |error| return json_error(error) }
183
- .on_failure(:critical_error) do |error|
184
- MyLogger.report_failure(error)
185
-
186
- return json_error(error)
187
- end
185
+ User::Create
186
+ .call(user_params)
187
+ .on_success(:created, :already_exists) { |user| return json_success(user) }
188
+ .on_failure(:invalid_name) { |errors| return json_error(errors) }
189
+ .on_failure(:creation_failed) do |errors|
190
+ MyLogger.report_failure(errors)
191
+
192
+ return json_error(errors)
193
+ end
188
194
  end
189
195
  end
190
196
  ```
@@ -206,9 +212,10 @@ If some step fails, it will short circuit the call chain.
206
212
  ```ruby
207
213
  class UsersController < BaseController
208
214
  def create
209
- result = User::Create.(user_params)
210
- .and_then { |user| User::Login.(user) }
211
- .and_then { |user| User::SendWelcomeEmail.(user) }
215
+ result = User::Create
216
+ .call(user_params)
217
+ .and_then { |user| User::Login.(user) }
218
+ .and_then { |user| User::SendWelcomeEmail.(user) }
212
219
 
213
220
  if result.successful?
214
221
  json_success(result.value)
@@ -224,17 +231,23 @@ You can use the `.to_proc` method on FService::Base to avoid explicit inputs whe
224
231
  ```ruby
225
232
  class UsersController < BaseController
226
233
  def create
227
- result = User::Create.(user_params)
228
- .and_then(&User::Login)
229
- .and_then(&User::SendWelcomeEmail)
234
+ result = User::Create
235
+ .call(user_params)
236
+ .and_then(&User::Login)
237
+ .and_then(&User::SendWelcomeEmail)
230
238
  # ...
231
239
  end
232
240
  end
233
241
  ```
234
242
 
243
+ > **Coming from 0.2.x?** `Success#then` and `Failure#then` were deprecated in 0.3.0 and
244
+ > removed in 0.4.0. Use `#and_then`, which has always been their alias and behaves
245
+ > identically. Note that `#then` also exists on every Ruby object since 2.6, so a leftover
246
+ > call does not raise — it silently yields the Result itself instead of its value.
247
+
235
248
  ### `Check` and `Try`
236
249
 
237
- You can use `Check` to converts a boolean to a Result, truthy values map to `Success`, and falsey values map to `Failures`:
250
+ You can use `Check` to convert a boolean into a Result: truthy values map to `Success`, falsey values to `Failure`.
238
251
 
239
252
  ```ruby
240
253
  Check(:math_works) { 1 < 2 }
@@ -248,73 +261,116 @@ Check(:math_works) { 1 > 2 }
248
261
  using the parameter `catch`.
249
262
 
250
263
  ```ruby
251
- class IHateEvenNumbers < FService::Base
264
+ class Number::DrawOdd < FService::Base
252
265
  def run
253
- Try(:rand_int) do
254
- n = rand(1..10)
255
- raise "Yuck! It's a #{n}" if n.even?
266
+ Try(:drawn_number) do
267
+ drawn_number = rand(1..10)
268
+ raise "Yuck! It's a #{drawn_number}" if drawn_number.even?
256
269
 
257
- n
270
+ drawn_number
258
271
  end
259
272
  end
260
273
  end
261
274
 
262
- IHateEvenNumbers.call
263
- # => #<Success @value=9, @types=[:rand_int]>
275
+ Number::DrawOdd.call
276
+ # => #<Success @value=9, @types=[:drawn_number]>
264
277
 
265
- IHateEvenNumbers.call
266
- # => #<Failure @error=#<RuntimeError: Yuck! It's a 4>, @types=[:rand_int]>
278
+ Number::DrawOdd.call
279
+ # => #<Failure @error=#<RuntimeError: Yuck! It's a 4>, @types=[:drawn_number]>
267
280
  ```
268
281
 
269
282
  ## Testing
270
283
 
271
- We provide some helpers and matchers to make ease to test code envolving Fservice services.
284
+ We provide helpers and matchers to make it easier to test code involving FService services.
272
285
 
273
- To make available in the system, in the file 'spec/spec_helper.rb' or 'spec/rails_helper.rb'
286
+ To make them available, add the following require to `spec/spec_helper.rb` or
287
+ `spec/rails_helper.rb`:
274
288
 
275
- add the folowing require:
276
-
277
- ```rb
289
+ ```ruby
278
290
  require 'f_service/rspec'
279
291
  ```
280
292
 
281
293
  ### Mocking a result
282
294
 
283
- ```rb
284
- mock_service(Uer::Create)
285
- # => Mocks a successful result with all values nil
295
+ `mock_service` stubs the service's `#call` and returns the Result you describe. It is a stub,
296
+ not a message expectation: it does not assert that the service was called, so add your own
297
+ `expect(...).to have_received(:call)` when that is the point of the test.
286
298
 
287
- mock_service(Uer::Create, result: :success)
288
- # => Mocks a successful result with all values nil
299
+ ```ruby
300
+ mock_service(User::Create)
301
+ # => stubs a successful result, with no types and a nil value
289
302
 
290
- mock_service(Uer::Create, result: :success, types: [:created, :success])
291
- # => Mocks a successful result with type created
303
+ mock_service(User::Create, result: :success, types: [:created])
304
+ # => stubs a Success typed :created
292
305
 
293
- mock_service(Uer::Create, result: :success, types: :created, value: instance_spy(User))
294
- # => Mocks a successful result with type created and a value
306
+ mock_service(User::Create, result: :success, types: [:created], value: instance_spy(User))
307
+ # => stubs a Success typed :created carrying a value
295
308
 
296
- mock_service(Uer::Create, result: :failure)
297
- # => Mocs a failure with all nil values
309
+ mock_service(User::Create, result: :failure, types: [:invalid_name])
310
+ # => stubs a Failure typed :invalid_name, with a nil error
298
311
 
299
- mock_service(User::Create, result: :failure, types: [:unprocessable_entity, :client_error])
300
- # => Mocs a failure with a failure type
312
+ mock_service(
313
+ User::Create,
314
+ result: :failure,
315
+ types: [:invalid_name],
316
+ value: { name: ["can't be blank"] }
317
+ )
318
+ # => stubs a Failure typed :invalid_name carrying an error
319
+ ```
301
320
 
302
- mock_service(User::Create, result: :failure, types: [:unprocessable_entity, :client_error], value: { name: ["can't be blank"] })
303
- # => Mocs a failure with a failure type and an error value
321
+ > `value:` fills `#value` on a Success and `#error` on a Failure — it is the payload either
322
+ > way. `types:` also accepts a bare symbol, but an array reads consistently. The deprecated
323
+ > singular `type:` argument was removed in 0.4.0.
324
+
325
+ Need the Result object itself rather than a stub — to pass it around in a unit test, say?
326
+ `f_service_result` builds one:
327
+
328
+ ```ruby
329
+ result = f_service_result(:failure, { name: ["can't be blank"] }, [:invalid_name])
330
+ # => #<Failure @error={name: ["can't be blank"]}, @types=[:invalid_name]>
304
331
  ```
305
332
 
306
333
  ### Matching a result
307
334
 
308
- ```rb
335
+ ```ruby
309
336
  expect(User::Create.(name: 'Joe')).to have_succeed_with(:created)
310
337
 
311
338
  expect(User::Create.(name: 'Joe')).to have_succeed_with(:created).and_value(an_instance_of(User))
312
339
 
313
- expect(User::Create.(name: nil)).to have_failed_with(:invalid_attributes)
340
+ expect(User::Create.(name: nil)).to have_failed_with(:invalid_name)
341
+
342
+ expect(User::Create.(name: nil))
343
+ .to have_failed_with(:invalid_name).and_error({ name: ["can't be blank"] })
344
+
345
+ expect(User::Create.(name: nil))
346
+ .to have_failed_with(:invalid_name).and_error(a_hash_including(name: ["can't be blank"]))
347
+ ```
348
+
349
+ > The matchers compare the type list for **equality**, not inclusion. A service answering
350
+ > `Success(:created, :persisted)` is matched by `have_succeed_with(:created, :persisted)` —
351
+ > `have_succeed_with(:created)` alone fails. Name every type the result carries.
352
+
353
+ Putting it together, a spec for the service built above:
314
354
 
315
- expect(User::Create.(name: nil)).to have_failed_with(:invalid_attributes).and_error({ name: ["can't be blank"] })
355
+ ```ruby
356
+ RSpec.describe User::Create do
357
+ subject(:create_user) { described_class.call(name: name) }
358
+
359
+ context 'when the name is given' do
360
+ let(:name) { 'Joe' }
361
+
362
+ it { is_expected.to have_succeed_with(:created).and_value(an_instance_of(User)) }
363
+ end
364
+
365
+ context 'when the name is missing' do
366
+ let(:name) { nil }
316
367
 
317
- expect(User::Create.(name: nil)).to have_failed_with(:invalid_attributes).and_error(a_hash_including(name: ["can't be blank"]))
368
+ it 'fails naming the offending attribute' do
369
+ expect(create_user)
370
+ .to have_failed_with(:invalid_name).and_error(a_hash_including(:name))
371
+ end
372
+ end
373
+ end
318
374
  ```
319
375
 
320
376
  ## API Docs
@@ -325,11 +381,17 @@ You can access the API docs [here](https://www.rubydoc.info/gems/f_service/).
325
381
 
326
382
  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 allows you to experiment.
327
383
 
328
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
384
+ To install this gem onto your local machine, run `bundle exec rake install`.
385
+
386
+ Releases are automated: the version, the `CHANGELOG.md`, the git tag and the push to
387
+ [rubygems.org](https://rubygems.org) are all derived from
388
+ [Conventional Commits](https://www.conventionalcommits.org/) by release-please. There
389
+ is no version to edit and no release command to run by hand — see
390
+ [CONTRIBUTING.md](CONTRIBUTING.md).
329
391
 
330
392
  ## Contributing
331
393
 
332
- Bug reports and pull requests are welcome on GitHub at https://github.com/Fretadao/f_service.
394
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Fretadao/f_service. Read [CONTRIBUTING.md](CONTRIBUTING.md) first — it covers the commit conventions the release automation depends on.
333
395
 
334
396
  ## License
335
397
 
data/f_service.gemspec CHANGED
@@ -26,10 +26,20 @@ Gem::Specification.new do |spec|
26
26
  spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/f_service'
27
27
  spec.metadata['changelog_uri'] = 'https://github.com/Fretadao/f_service/blob/master/CHANGELOG.md'
28
28
 
29
- # Specify which files should be added to the gem when it is released.
30
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
+ # Ship only what a consumer of the gem needs: the library, the docs and the
30
+ # licence. Everything else tracked in the repository is development tooling and
31
+ # was being packaged until now — CI workflows, git hooks, the Gemfile, and so on.
32
+ development_only = %r{
33
+ ^(bin|test|spec|features)/ # console/setup scripts and test suites
34
+ | ^\.git # .gitignore, .github/, .githooks/
35
+ | ^\.rubocop # linter configuration
36
+ | ^(Gemfile|Rakefile) # development entrypoints
37
+ | ^CONTRIBUTING # contributor documentation
38
+ | release-please # release automation configuration
39
+ }x
40
+
31
41
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
32
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
42
+ `git ls-files -z`.split("\x0").grep_v(development_only)
33
43
  end
34
44
  spec.bindir = 'exe'
35
45
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -78,36 +78,6 @@ module FService
78
78
  raise NotImplementedError, 'Services must implement #run'
79
79
  end
80
80
 
81
- # Returns a successful operation.
82
- # You'll probably want to return this inside {#run}.
83
- #
84
- #
85
- # @example
86
- # class User::ValidateAge < FService::Base
87
- # def initialize(age:)
88
- # @age = age
89
- # end
90
- #
91
- # def run
92
- # return failure(status: 'No age given!', data: @age) if age.blank?
93
- # return failure(status: 'Too young!', data: @age) if age < 18
94
- #
95
- # success(status: 'Valid age.', data: @age)
96
- # end
97
- # end
98
- #
99
- # @deprecated Use {#Success} instead.
100
- # @return [Result::Success] a successful operation
101
- def success(data = nil)
102
- FService.deprecate!(
103
- name: "#{self.class}##{__method__}",
104
- alternative: '#Success',
105
- from: caller[0]
106
- )
107
-
108
- Result::Success.new(data)
109
- end
110
-
111
81
  # Returns a successful result.
112
82
  # You can optionally specify a list of types and a value for your result.
113
83
  # You'll probably want to return this inside {#run}.
@@ -229,67 +199,5 @@ module FService
229
199
  rescue *catch => e
230
200
  Failure(*types, data: e)
231
201
  end
232
-
233
- # Returns a failed operation.
234
- # You'll probably want to return this inside {#run}.
235
- # @example
236
- # class User::ValidateAge < FService::Base
237
- # def initialize(age:)
238
- # @age = age
239
- # end
240
- #
241
- # def run
242
- # return failure(status: 'No age given!', data: @age) if age.blank?
243
- # return failure(status: 'Too young!', data: @age) if age < 18
244
- #
245
- # success(status: 'Valid age.', data: @age)
246
- # end
247
- # end
248
- #
249
- # @deprecated Use {#Failure} instead.
250
- # @return [Result::Failure] a failed operation
251
- def failure(data = nil)
252
- FService.deprecate!(
253
- name: "#{self.class}##{__method__}",
254
- alternative: '#Failure',
255
- from: caller[0]
256
- )
257
-
258
- Result::Failure.new(data)
259
- end
260
-
261
- # Return either {Result::Failure Success} or {Result::Failure Failure}
262
- # given the condition.
263
- #
264
- # @example
265
- # class YearIsLeap < FService::Base
266
- # def initialize(year:)
267
- # @year = year
268
- # end
269
- #
270
- # def run
271
- # return failure(status: 'No year given!', data: @year) if @year.nil?
272
- #
273
- # result(leap?, @year)
274
- # end
275
- #
276
- # private
277
- #
278
- # def leap?
279
- # ((@year % 4).zero? && @year % 100 != 0) || (@year % 400).zero?
280
- # end
281
- # end
282
- #
283
- # @deprecated Use {#Check} instead.
284
- # @return [Result::Success, Result::Failure]
285
- def result(condition, data = nil)
286
- FService.deprecate!(
287
- name: "#{self.class}##{__method__}",
288
- alternative: '#Check',
289
- from: caller[0]
290
- )
291
-
292
- condition ? success(data) : failure(data)
293
- end
294
202
  end
295
203
  end
@@ -22,13 +22,6 @@ module FService
22
22
  @matching_types = []
23
23
  end
24
24
 
25
- # Implements old attribute type. Its deprecated in favor of using types.
26
- def type
27
- FService.deprecate!(name: "#{self.class}##{__method__}", alternative: '#types', from: caller[0])
28
-
29
- types.size == 1 ? types.first : Array(@matching_types).first
30
- end
31
-
32
25
  # This hook runs if the result is successful.
33
26
  # Can receive one or more types to be checked before running the given block.
34
27
  #
@@ -110,12 +110,6 @@ module FService
110
110
  self
111
111
  end
112
112
 
113
- # See #and_then
114
- def then
115
- FService.deprecate!(name: "#{self.class}##{__method__}", alternative: '#and_then', from: caller[0])
116
- and_then
117
- end
118
-
119
113
  # Outputs a string representation of the object
120
114
  #
121
115
  #
@@ -83,13 +83,6 @@ module FService
83
83
  yield(*to_ary)
84
84
  end
85
85
 
86
- # See #and_then
87
- def then(&block)
88
- FService.deprecate!(name: "#{self.class}##{__method__}", alternative: '#and_then', from: caller[0])
89
-
90
- and_then(&block)
91
- end
92
-
93
86
  # Returns itself to the given block.
94
87
  # Use this to chain multiple actions or service calls (only valid when they return a Result).
95
88
  # It works just like the `.and_then` method, but only runs if service is a Failure.
@@ -12,17 +12,8 @@ module FServiceResultHelpers
12
12
  end
13
13
 
14
14
  # Mock a Fservice service call returning a result.
15
- def mock_service(service, result: :success, value: nil, type: :not_passed, types: [])
16
- result_types = Array(types)
17
-
18
- if type != :not_passed
19
- alternative = "mock_service(..., types: [#{type.inspect}])"
20
- name = 'mock_service'
21
- FService.deprecate_argument_name(name: name, argument_name: :type, alternative: alternative, from: caller[0])
22
- result_types = Array(type)
23
- end
24
-
25
- service_result = f_service_result(result, value, result_types)
15
+ def mock_service(service, result: :success, value: nil, types: [])
16
+ service_result = f_service_result(result, value, Array(types))
26
17
  allow(service).to receive(:call).and_return(service_result)
27
18
  end
28
19
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FService
4
4
  # Current version of the gem
5
- VERSION = '0.3.1'
5
+ VERSION = '0.4.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: f_service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fretadao Tech Team
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-07-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: |2
14
13
  FService is a small gem that provides a base class for your services (aka operations).
@@ -20,18 +19,9 @@ executables: []
20
19
  extensions: []
21
20
  extra_rdoc_files: []
22
21
  files:
23
- - ".github/.dependabot.yml"
24
- - ".github/workflows/tests-and-linter.yml"
25
- - ".gitignore"
26
- - ".rubocop.yml"
27
22
  - CHANGELOG.md
28
- - Gemfile
29
- - Gemfile.lock
30
23
  - LICENSE
31
24
  - README.md
32
- - Rakefile
33
- - bin/console
34
- - bin/setup
35
25
  - f_service.gemspec
36
26
  - lib/f_service.rb
37
27
  - lib/f_service/base.rb
@@ -55,7 +45,6 @@ metadata:
55
45
  source_code_uri: https://github.com/Fretadao/f_service
56
46
  documentation_uri: https://www.rubydoc.info/gems/f_service
57
47
  changelog_uri: https://github.com/Fretadao/f_service/blob/master/CHANGELOG.md
58
- post_install_message:
59
48
  rdoc_options: []
60
49
  require_paths:
61
50
  - lib
@@ -70,8 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
59
  - !ruby/object:Gem::Version
71
60
  version: '0'
72
61
  requirements: []
73
- rubygems_version: 3.5.11
74
- signing_key:
62
+ rubygems_version: 3.6.9
75
63
  specification_version: 4
76
64
  summary: A small, monad-based service class
77
65
  test_files: []
@@ -1,8 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: bundler
4
- directory: "/"
5
- schedule:
6
- interval: daily
7
- time: "09:00"
8
- open-pull-requests-limit: 10
@@ -1,28 +0,0 @@
1
- name: Ruby
2
-
3
- on:
4
- push:
5
- branches: [master]
6
- pull_request:
7
- branches: [master]
8
-
9
- jobs:
10
- build:
11
- runs-on: ubuntu-latest
12
- strategy:
13
- matrix:
14
- ruby: [3.0, 3.1, 3.2, 3.3]
15
-
16
- steps:
17
- - uses: actions/checkout@v2
18
- - name: Set up Ruby ${{ matrix.ruby }}
19
- uses: ruby/setup-ruby@v1
20
- with:
21
- ruby-version: ${{ matrix.ruby }}
22
- - name: Build and test with Rake
23
- run: |
24
- gem install bundler
25
- bundle install --jobs 4 --retry 3
26
- bundle exec rake
27
- - name: Rubocop Linter Action
28
- run: bundle exec rubocop --parallel
data/.gitignore DELETED
@@ -1,58 +0,0 @@
1
- *.gem
2
- *.rbc
3
- /.config
4
- /coverage/
5
- /InstalledFiles
6
- /pkg/
7
- /spec/reports/
8
- /spec/examples.txt
9
- /test/tmp/
10
- /test/version_tmp/
11
- /tmp/
12
-
13
- # Used by dotenv library to load environment variables.
14
- # .env
15
-
16
- # Ignore Byebug command history file.
17
- .byebug_history
18
-
19
- ## Specific to RubyMotion:
20
- .dat*
21
- .repl_history
22
- build/
23
- *.bridgesupport
24
- build-iPhoneOS/
25
- build-iPhoneSimulator/
26
-
27
- ## Specific to RubyMotion (use of CocoaPods):
28
- #
29
- # We recommend against adding the Pods directory to your .gitignore. However
30
- # you should judge for yourself, the pros and cons are mentioned at:
31
- # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
- #
33
- # vendor/Pods/
34
-
35
- ## Documentation cache and generated files:
36
- /.yardoc/
37
- /_yardoc/
38
- /doc/
39
- /rdoc/
40
-
41
- ## Environment normalization:
42
- /.bundle/
43
- /vendor/bundle
44
- /lib/bundler/man/
45
-
46
- # for a library or gem, you might want to ignore these files since the code is
47
- # intended to run in multiple environments; otherwise, check them in:
48
- # Gemfile.lock
49
- # .ruby-version
50
- # .ruby-gemset
51
-
52
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
- .rvmrc
54
-
55
- # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
- # .rubocop-https?--*
57
-
58
- .rspec_status
data/.rubocop.yml DELETED
@@ -1,38 +0,0 @@
1
- require:
2
- - rubocop-rspec
3
-
4
- AllCops:
5
- TargetRubyVersion: 3.0.0
6
- NewCops: enable
7
-
8
- Layout/LineLength:
9
- Max: 120
10
-
11
- Metrics/BlockLength:
12
- Exclude:
13
- - "spec/**/*"
14
-
15
- Style/DocumentationMethod:
16
- Enabled: true
17
-
18
- Naming/MethodName:
19
- Exclude:
20
- - lib/f_service/base.rb
21
-
22
- RSpec/ContextWording:
23
- Prefixes:
24
- - and
25
- - but
26
- - when
27
- - with
28
- - without
29
-
30
- RSpec/ExampleLength:
31
- Max: 20
32
-
33
- RSpec/NestedGroups:
34
- Enabled: false
35
-
36
- ##### RUBYGEMS #####
37
- Gemspec/RequireMFA:
38
- Enabled: false
data/Gemfile DELETED
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in f_service.gemspec
6
- gemspec
7
-
8
- group :development, :test do
9
- gem 'pry'
10
- gem 'pry-nav'
11
- gem 'rake', '~> 13.0.0'
12
- gem 'rubocop', '~> 1.60.2', require: false
13
- gem 'rubocop-rspec', require: false
14
- end
15
-
16
- group :docs do
17
- gem 'yard'
18
- end
19
-
20
- group :optional do
21
- gem 'solargraph'
22
- end
23
-
24
- group :test do
25
- gem 'rspec', '~> 3.0'
26
- gem 'simplecov', require: false
27
- end
data/Gemfile.lock DELETED
@@ -1,122 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- f_service (0.3.1)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- ast (2.4.2)
10
- backport (1.2.0)
11
- benchmark (0.3.0)
12
- coderay (1.1.3)
13
- diff-lcs (1.3)
14
- docile (1.3.5)
15
- e2mmap (0.1.0)
16
- jaro_winkler (1.5.6)
17
- json (2.7.1)
18
- kramdown (2.4.0)
19
- rexml
20
- kramdown-parser-gfm (1.1.0)
21
- kramdown (~> 2.0)
22
- language_server-protocol (3.17.0.3)
23
- method_source (1.0.0)
24
- mini_portile2 (2.8.6)
25
- nokogiri (1.16.5)
26
- mini_portile2 (~> 2.8.2)
27
- racc (~> 1.4)
28
- parallel (1.24.0)
29
- parser (3.3.0.5)
30
- ast (~> 2.4.1)
31
- racc
32
- pry (0.14.1)
33
- coderay (~> 1.1)
34
- method_source (~> 1.0)
35
- pry-nav (1.0.0)
36
- pry (>= 0.9.10, < 0.15)
37
- racc (1.7.3)
38
- rainbow (3.1.1)
39
- rake (13.0.1)
40
- regexp_parser (2.9.0)
41
- reverse_markdown (2.1.1)
42
- nokogiri
43
- rexml (3.2.8)
44
- strscan (>= 3.0.9)
45
- rspec (3.9.0)
46
- rspec-core (~> 3.9.0)
47
- rspec-expectations (~> 3.9.0)
48
- rspec-mocks (~> 3.9.0)
49
- rspec-core (3.9.1)
50
- rspec-support (~> 3.9.1)
51
- rspec-expectations (3.9.1)
52
- diff-lcs (>= 1.2.0, < 2.0)
53
- rspec-support (~> 3.9.0)
54
- rspec-mocks (3.9.1)
55
- diff-lcs (>= 1.2.0, < 2.0)
56
- rspec-support (~> 3.9.0)
57
- rspec-support (3.9.2)
58
- rubocop (1.60.2)
59
- json (~> 2.3)
60
- language_server-protocol (>= 3.17.0)
61
- parallel (~> 1.10)
62
- parser (>= 3.3.0.2)
63
- rainbow (>= 2.2.2, < 4.0)
64
- regexp_parser (>= 1.8, < 3.0)
65
- rexml (>= 3.2.5, < 4.0)
66
- rubocop-ast (>= 1.30.0, < 2.0)
67
- ruby-progressbar (~> 1.7)
68
- unicode-display_width (>= 2.4.0, < 3.0)
69
- rubocop-ast (1.30.0)
70
- parser (>= 3.2.1.0)
71
- rubocop-capybara (2.20.0)
72
- rubocop (~> 1.41)
73
- rubocop-factory_bot (2.25.1)
74
- rubocop (~> 1.41)
75
- rubocop-rspec (2.26.1)
76
- rubocop (~> 1.40)
77
- rubocop-capybara (~> 2.17)
78
- rubocop-factory_bot (~> 2.22)
79
- ruby-progressbar (1.13.0)
80
- simplecov (0.21.2)
81
- docile (~> 1.1)
82
- simplecov-html (~> 0.11)
83
- simplecov_json_formatter (~> 0.1)
84
- simplecov-html (0.12.3)
85
- simplecov_json_formatter (0.1.2)
86
- solargraph (0.41.2)
87
- backport (~> 1.1)
88
- benchmark
89
- bundler (>= 1.17.2)
90
- e2mmap
91
- jaro_winkler (~> 1.5)
92
- kramdown (~> 2.3)
93
- kramdown-parser-gfm (~> 1.1)
94
- parser (~> 3.0)
95
- reverse_markdown (>= 1.0.5, < 3)
96
- rubocop (>= 0.52)
97
- thor (~> 1.0)
98
- tilt (~> 2.0)
99
- yard (~> 0.9, >= 0.9.24)
100
- strscan (3.1.0)
101
- thor (1.3.0)
102
- tilt (2.3.0)
103
- unicode-display_width (2.5.0)
104
- yard (0.9.36)
105
-
106
- PLATFORMS
107
- ruby
108
-
109
- DEPENDENCIES
110
- f_service!
111
- pry
112
- pry-nav
113
- rake (~> 13.0.0)
114
- rspec (~> 3.0)
115
- rubocop (~> 1.60.2)
116
- rubocop-rspec
117
- simplecov
118
- solargraph
119
- yard
120
-
121
- BUNDLED WITH
122
- 2.2.32
data/Rakefile DELETED
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
- require 'yard'
6
-
7
- RSpec::Core::RakeTask.new(:spec)
8
-
9
- task default: :spec
10
-
11
- YARD::Rake::YardocTask.new
data/bin/console DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'bundler/setup'
5
- require 'f_service'
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require 'irb'
15
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here