module Pipeful

require “binding_of_caller” # if you'll use local mode

Public Class Methods

array(arr = []) click to toggle source

makes the given array callable, appending the piped object(s)

# File lib/pipeful.rb, line 38
def self.array(arr = [])
  def arr.call(*els)
    els.each { |el| self << el }
    self
  end
  arr
end
call(*args) click to toggle source
# File lib/pipeful.rb, line 248
def self.call(*args)
  superclass.call(*args, *@parenth_args, **@parenth_kwargs, &@block)
end
parenth_arity() click to toggle source
# File lib/pipeful.rb, line 243
def self.parenth_arity
  @parenth_args.count
end
pipe_arity() click to toggle source
# File lib/pipeful.rb, line 251
def self.pipe_arity
  superclass.method(:call)
            .extend(ArityRange)
            .arity_range(subtract: parenth_arity)
end

Public Instance Methods

method_missing(m, *method_args, **method_kwargs, &method_block) click to toggle source

allows parenthetical args and/or blocks after bare class/constant name: x >> SomeFunct(y) { … } or (FRAGILE! see local mode below) after callable object in local variable: x >> some_proc(y) { … }

Calls superclass method
# File lib/pipeful.rb, line 227
def method_missing(m, *method_args, **method_kwargs, &method_block)
  pipe_next = if @pipe_local_mode
                level = 1
                level += 1 while binding.of_caller(level).eval("__method__") == :method_missing
                binding.of_caller(level).eval(m.to_s)
              else
                self_module = methods.include?(:constants) ? self : self.class
                self_module.find_constant(m)
              end
  if pipe_next.nil?
    super
  elsif pipe_next.is_a?(Class)
    Class.new(pipe_next) do
      @parenth_args = method_args
      @parenth_kwargs = method_kwargs
      @block = method_block
      def self.parenth_arity
        @parenth_args.count
      end
      case pipe_type
      when :class_function
        def self.call(*args)
          superclass.call(*args, *@parenth_args, **@parenth_kwargs, &@block)
        end
        def self.pipe_arity
          superclass.method(:call)
                    .extend(ArityRange)
                    .arity_range(subtract: parenth_arity)
        end
      when :instance_function
        def self.call(*args)
          superclass.new(*@parenth_args, **@parenth_kwargs)
                    .call(*args, &@block)
        end
        def self.pipe_arity
          superclass.instance_method(:call)
                    .extend(ArityRange)
                    .arity_range
        end
      when :object_class
        def self.call(*args)
          superclass.new(*args, *@parenth_args, **@parenth_kwargs, &@block)
        end
        def self.pipe_arity
          superclass.instance_method(:initialize)
                    .extend(ArityRange)
                    .arity_range(subtract: parenth_arity)
        end
      end
    end
  else  # pipe_next is a callable object (in a constant, unless in local mode)
    Class.new do
      @funct_obj = pipe_next
      @parenth_args = method_args
      @parenth_kwargs = method_kwargs
      @block = method_block
      def self.parenth_arity
        @parenth_args.count
      end
      def self.call(*args)
        @funct_obj.call(*args, *@parenth_args, **@parenth_kwargs, &@block)
      end
      def self.pipe_arity
        @funct_obj.extend(ArityRange)
                  .arity_range(subtract: parenth_arity)
      end
    end
  end
end
pipe_local(&block) click to toggle source

not recommended for production! relies on binding_of_caller gem, and iffy stack-climbing (above)

# File lib/pipeful.rb, line 302
def pipe_local(&block)
  @pipe_local_mode = true
  result = block.call
  @pipe_local_mode = false
  result
end