Tk : non blocking Tk.mainloop

Hi all,

I’m new in this forum (but I have been following it for months)

I did some canvas tests on my Debian Squeeze with Ruby 1.8 + Tk, and
everything was OK.

Then I chose to move to Ruby 1.9 ; so I cleaned my old Ruby packages and
installed “ruby1.9.1-full package”, which comes with Tk8.4

My problem is I can’t get Ruby TK programs run properly, because the
Tk.mainloop is non blocking ; my program exists immediately, I only see
the Tk canvas appear and disappear.

This occurs even on the simpliest program, like :
require ‘tk’
rr=TkRoot.new
cc=TkCanvas.new(rr)
cc.pack
Tk.mainloop

Running it under IRB, the window appears correctly.

Any clue about this behaviour and how to make Tk.mainloop work as
expected ? Thanks

On Thu, Apr 14, 2011 at 1:20 AM, Juju SL [email protected] wrote:

Tk.mainloop is non blocking ; my program exists immediately, I only see
the Tk canvas appear and disappear.

fwiw, it should not exit, mine does not. i think nahi good help you
further.
best regards -botp

Hi,

I’m very sorry for my late response.

From: Juju SL [email protected]
Subject: Tk : non blocking Tk.mainloop
Date: Thu, 14 Apr 2011 02:20:37 +0900
Message-ID: [email protected]

I did some canvas tests on my Debian Squeeze with Ruby 1.8 + Tk, and
everything was OK.

Then I chose to move to Ruby 1.9 ; so I cleaned my old Ruby packages and
installed “ruby1.9.1-full package”, which comes with Tk8.4

My problem is I can’t get Ruby TK programs run properly, because the
Tk.mainloop is non blocking ; my program exists immediately, I only see
the Tk canvas appear and disappear.

I don’t use Debian. I couldn’t re-generate your trouble on my
environment.
It may depend on race condition of native threads.

Could you try the followings and report the results?

(1) If you call Tk.mainloop on the main thread only,
please call the follwing line berore “require ‘tk’”.
----------------------------------------------------------------------
module TkCore; RUN_EVENTLOOP_ON_MAIN_THREAD = true; end
----------------------------------------------------------------------

(2) Please run your simple script, which occurs your trouble, with -d
option.
e.g.
----------------------------------------------------------------------
ruby -d your_script.rb > exec.log 2>&1
----------------------------------------------------------------------
If it has same trouble, please send me the log file.

(3) Please apply the following patch.
If it has same trouble, please send the log when running with -d
option.

— tk.rb-orig 2011-04-25 06:37:19.000000000 +0900
+++ tk.rb 2011-04-25 06:54:13.000000000 +0900
@@ -1271,6 +1271,7 @@
}
set initial_state_of_rubytk 1
trace add variable initial_state_of_rubytk unset
startup_rbtk_mainloop
+update
EOS

     begin

@@ -1301,7 +1302,8 @@
}

   until INTERP_THREAD[:interp]
  •    Thread.pass
    
  •    #Thread.pass
    
  •    INTERP_THREAD.run
     end
     # INTERP_THREAD.run
     raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? 
    

Exception

From: Juju SL [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Fri, 29 Apr 2011 06:03:21 +0900
Message-ID: [email protected]

I tried your first suggestion with my simple script and the script ran
OK.

Then I tried another more complicated script, which did not work last
time ; it now runs OK too with your first hack.

First of all, it’s a good news that your script worked properly.

However, the first counterplan is not a good one.
Because, when you use it, you cannot call Tk.mainloop in a sub-thread
(e.g. “Thread.new{Tk.mainloop}” doesn’t work).

I haven’t tried your third suggestion, as I prefer to keep my packages
clean ; I keep it in mind in case the first hack does not solve my
problems.

I can understand your care. So, I can’t force you to try the third
counterplan. But I need your help to fix the problem, because I can’t
generate the problem.
If you try the third one temporally and it is effective, I can commit
the patch for the next release of Ruby.
Again, I never force you. But your trial report has very high value.

Hi,

Thank you for this answer Hidetoshi.

So, as I had gone back to Ruby 1.8, I desinstalled its packages and
reinstalled the 1.9 ones.

I tried your first suggestion with my simple script and the script ran
OK.

Then I tried another more complicated script, which did not work last
time ; it now runs OK too with your first hack.

I haven’t tried your third suggestion, as I prefer to keep my packages
clean ; I keep it in mind in case the first hack does not solve my
problems.

Thanks a lot for your help ; I will keep you aware if my problem occurs
again.

Best regards

JujuSL

Hi Hidetoshi,

I understand your need and as I asked for help, I have to help you back
:slight_smile:

So I applied the patch to tk.rb :


set initial_state_of_rubytk 1
trace add variable initial_state_of_rubytk unset
startup_rbtk_mainloop
update
EOS

    begin
      begin
        #TclTkLib.mainloop_abort_on_exception = false


and

}

  until INTERP_THREAD[:interp]
    #Thread.pass

INTERP_THREAD.run
end
# INTERP_THREAD.run
raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of?
Exception

Running the small script gives the same problem ; here is the end of the
debug output showing an exception :

tcltklib: destroy root widget
tcltklib: check finalize-hook-proc' tcltklib: checkforeach’ & after' tcltklib: cancel after callbacks tcltklib: finish ip_finalize ExceptionTypeError’ at /usr/lib/ruby/1.9.1/tk.rb:1283 - exception
class/object expected
tcltklib: eventloop_ensure: current-thread : 8802278
tcltklib: eventloop_ensure: eventloop-thread : 8802278
tcltklib: eventloop-ensure: new eventloop-thread -> 4
tcltklib: finish current eventloop 8802278
tcltklib: ip is deleted
tcltklib: ip is deleted
tcltklib: ip is deleted
tcltklib: delete deleted IP
tcltklib: free Tcl Interp 881a678
tcltklib: complete freeing Tcl Interp

But the weird thing is that sometimes it runs OK ! (once every 6 ou 7
times) ; I just run the same command again and again…

Hope this will help !

Best regards
Stéphane

EDIT :
I just moved back to the original “tk.rb” and the problem is in fact the
same : once every 6 or 7 times, the small script runs OK ! And as with
your patch, this seems to occur only with the “-d” option (without it,
the problem always occurs).

Very strange, how can a script not behave the same when I run it several
times ?..

From: Hidetoshi NAGAI [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Sat, 30 Apr 2011 07:27:07 +0900
Message-ID: [email protected]

I can focus to check when such race condition occurs.

Could you try the followiing patch?

— …/ruby-1.9.2-p0.orig/ext/tk/lib/tk.rb 2010-06-29
06:44:06.000000000 +0900
+++ ext/tk/lib/tk.rb 2011-05-02 18:16:29.000000000 +0900
@@ -1236,6 +1236,9 @@
raise e
end

  •    interp.mainloop_abort_on_exception = true
    
  •    Thread.current.instance_variable_set("@interp", interp)
    
  •    status = [nil]
       def status.value
         self[0]
    

@@ -1271,19 +1274,23 @@
}
set initial_state_of_rubytk 1
trace add variable initial_state_of_rubytk unset
startup_rbtk_mainloop
+
+# complete initializing
+ruby {TkCore::INTERP_THREAD[:interp] =
TkCore::INTERP_THREAD.instance_variable_get(’@interp’)}
EOS

     begin
       begin
         #TclTkLib.mainloop_abort_on_exception = false
         #Thread.current[:status].value = TclTkLib.mainloop(true)
  •        interp.mainloop_abort_on_exception = true
    
  •        Thread.current[:interp] = interp
    
  •        #interp.mainloop_abort_on_exception = true
    
  •        #Thread.current[:interp] = interp
           Thread.current[:status].value = interp.mainloop(true)
         rescue SystemExit=>e
           Thread.current[:status].value = e
         rescue Exception=>e
           Thread.current[:status].value = e
    
  •        p e if $DEBUG
           retry if interp.has_mainwindow?
         ensure
           INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast }
    

@@ -1300,12 +1307,20 @@
end
}

  •  # check a Tcl/Tk interpreter is initialized
     until INTERP_THREAD[:interp]
    
  •    Thread.pass
    
  •    # Thread.pass
    
  •    INTERP_THREAD.run
     end
    
  •  # INTERP_THREAD.run
     raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? 
    

Exception

  •  # check an eventloop is running
    
  •  while INTERP_THREAD.alive? && TclTkLib.mainloop_thread?.nil?
    
  •    INTERP_THREAD.run
    
  •  end
    
  •  INTERP = INTERP_THREAD[:interp]
     INTERP_THREAD_STATUS = INTERP_THREAD[:status]
    

@@ -1316,6 +1331,9 @@
INTERP_THREAD.kill
end
}
+

  •  # (for safety's sake) force the eventloop to run
    
  •  INTERP_THREAD.run
    

    end

    def INTERP.__getip

From: Juju SL [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Sat, 30 Apr 2011 04:37:52 +0900
Message-ID: [email protected]

I understand your need and as I asked for help, I have to help you back
:slight_smile:

I’m sorry that I bothered you about it, and thank you for your help.

Running the small script gives the same problem ; here is the end of the
(snip)
But the weird thing is that sometimes it runs OK ! (once every 6 ou 7
times) ; I just run the same command again and again…

Well, there is no wrong code about compatibility with your Tcl/Tk and
other libraries. And probably, it means that the trouble depends on
the race condition between a main thread and a background eventloop
(with initializing Tcl/Tk interpreter) thread.
I can focus to check when such race condition occurs.
Thank you for your report.

So, I patched manually the tk.rb file :

diff tk.rb.ORIG tk.rb

1238a1239,1241

    interp.mainloop_abort_on_exception = true
    Thread.current.instance_variable_set("@interp", interp)

1273a1277,1279

complete initializing

ruby {TkCore::INTERP_THREAD[:interp] =
TkCore::INTERP_THREAD.instance_variable_get(’@interp’)}

1280,1281c1286,1287
< interp.mainloop_abort_on_exception = true
< Thread.current[:interp] = interp

interp.mainloop_abort_on_exception = true

Thread.current[:interp] = interp

1286a1293

        p e if $DEBUG

1302a1310

  # check a Tcl/Tk interpreter is initialized

1304c1312,1313
< Thread.pass

Thread.pass

    INTERP_THREAD.run

1308a1318,1322

  # check an eventloop is running
  while INTERP_THREAD.alive? && TclTkLib.mainloop_thread?.nil?
    INTERP_THREAD.run
  end

1318a1333,1336

  # (for safety's sake) force the eventloop to run
  INTERP_THREAD.run

=====================================

Unfortunately, my small scripts ends with an exception :

tcltklib: delete slaves
tcltklib: destroy root widget
tcltklib: check finalize-hook-proc' tcltklib: checkforeach’ & after' tcltklib: cancel after callbacks tcltklib: finish ip_finalize ExceptionTypeError’ at /usr/lib/ruby/1.9.1/tk.rb:1288 - exception
class/object expected
tcltklib: eventloop_ensure: current-thread : 9e62658
tcltklib: eventloop_ensure: eventloop-thread : 9e62658
tcltklib: eventloop-ensure: new eventloop-thread -> 4
tcltklib: finish current eventloop 9e62658
tcltklib: ip is deleted
tcltklib: ip is deleted
tcltklib: ip is deleted
tcltklib: delete deleted IP
tcltklib: free Tcl Interp 9e7ae68
tcltklib: complete freeing Tcl Interp

Line 1288 is : Thread.current[:status].value = interp.mainloop(true)

Best regards
Stéphane

Thank you for your reply.

From: Juju SL [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Tue, 3 May 2011 05:46:55 +0900
Message-ID: [email protected]

So, I patched manually the tk.rb file :

You don’t need manual patch. Please use “patch” command.

Or, packaged version of tk.rb is not a normal one of ruby192p0?

If so, please tell me the version of your package.

Unfortunately, my small scripts ends with an exception :

Hmmm… Maybe, I misunderstood the reason of the trouble.
The exception is not important.
It is a normal situation when a Tcl/Tk interpreter is deleted at exit.

I want to know when and how Tk.mainloop exits.
Could you send me a FULL debug log with tk.rb (patched by previous
(ruby-talk:382536) patch) patched by the following?

— tk.rb~ 2011-05-02 18:16:29.000000000 +0900
+++ tk.rb 2011-05-03 11:18:17.000000000 +0900
@@ -1852,32 +1852,56 @@
TclTkLib.mainloop(check_root)

 else ### Ruby 1.9 !!!!!

+p :log001
unless TkCore::INTERP.default_master?
+p :log002
# [MultiTkIp] slave interp ?
return TkCore::INTERP._thread_tkwait(‘window’, ‘.’) if
check_root
end
+p :log003

   # like as 1.8, withdraw a root widget before calling Tk.mainloop
   TkCore::INTERP._eval_without_enc('catch {unset 

initial_state_of_rubytk}’)
+p :log004
INTERP_THREAD.run
+p :log005

   begin
     TclTkLib.set_eventloop_window_mode(true)

+p :log006
if check_root
+p :log007
INTERP_MUTEX.synchronize{
+p :log008
INTERP_ROOT_CHECK.wait(INTERP_MUTEX)
+p :log009
status = INTERP_THREAD_STATUS.value
+p [:log010, status]
if status && TkCore::INTERP.default_master?
INTERP_THREAD_STATUS.value = nil if $SAFE < 4
+p :log011
raise status if status.kind_of?(Exception)
end
+p :log012
}
else

  •      INTERP_THREAD.value
    

+p :log013

  •      # INTERP_THREAD.value
    
  •      begin
    
  •        INTERP_THREAD.value
    
  •      rescue Exception => e
    

+p [:log014, e]

  •        raise e
    
  •      end
       end
    
  •  rescue Exception => e
    

+p [:log015, e]

  •    raise e
     ensure
    

+p :log016
TclTkLib.set_eventloop_window_mode(false)
end
+p :log017
end
end

Good morning,
You’re doing better than me…
I’m working with an iMac Snow Leopard…and Ruby 1.8.7…
I have TK installed and can access it from the Bash command line - but
it is
not known to my Ruby, eg, require ‘Tk’ returns and error message in
irb…
I probably should have started a separate link…but I thought I stand a
good chance of getting some help here…
Thank you
----- Original Message -----
From: “Hidetoshi NAGAI” [email protected]
To: “ruby-talk ML” [email protected]; [email protected]
Sent: Monday, May 02, 2011 10:21 PM
Subject: Re: Tk : non blocking Tk.mainloop

From: “Patrick L.” [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Tue, 3 May 2011 22:52:45 +0900
Message-ID: [email protected]

I’m working with an iMac Snow Leopard…and Ruby 1.8.7…
I have TK installed and can access it from the Bash command line - but it is
not known to my Ruby, eg, require ‘Tk’ returns and error message in irb…
I probably should have started a separate link…but I thought I stand a
good chance of getting some help here…

I’m not a Mac user. So, I don’t have a proper answer.
However…
I heard that Snow Leopard stopped official support of Ruby/Tk.
It means that you must compile full or tcltklib extension of Ruby,
if you want use Ruby/Tk.
When compile, please pay attention to binary type; whether 32bit or
64bit. Ruby/Tk should work on each of 32bit and 64bit, if Ruby and
Tcl/Tk libraries are made as same binary type.

Good morning,

I’m a newbie to this site and I’m not sure if this is the way to start a
new
thread…if I’m doing something wrong, please let me know…

I’m also a newbie to the iMac Snow Leopard machine…
I have the ‘aluminum’ keyboard and it does not have a ‘forward delete’
button…
It does have the ‘backward delete’ button…
I’ve been able to solve the not having a ‘forward delete’ button by
using
‘fn’ + ‘[backward] delete’ in all other places but not within irb…
In irb, when I press ‘fn’+‘delete’ I get the ‘squigly’ character ‘~’…
…for example, if I’m in irb and want to delete the ‘2’ in the string
“123”, using ‘fn’+‘delete’, I get “1~23”…
No big deal, but it is driving me nuts…I’d appreciate any help…

Good day

Good morning Stu,
control+option+D indeed works as a ‘forward delete’ for an iMac with
Snow
Leopard and aluminum keyboard…
Thank you - I hope I can return the favor someday…
Ciao
----- Original Message -----
From: “Stu” [email protected]
To: “ruby-talk ML” [email protected]
Sent: Wednesday, May 04, 2011 1:31 PM
Subject: Re: Forward delete with irb on a iMac Snow Leopeard machine…

Hi Hidetoshi

Found some time to come back to my Tk problem.

You don’t need manual patch. Please use “patch” command.
That’s what I did, but it rejected 2 chunks, so I had no other choice…

Or, packaged version of tk.rb is not a normal one of ruby192p0?

If so, please tell me the version of your package.

Debian Squeeze comes with 1.9.1 packages, but Ruby version is 1.9.2p0

I want to know when and how Tk.mainloop exits.
Could you send me a FULL debug log with tk.rb (patched by previous
(ruby-talk:382536) patch) patched by the following?
Good news ! This patch applied with the previous one works ;Tk.mainloop
works as expected and waits after “log008” (I attached the log file)

Best regards
Stéphane

PS for the other guys : please create a new thread for your own problem
to keep this one clean. Thanks.

EDIT : Bad news ! Your patch works when I redirect standard and error
output to a file ; redirecting them to /dev/null, or running the script
without ‘-d’ option let the problem appear again

first hit on google:

http://hints.macworld.com/article.php?story=20050525040921189

~

I’m very sorry for bothering you.

Before this mail, a direct mail might be sent you.

The mail rejected by ruby-talk ML because of mail size.

So, I send this to ML for other ML members.

From: Juju SL [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Fri, 6 May 2011 05:11:23 +0900
Message-ID: [email protected]

You don’t need manual patch. Please use “patch” command.
That’s what I did, but it rejected 2 chunks, so I had no other choice…

Or, packaged version of tk.rb is not a normal one of ruby192p0?

If so, please tell me the version of your package.

Debian Squeeze comes with 1.9.1 packages, but Ruby version is 1.9.2p0

I see. I made a new diff from libtcltk-ruby1.9.1_1.9.2.0-2.

I want to know when and how Tk.mainloop exits.
Could you send me a FULL debug log with tk.rb (patched by previous
(ruby-talk:382536) patch) patched by the following?
Good news ! This patch applied with the previous one works ;Tk.mainloop
works as expected and waits after “log008” (I attached the log file)

It may be not so good news. Because, It shows that the problem may
depend on severe timing of thread switching.
I made a new patch to force to run the eventloop just before waiting a
condition variable.
Could you try it both of with and without $DEBUG (-d) option?
If not work, please send me the full log.
If work, please remove all debug log “log???” lines in mainloop method
and try it. (Probably, I’m too worried about changing timing of thread
switching by checking $DEBUG variable.)

— tk.rb.deb-libtcltk-ruby1.9.1_1.9.2.0-2 2010-11-01
17:54:54.000000000 +0900
+++ tk.rb 2011-05-07 06:25:42.000000000 +0900
@@ -1236,6 +1236,9 @@
raise e
end

  •    interp.mainloop_abort_on_exception = true
    
  •    Thread.current.instance_variable_set("@interp", interp)
    
  •    status = [nil]
       def status.value
         self[0]
    

@@ -1271,19 +1274,23 @@
}
set initial_state_of_rubytk 1
trace add variable initial_state_of_rubytk unset
startup_rbtk_mainloop
+
+# complete initializing
+ruby {TkCore::INTERP_THREAD[:interp] =
TkCore::INTERP_THREAD.instance_variable_get(’@interp’)}
EOS

     begin
       begin
         #TclTkLib.mainloop_abort_on_exception = false
         #Thread.current[:status].value = TclTkLib.mainloop(true)
  •        interp.mainloop_abort_on_exception = true
    
  •        Thread.current[:interp] = interp
    
  •        #interp.mainloop_abort_on_exception = true
    
  •        #Thread.current[:interp] = interp
           Thread.current[:status].value = interp.mainloop(true)
         rescue SystemExit=>e
           Thread.current[:status].value = e
         rescue Exception=>e
           Thread.current[:status].value = e
    
  •        p e if $DEBUG
           retry if interp.has_mainwindow?
         ensure
           INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast }
    

@@ -1300,12 +1307,20 @@
end
}

  •  # check a Tcl/Tk interpreter is initialized
     until INTERP_THREAD[:interp]
    
  •    Thread.pass
    
  •    # Thread.pass
    
  •    INTERP_THREAD.run
     end
    
  •  # INTERP_THREAD.run
     raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? 
    

Exception

  •  # check an eventloop is running
    
  •  while INTERP_THREAD.alive? && TclTkLib.mainloop_thread?.nil?
    
  •    INTERP_THREAD.run
    
  •  end
    
  •  INTERP = INTERP_THREAD[:interp]
     INTERP_THREAD_STATUS = INTERP_THREAD[:status]
    

@@ -1316,6 +1331,9 @@
INTERP_THREAD.kill
end
}
+

  •  # (for safety's sake) force the eventloop to run
    
  •  INTERP_THREAD.run
    

    end

    def INTERP.__getip
    @@ -1834,32 +1852,63 @@
    TclTkLib.mainloop(check_root)

    else ### Ruby 1.9 !!!
    +p :log001 if $DEBUG
    unless TkCore::INTERP.default_master?
    # [MultiTkIp] slave interp ?
    return TkCore::INTERP._thread_tkwait(‘window’, ‘.’) if
    check_root
    end
    +p :log002 if $DEBUG

     # like as 1.8, withdraw a root widget before calling Tk.mainloop
    

+p :log003 if $DEBUG
TkCore::INTERP._eval_without_enc(‘catch {unset
initial_state_of_rubytk}’)
+p :log004 if $DEBUG
INTERP_THREAD.run

   begin

+p :log005 if $DEBUG
TclTkLib.set_eventloop_window_mode(true)
+
+p :log006 if $DEBUG

  •    # force run the eventloop
    
  •    TkCore::INTERP._eval_without_enc('update')
    

+p :log007 if $DEBUG

  •    TkCore::INTERP._eval_without_enc('catch {set 
    

initial_state_of_rubytk}’)
+p :log008 if $DEBUG

  •    INTERP_THREAD.run
       if check_root
    

+p :log009 if $DEBUG
INTERP_MUTEX.synchronize{
+p :log010 if $DEBUG
INTERP_ROOT_CHECK.wait(INTERP_MUTEX)
+p :log011 if $DEBUG
status = INTERP_THREAD_STATUS.value
+p [:log012, status] if $DEBUG
if status && TkCore::INTERP.default_master?
INTERP_THREAD_STATUS.value = nil if $SAFE < 4
+p :log013 if $DEBUG
raise status if status.kind_of?(Exception)
end
+p :log014 if $DEBUG
}
else

  •      INTERP_THREAD.value
    

+p :log015 if $DEBUG

  •      # INTERP_THREAD.value
    
  •      begin
    
  •        INTERP_THREAD.value
    
  •      rescue Exception => e
    

+p [:log016, e] if $DEBUG

  •        raise e
    
  •      end
       end
    
  •  rescue Exception => e
    

+p [:log017, e] if $DEBUG

  •    raise e
     ensure
    

+p :log018 if $DEBUG
TclTkLib.set_eventloop_window_mode(false)
end
+p :log019 if $DEBUG
end
end

================================================================

Hi Hidetoshi,

First, sorry for the long delay but I was very busy and could not find
time to test your patch.

But I tried it today (had to partially patch by hand because 1 hunk was
rejected).

And guess ? It worker like a charm, with and without debug option, and
without the debug logs !

Congratulation for this great work !

Best regards
Stéphane

From: Juju SL [email protected]
Subject: Re: Tk : non blocking Tk.mainloop
Date: Tue, 17 May 2011 04:15:39 +0900
Message-ID: [email protected]

But I tried it today (had to partially patch by hand because 1 hunk was
rejected).

And guess ? It worker like a charm, with and without debug option, and
without the debug logs !

I’m glad to hear that. :slight_smile:
Thank you for your help and kindness.

I’ll commit the changes to trunk.
Probably, a maintainer of ruby192 will decide whether backport it to
1.9.2 or not.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs