Skip to content

Commit

Permalink
Some final cleaning of the hacking spree, before speccing
Browse files Browse the repository at this point in the history
  • Loading branch information
alloy committed Jul 14, 2010
1 parent d3513a6 commit abfd9df
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 101 deletions.
4 changes: 3 additions & 1 deletion bin/dietrb
Expand Up @@ -32,7 +32,9 @@ end
IRB.formatter.filter_from_backtrace << /^#{__FILE__}/

if ARGV.empty?
require 'irb/driver/readline'
# require 'irb/driver/readline'
# require 'irb/driver/tty'
require 'irb/driver/socket'
else
path = ARGV.shift
require 'irb/driver/file'
Expand Down
14 changes: 5 additions & 9 deletions lib/irb/context.rb
Expand Up @@ -15,7 +15,7 @@ def processors
end

attr_reader :object, :binding, :line, :source, :processors
attr_accessor :driver, :formatter
attr_accessor :formatter

def initialize(object, explicit_binding = nil)
@object = object
Expand All @@ -34,11 +34,11 @@ def __evaluate__(source, file = __FILE__, line = __LINE__)
def evaluate(source)
result = __evaluate__(source.to_s, '(irb)', @line - @source.buffer.size + 1)
store_result(result)
output.puts(formatter.result(result))
puts(formatter.result(result))
result
rescue Exception => e
store_exception(e)
output.puts(formatter.exception(e))
puts(formatter.exception(e))
end

# Returns whether or not the user wants to continue the current runloop.
Expand All @@ -61,7 +61,7 @@ def process_line(line)
return false if @source.terminate?

if @source.syntax_error?
output.puts(formatter.syntax_error(@line, @source.syntax_error))
puts(formatter.syntax_error(@line, @source.syntax_error))
@source.pop
elsif @source.code_block?
evaluate(@source)
Expand All @@ -77,14 +77,10 @@ def prompt
end

def input_line(line)
output.puts(formatter.prompt(self) + line)
puts(formatter.prompt(self) + line)
process_line(line)
end

def output
@driver || $stdout
end

def formatter
@formatter ||= IRB.formatter
end
Expand Down
60 changes: 60 additions & 0 deletions lib/irb/driver.rb
@@ -0,0 +1,60 @@
module IRB
class << self
attr_accessor :driver_class

def driver=(driver)
Thread.current[:irb_driver] = driver
end

def driver
current_thread = Thread.current
current_thread[:irb_driver] ||= begin
if group = current_thread.group
group.list.each do |thread|
break(driver) if driver = thread[:irb_driver]
end
end
end
end
end

module Driver
class OutputRedirector
def self.target
if driver = IRB.driver
driver.output
else
$stderr
end
end

# A standard output object has only one mandatory method: write.
# It returns the number of characters written
def write(object)
string = object.respond_to?(:to_str) ? object : object.to_s
send_to_target :write, string
string.length
end

# if puts is not there, Ruby will automatically use the write
# method when calling Kernel#puts, but defining it has 2 advantages:
# - if puts is not defined, you cannot of course use $stdout.puts directly
# - (objc) when Ruby emulates puts, it calls write twice
# (once for the string and once for the carriage return)
# but here we send the calls to another thread so it's nice
# to be able to save up one (slow) interthread call
def puts(*args)
send_to_target :puts, *args
nil
end

# Override this if for your situation you need to dispatch from a thread
# in a special manner.
#
# TODO: for macruby send to main thread
def send_to_target(method, *args)
self.class.target.__send__(method, *args)
end
end
end
end
12 changes: 1 addition & 11 deletions lib/irb/driver/socket.rb
Expand Up @@ -3,16 +3,6 @@

module IRB
module Driver
class SocketTTY < TTY
# We don't want to put the real standard output object on the
# OutputRedirector target stack.
def assign_output_redirector!
before = $stdout
$stdout = IRB::Driver::OutputRedirector.new
before
end
end

class Socket
# Initializes with the object and binding that each new connection will
# get as Context. The binding is shared, so local variables will stay
Expand All @@ -34,7 +24,7 @@ def run
connection = @server.accept
Thread.new do
# assign driver with connection to current thread and start runloop
IRB.driver = SocketTTY.new(connection, connection)
IRB.driver = TTY.new(connection, connection)
irb(@object, @binding)
connection.close
end
Expand Down
87 changes: 7 additions & 80 deletions lib/irb/driver/tty.rb
@@ -1,80 +1,13 @@
require 'irb/driver'

module IRB
class << self
attr_accessor :driver_class

def driver=(driver)
Thread.current[:irb_driver] = driver
end

def driver
current_thread = Thread.current
current_thread[:irb_driver] ||= begin
driver = nil
if group = current_thread.group
group.list.each do |thread|
break if driver = thread[:irb_driver]
end
end
driver || driver_class.new
end
end
end

module Driver
class OutputRedirector
# The output object for the current thread.
def self.target=(output)
Thread.current[:irb_stdout_target] = output
end

# TODO cache, or not to cache?
def self.target
current_thread = Thread.current
if target = current_thread[:irb_stdout_target]
elsif group = current_thread.group
group.list.each do |thread|
break if target = thread[:irb_stdout_target]
end
end
target || $stderr
end

# A standard output object has only one mandatory method: write.
# It returns the number of characters written
def write(object)
string = object.respond_to?(:to_str) ? object : object.to_s
send_to_target :write, string
string.length
end

# if puts is not there, Ruby will automatically use the write
# method when calling Kernel#puts, but defining it has 2 advantages:
# - if puts is not defined, you cannot of course use $stdout.puts directly
# - (objc) when Ruby emulates puts, it calls write twice
# (once for the string and once for the carriage return)
# but here we send the calls to another thread so it's nice
# to be able to save up one (slow) interthread call
def puts(*args)
send_to_target :puts, *args
nil
end

# Override this if for your situation you need to dispatch from a thread
# in a special manner.
#
# TODO: for macruby send to main thread
def send_to_target(method, *args)
self.class.target.__send__(method, *args)
end
end

class TTY
attr_accessor :current_context
attr_reader :input, :output

def initialize(input = $stdin, output = $stdout)
@input = input
@output = output
OutputRedirector.target = output

@thread_group = ThreadGroup.new
@thread_group.add(Thread.current)
Expand Down Expand Up @@ -104,7 +37,6 @@ def print(*args)

def run(context)
ensure_output_redirector do
context.driver = self
while line = consume(context)
continue = context.process_line(line)
break unless continue
Expand All @@ -115,27 +47,22 @@ def run(context)
# Ensure that the standard output object is a OutputRedirector. If it's
# already a OutputRedirector, do nothing.
def ensure_output_redirector
before = assign_output_redirector! unless $stdout.is_a?(IRB::Driver::OutputRedirector)
unless $stdout.is_a?(IRB::Driver::OutputRedirector)
before, $stdout = $stdout, IRB::Driver::OutputRedirector.new
end
yield
ensure
$stdout = before if before
end

def assign_output_redirector!
before = IRB::Driver::OutputRedirector.target = $stdout
$stdout = IRB::Driver::OutputRedirector.new
before
end
end
end
end

IRB.driver_class = IRB::Driver::TTY
IRB.driver = IRB::Driver::TTY.new

module Kernel
# Creates a new IRB::Context with the given +object+ and runs it.
def irb(object, binding = nil)
# IRB.driver.run(IRB::Context.new(IRB.driver, object, binding))
IRB.driver.run(IRB::Context.new(object, binding))
end

Expand Down
5 changes: 5 additions & 0 deletions spec/driver/tty_spec.rb
@@ -0,0 +1,5 @@
require File.expand_path('../../spec_helper', __FILE__)

describe "IRB::Driver::TTY" do

end

0 comments on commit abfd9df

Please sign in to comment.