Class: Xmlmap

Inherits:
Object
  • Object
show all
Defined in:
lib/xmlmap.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(element) ⇒ Xmlmap

this is the method that will run when an inheritor class receives a ::new message



98
99
100
# File 'lib/xmlmap.rb', line 98

def initialize(element)
  @xml_element = element
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

we divert all calls to unknown methods of instances of classes that inherit Xmlmap to the associated Nokogiri object for that instance. That way you can use Nokogiri methods like #at, #inner_text, etc directly against the Xmlmap objects



103
104
105
# File 'lib/xmlmap.rb', line 103

def method_missing(name, *args, &block)
  @xml_element.send(name, *args, &block)
end

Class Method Details

.allObject

the #all method, which will create an array of fresh instances for all the elements that match the chosen path



40
41
42
43
44
# File 'lib/xmlmap.rb', line 40

def all
  find_many(self.get_xml_path).map do |xml_element|
    self.new(xml_element)
  end
end

.find_many(path_parts) ⇒ Object



50
51
52
# File 'lib/xmlmap.rb', line 50

def find_many(path_parts)
  @xml_map[:xml_object].search stringify_path(path_parts) 
end

.get_destination_relative_path_to_self(destination_name) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/xmlmap.rb', line 67

def get_destination_relative_path_to_self(destination_name)
  destination_path = destination_name.classify.constantize.get_xml_path
  if destination_path.is_a? Array
    destination_path.last
  else
    destination_path
  end
end

.get_xml_pathObject



46
47
48
# File 'lib/xmlmap.rb', line 46

def get_xml_path
  @xml_map[:path]
end

.has_many(what, opts = {}) ⇒ Object

lets build a method with the name of the associated entity (yay metaprogramming!), that searches for subelements using the part that is relative to the base (the last) or in the case that the destination entity is not nested into the origin one (that happens when we receive the :non_descendant_path option), calling the ::all method on the associated class. If an anonymous function (Proc) called :conditions is present in options, the found instances will be filtered by it.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/xmlmap.rb', line 78

def has_many(what, opts={})
  define_method(what) do
    if opts[:non_descendant_path]
      result_instances = what.to_s.classify.constantize.all
    else
      subpath = self.class.get_destination_relative_path_to_self(what.to_s)
      result_instances = find_many(subpath, what.to_s)
    end

    if opts[:conditions]
      result_instances = result_instances.select {|result_instance| opts[:conditions].call(self, result_instance) }
    end
    result_instances
  end
end

.inherited(subclass) ⇒ Object

when Xmlmap is inherited, we create the @xml_map variable in the context of the inheritor metaclass, this variable will contain the results of configuration



19
20
21
22
23
# File 'lib/xmlmap.rb', line 19

def inherited(subclass)
  subclass.class_eval do
    @xml_map = {}
  end
end

.set_path(path, opts = {}) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/xmlmap.rb', line 30

def set_path(path, opts = {})
       #if there is an established base we'll build an anonymous function (Proc) that triggers the construction of the route that corresponds to taht base function, else the path for this class will simply be the string in the path parameter. Pay attention to the fact that the xml_path method we call here simpy returns the contents of @xml_map[:path] in the base class. So what we are doing is we are going up the hierarchy until we reeach a "patriarch" class that contains an absolute path and then we add strings for routes as we go down.
  if opts[:base]
    @xml_map[:path] = [ Proc.new { opts[:base].to_s.classify.constantize.get_xml_path }, path ]
  else 
    @xml_map[:path] = path
  end
end

.set_url(url) ⇒ Object



25
26
27
28
# File 'lib/xmlmap.rb', line 25

def set_url(url)
  @xml_map[:url] = url
  @xml_map[:xml_object] = Nokogiri::XML(open(@xml_map[:url]))
end

.stringify_path(path_parts) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/xmlmap.rb', line 54

def stringify_path(path_parts)
       #if this is a single element, we'll still create an array with a single element just like when we receive an array - we verify in Duck Typing fashion
  path_parts = [path_parts] unless path_parts.respond_to?(:join)
  path_parts = path_parts.flatten.map do |path_part|
    if path_part.respond_to?(:call)
      path_part.call
    else
      path_part
    end
  end
  path_parts.join(' ')
end

Instance Method Details

#find_many(subpath, class_name) ⇒ Object

find_many simpy passes the call to the #search Nokogiri method, to bring subelelements by a css string or xpath and creates instances for the corresponding class



108
109
110
# File 'lib/xmlmap.rb', line 108

def find_many(subpath, class_name)
  self.search(subpath).map {|xml_element| class_name.classify.constantize.new(xml_element) }
end