[Kde-bindings] Understanding QtRuby
Richard Dale
rdale at foton.es
Tue Apr 8 10:16:02 UTC 2008
On Monday 07 April 2008 22:40:14 Jonathan Gardner wrote:
> I am no pro at Ruby. I do understand Python really well, including it's
> C interface.
>
> I am attempting to build a package in Lisp that will allow me to connect
> with Qt, possibly using the Smoke library. So I am poking at the QtRuby
> code to get started.
>
> However, I am completely befuddled by the most basic of statements. I am
> sure that a few pointers to the documentation would help me get on the
> right path.
>
> Consider the example shown at
> http://developer.kde.org/language-bindings/ruby/index.html
>
> #!/usr/bin/ruby -w
> require 'Qt'
>
> I believe that "require 'Qt'" loads the Qt.rb file, which simply loads the
> qtruby.qt file.
Yes, the require Qt statement loads qtruby4.so, which in turn loads
qtruby4.rb.
> a = Qt::Application.new(ARGV)
>
> This, I believe, is a simply constructor for the Qt::Application defined at
> line 182 in qtruby.rb. There is no C magic yet.
Yes, it is a constructor, but there has actually already been a lot of C
magic.
> hello = Qt::PushButton.new("Hello World!", nil)
>
> The PushButton class doesn't exist in qtruby.qt. I can't tell how this is
> getting dispatched.
The QtRuby classes are created dynamically at runtime. At the end of the
Qt.cpp source there is a call to the ruby method init_all_classes in
qtruby4.rb, which in turn calls another method init_class() in qtruby4.rb.
That method calls create_qt_class() or create_qobject_class() which actually
create the Ruby classes under Qt::Base.
> hello.resize(100, 30)
>
> Pending an understanding of what PushButton is.
>
> a.mainWidget = hello
>
> I can't tell how the mainWidget assignment is dispatched either.
Method calls in ruby can look like assignments, and this is a call to
the 'mainWidget=()' method. It is changed at runtime to 'setMainWidget()'
that is the name of the actual C++ method that is called.
> hello.show()
> a.exec()
>
> I believe the exec method here is defined at line 183.
>
> def exec
> method_missing(:exec)
> self.dispose
> Qt::Internal.application_terminated = true
> end
>
> I am not sure what this is doing. What is method_missing? where is dispose
> defined?
Ruby classes are open and so this isn't the complete definition of
Qt::Application, it is just adding the exec() method to it. Normally the Ruby
method_missing() call is used to trap method calls (see do_method_missing()
in Qt.cpp), but here exec needs to be special cased.
'method_missing(:exec)' is explicitely despatching the :exec message to
method_missing() on the Qt::Application instance, whereas it normally would
happen because Qt::Application didn't actually have a method of that name.
> Although I can find the Qt::Internal module, I don't see how
> application_terminated is defined.
It's a C function in Qt.cpp called set_application_terminated(). It is mapped
onto the Ruby method 'application_terminated=()' in Qt.cpp like this:
rb_define_module_function(qt_internal_module, "application_terminated=",
(VALUE (*) (...)) set_application_terminated, 1);
> I am sorry for being such a newbie when it comes to Ruby, but I think if I
> can get a few pointers I can get underway.
Yes, just keep doing a Q and A, and I can gradually explain how it works. The
first thing to understand though is how method_missing() is working in the
binding, and how you might do the same thing in lisp. Try this code:
class TestMethodMissing
def method_missing(symbol, *args)
puts "attempting to call a missing method: #{symbol} in
TestMethodMissing"
if args.length > 0
puts "first argument: #{args[0]}"
end
if args.length > 1
puts "second argument: #{args[1]}"
end
end
end
t = TestMethodMissing.new
t.foobar
t.bar(1)
t.baz("hello", "ruby")
-- Richard
More information about the Kde-bindings
mailing list