lib/trailblazer/operation/pipetree.rb in trailblazer-operation-0.0.5 vs lib/trailblazer/operation/pipetree.rb in trailblazer-operation-0.0.6
- old
+ new
@@ -2,11 +2,11 @@
require "pipetree/flow"
require "trailblazer/operation/result"
require "uber/option"
class Trailblazer::Operation
- New = ->(klass, options) { klass.new(options) } # returns operation instance.
+ New = ->(klass, options) { klass.new(options) } # returns operation instance.
# Implements the API to populate the operation's pipetree and
# `Operation::call` to invoke the latter.
# http://trailblazer.to/gems/operation/2.0/pipetree.html
module Pipetree
@@ -45,62 +45,110 @@
def >>(*args); _insert(:>>, *args) end
def >(*args); _insert(:>, *args) end
def &(*args); _insert(:&, *args) end
def <(*args); _insert(:<, *args) end
+ # self.| ->(*) { }, before: "operation.new"
+ # self.| :some_method
+ def |(cfg, user_options={})
+ DSL.import(self, self["pipetree"], cfg, user_options) &&
+ heritage.record(:|, cfg, user_options)
+ end
+
+ alias_method :step, :|
+ alias_method :consider, :&
+ alias_method :failure, :<
+ alias_method :success, :>
+
# :private:
- # High-level user step API that allows ->(options) procs.
- def _insert(operator, proc, options={})
- heritage.record(:_insert, operator, proc, options)
+ module Option
+ def self.call(proc, &block)
+ type = :proc
+ option =
+ if proc.is_a? Symbol
+ type = :symbol
+ ->(input, *_options) { input.send(proc, *_options) }
+ elsif proc.is_a? Proc
+ # ->(input, options) { proc.(**options) }
+ ->(input, *_options) { proc.(*_options) }
+ elsif proc.is_a? Uber::Callable
+ type = :callable
+ ->(input, *_options) { proc.(*_options) }
+ end
+
+ yield type if block_given?
+ option
+ end
+ end
+
+ # :public:
+ # Wrap the step into a proc that only passes `options` to the step.
+ # This is pure convenience for the developer and will be the default
+ # API for steps. ATM, we also automatically generate a step `:name`.
+ def self.insert(pipe, operator, proc, options={}, kws={}) # TODO: definer_name is a hack for debugging, only.
# proc = Uber::Option[proc]
_proc =
if options[:wrap] == false
proc
- elsif proc.is_a? Symbol
- options[:name] ||= proc
- ->(input, _options) { input.send(proc, _options) }
- elsif proc.is_a? Proc
- options[:name] ||= "#{self.name}:#{proc.source_location.last}" if proc.is_a? Proc
- # ->(input, options) { proc.(**options) }
- ->(input, _options) { proc.(_options) }
- elsif proc.is_a? Uber::Callable
- options[:name] ||= proc.class
- ->(input, _options) { proc.(_options) }
+ else
+ Option.(proc) do |type|
+ options[:name] ||= proc if type == :symbol
+ options[:name] ||= "#{kws[:definer_name]}:#{proc.source_location.last}" if proc.is_a? Proc if type == :proc
+ options[:name] ||= proc.class if type == :callable
+ end
end
- self["pipetree"].send(operator, _proc, options) # ex: pipetree.> Validate, after: Model::Build
+ pipe.send(operator, _proc, options) # ex: pipetree.> Validate, after: Model::Build
end
- def ~(cfg)
- heritage.record(:~, cfg)
+ def self.import(operation, pipe, cfg, user_options={})
+ if cfg.is_a?(Array) # e.g. from Contract::Validate
+ mod, args, block = cfg
- self.|(cfg, inheriting: true) # FIXME: not sure if this is the final API.
- end
+ import = Import.new(pipe, user_options) # API object.
- def |(cfg, user_options={}) # sorry for the magic here, but still playing with the DSL.
- if cfg.is_a?(Macro) # e.g. Contract::Validate
- import = Import.new(self, user_options)
+ return mod.import!(operation, import, *args, &block)
+ end
- return cfg.import!(self, import) &&
- heritage.record(:|, cfg, user_options)
+ insert(pipe, :>, cfg, user_options, {}) # DOEES NOOOT calls heritage.record
+ end
+
+ Macros = Module.new
+ def self.macro!(name, constant)
+ Macros.send :define_method, name do |*args, &block|
+ [constant, args, block]
end
+ end
- self.> cfg, user_options # calls heritage.record
+ # :private:
+ # High-level user step API that allows ->(options) procs.
+ def _insert(operator, proc, options={})
+ heritage.record(:_insert, operator, proc, options)
+
+ DSL.insert(self["pipetree"], operator, proc, options, definer_name: self.name)
end
+ def ~(cfg)
+ heritage.record(:~, cfg)
+
+ self.|(cfg, inheriting: true) # FIXME: not sure if this is the final API.
+ end
+
# Try to abstract as much as possible from the imported module. This is for
# forward-compatibility.
# Note that Import#call will push the step directly on the pipetree which gives it the
# low-level (input, options) interface.
- Import = Struct.new(:operation, :user_options) do
+ Import = Struct.new(:pipetree, :user_options) do
def call(operator, step, options)
- operation["pipetree"].send operator, step, options.merge(user_options)
+ pipetree.send operator, step, options.merge(user_options)
end
def inheriting?
user_options[:inheriting]
end
end
end
end
+
+ extend Pipetree::DSL::Macros
end