BeMathis
BeMathis

Reputation: 194

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?

Upvotes: 0

Views: 972

Answers (3)

BeMathis
BeMathis

Reputation: 194

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)?

Upvotes: 0

Mike Lewis
Mike Lewis

Reputation: 64147

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.

Upvotes: 3

imax
imax

Reputation: 238

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

Upvotes: 1

Related Questions