[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

accessors and anonymous classes

Russell Fulton

7/8/2006 9:59:00 PM

Hmmm... odd I wrote a version of this last night but it would appear
that I failed to post it to the forum, doh! so here it goes again. If
it did get out and this is a duplicate then please accept my apologies
for the waste of bandwidth.


I am writing a recursive descent parser to parse a configuration file
that consists of nested 'Sections' which all look like this:
[<section type> <possibly optional name>] {
<item>
<item>
.
.
}

where <item> may be another section.

I wrote a clase Section to parse the basic structure. Section.initialise
calls method specificItems to parse non section items (see below). For
each type of section I have an anonymous class tied to a Class variable
-- I have included one such class below. I had to make the classes
anonymous because I needed to include references to the classes in a
data structure (see subSections ) which tells the parser which section
types are valid in this section and what to do with them.

[ aside: someone asked why I wanted reference to scalar variable in my
previous post -- this is why. I needed to have a refernce to a variable
in that structure into which I could store the parsed class]

Now to the problem: As you see I have defined a bunch of accessor
methods using attr_reader and attr_writer, but these don't work ( I get
an undefined method error ). Adding the accessor methods explicitly
works fine. Odd!

I'm not sure if this is a bug, a feature or simply some lack in my
understanding of how things should work.

Any ideas?

Also this is my first real OO Ruby program and I would appreciate
comments -- it is too large (currently 1000 lines) to post here but if
anyone would be willing to have a look at it I'd be happy to email it to
them. My email is r.fulton@auckland.ac.nz.

I have run into various problems in this project and have managed to
solve all of them but I am far from confident that my solution was the
best way of doing it. The use of anonymous classes is one example. I
wrote a generic text parser for this project and because Ruby does not
support multiple inheiritance I ended up passing an instance of the
parser as a parameter to all the methods -- I figured that since the
parser needed to maintain state that I could not make it a mixin...

Cheers, Russell


@@hostService = Class.new( Section ) {

attr_reader = :services, :converted, :actions, :patterns,
:realTime,
:periodic, :files
attr_writer = :converted

def initialize( head, parser )
@services = []
@actions = []
@patterns = []
@realTime = []
@periodic = []
@files = []
@converted = false
super( head, parser )
end

# accessor methods --- since the shorthand way did not work
def actions
@actions
end

[ boring repeditive stuff snipped ]

def converted=(value)
@converted = value
end

# this handles the non section items in the section

def specificItem( firstToken, parser )

case firstToken
when 'service'
if token = parser.expect(/^(\w+)/, "service name") then
@services.push( token )
else
@errors = true
parser.restofLine # ignore the rest of the line
end
else
@errors = true
parser.error( "#{firstToken} not valid in host section" )
parser.restofLine # ignore the rest of the line
end
end

# defines which sections may be nested within this section
# Key is the section type the vailue is [ <name required>,
# class to parse section and where to store the result ]

def subSections( kind )
{'actions' => [nil, @@actionList, @actions ],
'files' => [nil, @@commaList, @files],
'patterns' => [nil, @@patternList, @patterns],
'realtime' => [nil, @@matchList, @realTime],
'periodic' => [nil, @@matchList, @periodic]
}[kind]
end
} # end of hostSection

--
Posted via http://www.ruby-....

6 Answers

Russell Fulton

7/9/2006 12:04:00 AM

0

Russell Fulton wrote:
>
> Now to the problem: As you see I have defined a bunch of accessor
> methods using attr_reader and attr_writer, but these don't work ( I get
> an undefined method error ). Adding the accessor methods explicitly
> works fine. Odd!
>

Hmmmm... I have now done what I should have done before posting this --
written a little test program that illustrates the problem. Of course
it works as expected so something more complex is going on. I'll go
back and double check everything yet again. If I can reporduce the
'problem' in a small program I'll post again.

If anyone feels like looking at the full program email me -- address in
original post.

Russell

--
Posted via http://www.ruby-....

dblack

7/9/2006 12:28:00 AM

0

Russell Fulton

7/9/2006 2:25:00 AM

0

unknown wrote:
> Hi --
>
> On Sun, 9 Jul 2006, Russell Fulton wrote:
>
>> @@hostService = Class.new( Section ) {
>>
>> attr_reader = :services, :converted, :actions, :patterns,
>> :realTime,
>> :periodic, :files
>> attr_writer = :converted
>
> Just looking at this quickly: you're assigning to local variables
> called attr_reader and attr_writer, when what you want to do is call
> the methods of those names:
>
> attr_reader :services, :converted, :actions, ....
>
>

Thanks David! Doh! it had to be something simple and obvious.

And that's why my orginal test program worked fine - it was correct.

I see ruby suffers from the same problem as perl -- just about anything
is valid syntax, so it compiles but the semantics are not quite what you
intended ;)

In a past life I spent half each day for several years as a programming
consultant in a large university (in the days of mainframes) I lost
count of the number of times that I had people come in with a listing of
their program, lay it out in front of me and start explaining the latest
incomprehensible behaviour then suddenly stop, go bright red and quickly
gather everything up muttering that they now knew what the problem was.
I know how they feel :)

Russell (who has just spent an hour or so carefully paring down his
program to 10 lines that illustrates the problem :)

--
Posted via http://www.ruby-....

Robert Klemme

7/10/2006 5:57:00 AM

0

2006/7/9, Russell Fulton <r.fulton@auckland.ac.nz>:
> I see ruby suffers from the same problem as perl -- just about anything
> is valid syntax, so it compiles but the semantics are not quite what you
> intended ;)

Although Ruby's syntax is indeed quite flexible I'm rarely bitten by
this. I definitively struggled more with Perl in the old days I used
it rather frequently. So, the good news is: although you stepped into
this once you likely won't too often in the future. Ah, and btw, the
flag "-w" is also a good way to learn about some of these errors.

Kind regards

robert

--
Have a look: http://www.flickr.com/photos/fu...

Pit Capitain

7/10/2006 6:16:00 PM

0

Russell, some of your questions haven't been answered yet:

> (...)
> I had to make the classes
> anonymous because I needed to include references to the classes in a
> data structure (see subSections ) which tells the parser which section
> types are valid in this section and what to do with them.

I think you can use named classes just as well as anonymous classes:

class HostService < Section
...
def sub_sections( kind )
{'actions' => [nil, ActionList, @actions ],
'files' => [nil, CommaList, @files],
...
end
end

(Note that I renamed the method. See
http://wiki.rubygarden.org/Ruby/page/show/Ruby...)

If you need to reference the classes before they are created, there are
other possibilities besides class variables: you could use the names of
the classes in the references and then call Module#const_get to get to
the class object:

def sub_sections( kind )
{'actions' => [nil, "ActionList", @actions ],
'files' => [nil, "CommaList", @files],
...
end

def class_for_name( name )
Object.const_get( name )
end

Or you could pre-create the classes and re-open them later:

class HostService < Section; end
class ActionList < Section; end
class CommaList < Section; end
...

class HostService
def sub_sections( kind )
{'actions' => [nil, ActionList, @actions ],
'files' => [nil, CommaList, @files],
...
end
end

You could also add a convenience method to Section:

class Section

def self.define_sub_sections( *names )
names.each do |name|
const_set( name, Class.new( Section ) )
end
end

define_sub_sections "HostService", "ActionList", "CommaList"

class HostService
...
end

end

> [ aside: someone asked why I wanted reference to scalar variable in my
> previous post -- this is why. I needed to have a refernce to a variable
> in that structure into which I could store the parsed class]

I still don't understand the need to reference a variable. It seems all
you want is to store a value in a variable, which you did with the class
variables.

> (...)
> I have run into various problems in this project and have managed to
> solve all of them but I am far from confident that my solution was the
> best way of doing it. The use of anonymous classes is one example.

See above.

> I
> wrote a generic text parser for this project and because Ruby does not
> support multiple inheiritance I ended up passing an instance of the
> parser as a parameter to all the methods -- I figured that since the
> parser needed to maintain state that I could not make it a mixin...

Modules in Ruby can maintain state. The only caveat is initializing the
state. There are different ways to do it, and it has been discussed
often on ruby-talk, but I don't have a reference.

Regards,
Pit

Russell Fulton

7/15/2006 6:37:00 AM

0

Pit, thanks very my for your comments and insights!

Pit Capitain wrote:
>
> I think you can use named classes just as well as anonymous classes:
>
> class HostService < Section
> ...
> def sub_sections( kind )
> {'actions' => [nil, ActionList, @actions ],
> 'files' => [nil, CommaList, @files],
> ...
> end
> end

Yup, that works. I tried this initially but had problems (clearly
something else was wrong). That's a useful simplication.

>
> (Note that I renamed the method. See
> http://wiki.rubygarden.org/Ruby/page/show/Ruby...)

Ah, right... time for some global sustitutions :)

[good stuff snipped for brevity ]

>> wrote a generic text parser for this project and because Ruby does not
>> support multiple inheiritance I ended up passing an instance of the
>> parser as a parameter to all the methods -- I figured that since the
>> parser needed to maintain state that I could not make it a mixin...
>
> Modules in Ruby can maintain state.
>

Yep, I worked that out eventually and the parser now works much better
as a mixin. I've renamed initialize to setup and call it explictly...

Seems to work fine. :)

I have redesigned things so I am not having to resort to reference to
get values out of sub classes. So everything is looking good -- thanks
to the good folk on this list/forum!

Russell

--
Posted via http://www.ruby-....