Xrcise tutorial, undefined method 'upper_bt'

Hi
I’m trying to follow the tutorial on xrcise at
http://wxruby.rubyforge.org/wiki/wiki.pl?UsingXRCise

But I keep getting the following error when I try to run the example;
tutorial.rb:21:in initialize': undefined method 'upper_bt' for #<CaseChangeFrame:0x2d610f8> (NoMethodError) from tutorial.rb:28:in new’
from tutorial.rb:28:in on_init' from c:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.2-i386-mswin32/lib/wx/classes/app.rb:16:in main_loop’
from
c:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.2-i386-mswin32/lib/wx/classes/app.rb:16:in
`run’
from tutorial.rb:27

The relevant ruby code looks like.

Inherit from the generated base class and set up event handlers

class CaseChangeFrame < TextFrameBase
def initialize
super
evt_button(upper_bt) { text_box.upcase! }
evt_button(lower_bt) { text_box.downcase! }
end
end

I have triple checked that I have given the button widget an Id name of
upper_bt in DialogBlocks

Has anyone come across this before?

Thanks
Tim

Hi Tim

Tim Field wrote:

main_loop' from c:/ruby/lib/ruby/gems/1.8/gems/wxruby-1.9.2-i386-mswin32/lib/wx/classes/app.rb:16:inrun’
from tutorial.rb:27
Thanks for the report. Hard to say what’s going on here - could you post
the my_frame.xrc that you’re running XRCise against, and also the
my_frame.rb that’s been generated?

alex

To my eyes, this looks like a simple syntax slip. The argument to
evt_button is being interpreted as a method call, not a symbol as
intended.
Note the colons:

evt_button(:upper_bt) { text_box.upcase! }
evt_button(:lower_bt) { text_box.downcase! }

  • Ash

Ash Wilson wrote:

To my eyes, this looks like a simple syntax slip. The argument to
evt_button is being interpreted as a method call, not a symbol as
intended. Note the colons:

evt_button(:upper_bt) { text_box.upcase! }
evt_button(:lower_bt) { text_box.downcase! }
The first argument to evt_button, as to the other event handlers that
capture commands from Controls, is a Window or a Window id that is the
source of the vents

So these should be methods which return a Wx::Button

alex

Hi Alex

Thanks for taking a look, Here are the files, I also tried the syntax
changes mentioned by Ash but this didn’t work either,
resulted in this error.
Must specify Wx::Window event source or its Wx id, not ‘:upper_bt’
(ArgumentError)
I’m fairly new to ruby syntax so it wouldn’t be beyond me to have such a
problem but seems its something else

Tim

Hey Tim and Alex,

Tim Field wrote:

Tim
Wow, must be one of the first fast ones I’ve actually debugged here.
I’ve done my own debugging, and it looks like, your trying to setup the
ID for your objects, and they haven’t even been defined yet. And for
you Alex, in order to access “finder” You should proabbly store that as
a Method Call, or store it as a Class Variable, so that it can be
accessed, in this sistuation.

Anyways, the core problem, is first, for the method at which your
generating the code, and adding to it, you need to change the “finder”
variable in my_frame.rb in TestFrameBase#initialize() to a class
variable, so it can be accessed by sub-classed versions of the
TestFrameBase. You can do this easily by just adding an ‘@’ symbol to
it. Nothing to it really.

Next, in your sub-classed version in tutorial.rb, I made a few changes.
Basically, I added the three calls to
@finder.call(“id_we_are_looking_for”) for upper_bt, lower_bt, and
text_box, then changed the upcase and downcase to the following:
text_box.value = text_box.value.upcase/downcase As you can modify the
string with upcase!/downcase!, but it doesn’t modify it in the wxRuby
Buffer, so you need to re-assign it to the buffer, so that it will
convert over properly for you, and display the changes. The New code
goes as follows:

======================my_frame.rb=======================

This class was automatically generated from XRC source. It is not

recommended that this file is edited directly; instead, inherit from

this class and extend its behaviour there.

Source file: tutorial.xrc

Generated at: Sat Nov 03 13:22:37 +1300 2007

class TextFrameBase < Wx::Frame

def initialize(parent = nil)
super()
xml = Wx::XmlResource.get
xml.flags = 2 # Wx::XRC_NO_SUBCLASSING
xml.init_all_handlers
xml.load(“tutorial.xrc”)
xml.load_frame_subclass(self, parent, “ID_WXFRAME”)

@finder = lambda do | x |
  int_id = Wx::xrcid(x)
  begin
    Wx::Window.find_window_by_id(int_id, self) || int_id
  # Temporary hack to work around regression in 1.9.2; remove
  # begin/rescue clause in later versions
  rescue RuntimeError
    int_id
  end
end

end
end

=====================tutorial.rb===========================
require ‘wx’

load in the generated code

require ‘my_frame’

Mix-in for a Wx::TextCtrl

module CaseChangeTextCtrl

convert all the text in the control to upper case

def upcase!
self.value = self.value.upcase
end

convert all the text in the control to lower case

def downcase!
self.value = self.value.downcase
end
end

Inherit from the generated base class and set up event handlers

class CaseChangeFrame < TextFrameBase
def initialize
super
upper_bt = @finder.call(“upper_bt”)
lower_bt = @finder.call(“lower_bt”)
text_box = @finder.call(“text_box”)
evt_button(upper_bt) { text_box.value = text_box.value.upcase }
evt_button(lower_bt) { text_box.value = text_box.value.downcase }
end
end

Run the class

Wx::App.run do
CaseChangeFrame.new.show
end

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

Enjoy the new code, and Alex, you should look into this, incase someone
decides they want to do something similar to this. This would exactly
be the way that I would want to do it.

L8ers,

Mario S.

Hi Tim

Tim Field wrote:

Thanks for taking a look, Here are the files, I also tried the syntax
changes mentioned by Ash but this didn’t work either,
As Mario says, it’s the missing finder calls that are the problem, but
these should be in the autogenerated base class, not the user class
you’re writing. Finder is meant to be a private implementation detail.

There is something strange going on because when I run xrcise over the
xrc file you sent, it does generate the missing lines in my_frame.rb

attr_reader :text_box, :upper_bt, :lower_bt

@text_box = finder.call("text_box")
@text_box.extend(CaseChangeTextCtrl)
@upper_bt = finder.call("upper_bt")
@lower_bt = finder.call("lower_bt")

Please could you double-check you’re running xrcise over the latest
saved version of your xrc file, as you posted it here.

If those lines are still not showing up, could you say what ruby version
and platform you’re on.

thanks
alex

thanks
alex

Hi Mario

Wow thanks for that sure enough it works!

Do you think the tutorial at
http://wxruby.rubyforge.org/wiki/wiki.pl?UsingXRCise should be updated,
I’m
surprised this hasn’t been an issue for someone else?

Also I was thinking in php (i work with php for a living) there are
special get and set methods you can define which are only triggered when
your object or inherited object doesn’t contain the member or method
you’re
trying to access.
(PHP: Overloading - Manual
)

so in this example in php I would write something like.

function __get($name){
if($element = $this->finder($name))
return $element;
trigger_error(“undefined property $name”);
}

Maybe such a function would be useful in the base class in the tutorial
example to look up the form elements thus preventing the need for the
“upper_bt = @finder.call(“upper_bt”)” lines.

Anyway I had a good look at the ruby manual I have and couldn’t find a
way
to do this, I’m sure there is? or perhaps you guys can think of a more
elegant solution?

Thanks again for helping me though that issue guys!

Tim

Tim Field wrote:

Also I was thinking in php (i work with php for a living) there are
special get and set methods you can define which are only triggered
when your object or inherited object doesn’t contain the member or
method you’re trying to access. (
PHP: Overloading - Manual)
Object#method_missing is what you’re looking for.

class Foo
def method_missing(meth, *args)
puts “Called non-existing method ‘#{meth}’ with arguments
‘#{args.join(’,‘)}’”
end
end

It’s best used with discretion, because it breaks reflection on an
object’s supported methods eg,

Foo.new.respond_to?(:blah)
=> false

Even if ‘blah’ would be a valid method call.

cheers
alex

Hi Alex,

Those lines definitely aren’t showing up. (when using that xrc file or
another one I have)

I’m running ruby 1.8.6 on winxp

-Tim

Tim

Tim Field wrote:

Those lines definitely aren’t showing up. (when using that xrc file or
another one I have)

I’m running ruby 1.8.6 on winxp
I couldn’t reproduce the bug with XP/1.8.4, but I tried installing the
latest 1.8.6 and now can.

It’s due to some incompatible change in REXML shipped with ruby 1.8.4
(version 3.1.3) and 1.8.6 (version 3.1.6), somewhere in it’s XPath
parsing, but exactly what’s needed is eluding me right now.

Anyway, thanks again for the report. We should be able to pin down
what’s up and put out a version of wxSugar inc XRCise that works on
1.8.6 in the next week or so.

alex

Alex F. wrote:

I couldn’t reproduce the bug with XP/1.8.4, but I tried installing the
latest 1.8.6 and now can.

It’s due to some incompatible change in REXML shipped with ruby 1.8.4
(version 3.1.3) and 1.8.6 (version 3.1.6), somewhere in it’s XPath
parsing, but exactly what’s needed is eluding me right now.

Anyway, thanks again for the report. We should be able to pin down
what’s up and put out a version of wxSugar inc XRCise that works on
1.8.6 in the next week or so.

alex

Hey I get the same thing… running 1.8.6 on Mac OS X 10.5.2. Got a gem
of the latest wxSugar 0.1.20 but this still seems to be an issue in this
version.

Anyone know?

Thx!