Class: Pal::REPL

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

Overview

Public: Creates a REPL instance.

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, context) ⇒ REPL

Returns a new instance of REPL.



44
45
46
47
48
49
# File 'lib/pal.rb', line 44

def initialize(name, context)
  @name = name
  @context = context
  @line = 1
  @statements = []
end

Class Attribute Details

.messengerObject (readonly)

Internal: Gets the current REPL instance.



34
35
36
# File 'lib/pal.rb', line 34

def messenger
  @messenger
end

Instance Attribute Details

#contextObject (readonly)

Public: Gets the evaluation context associated with the REPL instance.



27
28
29
# File 'lib/pal.rb', line 27

def context
  @context
end

#nameObject (readonly)

Public: Gets the name of the REPL instance, used to generate the prompt text and debugging information.



24
25
26
# File 'lib/pal.rb', line 24

def name
  @name
end

#resultObject (readonly)

Public: Gets the result of the last-evaluated expression.



30
31
32
# File 'lib/pal.rb', line 30

def result
  @result
end

Class Method Details

.create(name = "pal", context = Context.new) ⇒ Object

Public: Creates a new REPL instance. The ‘messenger` class instance variable is used by the REPL instance to correctly set and expose the result of the last-evaluated expression to the evaluation context.



39
40
41
# File 'lib/pal.rb', line 39

def create(name = "pal", context = Context.new)
  @messenger = new(name, context)
end

Instance Method Details

#evaluate(value) ⇒ Object

Public: Evaluates a line of code in the current context. If an error was raised, the stack trace is printed. To reduce noise, all lines containing the current file name are removed.



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/pal.rb', line 87

def evaluate(value)
  @result = eval(value, @context.instance_eval { binding }, "(#{@name})", @line)
  @context.instance_variable_set(:@_, REPL.messenger.result)
rescue Exception => exception
  @error = true
  stack = exception.backtrace.take_while { |line| not line.include? File.basename(__FILE__) }
  stack.unshift exception.message
  warn %Q{#{exception.class}: #{stack.join($/ + " " * 4)}}
ensure
  @line += 1
end

#loopObject

Public: Starts the REPL. The REPL will persist until an ‘exit` signal is received.



53
54
55
56
57
# File 'lib/pal.rb', line 53

def loop
  catch :exit do
    read while true
  end
end

Public: Prints the last output, prepending the output symbol to a human-readable representation of the result.



101
102
103
# File 'lib/pal.rb', line 101

def print(result)
  puts "=> #{result.inspect}" unless @error
end

#read(prompt = @name) ⇒ Object

Public: Reads, evaluates, and prints a line of Ruby code. If the line is ‘exit` or `quit`, an `exit` signal is sent and the loop terminates. If an interrupt is sent via Control-C, a blank line is printed before exiting. Multiple lines of code may be evaluated by terminating each line with an escape character (``).



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/pal.rb', line 64

def read(prompt = @name)
  @error = nil
  @input = Readline.readline("#{prompt}> ", true)
  throw :exit if @input.nil? || %w{exit quit}.include?(@input)
  unless @input.empty?
    @statements << @input
    if @statements.last[-1] == "\\"
      @statements.last.chop!
      read ?. * @name.size
    else
      @input = @statements.join($/)
      @statements.clear
      evaluate @input
      print @result
    end
  end
rescue Interrupt
  puts
end