Mixin classes (continuning from the last post)


#1

Although I am a seasoned C/C++ programmer(+10 years), I am relatively
new to the ruby (about 2 days) despite having some reservations(ruby
debugger should be theslowest thing in the world) i am otherwise very
impressed with the language, I intend to use Ruby for some code
generation task ,Everything was going well until i hit that roadblock

class REXML::Element
include TSort
def initialize
@dependencies=[]
end
def tsort_each_node(&block)
@elements.each(&block)
end
def tsort_each_child(node, &block)
@dependencies.each(&block) if @dependencies.size>0
end
end
well as you can see, i need to topologically sort some nodes in an
xml file and there was a module Tsort in the
ruby. from what understand i need to extend to class REXML::Element
to feed Tsort algorithm. I have no problems
with adding the methods but when i feed this new node to tsort() I get
something like this

undefined method size' for nil:NilClass H:/ruby/somCompiler.rb:112:intsort_each_child’
c:/ruby/lib/ruby/1.8/tsort.rb:204:in
each_strongly_connected_component_from c:/ruby/lib/ruby/1.8/tsort.rb:183:ineach_strongly_connected_component’
c:/ruby/lib/ruby/1.8/rexml/element.rb:939:in each' c:/ruby/lib/ruby/1.8/rexml/xpath.rb:53:ineach’
c:/ruby/lib/ruby/1.8/rexml/element.rb:939:in each' H:/ruby/somCompiler.rb:109:intsort_each_node’

From what I understand i am unable to add @dependencies array to the
REXML::Element.Is it not possible
or i am missing something terribly here?
Any help would be greatly appreciated…
Hurcan


#2

On Mar 17, 2007, at 5:10 PM, hurcan solter wrote:

end
def tsort_each_node(&block)
    @elements.each(&block)
end
def tsort_each_child(node, &block)
    @dependencies.each(&block) if @dependencies.size>0
end

end

Just a guess but I suspect your problem is that you’ve effectively
thrown away the initialize method for REXML::Element and replaced it
with your own. I think you want:

alias __original_initialize initialize
def initialize(*args, &block)
__original_initialize(*args, &block)
@dependencies = []
end

This way you make sure the original version of initialize
executes as well as your new code.

Gary W.


#3

On 17.03.2007 22:33, Gary W. wrote:

include TSort

This way you make sure the original version of initialize
executes as well as your new code.

While this is true, at least @dependencies should be properly
initialized unless REXML::Element instances are not created via new.

There’s another gotcha: by including TSort initialization might be
broken, if TSort defines initialize and does not propagate to the parent
class.

To OP: “if @dependencies.size>0” can be rewritten as “unless
@dependencies.empty?” which again is superfluous here: #each will take
care of empty collections.

Maybe you need provide more code. From what you have shown so far it is
not clear to me why @dependencies would be nil.

Kind regards

robert


#4

It looks like REXML already provides the two
iterators you need to satisfy TSort. Try this:

require ‘rexml/document’
require ‘tsort’

class REXML::Element
include TSort
def tsort_each_node(&block)
each_recursive(&block)
end
def tsort_each_child(node, &block)
node.each_child(&block) if node.respond_to?(:each_child)
end
end

doc = REXML::Document.new <<EOS

Text, text, text

EOS
p doc.tsort

Gary W.


#5

On Mar 18, 2:00 am, Gary W. removed_email_address@domain.invalid wrote:

end
p doc.tsort

Gary W.

well my sorting criteria something different from that.Consider this;

    <fixedRecordData name="EntityIdentifierStruct">
            <field name="FederateID" dataType="short int"/>
<field name="FederateIdentifier" 

dataType=“FederateIdentifierStruct”/

<field name="orientation" dataType="OrientationStruct"/>
EntityIdentifierStruct depends on FederateIdentifierStruct and FederateIdentifierStruct depends on none (primitives not important) and i also have to extract that denpendency information from child node attributes so one to one comparison wont work. So I have to compose a dependency graph first and keep it somewhere (I am thinking the element itself ,so the need for instance variable) only then i can give it to tsort_each_child to iterate over.., hurcan

#6

On Mar 17, 11:33 pm, Gary W. removed_email_address@domain.invalid wrote:

class REXML::Element
end

This way you make sure the original version of initialize
executes as well as your new code.

Gary W.

On the contrary, it’s the original version that executes not mine.
You see,it’s the REXML module that creates the Element instance
and it calls the original constructor(if it’s the term) not mine. I
erronously thought
i am effectively replacing the REXML:Element with my own version.
What i am trying to accomplish is adding to an existing class a new
instance variable
in its definition.

For example
require “rexml/document”
include REXML

class REXML::Element
def some_method
puts “some_method called”
end

doc = Document.new File.open(“mydoc.xml”)
doc.each_element(“somexmltag”){|node| # i have no intervention here
REXML does all the stuff
puts node.methods #=> [“some_method” “namespaces” “attributes”]
etc etc
node.some_method #=> some_method called
the above code snippet works, and adds a method to an existing class
in some other module
i just wonder is it possible to add some instance variable in same
manner?


#7

On Mar 17, 2007, at 8:55 PM, hurcan solter wrote:

well my sorting criteria something different from that.Consider this;

Then you are going to have to implement Tsort over a different type
of collection. Tsort uses the eql? method to compare nodes and I
don’t think you want to mess around with REXML’s notion of equality.

I think it would be better off iterating over all the nodes in the
document and creating a new dependency graph based on your criteria
and then applying Tsort to that new data structure instead of the
REXML data structure.

I’ll admit to not looking too deep into your problem but I get the
feeling that you are applying TSort to the wrong data structure.

Gary W.