Sha256: feb18605896943a84e39b468f705138bb4a9571f90a9bf3724ef1e9eacecde74

Contents?: true

Size: 1.7 KB

Versions: 5

Compression:

Stored size: 1.7 KB

Contents

require 'binding_of_caller'

class Cps
  # Syntactic sugar for and_then chains.
  def self.seql(depth=1, &block)
    # EXPERIMENTAL
    # The trick here is to execute the block in a context where
    # 1. we can simulate local let-bound variables, and
    # 2. the block can access variables and methods available
    #    outside the call to seql.
    #
    # To achieve this, we instance_exec the block in a SeqWithLet
    # object, which provides the let bound variables (as methods)
    # and uses method_missing to proxy other methods to the parent
    # binding.
    #
    # Note: parent instance variables are not available inside the block.
    # Note: keyword arguments are not proxied to methods called in the parent binding
    context = SeqWithLet.new(binding.of_caller(depth))
    context.instance_exec(&block)
    context.__chain
  end

  class SeqWithLet

    def and_then(&block)
      @__chain = __chain.and_then(&block)
    end

    def and_lift(&block)
      @__chain = __chain.and_lift(&block)
    end

    def let(name, &block)
      and_then(&block)
      and_then do |value|
        __values[name] = value
        Cps.lift{value}
      end
    end

    def initialize(parent_binding)
      @__parent_binding = parent_binding
    end

    def __chain
      @__chain ||= Cps.identity
    end

    def method_missing(name, *args, &block)
      __values.fetch(name) { __parent_call(name.to_s, *args, &block) }
    end

    def __parent_call(name, *args, &block)
      @__parent_caller ||= @__parent_binding.eval <<-EOD
      proc do |name, *args, &block|
        send(name, *args, &block)
      end
      EOD
      @__parent_caller.call(name, *args, &block)
    end

    def __values
      @__values ||= {}
    end
  end
end

Version data entries

5 entries across 5 versions & 1 rubygems

Version Path
mercury_amqp-0.1.5 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.4 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.3 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.2 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.0 lib/mercury/cps/seq_with_let.rb