Skip to content

Commit

Permalink
misc: Refact service structure
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-pochet committed Nov 5, 2024
1 parent 291edf5 commit 4ca7018
Show file tree
Hide file tree
Showing 20 changed files with 184 additions and 148 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Rubocop
on: [pull_request]

jobs:
linters:
name: Linters
runs-on: ubuntu-latest
if: ${{ github.actor != 'dependabot[bot]' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Ruby
uses: ruby/setup-ruby@v1
- name: Setup Rubocop
# A bug requires the use of `bundle install` to use `rubocop-rails`. A fix is coming to Rubocop.
# See: https://github.com/rubocop/rubocop/issues/12823
run: |
bundle install
- name: Run Rubocop
# We must pass the list of files because for now, rubocop on the entire project throws too many errors.
# We exclude the db/schema.rb file explicitly because passing a list of files will override the `AllCops.Exclude` config in .rubocop.yml
run: |
FILES=$(git diff --diff-filter=d --name-only origin/${{ github.base_ref }}...HEAD -- '*.rb' ':!db/*schema.rb')
if [ -z "$FILES" ]; then
echo "No Ruby files to lint"
exit 0
else
echo "Linting Ruby files"
bundle exec rubocop $FILES
fi
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ bundle install
### Basic usage:

```ruby
class MyService < TurbineService::Base
class MyService < Turbine::Base
def initialize(my_args)
@my_args = my_args

Expand All @@ -40,13 +40,13 @@ end
result = MyService.call(my_args)
result.success? # => true
result.failure? # => false
result.raise_if_error! # => TurbineService::Result instance
result.raise_if_error! # => Turbine::Result instance
```

### With failures

```ruby
class MyService < TurbineService::Base
class MyService < Turbine::Base
def initialize(my_args)
@my_args = my_args

Expand All @@ -72,14 +72,14 @@ result.failure? # => true

result.error.code # => :my_error_code

result.raise_if_error! # => raises TurbineService::ServiceFailure
result.raise_if_error! # => raises Turbine::ServiceFailure
```

### With data attached to the result

```ruby
class MyService < TurbineService::Base
class Result < TurbineService::Result
class MyService < Turbine::Base
class Result < Turbine::Result
attr_accessor :my_data
end

Expand Down
16 changes: 16 additions & 0 deletions lib/turbine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

require "turbine/version"

# Base structure
require "turbine/service/result"
require "turbine/service/base"

# Failures
require "turbine/failures/base_failure"
require "turbine/failures/forbidden_failure"
require "turbine/failures/not_allowed_failure"
require "turbine/failures/not_found_failure"
require "turbine/failures/service_failure"
require "turbine/failures/unauthorized_failure"
require "turbine/failures/validation_failure"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module TurbineService
module Turbine
module Failures
class BaseFailure < StandardError
attr_reader :result
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module TurbineService
module Turbine
module Failures
class ForbiddenFailure < BaseFailure
attr_reader :code
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module TurbineService
module Turbine
module Failures
class NotAllowedFailure < BaseFailure
attr_reader :code
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module TurbineService
module Turbine
module Failures
class NotFoundFailure < BaseFailure
attr_reader :resource
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module TurbineService
module Turbine
module Failures
class ServiceFailure < BaseFailure
attr_reader :code, :error_message
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module TurbineService
module Turbine
module Failures
class UnauthorizedFailure < BaseFailure
attr_reader :code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "json"

module TurbineService
module Turbine
module Failures
class ValidationFailure < BaseFailure
attr_reader :messages
Expand Down
25 changes: 25 additions & 0 deletions lib/turbine/service/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Turbine
module Service
class Base
Result = Turbine::Service::Result

def self.call(*args, **keyword_args, &block)
new(*args, **keyword_args).call(&block)
end

def initialize(*, **)
@result = self.class::Result.new
end

def call(**args, &block)
raise NotImplementedError
end

private

attr_reader :result
end
end
end
71 changes: 71 additions & 0 deletions lib/turbine/service/result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

module Turbine
module Service
class Result
attr_reader :error

def initialize
@failure = false
@error = nil
end

def failure?
failure
end

def success?
!failure
end

def fail_with_error!(error)
@failure = true
@error = error

self
end

def forbidden_failure!(code: "feature_unavailable")
fail_with_error!(Turbine::Failures::ForbiddenFailure.new(self, code))
end

def not_allowed_failure!(code:)
fail_with_error!(Turbine::Failures::NotAllowedFailure.new(self, code))
end

def not_found_failure!(resource:)
fail_with_error!(Turbine::Failures::NotFoundFailure.new(self, resource))
end

def service_failure!(code:, message:)
fail_with_error!(Turbine::Failures::ServiceFailure.new(self, code, message))
end

def unauthorized_failure!(code: "unauthorized")
fail_with_error!(Turbine::Failures::UnauthorizedFailure.new(self, code))
end

def validation_failure!(errors:)
fail_with_error!(Turbine::Failures::ValidationFailure.new(self, errors))
end

def record_validation_failure!(record)
validation_failure!(errors: record.errors.messages)
end

def single_validation_failure!(code:, field: :base)
validation_failure!(errors: {field.to_sym => [code]})
end

def raise_if_error!
return self if success?

raise(error)
end

private

attr_accessor :failure
end
end
end
2 changes: 1 addition & 1 deletion lib/turbine_service/version.rb → lib/turbine/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module TurbineService
module Turbine
VERSION = "0.0.1"
end
16 changes: 0 additions & 16 deletions lib/turbine_service.rb

This file was deleted.

23 changes: 0 additions & 23 deletions lib/turbine_service/base.rb

This file was deleted.

69 changes: 0 additions & 69 deletions lib/turbine_service/result.rb

This file was deleted.

2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "debug"

require "turbine_service"
require "turbine"

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

0 comments on commit 4ca7018

Please sign in to comment.