Sha256: 331502f1394fc1b802cf1cdc64c72d1726914b818381d4eadab603c5b3e7aefe

Contents?: true

Size: 1.82 KB

Versions: 12

Compression:

Stored size: 1.82 KB

Contents

require 'binding_of_caller'

class Mercury
  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
end

Version data entries

12 entries across 12 versions & 1 rubygems

Version Path
mercury_amqp-0.9.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.8.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.7.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.6.1 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.6.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.5.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.4.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.3.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.2.0 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.9 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.7 lib/mercury/cps/seq_with_let.rb
mercury_amqp-0.1.6 lib/mercury/cps/seq_with_let.rb