[macruby-changes] [4726] DietRB/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Oct 8 04:05:35 PDT 2010
Revision: 4726
http://trac.macosforge.org/projects/ruby/changeset/4726
Author: eloy.de.enige at gmail.com
Date: 2010-10-08 04:05:34 -0700 (Fri, 08 Oct 2010)
Log Message:
-----------
Make socket driver work. Each connection starts a session on a new thread. For now the binding is shared.
From: Eloy Duran <eloy.de.enige at gmail.com>
Modified Paths:
--------------
DietRB/trunk/Rakefile
DietRB/trunk/bin/dietrb
DietRB/trunk/lib/irb/context.rb
DietRB/trunk/lib/irb/driver/socket.rb
DietRB/trunk/lib/irb/driver/tty.rb
Modified: DietRB/trunk/Rakefile
===================================================================
--- DietRB/trunk/Rakefile 2010-10-08 11:05:23 UTC (rev 4725)
+++ DietRB/trunk/Rakefile 2010-10-08 11:05:34 UTC (rev 4726)
@@ -12,7 +12,7 @@
desc "Run dietrb"
task :run do
- sh "#{ruby_bin} -I lib ./bin/dietrb -r irb/ext/colorize -r pp"
+ sh "#{ruby_bin} -I lib ./bin/dietrb -d -r irb/ext/colorize -r pp"
end
namespace :macruby do
Modified: DietRB/trunk/bin/dietrb
===================================================================
--- DietRB/trunk/bin/dietrb 2010-10-08 11:05:23 UTC (rev 4725)
+++ DietRB/trunk/bin/dietrb 2010-10-08 11:05:34 UTC (rev 4726)
@@ -32,8 +32,8 @@
IRB.formatter.filter_from_backtrace << /^#{__FILE__}/
if ARGV.empty?
- # irb(self, TOPLEVEL_BINDING.dup)
- IRB::Driver::Socket.new.run
+ irb(self, TOPLEVEL_BINDING.dup)
+ puts "ENDED! and this message should show up on stdout"
else
path = ARGV.shift
context = IRB::Context.new(self, TOPLEVEL_BINDING.dup)
Modified: DietRB/trunk/lib/irb/context.rb
===================================================================
--- DietRB/trunk/lib/irb/context.rb 2010-10-08 11:05:23 UTC (rev 4725)
+++ DietRB/trunk/lib/irb/context.rb 2010-10-08 11:05:34 UTC (rev 4726)
@@ -9,27 +9,26 @@
module IRB
class Context
class << self
- attr_accessor :current
+ # attr_accessor :current
+ #
+ # def make_current(context)
+ # # Messing with a current context is gonna bite me in the ass when we
+ # # get to multi-threading, but we'll it when we get there.
+ # before, @current = @current, context
+ # yield
+ # ensure
+ # @current = before
+ # end
- def make_current(context)
- # Messing with a current context is gonna bite me in the ass when we
- # get to multi-threading, but we'll it when we get there.
- before, @current = @current, context
- yield
- ensure
- @current = before
- end
-
def processors
@processors ||= []
end
end
attr_reader :object, :binding, :line, :source, :processors
- attr_accessor :io, :formatter
+ attr_accessor :io, :formatter, :driver
- def initialize(driver, object, explicit_binding = nil)
- @driver = driver
+ def initialize(object, explicit_binding = nil)
@object = object
@binding = explicit_binding || object.instance_eval { binding }
@line = 1
Modified: DietRB/trunk/lib/irb/driver/socket.rb
===================================================================
--- DietRB/trunk/lib/irb/driver/socket.rb 2010-10-08 11:05:23 UTC (rev 4725)
+++ DietRB/trunk/lib/irb/driver/socket.rb 2010-10-08 11:05:34 UTC (rev 4726)
@@ -2,34 +2,54 @@
require 'irb/driver/tty'
require 'socket'
-TOPLEVEL_OBJECT = self
-
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
- # DEFAULTS = {
- # :tty_exit_on_eof => false,
- # :term => "\r\0"
- # }
-
- def initialize(host = '127.0.0.1', port = 7829)
- # @options = DEFAULTS.merge(options)
+ # Initializes with the object and binding that each new connection will
+ # get as Context. The binding is shared, so local variables will stay
+ # around. The benefit of this is that a socket based irb session is most
+ # probably used to debug a running application in development. In this
+ # scenario it could be beneficial to keep local vars in between sessions.
+ #
+ # TODO see if that actually works out ok.
+ def initialize(object, binding, host = '127.0.0.1', port = 7829)
+ @object, @binding = object, binding
@host, @port = host, port
@server = TCPServer.new(host, port)
end
+ # TODO libedit doesn't use the right input and output, so we can't use Readline for now!!
def run
$stderr.puts "[!] Running IRB server on #{@host}:#{@port}"
loop do
connection = @server.accept
- # TODO libedit doesn't use the right input and output!!
- # IRB.driver = IRB::Driver::Readline.new(connection, connection)
- IRB.driver = IRB::Driver::TTY.new(connection, connection)
- context = IRB::Context.new(IRB.driver, TOPLEVEL_OBJECT, TOPLEVEL_BINDING.dup)
- IRB.driver.run(context)
- connection.close
+ Thread.new do
+ # assign driver with connection to current thread and start runloop
+ IRB.driver = SocketTTY.new(connection, connection)
+ irb(@object, @binding)
+ connection.close
+ end
end
end
end
end
+end
+
+def self.irb(object, binding = nil)
+ unless @server
+ @server = IRB::Driver::Socket.new(object, binding)
+ @server.run
+ else
+ super
+ end
end
\ No newline at end of file
Modified: DietRB/trunk/lib/irb/driver/tty.rb
===================================================================
--- DietRB/trunk/lib/irb/driver/tty.rb 2010-10-08 11:05:23 UTC (rev 4725)
+++ DietRB/trunk/lib/irb/driver/tty.rb 2010-10-08 11:05:34 UTC (rev 4726)
@@ -1,67 +1,132 @@
module IRB
- class Context
- class << self
- # attr_accessor :current
- def current
- Thread.current[:context]
- end
-
- def current=(context)
- Thread.current[:context] = context
- end
-
- # TODO move into driver
- def make_current(context)
- before, self.current = self.current, context
- yield
- ensure
- self.current = before
- end
- end
- end
+ # class Context
+ # class << self
+ # # attr_accessor :current
+ # def current
+ # Thread.current[:context]
+ # end
+ #
+ # def current=(context)
+ # Thread.current[:context] = context
+ # end
+ #
+ # # TODO move into driver
+ # # def make_current(context)
+ # # before, self.current = self.current, context
+ # # yield
+ # # ensure
+ # # self.current = before
+ # # end
+ # end
+ # end
class << self
- # attr_accessor :driver
- # def driver
- # @driver ||= Driver::TTY.new
- # end
+ attr_accessor :driver_class
def driver=(driver)
- Thread.current[:driver] = driver
+ Thread.current[:irb_driver] = driver
end
def driver
- Thread.current[: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
+ p driver
+ 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
+
def initialize(input = $stdin, output = $stdout)
@input = input
@output = output
- @running = false
+ OutputRedirector.target = output
+
+ @thread_group = ThreadGroup.new
+ @thread_group.add(Thread.current)
end
- def context
- Context.current
- end
-
def readline
- @output.print(context.prompt)
+ @output.print(current_context.prompt)
@input.gets
end
+ # TODO make it take the current context instead of storing it
def consume
readline
rescue Interrupt
- context.clear_buffer
+ current_context.clear_buffer
""
end
+ def puts(*args)
+ @output.puts(*args)
+ end
+
+ def print(*args)
+ @output.print(*args)
+ @output.flush
+ end
+
def run(context)
- with_io do
- Context.make_current(context) do
+ ensure_output_redirector do
+ make_current(context) do
while line = consume
continue = context.process_line(line)
break unless continue
@@ -70,34 +135,39 @@
end
end
- def puts(*args)
- @output.puts(*args)
+ def make_current(context)
+ context.driver = self
+ before, self.current_context = self.current_context, context
+ yield
+ ensure
+ self.current_context = before
end
- def print(*args)
- @output.print(*args)
- @output.flush
- end
-
- def with_io
- if @input_before.nil?
- @input_before, @output_before = $stdin, $stdout
- $stdin, $stdout = @input, @output
- end
+ # 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)
yield
ensure
- $stdin, $stdout = @input_before, @output_before
+ $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 = IRB::Driver::TTY.new
+IRB.driver_class = IRB::Driver::TTY
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(IRB.driver, object, binding))
+ IRB.driver.run(IRB::Context.new(object, binding))
end
private :irb
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20101008/ae69e277/attachment-0001.html>
More information about the macruby-changes
mailing list