I hadn’t planned on making another submission, but after tinkering with
it a bit I realized a few things:
- A simple GUI would be nice. I used FXRuby.
- The SAX Listener was barfing when the number of vendors was six or
more. Funny thing was that it only had a problem when the XML was
formatted. If I removed the whitespace it did just fine. In any case,
I switched to using a StreamListener instead.
- There was an inconsistency in the logic in my original in_range?
method.
Anyway, here is the Ruby code followed by sample XML:
#!/usr/local/bin/ruby -w
require ‘rexml/document’
require ‘rexml/streamlistener’
require ‘fox16’
include Fox
class VendorListener
include REXML::StreamListener
def initialize(low_price, high_price, vendor_search_window)
begin
@low_price = Float(low_price)
rescue
@low_price = 0
end
begin
@high_price = Float(high_price)
rescue
#if someone can spend more than this then
#she or he can afford a better program
@high_price = 10**15
end
@vdr_srch_wdw = vendor_search_window
end
def tag_start(name, attrs)
if name == ‘Vendor’
@vendor_name = attrs[‘name’]
end
end
def tag_end(name)
if name == ‘Vendor’ and
if in_range?
@vdr_srch_wdw.add_vendor(@vendor_name)
end
elsif name == ‘LowPrice’
@vendor_low_price = Float(@data)
elsif name == ‘HighPrice’
@vendor_high_price = Float(@data)
end
end
def text(text)
@data = text
end
def in_range?
@low_price <= @high_price and
(@low_price >= @vendor_low_price or @high_price >=
@vendor_low_price) and
(@low_price <= @vendor_high_price or @high_price <=
@vendor_high_price)
end
end
class VendorSearchWindow < FXMainWindow
def initialize(app)
# Invoke base class initialize first
super(app, “Ruby Q. #164: Vendor Search”, nil, nil, DECOR_TITLE |
DECOR_CLOSE)
#Add text field frame at the top
textfields = FXHorizontalFrame.new(self,
LAYOUT_SIDE_TOP|LAYOUT_CENTER_X)
FXLabel.new(textfields, “Enter a range:”, nil, JUSTIFY_LEFT)
FXLabel.new(textfields, “low:”, nil, JUSTIFY_RIGHT)
@low_field = FXTextField.new(textfields, 10, nil, 0,
JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
FXLabel.new(textfields, “high:”, nil, JUSTIFY_RIGHT)
@high_field = FXTextField.new(textfields, 10, nil, 0,
JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
#add button frame at the bottom
buttons = FXHorizontalFrame.new(self,
LAYOUT_SIDE_BOTTOM|LAYOUT_CENTER_X|PACK_UNIFORM_WIDTH)
show_button = FXButton.new(buttons, “Show Vendors”)
show_button.connect(SEL_COMMAND, method(:on_show_vendors))
exit_button = FXButton.new(buttons, “Exit”)
exit_button.connect(SEL_COMMAND, method(:on_exit))
#Place the list in a sunken frame
sunken_frame = FXHorizontalFrame.new(self,
LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK,
:padding => 0)
@vendor_list = FXList.new(sunken_frame, :opts =>
LIST_SINGLESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y)
end
def on_exit(sender, sel, ptr)
getApp().exit
end
def on_show_vendors(sender, sel, ptr)
@vendor_list.clearItems(false)
REXML::Document.parse_stream(File.new(‘vendors.xml’ ),
VendorListener.new(@low_field.text, @high_field.text, self))
end
def add_vendor(vndr_name)
@vendor_list.appendItem(vndr_name)
end
def create
super
show(PLACEMENT_SCREEN)
end
end
application = FXApp.new
VendorSearchWindow.new(application)
application.create
application.run
<?xml version="1.0" encoding="UTF-8"?>
1000
3000
6000
10000
500
2500