Live to_s calls for rexml attribute

G

Gavin Kistner

Summary
--------------------------
I want an elegant way to add an object instance as an attribute of an
REXML::Element, and have the result of the #to_s method of the instance
used for the value when the Element has to_s/write called on it, NOT
when the assignment occurs.

class Foo
attr_accessor :bar
def to_s; "--#{bar}--"; end
end

require 'rexml/document'
d =3D REXML::Document.new
d << REXML::Element.new( 'root' )

f =3D Foo.new
f.bar =3D 'old value'
d.root.attributes[ 'foo' ] =3D f
f.bar =3D 'new value'
puts d
#=3D> <root foo=3D'--old value--'/>
# ^^^^^^^^^ I want 'new value' here



Options
--------------------------
One option would be to beg the author or REXML to redo REXML do support
lazy evaluation (possibly as an option).=20

Another would be to subclass REXML::Element, find all the existing
methods where the to_s is invoked on attributes, and override those
methods to delay the evaluation.

Another is to subclass the element, assign 'f' as an instance variable,
subclass the #write method and add it to the attribute list right before
calling the super #write. (This is what I'm doing right now, but I
really don't like it.)

class Bar < REXML::Element
attr_accessor :foo
def write( *args )
self.attributes[ 'foo' ] =3D @foo if @foo
output =3D super
self.attributes[ 'foo' ] =3D nil if @foo
output
end
end



Motivation
--------------------------
I'm writing my own SVG library (intended to be API-compatible with
ruby-svg[1]) where every element is based off of REXML::Element. (I'm
doing this because I like the power of document manipulation that REXML
provides, because ruby-svg doesn't emit svg that Firefox likes, and
because ruby-svg could be taken further than 'just' convenience methods
for attributes.)

In ruby-svg, there is an SVG::Style element which provides convenient
access to style attributes by name. For example:

circle =3D SVG::Circle.new(0,0,10){
self.style =3D SVG::Style.new( :eek:pacity =3D> 0.5 )
self.style.stroke =3D "red"
}
circle.style.fill =3D '#ff6'
puts circle
#=3D> <circle cx=3D"0" cy=3D"0" r=3D"10" style=3D"fill:#ff6; =
opacity:0.5;
stroke:red;" />

ruby-svg gets away with this because it rolls all its own classes and
to_s methods, and calls to_s on the Style class only when serializing
the document.=20

Since my Circle class ultimately inherits from REXML::Element, I'm
getting all the benefits of REXML's built-in to_s methods...but at the
same time I'm limited by them.

I will need to do this for other instances as well (I envision allowing
complex transform objects, descriptions of paths, etc.), so I want a
cleaner way than adding and removing items during serialization.=20


Thoughts?


[1] http://raa.ruby-lang.org/project/ruby-svg/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top