Class: Rexpl::GeneratorProxy

Inherits:
Object
  • Object
show all
Defined in:
lib/rexpl/generator_proxy.rb

Overview

This class acts as a Proxy between the user and an actual Generator.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGeneratorProxy

Initializes a new Rexpl::GeneratorProxy instance with an empty instruction set.



17
18
19
# File 'lib/rexpl/generator_proxy.rb', line 17

def initialize
  @instructions = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

Swallows every message passed onto the instance and stores it in the instruction set.



23
24
25
26
# File 'lib/rexpl/generator_proxy.rb', line 23

def method_missing(method, *args)
  @instructions << [method, *args]
  nil
end

Instance Attribute Details

#instructionsObject

Returns the value of attribute instructions.



13
14
15
# File 'lib/rexpl/generator_proxy.rb', line 13

def instructions
  @instructions
end

Instance Method Details

#drawObject

Visually represents the state of the stack after each instruction is ran.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rexpl/generator_proxy.rb', line 76

def draw
  instructions = @instructions.dup
  klass = Class.new do
    dynamic_method(:draw) do |g|

      instructions.each_with_index do |instruction, idx|
        # Execute the instruction
        before = g.size
        g.__send__ *instruction
        after = g.size

        # Print the instruction header
        produced = after - before
        verb = 'produced'
        if produced < 0
          verb = 'consumed'
          produced = produced.abs
        end
        g.push_self
        g.push_literal "[#{idx}] [#{instruction.first} #{instruction[1..-1].map(&:inspect).join(', ')}] #{verb} #{produced} stack, size is now #{after}"
        g.send :puts, 1, true
        g.pop

        # Visually print the entire stack
        g.return_stack
        g.push_const :Rexpl
        g.find_const :Output
        g.swap_stack
        g.send :print_stack, 1, true
        g.pop
      end

      g.push_nil
      g.ret
    end
  end

  klass.new.draw
end

#listObject

Prints a list of the current instruction set.



67
68
69
70
71
72
73
# File 'lib/rexpl/generator_proxy.rb', line 67

def list
  puts
  @instructions.each_with_index do |instruction, idx|
    Output.print_instruction instruction, idx
  end
  puts
end

#resetObject

Empties the instruction set.



61
62
63
64
# File 'lib/rexpl/generator_proxy.rb', line 61

def reset
  Output.print_reset
  initialize
end

#visit(generator) ⇒ Object

Applies the set of instructions to an actual generator.

It captures errors in case an instruction is unknown or called with wrong arguments.

Examples:


proxy = Rexpl::GeneratorProxy.new
proxy.push 83
proxy.push_literal 'bar'

dynamic_method(:foo) do |g|
  proxy.visit(g)
  g.ret
end

Parameters:

  • generator (Rubinius::Generator)

    the generator onto which apply the instructions.



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rexpl/generator_proxy.rb', line 47

def visit(generator)
  last_instruction = nil
  begin
    @instructions.each do |instruction|
      last_instruction = instruction
      generator.__send__ *instruction
    end
  rescue NameError, ArgumentError=>e
    puts "[ERROR]: #{e}"
    @instructions.delete(last_instruction)
  end
end