[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Initialize a variable in an extended class

Eric Armstrong

7/13/2006 11:55:00 PM

Interesting problem. There is undoubtedly much to
will learn from suggested solutions. Here it is:

I'm working with xhtml data, and want to extend
the REXML Element type with an inline? method that
returns true when
%w(a b code em emphasis i strong tt).member?(name)

That would be a simple addition to the Element class,
except that the program already contains an @inline
variable, and I don't want to repeat myself. (Important,
because <br> is not considered an inline tag at the
moment. If at some point it turns out to be a good idea,
I want one list to modify, rather than two.)

The question is: How do I make the contents of the
variable known to the Element class?

Possibilities:
-------------
a) Use a global variable. This should work:
class REXML::Element
def inline?
return $inline.member?(name)
end
end

Of course, we don't much like global variables.
But that's one way to single-source the data and
make it available in two different classes.

b) Use a class variable:
class REXML::Element
@@inline = %w(a b code em emphasis i strong tt)
def inline?
return @@inline.member?(name)
end
end

Note: For a long time it wasn't clear to me that
it is impossible to initialize an instance variable
outside of a method. Coming from the Java world, I
just assumed that this would be legal:
class Foo
@bar = 2
end

But it isn't. (A fact that needs to be spelled out
somewhere, for Java types.) Class variables can be
initialized outside of a method, though, so this
solution works--but it violates the DRY principle.

Is there a way to use the data stored in the @inline
variable? Perhaps by using eval or instance_eval?

c) Add an an additional initialize call? Does this
work?
class REXML::Element
def initialize
@inline = %w(a b code em emphasis i strong tt)
end

def inline?
return @inline.member?(name)
end
end

This also leaves the DRY problem untouched, but
I find myself wondering whether initialize()
invocations are additive, as well. (I thought I
saw that once, but have been unable to find any
reference to the concept.)

d) Do some other clever thing with closures or eval,
so the Element object can reference data defined
in my class? Is there a way to do that?

Looking forward to responses. Much learning awaits.
:_)


6 Answers

Sean O'Halpin

7/14/2006 12:03:00 AM

0

On 7/14/06, Eric Armstrong <Eric.Armstrong@sun.com> wrote:
> Interesting problem. There is undoubtedly much to
> will learn from suggested solutions. Here it is:
>
> I'm working with xhtml data, and want to extend
> the REXML Element type with an inline? method that
> returns true when
> %w(a b code em emphasis i strong tt).member?(name)
>
> That would be a simple addition to the Element class,
> except that the program already contains an @inline
> variable, and I don't want to repeat myself. (Important,
> because <br> is not considered an inline tag at the
> moment. If at some point it turns out to be a good idea,
> I want one list to modify, rather than two.)
>
> The question is: How do I make the contents of the
> variable known to the Element class?
>
> Possibilities:
> -------------
> a) Use a global variable. This should work:
> class REXML::Element
> def inline?
> return $inline.member?(name)
> end
> end
>
> Of course, we don't much like global variables.
> But that's one way to single-source the data and
> make it available in two different classes.
>
> b) Use a class variable:
> class REXML::Element
> @@inline = %w(a b code em emphasis i strong tt)
> def inline?
> return @@inline.member?(name)
> end
> end
>
> Note: For a long time it wasn't clear to me that
> it is impossible to initialize an instance variable
> outside of a method. Coming from the Java world, I
> just assumed that this would be legal:
> class Foo
> @bar = 2
> end
>
> But it isn't. (A fact that needs to be spelled out
> somewhere, for Java types.) Class variables can be
> initialized outside of a method, though, so this
> solution works--but it violates the DRY principle.
>
> Is there a way to use the data stored in the @inline
> variable? Perhaps by using eval or instance_eval?
>
> c) Add an an additional initialize call? Does this
> work?
> class REXML::Element
> def initialize
> @inline = %w(a b code em emphasis i strong tt)
> end
>
> def inline?
> return @inline.member?(name)
> end
> end
>
> This also leaves the DRY problem untouched, but
> I find myself wondering whether initialize()
> invocations are additive, as well. (I thought I
> saw that once, but have been unable to find any
> reference to the concept.)
>
> d) Do some other clever thing with closures or eval,
> so the Element object can reference data defined
> in my class? Is there a way to do that?
>
> Looking forward to responses. Much learning awaits.
> :_)
>
Use a constant:

class REXML::Element
INLINE = %w(a b code em emphasis i strong tt)
def inline?
INLINE.member?(name)
end
end

BTW

> Coming from the Java world, I
> just assumed that this would be legal:
> class Foo
> @bar = 2
> end
>
> But it isn't.

It is, it just doesn't do what you were expecting. Instead of
initialising an instance variable belong to an instance of the class,
it initialises an instance variable belonging to the instance of Class
that is the class definition. A class is an object too.

Regards,
Sean

dblack

7/14/2006 12:36:00 AM

0

Eric Armstrong

7/14/2006 12:36:00 AM

0

Sean O'Halpin wrote:
>>
> Use a constant:
>
> class REXML::Element
> INLINE = %w(a b code em emphasis i strong tt)
> def inline?
> INLINE.member?(name)
> end
> end
>
Yup. Another good alernative. Do I then I share that
constant with the surrounding program like this:

INLINE = REXML::Element::INLINE

It would be better to access the constant defined
in my class:

class Main
INLINE = %w(a b code em emphasis i strong tt)
attr_reader :INLINE

class REXML::Element
def inline?
return Main.INLINE.member?(name)
end
end
end

But that doesn't seem to work..
error: in `inline?': undefined method `INLINE' for
MY_MODULE::Main:Class (NoMethodError)

> BTW
>
>> Coming from the Java world, I
>> just assumed that this would be legal:
>> class Foo
>> @bar = 2
>> end
>>
>> But it isn't.
>
> It is, it just doesn't do what you were expecting. Instead of
> initialising an instance variable belong to an instance of the class,
> it initialises an instance variable belonging to the instance of Class
> that is the class definition. A class is an object too.
>
Ah ha! I knew it was there when the class is being read, but
not when the object is constructed. I didn't quite realize
that it is still there as part of the class definition. That
helps to refine my mental model. Thanks much.

Eric Armstrong

7/14/2006 12:41:00 AM

0

dblack@wobblini.net wrote:
> On Fri, 14 Jul 2006, Eric Armstrong wrote:
>
>> Note: For a long time it wasn't clear to me that
>> it is impossible to initialize an instance variable
>> outside of a method. Coming from the Java world, I
>> just assumed that this would be legal:
>> class Foo
>> @bar = 2
>> end
>>
>> But it isn't. (A fact that needs to be spelled out
>> somewhere, for Java types.)
>
> I'm not sure what you mean by "somewhere". It gets talked about and
> explained regularly here, as well as in various books, wikis, etc.
> The workings of instance variables are not a closely guarded secret
> :-)
>
Thanks for the smiley. I haven't been spending enough time
here, it seems.
:_)

> When you see this:
>
> @var
>
> you are seeing an instance variable belonging to whatever object is,
> at that point, playing the role of "self" (the default object).
>
> At the top level of a class definition block, "self" is the class
> object (Foo in your example).
>
> So in your example, you've got an instance variable belonging to the
> class object Foo. There's no connection at all between this instance
> variable and any instance variable that may come into being later when
> some other object is "self" (including an instance of Foo).
>
Getting clearer all the time.
thanks.

Now for the bigger problem... how to reuse data when
I'm extending an existing class...


Ara.T.Howard

7/14/2006 1:21:00 AM

0

Eric Armstrong

7/14/2006 1:42:00 AM

0

Yes! That is indeed clever. I overlooked
the extend method.

I'm probababy going to be kicking myself for
not figuring out the rest of the solution,
but I'll ask anyway:

What's the best way to share TAGS between
this module and my main module?

Also:
Where is the best place to read about
modules. I have yet to grok their essence,
as shown by this example and my HTree
question!

ara.t.howard@noaa.gov wrote:
> On Fri, 14 Jul 2006, Eric Armstrong wrote:
>
>
>> d) Do some other clever thing with closures or eval,
>> so the Element object can reference data defined
>> in my class? Is there a way to do that?
>
> why not a module?
>
> module ElementExtension
> TAGS = %w( i p foo bar )
>
> def inline?
> TAGS.include? name
> end
> end
>
> REXML::Element.extend ElementExtension
>
>
> -a