Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# The behavior of RuboCop can be controlled via the .rubocop.yml
# configuration file. It makes it possible to enable/disable
# certain cops (checks) and to alter their behavior if they accept
# any parameters. The file can be placed either in your home
# directory or in some project directory.
#
# RuboCop will start looking for the configuration file in the directory
# where the inspected file is and continue its way up to the root directory.
#
# See https://docs.rubocop.org/rubocop/configuration

require: rubocop-performance

AllCops:
NewCops: enable
SuggestExtensions: false
Exclude:
- 'bin/*'

Style/Lambda:
Enabled: false

Style/Alias:
EnforcedStyle: prefer_alias_method

Style/StringLiterals:
EnforcedStyle: double_quotes

Style/HashSyntax:
Exclude:
- Rakefile

Metrics/BlockLength:
Exclude:
- 'spec/**/*.rb'
- 'lib/pathway/rspec/matchers/*.rb'

Layout/EmptyLinesAroundBlockBody:
Exclude:
- 'spec/**/*.rb'

Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented_relative_to_receiver

Naming/MethodParameterName:
MinNameLength: 2

Style/ParallelAssignment:
Enabled: False

Style/CaseEquality:
Enabled: False

Style/Documentation:
Enabled: false

Lint/MissingSuper:
AllowedParentClasses: [Result]

Style/AccessModifierDeclarations:
AllowModifiersOnAliasMethod: true
6 changes: 1 addition & 5 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec) do |t|
unless RUBY_VERSION =~ /^2\.7|^3\./
t.exclude_pattern = 'spec/operation_call_pattern_matching_spec.rb,spec/state_pattern_matching_spec.rb'
end
end
RSpec::Core::RakeTask.new(:spec)

task :default => :spec
27 changes: 27 additions & 0 deletions bin/racc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'racc' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("racc", "racc")
27 changes: 27 additions & 0 deletions bin/rubocop
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'rubocop' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("rubocop", "rubocop")
27 changes: 27 additions & 0 deletions bin/ruby-parse
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'ruby-parse' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("parser", "ruby-parse")
27 changes: 27 additions & 0 deletions bin/ruby-rewrite
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'ruby-rewrite' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("parser", "ruby-rewrite")
65 changes: 31 additions & 34 deletions lib/pathway.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# frozen_string_literal: true

require 'forwardable'
require 'dry/inflector'
require 'contextualizer'
require 'pathway/version'
require 'pathway/result'
require "forwardable"
require "dry/inflector"
require "contextualizer"
require "pathway/version"
require "pathway/result"

module Pathway
Inflector = Dry::Inflector.new
Expand Down Expand Up @@ -56,7 +56,7 @@ def default_message_for(type)

class State
extend Forwardable
delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash
delegate %i[[] []= fetch store include? values_at deconstruct_keys] => :@hash

def initialize(operation, values = {})
@hash = operation.context.merge(values)
Expand All @@ -72,16 +72,16 @@ def result = @hash[@result_key]
def to_hash = @hash

def use(&bl)
raise ArgumentError, 'a block must be provided' if !block_given?
raise ArgumentError, "a block must be provided" if !block_given?
if bl.parameters in [*, [:rest|:keyrest,], *]
raise ArgumentError, 'rest arguments are not supported'
raise ArgumentError, "rest arguments are not supported"
end

keys = bl.parameters.select { _1 in :key|:keyreq, }.map(&:last)
names = bl.parameters.select { _1 in :req|:opt, }.map(&:last)

if keys.any? && names.any?
raise ArgumentError, 'cannot mix positional and keyword arguments'
raise ArgumentError, "cannot mix positional and keyword arguments"
elsif keys.any?
bl.call(**to_hash.slice(*keys))
else
Expand Down Expand Up @@ -120,12 +120,12 @@ def inherited(subclass)
module InstanceMethods
extend Forwardable

delegate :result_key => 'self.class'
delegate :result_key => "self.class"
delegate %i[result success failure] => Result

alias_method :wrap, :result

def call(*) = raise 'must implement at subclass'
def call(*) = raise "must implement at subclass"

def error(type, message: nil, details: nil)
failure(Error.new(type:, message:, details:))
Expand Down Expand Up @@ -156,27 +156,17 @@ def run(&steps)
end

# Execute step and preserve the former state
def step(callable,...)
#:nocov:
if block_given?
warn "[DEPRECATION] Passing a block to the step method using `DSLMethods#step` is deprecated"
end
#:nocov:
bl = _callable(callable)
@result = @result.tee { |state| bl.call(state,...) }
def step(callable,*,**, &)
bl = _callable(callable, &)
@result = @result.tee { |state| bl.call(state,*,**) }
end

# Execute step and modify the former state setting the key
def set(callable, *args, to: @operation.result_key, **kwargs, &bl)
#:nocov:
if block_given?
warn "[DEPRECATION] Passing a block to the step method using `DSLMethods#set` is deprecated"
end
#:nocov:
bl = _callable(callable)
def set(callable, *args, to: @operation.result_key, **kwargs, &)
bl = _callable(callable, &)

@result = @result.then do |state|
wrap(bl.call(state, *args, **kwargs, &bl))
wrap(bl.call(state, *args, **kwargs))
.then { |value| state.update(to => value) }
end
end
Expand Down Expand Up @@ -214,14 +204,21 @@ def if_false(cond, &steps)

def wrap(obj) = Result.result(obj)

def _callable(callable)
case callable
when Proc # unless (callable.binding rescue nil)&.receiver == @operation
->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) }
when Symbol
->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) }
def _callable(callable, &bl)
if block_given?
raise ArgumentError, 'You must either pass a block or a callable but not both' if !callable.is_a?(Symbol)
warn "The operation already responds to a message of the same name" if @operation.responds_to?(callable)

->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &bl) }
else
callable
case callable
when Proc
->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) }
when Symbol
->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) }
else
callable
end
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/pathway/plugins/auto_deconstruct_state.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ module DSLMethods

def _callable(callable)
if callable.is_a?(Symbol) && @operation.respond_to?(callable, true) &&
@operation.method(callable).arity != 0 &&
@operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block,*] }
@operation.method(callable).arity != 0 &&
@operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block, *] }

-> state { @operation.send(callable, **state) }
->(state) { @operation.send(callable, **state) }
else
super
end
Expand Down
6 changes: 3 additions & 3 deletions lib/pathway/plugins/dry_validation.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require 'dry/validation'
require "dry/validation"

module Pathway
module Plugins
Expand All @@ -16,7 +16,7 @@ def contract(base = nil, &)
elsif base
self.contract_class = base
else
raise ArgumentError, 'Either a contract class or a block must be provided'
raise ArgumentError, "Either a contract class or a block must be provided"
end
end

Expand Down Expand Up @@ -50,7 +50,7 @@ def _base_contract
module InstanceMethods
extend Forwardable

delegate %i[build_contract contract_options auto_wire] => 'self.class'
delegate %i[build_contract contract_options auto_wire] => "self.class"
alias_method :contract, :build_contract

def validate(state, with: nil)
Expand Down
2 changes: 1 addition & 1 deletion lib/pathway/plugins/responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def failure(type = nil, &bl)
def respond
if @result.success?
@context.instance_exec(@result.value, &@ok)
elsif Error === @result.error && fail_block = @fails[@result.error.type]
elsif Error === @result.error && (fail_block = @fails[@result.error.type])
@context.instance_exec(@result.error, &fail_block)
else
@context.instance_exec(@result.error, &@fail_default)
Expand Down
10 changes: 5 additions & 5 deletions lib/pathway/plugins/sequel_models.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require 'sequel/model'
require "sequel/model"

module Pathway
module Plugins
Expand Down Expand Up @@ -33,8 +33,8 @@ def after_rollback(step_name = nil, if: nil, unless: nil, &steps)
def _opts_if_unless(bg) = %i[if unless].map { bg.local_variable_get(_1) }

def _with_db_steps(steps, step_name=nil, if_cond=nil, unless_cond=nil, &db_logic)
raise ArgumentError, 'options :if and :unless are mutually exclusive' if if_cond && unless_cond
raise ArgumentError, 'must provide either a step or a block but not both' if !!step_name == !!steps
raise ArgumentError, "options :if and :unless are mutually exclusive" if if_cond && unless_cond
raise ArgumentError, "must provide either a step or a block but not both" if !!step_name == !!steps
steps ||= proc { step step_name }

if if_cond
Expand Down Expand Up @@ -69,15 +69,15 @@ def inherited(subclass)

module InstanceMethods
extend Forwardable
delegate %i[model_class search_field model_not_found] => 'self.class'
delegate %i[model_class search_field model_not_found] => "self.class"
delegate :db => :model_class

def fetch_model(state, from: model_class, search_by: search_field, using: search_by, to: result_key, overwrite: false, error_message: nil)
error_message ||= if (from == model_class)
model_not_found
elsif from.respond_to?(:name) || from.respond_to?(:model)
from_name = (from.respond_to?(:name) ? from : from.model).name
Inflector.humanize(Inflector.underscore(Inflector.demodulize(from_name))) + ' not found'
Inflector.humanize(Inflector.underscore(Inflector.demodulize(from_name))) + " not found"
end

if state[to].nil? || overwrite
Expand Down
Loading