Skip to content

Commit

Permalink
Improve code with with new ruby features
Browse files Browse the repository at this point in the history
  • Loading branch information
pabloh committed Aug 7, 2024
1 parent a3bda7d commit c6fe0b8
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 123 deletions.
81 changes: 32 additions & 49 deletions lib/pathway.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class DSL

class Error
attr_reader :type, :message, :details

singleton_class.send :attr_accessor, :default_messages

@default_messages = {}
Expand All @@ -44,13 +45,8 @@ def initialize(type:, message: nil, details: nil)
@details = details || {}
end

def deconstruct
[type, message, details]
end

def deconstruct_keys(_)
{ type: type, message: message, details: details }
end
def deconstruct = [type, message, details]
def deconstruct_keys(_) = { type:, message:, details: }

private

Expand All @@ -61,38 +57,32 @@ def default_message_for(type)

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

def initialize(operation, values = {})
@hash = operation.context.merge(values)
@result_key = operation.result_key
end

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

def update(kargs)
@hash.update(kargs)
self
end

def result
@hash[@result_key]
end

def to_hash
@hash
end
def result = @hash[@result_key]
def to_hash = @hash

def use(&bl)
raise ArgumentError, 'a block must be provided' if !block_given?

params = bl.parameters

if !params.all? { |(type,_)| [:block, :key, :keyreq, :keyrest].member?(type) }
if !params.all? { _1 in [:block|:key|:keyreq|:keyrest, _] }
raise ArgumentError, 'only keyword arguments are supported'
elsif params.any? {|(type,_)| type == :keyrest }
elsif params in [*, [:keyrest, _], *]
bl.call(**to_hash)
else
keys = params.select {|(type,_)| type == :key || type == :keyreq }.map(&:last)
keys = params.select { _1 in [:key|:keyreq, _] }.map(&:last)
bl.call(**to_hash.slice(*keys))
end
end
Expand All @@ -106,20 +96,19 @@ module Plugins
module Base
module ClassMethods
attr_accessor :result_key
alias :result_at :result_key=

alias_method :result_at, :result_key=

def process(&bl)
dsl = self::DSL
define_method(:call) do |input|
dsl.new(State.new(self, input: input), self)
dsl.new(State.new(self, input:), self)
.run(&bl)
.then(&:result)
end
end

def call(ctx,...)
new(ctx).call(...)
end
def call(ctx,...) = new(ctx).call(...)

def inherited(subclass)
super
Expand All @@ -133,18 +122,16 @@ module InstanceMethods
delegate :result_key => 'self.class'
delegate %i[result success failure] => Result

alias :wrap :result
alias_method :wrap, :result

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

def error(type, message: nil, details: nil)
failure(Error.new(type: type, message: message, details: details))
failure(Error.new(type:, message:, details:))
end

def wrap_if_present(value, type: :not_found, message: nil, details: {})
value.nil? ? error(type, message: message, details: details) : success(value)
value.nil? ? error(type, message:, details:) : success(value)
end
end

Expand All @@ -166,60 +153,56 @@ def run(&bl)
# Execute step and preserve the former 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)
def set(callable, *args, to: @operation.result_key, **kwargs)
bl = _callable(callable)

@result = @result.then do |state|
wrap(bl.call(state, *args))
wrap(bl.call(state, *args, **kwargs))
.then { |value| state.update(to => value) }
end
end

# Execute step and replace the current state completely
def map(callable)
def map(callable,...)
bl = _callable(callable)
@result = @result.then(bl)
@result = @result.then { |state| bl.call(state,...) }
end

def around(wrapper, &steps)
def around(execution_strategy, &dsl_block)
@result.then do |state|
seq = -> (dsl = self) { @result = dsl.run(&steps) }
_callable(wrapper).call(seq, state)
dsl_runner = ->(dsl = self) { @result = dsl.run(&dsl_block) }

_callable(execution_strategy).call(dsl_runner, state)
end
end

def if_true(cond, &steps)
def if_true(cond, &dsl_block)
cond = _callable(cond)
around(-> seq, state {
seq.call if cond.call(state)
}, &steps)
around(->(dsl_runner, state) { dsl_runner.call if cond.call(state) }, &dsl_block)
end

def if_false(cond, &steps)
def if_false(cond, &dsl_block)
cond = _callable(cond)
if_true(-> state { !cond.call(state) }, &steps)
if_true(->(state) { !cond.call(state) }, &dsl_block)
end

alias_method :sequence, :around
alias_method :guard, :if_true

private

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

def _callable(callable)
case callable
when Proc
-> *args, **kwargs { @operation.instance_exec(*args, **kwargs, &callable) }
->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) }
when Symbol
-> *args, **kwargs { @operation.send(callable, *args, **kwargs) }
->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) }
else
callable
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pathway/plugins/dry_validation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module DryValidation
def self.apply(operation, **kwargs)
#:nocov:
if Gem.loaded_specs['dry-validation'].version < Gem::Version.new('0.11')
fail 'unsupported dry-validation gem version'
raise 'unsupported dry-validation gem version'
elsif Gem.loaded_specs['dry-validation'].version < Gem::Version.new('0.12')
require 'pathway/plugins/dry_validation/v0_11'
operation.plugin(Plugins::DryValidation::V0_11, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion lib/pathway/plugins/dry_validation/v0_11.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def validate(state, with: nil)
end
opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
validate_with(state[:input], opts)
.then { |params| state.update(params: params) }
.then { |params| state.update(params:) }
end

def validate_with(params, opts = {})
Expand Down
2 changes: 1 addition & 1 deletion lib/pathway/plugins/dry_validation/v0_12.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def validate(state, with: nil)
end
opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
validate_with(state[:input], opts)
.then { |params| state.update(params: params) }
.then { |params| state.update(params:) }
end

def validate_with(params, opts = {})
Expand Down
2 changes: 1 addition & 1 deletion lib/pathway/plugins/dry_validation/v1_0.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def validate(state, with: nil)
end
opts = Hash(with).map { |to, from| [to, state[from]] }.to_h
validate_with(state[:input], **opts)
.then { |params| state.update(params: params) }
.then { |params| state.update(params:) }
end

def validate_with(input, **opts)
Expand Down
4 changes: 1 addition & 3 deletions lib/pathway/plugins/responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ def initialize(result, &bl)
instance_eval(&bl)
end

def success(&bl)
@ok = bl
end
def success(&bl)= @ok = bl

def failure(type = nil, &bl)
if type.nil?
Expand Down
30 changes: 15 additions & 15 deletions lib/pathway/plugins/sequel_models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,33 @@ module Pathway
module Plugins
module SequelModels
module DSLMethods
def transaction(step_name = nil, &bl)
fail 'must provide a step or a block but not both' if !step_name.nil? == block_given?
def transaction(step_name = nil, &dsl_bl)
raise 'must provide a step or a block but not both' if !step_name.nil? == block_given?

if step_name
transaction { step step_name }
else
around(-> steps, _ {
around(->(runner, _) {
db.transaction(savepoint: true) do
raise Sequel::Rollback if steps.call.failure?
raise Sequel::Rollback if runner.call.failure?
end
}, &bl)
}, &dsl_bl)
end
end

def after_commit(step_name = nil, &bl)
fail 'must provide a step or a block but not both' if !step_name.nil? == block_given?
def after_commit(step_name = nil, &dsl_bl)
raise 'must provide a step or a block but not both' if !step_name.nil? == block_given?

if step_name
after_commit { step step_name }
else
around(-> steps, state {
dsl = self.class::DSL.new(State.new(self, state.to_h.dup), self)
around(->(runner, state) {
dsl_copy = self.class::DSL.new(State.new(self, state.to_h.dup), self)

db.after_commit do
steps.call(dsl)
runner.call(dsl_copy)
end
}, &bl)
}, &dsl_bl)
end
end
end
Expand All @@ -41,10 +41,10 @@ module ClassMethods
attr_accessor :model_class, :search_field, :model_not_found

def model(model_class, search_by: model_class.primary_key, set_result_key: true, set_context_param: true, error_message: nil)
self.model_class = model_class
self.search_field = search_by
self.result_key = Inflector.underscore(Inflector.demodulize(model_class.name)).to_sym if set_result_key
self.model_not_found = error_message || "#{Inflector.humanize(Inflector.underscore(Inflector.demodulize(model_class.name)))} not found".freeze
self.model_class = model_class
self.search_field = search_by
self.result_key = Inflector.underscore(Inflector.demodulize(model_class.name)).to_sym if set_result_key
self.model_not_found = error_message || "#{Inflector.humanize(Inflector.underscore(Inflector.demodulize(model_class.name)))} not found".freeze

self.context(result_key => Contextualizer::OPTIONAL) if set_result_key && set_context_param
end
Expand Down
4 changes: 1 addition & 3 deletions lib/pathway/plugins/simple_auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ def authorize_with(*objs)
authorized?(*objs) ? wrap(objs) : error(:forbidden)
end

def authorized?(*)
true
end
def authorized?(*) = true
end
end
end
Expand Down
Loading

0 comments on commit c6fe0b8

Please sign in to comment.