Class: Saxaphone::Element

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

Defined Under Namespace

Classes: ElementHandler

Constant Summary collapse

@@base_class_name =
'Saxaphone::Element'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name = '', content = '', attribute_array = []) ⇒ Element

Returns a new instance of Element.



169
170
171
172
173
174
# File 'lib/saxaphone/element.rb', line 169

def initialize(name = '', content = '', attribute_array = [])
  self.name = name
  self.content = content
  self.attributes = Hash[attribute_array.select { |(key, value)| self.class.stored_attributes.include?(key) }]
  setup
end

Instance Attribute Details

#attributesObject

Returns the value of attribute attributes.



168
169
170
# File 'lib/saxaphone/element.rb', line 168

def attributes
  @attributes
end

#contentObject

Returns the value of attribute content.



168
169
170
# File 'lib/saxaphone/element.rb', line 168

def content
  @content
end

#nameObject

Returns the value of attribute name.



168
169
170
# File 'lib/saxaphone/element.rb', line 168

def name
  @name
end

Class Method Details

.element_attribute(element_name, options = {}) ⇒ Object

Define a single element that should be stored as an attribute.

WidgetElement < Saxaphone::Element
  element_attribute 'price'
end

element = WidgetElement.parse %{
  <widget>
    <price>4.33</price>
  </widget>
}

element.attributes # => {"price" => "4.33"}

The name of the stored attribute can optionally be changed with the :as option:

WidgetElement < Saxaphone::Element
  element_attribute 'price', as: 'dollars'
end

element = WidgetElement.parse %{
  <widget>
    <price>4.33</price>
  </widget>
}

element.attributes # => {"dollars" => "4.33"}


78
79
80
81
82
83
84
# File 'lib/saxaphone/element.rb', line 78

def element_attribute(element_name, options = {})
  converted_name = options.delete(:as)

  has_element(element_name) do |element|
    attributes[converted_name || element.name] = element.content
  end
end

.element_attributes(element_names) ⇒ Object

Define elements that should be stored as attributes:

WidgetElement < Saxaphone::Element

element_attributes %w(color price)

end

element = WidgetElement.parse %{
  <widget>
    <color>red</color>
    <price>4.33</price>
  </widget>
}

element.attributes # => => “red”, “price” => “4.33”



44
45
46
47
48
# File 'lib/saxaphone/element.rb', line 44

def element_attributes(element_names)
  element_names.each do |element_name|
    element_attribute(element_name)
  end
end

.handler_for(element_name) ⇒ Object



150
151
152
# File 'lib/saxaphone/element.rb', line 150

def handler_for(element_name)
  element_handlers[element_name] || element_handlers['*']
end

.has_element(element_name, class_name = @@base_class_name, &block) ⇒ Object

Define what to do for a particular child element. After the element is parsed, it is passed to the block:

WidgetElement < Saxaphone::Element
  attr_accessor :cents

  has_element 'price' do |element|
    self.cents = element.content.to_f * 100
  end
end

element = WidgetElement.parse %{
  <widget>
    <price>4.33</price>
  </widget>
}

element.cents # => 433.0

It is possible to define the class name that is used to parse the child element:

PriceElement < Saxaphone::Element
  def cents
    content.to_f * 100
  end
end

WidgetElement < Saxaphone::Element
  attr_accessor :cents

  has_element 'price', 'PriceElement' do |element|
    self.cents = element.cents
  end
end

The children elements can have children of their own,
and each uses has_element to define what to do.


125
126
127
# File 'lib/saxaphone/element.rb', line 125

def has_element(element_name, class_name = @@base_class_name, &block)
  element_handlers[element_name] = ElementHandler.new(class_name, block)
end

.parse(xml) ⇒ Object



158
159
160
# File 'lib/saxaphone/element.rb', line 158

def parse(xml)
  Saxaphone::Document.parse(xml, self)
end

.setup(&block) ⇒ Object

A block can be passed to setup, which is called after the element is initialized.

 WidgetElement < Saxaphone::Element
   attr_accessor :foo

   setup do
     self.foo = 'bar'
   end
 end

It is recommended to use setup rather than
overriding initialize.


25
26
27
# File 'lib/saxaphone/element.rb', line 25

def setup(&block)
  define_method(:setup, &block)
end

.store_attributes(*attribute_names) ⇒ Object

Define a white list of the attributes that are extracted from the XML element and stored in the attribute hash:

WidgetElement < Saxaphone::Element
  store_attributes 'name', 'color'
end

element = WidgetElement.parse %{
  <widget name="Acme" color="red" price="3.21">
    ...
  </widget>
}

element.attributes # => {"name" => "Acme", "color" => "red"}

Notice that the “price” attribute is not stored.



146
147
148
# File 'lib/saxaphone/element.rb', line 146

def store_attributes(*attribute_names)
  @stored_attributes = attribute_names.flatten.to_set
end

.stored_attributesObject



154
155
156
# File 'lib/saxaphone/element.rb', line 154

def stored_attributes
  @stored_attributes ||= Set.new
end

Instance Method Details

#add_element(element) ⇒ Object



179
180
181
182
183
# File 'lib/saxaphone/element.rb', line 179

def add_element(element)
  if element_handler = self.class.handler_for(element.name)
    instance_exec(element, &element_handler.proc) if element_handler.proc
  end
end

#append_content(string) ⇒ Object



194
195
196
# File 'lib/saxaphone/element.rb', line 194

def append_content(string)
  content << string
end

#element_for(element_name) ⇒ Object



185
186
187
188
189
190
191
192
# File 'lib/saxaphone/element.rb', line 185

def element_for(element_name)
  if element_handler = self.class.handler_for(element_name)
    Saxaphone::Util.constantize(element_handler.class_name)
  else
    Saxaphone::Element
  end
  
end

#setupObject



176
177
# File 'lib/saxaphone/element.rb', line 176

def setup
end