[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Live to_s calls for rexml attribute

Gavin Kistner

9/11/2006 4:22:00 PM

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 = REXML::Document.new
d << REXML::Element.new( 'root' )

f = Foo.new
f.bar = 'old value'
d.root.attributes[ 'foo' ] = f
f.bar = 'new value'
puts d
#=> <root foo='--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).

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' ] = @foo if @foo
output = super
self.attributes[ 'foo' ] = 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 = SVG::Circle.new(0,0,10){
self.style = SVG::Style.new( :opacity => 0.5 )
self.style.stroke = "red"
}
circle.style.fill = '#ff6'
puts circle
#=> <circle cx="0" cy="0" r="10" style="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.

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.


Thoughts?


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