Sean O'Halpin
7/14/2006 12:03:00 AM
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