TL;DR
I have no time to read tons of docs.
Just show me an example use case and I'll quickly craft something similar 😎.— A lazy developer
# Any source code in the project.
def read_file_content(path)
result = ReadFileContent.result(path: path)
if result.success?
##
# Service tried to read the file content and completed it.
#
result.data[:content] # File content.
elsif result.failure?
##
# Service tried to read file content but did NOT complete it due to some expected reason.
#
App.logger.warn { result.message.to_s }
"" # Fallback value or any other reasonable fallback behavior.
else # result.error?
##
# Service NOT even tried to read file content due to a validation issue or exception.
#
App.logger.error { result.message.to_s }
raise VerboseException, result.message.to_s # Self-explanatory exception or any other reasonable fallback behavior.
end
end
- Standard
- Rails
- Dry
- Custom
require "convenient_service"
require "active_model" # NOTE: Minimal `active_model` version - `5.2.0`.
require "convenient_service"
ConvenientService::Dependencies.require_assigns_attributes_in_constructor_using_active_model_attribute_assignment
ConvenientService::Dependencies.require_has_attributes_using_active_model_attributes
ConvenientService::Dependencies.require_has_j_send_result_params_validations_using_active_model_validations
require "dry-initializer" # NOTE: Minimal `dry-initializer` version - `3.0.0`.
require "dry-validation" # NOTE: Minimal `dry-validation` version - `1.5.0`.
require "convenient_service"
ConvenientService::Dependencies.require_assigns_attributes_in_constructor_using_dry_initializer
ConvenientService::Dependencies.require_has_result_params_validations_using_dry_validation
require "active_model" # NOTE: Minimal `active_model` version - `5.2.0`.
require "dry-initializer" # NOTE: Minimal `dry-initializer` version - `3.0.0`.
require "awesome_print" # NOTE: Minimal `awesome_print` version - `1.0.0`.
require "convenient_service"
ConvenientService::Dependencies.require_has_j_send_result_params_validations_using_active_model_validations
ConvenientService::Dependencies.require_assigns_attributes_in_constructor_using_dry_initializer
ConvenientService::Dependencies.require_rescues_result_unhandled_exceptions
ConvenientService::Dependencies.require_awesome_print_inspect if Rails.env.development? || Rails.env.test?
- Standard
- Rails
- Dry
- Custom
module ApplicationService
module Config
include ConvenientService::Concern
included do
include ConvenientService::Standard::Config
end
end
end
module RailsService
module Config
include ConvenientService::Concern
included do
include ConvenientService::Standard::Config
concerns do
use ConvenientService::Plugins::Common::AssignsAttributesInConstructor::UsingActiveModelAttributeAssignment::Concern
use ConvenientService::Plugins::Common::HasAttributes::UsingActiveModelAttributes::Concern
use ConvenientService::Plugins::Service::HasJSendResultParamsValidations::UsingActiveModelValidations::Concern
end
middlewares :initialize do
use ConvenientService::Plugins::Common::AssignsAttributesInConstructor::UsingActiveModelAttributeAssignment::Middleware
end
middlewares :result do
insert_before \
ConvenientService::Plugins::Service::CanHaveConnectedSteps::Middleware,
ConvenientService::Plugins::Service::HasJSendResultParamsValidations::UsingActiveModelValidations::Middleware
end
end
end
end
module DryService
module Config
include ConvenientService::Concern
included do
include ConvenientService::Standard::Config
concerns do
use ConvenientService::Plugins::Common::AssignsAttributesInConstructor::UsingDryInitializer::Concern
use ConvenientService::Plugins::Service::HasJSendResultParamsValidations::UsingDryValidation::Concern
end
middlewares :result do
insert_before \
ConvenientService::Plugins::Service::CanHaveConnectedSteps::Middleware,
ConvenientService::Plugins::Service::HasJSendResultParamsValidations::UsingDryValidation::Middleware
end
end
end
end
module CustomService
module Config
include ConvenientService::Concern
included do
include ConvenientService::Standard::Config
if Rails.env.development? || Rails.env.test?
include ConvenientService::AwesomePrintInspect::Config
end
concerns do
use ConvenientService::Plugins::Common::AssignsAttributesInConstructor::UsingDryInitializer::Concern
use ConvenientService::Plugins::Service::HasJSendResultParamsValidations::UsingActiveModelValidations::Concern
end
middlewares :result do
insert_before \
ConvenientService::Plugins::Service::CanHaveConnectedSteps::Middleware,
ConvenientService::Plugins::Service::HasJSendResultParamsValidations::UsingActiveModelValidations::Middleware
end
if !Rails.env.test?
middlewares :result do
use ConvenientService::Plugins::Service::RescuesResultUnhandledExceptions::Middleware
end
middlewares :result, scope: :class do
use ConvenientService::Plugins::Service::RescuesResultUnhandledExceptions::Middleware
end
end
end
end
end
- Standard
- Rails
- Dry
- Custom
class AssertFileExists
include ApplicationService::Config
attr_reader :path
def initialize(path:)
@path = path
end
def result
return error("Path is `nil`") if path.nil?
return error("Path is empty") if path.empty?
return failure("File does not exist at path `#{path}`") unless ::File.exist?(path)
success
end
end
class AssertFileExists
include RailsService::Config
attribute :path, :string
validates :path, presence: true
def result
return failure("File does not exist at path `#{path}`") unless ::File.exist?(path)
success
end
end
class AssertFileExists
include DryService::Config
option :path
contract do
schema do
required(:path).value(:string)
end
end
def result
return failure("File does not exist at path `#{path}`") unless ::File.exist?(path)
success
end
end
class AssertFileExists
include CustomService::Config
option :path
validates :path, presence: true
def result
return failure("File does not exist at path `#{path}`") unless ::File.exist?(path)
success
end
end
result = AssertFileExists.result(path: "Gemfile")
- Standard
- Rails
- Dry
- Custom
class AssertFileNotEmpty
include ApplicationService::Config
attr_accessor :path
def initialize(path:)
@path = path
end
def result
return error("Path is `nil`") if path.nil?
return error("Path is empty") if path.empty?
return failure("File is empty at path `#{path}`") if ::File.zero?(path)
success
end
end
class AssertFileNotEmpty
include RailsService::Config
attribute :path, :string
validates :path, presence: true
def result
return failure("File is empty at path `#{path}`") if ::File.zero?(path)
success
end
end
class AssertFileNotEmpty
include DryService::Config
option :path
contract do
schema do
required(:path).value(:string)
end
end
def result
return failure("File is empty at path `#{path}`") if ::File.zero?(path)
success
end
end
class AssertFileNotEmpty
include CustomService::Config
option :path
validates :path, presence: true
def result
return failure("File is empty at path `#{path}`") if ::File.zero?(path)
success
end
end
result = AssertFileNotEmpty.result(path: "Gemfile")
- Standard
- Rails
- Dry
- Custom
class ReadFileContent
include ApplicationService::Config
attr_reader :path
step :validate_path
step AssertFileExists, in: :path
step AssertFileNotEmpty, in: :path
step :result, in: :path, out: :content
def initialize(path:)
@path = path
end
def result
success(content: ::File.read(path))
end
private
def validate_path
return error("Path is `nil`") if path.nil?
return error("Path is empty") if path.empty?
success
end
end
class ReadFileContent
include RailsService::Config
attribute :path, :string
validates :path, presence: true
step AssertFileExists, in: :path
step AssertFileNotEmpty, in: :path
step :result, in: :path, out: :content
def result
success(content: ::File.read(path))
end
end
class ReadFileContent
include DryService::Config
option :path
contract do
schema do
required(:path).value(:string)
end
end
step AssertFileExists, in: :path
step AssertFileNotEmpty, in: :path
step :result, in: :path, out: :content
def result
success(content: ::File.read(path))
end
end
class ReadFileContent
include CustomService::Config
option :path
validates :path, presence: true
step AssertFileExists, in: :path
step AssertFileNotEmpty, in: :path
step :result, in: :path, out: :content
def result
success(content: ::File.read(path))
end
end
result = ReadFileContent.result(path: "Gemfile")
More examples​
Source Code | RSpec Specs |
---|---|
lib/convenient_service/examples | spec/lib/convenient_service |