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 8, 2024
1 parent 08c42c1 commit 3b2917c
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 118 deletions.
72 changes: 27 additions & 45 deletions lib/pathway.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,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 +56,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 +95,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 +121,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,7 +152,6 @@ def run(&bl)
# Execute step and preserve the former state
def step(callable,...)
bl = _callable(callable)

@result = @result.tee { |state| bl.call(state,...) }
end

Expand All @@ -186,40 +171,37 @@ def map(callable)
@result = @result.then(bl)
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
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
58 changes: 16 additions & 42 deletions lib/pathway/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@ class Result
attr_reader :value, :error

class Success < Result
def initialize(value)
@value = value
end

def success?
true
end
def initialize(value) = @value = value
def success? = true

def then(bl=nil)
result(block_given? ? yield(value): bl.call(value))
Expand All @@ -25,40 +20,35 @@ def tee(bl=nil, &block)

private

alias :value_for_deconstruct :value
alias_method :value_for_deconstruct, :value
end

class Failure < Result
def initialize(error)
@error = error
end

def success?
false
end

def then(_=nil)
self
end

def tee(_=nil)
self
end
def initialize(error) = @error = error
def success? = false
def then(_=nil) = self
def tee(_=nil) = self

private

alias :value_for_deconstruct :error
alias_method :value_for_deconstruct, :error
end

module Mixin
Success = Result::Success
Failure = Result::Failure
end

def deconstruct
[value_for_deconstruct]
def self.success(value) = Success.new(value)
def self.failure(error) = Failure.new(error)

def self.result(object)
object.is_a?(Result) ? object : success(object)
end

def failure? = !success?
def deconstruct = [value_for_deconstruct]

def deconstruct_keys(keys)
if value_for_deconstruct.respond_to?(:deconstruct_keys)
value_for_deconstruct.deconstruct_keys(keys)
Expand All @@ -67,22 +57,6 @@ def deconstruct_keys(keys)
end
end

def failure?
!success?
end

def self.success(value)
Success.new(value)
end

def self.failure(error)
Failure.new(error)
end

def self.result(object)
object.is_a?(Result) ? object : success(object)
end

delegate :result => 'self.class'
end
end
12 changes: 6 additions & 6 deletions lib/pathway/rspec/matchers/fail_on.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@
@type = type
end

alias :with_type :type
alias :and_type :type
alias_method :with_type, :type
alias_method :and_type, :type

chain :message do |message|
@message = message
end

alias :with_message :message
alias :and_message :message
alias_method :with_message, :message
alias_method :and_message, :message

chain :details do |details|
@details = details
end

alias :with_details :details
alias :and_details :details
alias_method :with_details, :details
alias_method :and_details, :details

description do
'fail' + (@type ? " with :#@type error" : '')
Expand Down
2 changes: 1 addition & 1 deletion lib/pathway/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Pathway
VERSION = '0.12.2'
VERSION = '1.0.0b1'
end
Loading

0 comments on commit 3b2917c

Please sign in to comment.