Skip to content

Commit

Permalink
[Feature] - Add call! method to halt the execution of the current ser…
Browse files Browse the repository at this point in the history
…vice
  • Loading branch information
federicoaldunate committed Nov 17, 2024
1 parent ff1c535 commit e3a10af
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 22 deletions.
11 changes: 8 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Metrics/BlockLength:
- 'sea_food.gemspec'
- config/**/*
- spec/**/*
ExcludedMethods:
AllowedMethods:
- class_methods

Metrics/BlockNesting:
Expand Down Expand Up @@ -97,9 +97,14 @@ Style/MissingRespondToMissing:
Exclude:
- 'lib/sea_food/service.rb'

Style/MethodMissingSuper:
Lint/MissingSuper:
Exclude:
- 'lib/sea_food/service.rb'
- spec/**/*

Naming/PredicateName:
Enabled: false
Enabled: false

Lint/ConstantDefinitionInBlock:
Exclude:
- 'spec/**/*'
18 changes: 15 additions & 3 deletions lib/sea_food/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ class << self
# @param args [Hash] Arguments to pass to the service.
# @return [ServiceResult] The result of the service call.
def call(params = {})
# debugger
service = new(**params)
service.call
service.result || ServiceResult.new
rescue ServiceError => e
service.result
service.result || e.try(:result)
end

def call!(params = {})
result = call(params)
return result || ServiceResult.new unless result.fail?

raise ServiceError, result
end
end

Expand Down Expand Up @@ -113,7 +119,13 @@ def method_missing(key)
end
end

class ServiceError < StandardError; end
class ServiceError < StandardError
attr_reader :result

def initialize(result)
@result = result
end
end

private

Expand Down
3 changes: 2 additions & 1 deletion sea_food.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
spec.summary = 'A Ruby gem for seamlessly integrating form and service object patterns.'
spec.homepage = 'https://github.com/eagerworks/sea_food'
spec.license = 'MIT'
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')

# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
# to allow pushing to a single host or delete this section to allow pushing to any host.
Expand Down Expand Up @@ -43,6 +44,6 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'debug'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rubocop', '~> 0.80.0'
spec.add_development_dependency 'rubocop', '~> 1.0'
spec.add_development_dependency 'sqlite3', '~> 1.5.0'
end
117 changes: 107 additions & 10 deletions spec/sea_food/service/service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def call
# Test enforcing the interface of the service
######

context "when the configuration is set to enforce the interface" do
context 'when the configuration is set to enforce the interface' do
before do
SeaFood.configure do |config|
config.enforce_interface = true
Expand All @@ -79,8 +79,7 @@ def call

it 'rasies an error when the #initialize method is not implemented' do
TestService = Class.new(SeaFood::Service) do
def call
end
def call; end
end

expect { TestService.call }.to raise_error(
Expand Down Expand Up @@ -148,9 +147,9 @@ def call; end
expect(result.email).to be_nil
end

######
# Test the difference behavior of #success #fail #fail!
######
######
# Test the difference behavior of #success #fail #fail!
######

it 'call #success twice' do
TestSuccessService = Class.new(SeaFood::Service) do
Expand Down Expand Up @@ -208,11 +207,10 @@ def call

it '#fail then #success' do
TestFailService = Class.new(SeaFood::Service) do

def initialize(email:)
@email = email
end

def call
fail(email: '[email protected]')
success(email: @email)
Expand All @@ -230,10 +228,10 @@ def call
def initialize(email:)
@email = email
end

def call
fail!(email: '[email protected]')
success!(email: @email)
success(email: @email)
end
end

Expand All @@ -242,5 +240,104 @@ def call
expect(result).to be_fail
expect(result.email).to eq('[email protected]')
end

context 'testing nested services with call' do
it 'it fails on the first service but not on the second one' do
TestInnerFailService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
fail!(email: @email)
end
end

TestParentFailService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
TestInnerFailService.call(email: '[email protected]')
success(email: @email)
end
end

result = TestParentFailService.call(email: '[email protected]')

expect(result).to be_success
expect(result.email).to eq('[email protected]')
end
end

context 'testing nested services with call!' do
it 'it fails on the first service so it fails the second one' do
TestInnerFailService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
fail!(email: @email)
end
end

TestParentFailService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
TestInnerFailService.call!(email: '[email protected]')
success(email: @email)
end
end

result = TestParentFailService.call(email: '[email protected]')
expect(result).to be_fail
expect(result.email).to eq('[email protected]')
end
end

context 'testing three levels nested services with call!' do
it 'it fails on the third level service but does not cascade' do
TestThirdFailService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
fail!(email: @email)
end
end

TestSecondFailService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
TestInnerFailService.call!(email: '[email protected]')
success(email: @email)
end
end

TestFirstService = Class.new(SeaFood::Service) do
def initialize(email:)
@email = email
end

def call
TestInnerFailService.call(email: 'a')
success(email: @email)
end
end

result = TestFirstService.call(email: '[email protected]')
expect(result).to be_success
expect(result.email).to eq('[email protected]')
end
end
end
end
10 changes: 5 additions & 5 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'

require 'sea_food'
load File.dirname(__FILE__) + '/support/schema.rb'
require File.dirname(__FILE__) + '/support/form/user_form.rb'
require File.dirname(__FILE__) + '/support/form/address_form.rb'
require File.dirname(__FILE__) + '/support/user.rb'
require File.dirname(__FILE__) + '/support/address.rb'
load "#{File.dirname(__FILE__)}/support/schema.rb"
require "#{File.dirname(__FILE__)}/support/form/user_form.rb"
require "#{File.dirname(__FILE__)}/support/form/address_form.rb"
require "#{File.dirname(__FILE__)}/support/user.rb"
require "#{File.dirname(__FILE__)}/support/address.rb"

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
Expand Down

0 comments on commit e3a10af

Please sign in to comment.