Extending Objects in Ruby
I want to extend the Nokohiri开发者_如何学运维::XML::Node
object into my own unique object with custom behaviors (methods).
I have the following object:
class RDFNode < Nokogiri::XML::Node
def get_tag
self.at_xpath("Path/to/tag")
end
end
and the Node Factory:
class RDFNodeFactory
@doc = Nokogiri::XML.parse('rdf_file.xml')
def self.get_node(id)
@doc.xpath_at("Path/to/rdf/node[@id=#{id}]")
end
end
My question is about best Ruby practices and basic OOP in Ruby.
How can I get RDFNodeFactory.get_node("someid")
to return an RDFNode
instead of a Nokogiri::XML::Node
? I used to use type casting in Java but we don't have that in Ruby.
Should I just modify Nokogiri::XML::Node
class instead of extending it to a custom class? What is a more acceptable practice?
Instead of extending the Nokogiri::XML::Node
class just to add one method, you should move the get_tag method and add it to the already existing Nokogiri::XML::Node
using the concept of Open Classes. This would look like:
class Nokogiri::XML::Node
def get_tag
self.at_xpath("Path/to/tag")
end
end
This is completely fine in terms of Ruby Standards, just be sure there aren't any side affects when adding this method to Nokogiri::XML::Node, such as get_tag already exists.
With regards to open class(under the assumption that there are no current conflicts) vs inheriting 3rd party libraries:
This is a valid fear, this is why you have to be very careful when you utilize open classes and updating 3rd party libraries. However if you think of it, if a library changes their code in such a way that it messes up your code... This will happen both when you use open classes or inherit from their code. When it all boils down, you have a dependency, and you must be careful no matter what.
Instance methods tied to object, not class, so there is no way to "cast" object to another class. But in ruby you can add methods to existing class:
class Nokogiri::XML::Node
def get_tag
self.at_xpath("Path/to/tag")
end
end
Or even add method to single object:
def @doc.get_tag
self.at_xpath("Path/to/tag")
end
A (sort of) solution I have is containment
class RDFNode
attr_reader :node
def initialize(node)
@node = node
end
def get_tag(id)
node.at_xpath("Path/to/tag")
end
end
Now I have preserved modularity but lost all the awesomeness of inheritance! Not perfect but it's a start. Perhaps there is some way improve on this (extend RDFNode with Nokogiri::XML::Node and make self = node for Nokogiri methods)?
精彩评论