class Opal::REPL

Constants

HISTORY_PATH
LINEBREAKS

Attributes

colorize[RW]

Public Class Methods

new() click to toggle source
# File lib/opal/repl.rb, line 15
def initialize
  @argv = []
  @colorize = true

  begin
    require 'readline'
  rescue LoadError
    abort 'opal-repl depends on readline, which is not currently available'
  end

  begin
    FileUtils.touch(HISTORY_PATH)
  rescue
    nil
  end
  @history = File.exist?(HISTORY_PATH)
end

Public Instance Methods

eval_ruby(code) click to toggle source
# File lib/opal/repl.rb, line 75
def eval_ruby(code)
  builder = Opal::Builder.new
  silencer = Silencer.new

  code = "#{@incomplete}#{code}"
  if code.start_with? 'ls '
    eval_code = code[3..-1]
    mode = :ls
  elsif code == 'ls'
    eval_code = 'self'
    mode = :ls
  elsif code.start_with? 'show '
    eval_code = code[5..-1]
    mode = :show
  else
    eval_code = code
    mode = :inspect
  end

  begin
    silencer.silence do
      builder.build_str(eval_code, '(irb)', irb: true, const_missing: true)
    end
    @incomplete = nil
  rescue Opal::SyntaxError => e
    if LINEBREAKS.include?(e.message)
      @incomplete = "#{code}\n"
    else
      @incomplete = nil
      if silencer.warnings.empty?
        warn e.full_message
      else
        # Most likely a parser error
        warn silencer.warnings
      end
    end
    return
  end
  builder.processed[0...-1].each { |js_code| eval_js(:silent, js_code.to_s) }
  last_processed_file = builder.processed.last.to_s

  if mode == :show
    puts last_processed_file
    return
  end

  eval_js(mode, last_processed_file)
rescue Interrupt, SystemExit => e
  raise e
rescue Exception => e # rubocop:disable Lint/RescueException
  puts e.full_message(highlight: true)
end
finish() click to toggle source
# File lib/opal/repl.rb, line 69
def finish
  @pipe.close
rescue
  nil
end
load_opal() click to toggle source
# File lib/opal/repl.rb, line 45
def load_opal
  runner = @argv.reject { |i| i == '--repl' }
  runner += ['-e', 'require "opal/repl_js"']
  runner = [RbConfig.ruby, "#{__dir__}/../../exe/opal"] + runner

  @pipe = IO.popen(runner, 'r+',
    # What I try to achieve here: let the runner ignore
    # interrupts. Those should be handled by a supervisor.
    pgroup: true,
    new_pgroup: true,
  )
end
run(argv = []) click to toggle source
# File lib/opal/repl.rb, line 33
def run(argv = [])
  @argv = argv

  savepoint = save_tty
  load_opal
  load_history
  run_input_loop
ensure
  dump_history
  restore_tty(savepoint)
end
run_input_loop() click to toggle source
# File lib/opal/repl.rb, line 58
def run_input_loop
  while (line = readline)
    eval_ruby(line)
  end
rescue Interrupt
  @incomplete = nil
  retry
ensure
  finish
end

Private Instance Methods

dump_history() click to toggle source
# File lib/opal/repl.rb, line 180
def dump_history
  return unless @history
  length = Readline::HISTORY.size > 1000 ? 1000 : Readline::HISTORY.size
  File.write(HISTORY_PATH, Readline::HISTORY.to_a[-length..-1].join("\n"))
end
eval_js(mode, code) click to toggle source
# File lib/opal/repl.rb, line 153
def eval_js(mode, code)
  obj = { mode: mode, code: code, colors: colorize }.to_json
  @pipe.puts obj
  while (line = @pipe.readline)
    break if line.chomp == '<<<ready>>>'
    puts line
  end
rescue Interrupt => e
  # A child stopped responding... let's create a new one
  warn "* Killing #{@pipe.pid}"
  Process.kill('-KILL', @pipe.pid)
  load_opal
  raise e
rescue EOFError, Errno::EPIPE
  exit $?.nil? ? 0 : $?.exitstatus
end
load_history() click to toggle source
# File lib/opal/repl.rb, line 175
def load_history
  return unless @history
  File.read(HISTORY_PATH).lines.each { |line| Readline::HISTORY.push line.strip }
end
readline() click to toggle source
# File lib/opal/repl.rb, line 170
def readline
  prompt = @incomplete ? '.. ' : '>> '
  Readline.readline prompt, true
end
restore_tty(savepoint) click to toggle source
# File lib/opal/repl.rb, line 193
def restore_tty(savepoint)
  system('stty', savepoint)
rescue
  nil
end
save_tty() click to toggle source

How do we support Win32?

# File lib/opal/repl.rb, line 187
def save_tty
  %x{stty -g}.chomp
rescue
  nil
end