Notable changes since 0.1.4:
- All debugging is done via TCP instead of UNIX sockets
- Instance variables view
- Increased efficiency overall
(Thanks to Matthias Georgi for his help)
Website: http://mr-guid.rubyforge.org
Project page: http://rubyforge.org/projects/mr-guid
Mitchell's Ruby GUI Debugger (Mr. Guid) is a simple cross-platform Ruby
GUI debugger written in Ruby using the Ruby/Gtk2 bindings for GTK+. It
is only meant to be a debugger, not an editor or IDE.
-- henon
I would appreciate more help figuring out how to work around this
problem of course so that cygwin is not needed.
Here is what I have figured out:
1. The TCPServer starts correctly and runs the 'accept' method waiting
for a connection
2. The TCPSocket successfully connects to the TCPServer.
3. The TCPServer "freezes" (or craps out) when trying to print data
(print, puts methods)
4. The TCPSocket "freezes" (or craps out) when trying to recieve data
(gets method)
3 and 4 work as expected in Unix/Linux, so Mr. Guid functions just
fine. It's just pesky Windows...
Hi, I'm just jumping in here... dunno if this helps. But up
through 1.8.2, Ruby didn't support non-blocking socket I/O on
Windows. I haven't personally tried non-blocking I/O on 1.8.4
Windows Ruby yet--however, looking through the sources, it
appears it is now supported!
That said, I'm not certain gets/puts are nonblocking-savvy on
Windows or not, even in 1.8.4. But it looks like send() should
be, now.
(And even in 1.8.4 I'm guessing popen() will still block in
Windows. (It definitely blocks in 1.8.2...))
Well anyway, for what it's worth ...........
Regards,
Bill
- henon
Looks cool. Simple and to the point.
Any MacOS X plans?
--Steve
Hi, could you explain more about what you mean by buffereing issues?
I primarily use send/recv with TCP. It's not hard to make a
puts/gets wrapper around send/recv, for instance.
For ex: (untested, but similar to what i frequently have used)
def send_string(sock, str)
begin
while str.length > 0
if select(nil, [sock], nil, nil)
sent = sock.send(str, 0)
str = str[sent..-1]
end
end
rescue IOError, SystemCallError, SocketError
# ... set eof flag?
end
end
def puts(sock, str)
send_string(sock, "#{str}\n")
end
sock.fcntl(Fcntl::F_SETFL, sock.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) if defined? Fcntl::O_NONBLOCK
puts(sock, "hello")
Regards,
Bill
Theoretically it should work on OSX because it can run linux apps. I
dont have a mac or access to one, so I could be wrong, but all you
would need I think is (preferrably the unix/linux versions of) ruby and
ruby-gtk2 (libglade and gtk2)
Mr. Guid acts on each line the debugger sends to it. The gets method
would recieve one line at a time, which is just what I want, but this
only seems to work in linux. For recv, I have to get a block of data
not necessarily delimited by line. This means if the previous line
takes a longer amount of time to process than the debugger can send
data (say listing global variables), the next recv call gets a chunk of
data rather than line by line. I therefore lose data to process. (You
can observe this by changing every 'gets' method to 'recv' and every
'puts' method to 'send' in both mr_guid.rb and gdebug.rb and trying to
get a list of global variables)
Bill,
Mr. Guid processes debugging output as each line comes in. The gets
function does just what I need to in linux. In windows, it freezes up
the application for some unknown reason. Although send/recv work in
windows, recv gets a block of data based on what the debugger has sent.
If Mr. Guid takes longer to process debug output than what the debugger
is sending in, (like displaying global variables), the recv grabs the
chunk of data that's been accumulating and processes it as what it
thinks is a separate line of output when in reality it's a few lines.
This leads to dropped data.
What I meant, is it's fairly trivial to write wrappers
around send/recv that act like gets/puts. I provided
an example of a "puts" version of send in my previous email.
It's similarly easy to write a wrapper around recv that
acts like "gets".
BTW, has anyone tried Mr. Guid on 1.8.4 Windows? Maybe
gets/puts will work on 1.8.4 on windows if you set
nonblocking mode on your socket. (?)
Regards,
Bill
why don't you post a gets that is a wrapper of recv? i think that would help
mitchell a lot. i would do it myself,
but i am a complete TCP noob. thx in advance.
-- henon
[....]
Hi, I'll be happy to when I get a chance.... Trying to get
this software done in time to send to the people who have
already gotten on the airplane to demo it at the show. :)
Regards,
Bill
Hi mitchell,
As it happens windows ruby didn't support nonblocking I/O in 1.8.2
and prior anyway. I haven't personally tried 1.8.4 on windows yet,
but I believe nonblocking socket I/O is finally supported (!!!!!!)
for which I am/will-be very grateful. :)
However, the following methods should work as nonblocking
replacements for gets/puts on windows, even under 1.8.2.
I've tested them on ruby 1.8.2 (2004-12-25) [i386-mswin32] and
they appear to work. (Apologies if there are any bugs.)
Hope this helps,
Regards,
Bill
require 'socket'
class TCPSocket
# Nonblocking puts.
# Since 1.8.2 on win32 doesn't support nonblocking socket I/O,
# we'll select on each character we send().
#
alias_method :orig_puts, :puts
def puts(str)
str = "#{str}\n" unless str[-1] == ?\n
str.each_byte do |val|
Kernel.select(nil, [self], nil, nil)
self.send(val.chr, 0)
end
end
# Buffered nonblocking gets. Returns partial last line if any.
# Returns nil when eof reached.
#
alias_method :orig_gets, :gets
def gets
buf = (@nb_gets_buf ||= "")
while (lineparse = buf.split(/\n/, 2)).length < 2
Kernel.select([self], nil, nil, nil)
dat = self.recv(65536) # arbitrary read length
if dat.empty? # reached eof?
@nb_gets_buf = nil
return buf.empty? ? nil : buf # return partial last line if we have one
end
buf << dat
end
buf.replace(lineparse[1]) # store remaining unparsed data back in buffer
lineparse[0] + "\n"
end
end
# here's the code I tested it with... i should have made them automated
# tests i guess - these require visual inspection of the output....
# it prints a big ugly mess of stuff to the console... ;-/
require 'thread'
$stdout.sync = true
sv = TCPServer.new(12345)
cl = TCPSocket.new('localhost', 12345)
sv_cl = sv.accept
happy_th = Thread.new { loop { puts "happy!"; sleep 1 } }
gobble_th = Thread.new {
while line = sv_cl.gets
print "gobble!(#{line.inspect}) "
sleep(0.1) if rand > 0.99 # make sure we fall behind the main puts() thread
end
}
0.upto(12288) do |i|
print "#{i} "
cl.puts(i.to_s)
end
cl.send("p", 0) # end with a "partial" line
cl.close
gobble_th.join
# if the final gobbles you see in the console before the program
# exits are:
# gobble!("12288\n") gobble!("p")
# ... then it "worked".
With Bill's wrappers, I can get remote debugging to work, but local
debugging still freezes because of thread issues in windows. I am
growing very tired very fast with that operating system and would
definately appreciate any help getting Mr. Guid to play nicely with it.
Until then however, I cannot spend too much time concerning myself with
the issue. For all the windows users who wish to use Mr. Guid, I am
sorry. My only recommendation right now is to get ruby running in
cygwin. I will probably tinker with that and post my results and or
HOWTO's.
Sorry for all the inconvenience.
As I've mentioned in a previous thread, it does work under OS X. You
have to do a bit of a song and dance, and run it under X, but it does
work.
So as far as the windows version is concerned, I'm pretty much open to
anything that would work right now. The Linux version has been rock
solid so far.