Module: HappyMapper::ClassMethods
- Defined in:
- lib/happymapper.rb
Instance Attribute Summary collapse
-
#nokogiri_config_callback ⇒ Proc
readonly
The callback defined through #with_nokogiri_config.
Instance Method Summary collapse
-
#after_parse {|object| ... } ⇒ Object
Register a new after_parse callback, given as a block.
-
#after_parse_callbacks ⇒ Object
The list of registered after_parse callbacks.
-
#attribute(name, type, options = {}) ⇒ Object
The xml has the following attributes defined.
-
#attributes ⇒ Array<Attribute>
The elements defined through #attribute.
-
#content(name, type = String, options = {}) ⇒ Object
The value stored in the text node of the current element.
- #defined_content ⇒ Object
-
#element(name, type, options = {}) ⇒ Object
An element defined in the XML that is parsed.
- #elements ⇒ Array<Element>
-
#has_many(name, type, options = {}) ⇒ Object
The object has many of these elements in the XML.
-
#has_one(name, type, options = {}) ⇒ Object
The object has one of these elements in the XML.
-
#has_xml_content ⇒ Object
Sets the object to have xml content, this will assign the XML contents that are parsed to the attribute accessor xml_content.
-
#namespace(namespace = nil) ⇒ Object
Specify a namespace if a node and all its children are all namespaced elements.
- #parse(xml, options = {}) ⇒ Object
-
#register_namespace(name, href) ⇒ Object
Register a namespace that is used to persist the object namespace back to XML.
- #tag(new_tag_name) ⇒ Object
-
#tag_name ⇒ String
The name of the tag.
-
#with_nokogiri_config(&blk) ⇒ Object
Register a config callback according to the block Nokogori expects when calling Nokogiri::XML::Document.parse().
-
#wrap(name, &blk) ⇒ Object
There is an XML tag that needs to be known for parsing and should be generated during a to_xml.
Instance Attribute Details
#nokogiri_config_callback ⇒ Proc (readonly)
The callback defined through #with_nokogiri_config.
271 272 273 |
# File 'lib/happymapper.rb', line 271 def nokogiri_config_callback @nokogiri_config_callback end |
Instance Method Details
#after_parse {|object| ... } ⇒ Object
Register a new after_parse callback, given as a block.
201 202 203 |
# File 'lib/happymapper.rb', line 201 def after_parse(&block) after_parse_callbacks.push(block) end |
#after_parse_callbacks ⇒ Object
The list of registered after_parse callbacks.
192 193 194 |
# File 'lib/happymapper.rb', line 192 def after_parse_callbacks @after_parse_callbacks ||= [] end |
#attribute(name, type, options = {}) ⇒ Object
The xml has the following attributes defined.
57 58 59 60 61 |
# File 'lib/happymapper.rb', line 57 def attribute(name, type, = {}) attribute = Attribute.new(name, type, ) @attributes[name] = attribute attr_accessor attribute.method_name.intern end |
#attributes ⇒ Array<Attribute>
The elements defined through #attribute.
69 70 71 |
# File 'lib/happymapper.rb', line 69 def attributes @attributes.values end |
#content(name, type = String, options = {}) ⇒ Object
The value stored in the text node of the current element.
145 146 147 148 |
# File 'lib/happymapper.rb', line 145 def content(name, type = String, = {}) @content = TextNode.new(name, type, ) attr_accessor @content.method_name.intern end |
#defined_content ⇒ Object
387 388 389 |
# File 'lib/happymapper.rb', line 387 def defined_content @content if defined? @content end |
#element(name, type, options = {}) ⇒ Object
An element defined in the XML that is parsed.
112 113 114 115 116 |
# File 'lib/happymapper.rb', line 112 def element(name, type, = {}) element = Element.new(name, type, ) attr_accessor element.method_name.intern unless @elements[name] @elements[name] = element end |
#elements ⇒ Array<Element>
125 126 127 |
# File 'lib/happymapper.rb', line 125 def elements @elements.values end |
#has_many(name, type, options = {}) ⇒ Object
The object has many of these elements in the XML.
185 186 187 |
# File 'lib/happymapper.rb', line 185 def has_many(name, type, = {}) element name, type, { single: false }.merge() end |
#has_one(name, type, options = {}) ⇒ Object
The object has one of these elements in the XML. If there are multiple, the last one will be set to this value.
171 172 173 |
# File 'lib/happymapper.rb', line 171 def has_one(name, type, = {}) element name, type, { single: true }.merge() end |
#has_xml_content ⇒ Object
Sets the object to have xml content, this will assign the XML contents that are parsed to the attribute accessor xml_content. The object will respond to the method #xml_content and will return the XML data that it has parsed.
156 157 158 |
# File 'lib/happymapper.rb', line 156 def has_xml_content attr_accessor :xml_content end |
#namespace(namespace = nil) ⇒ Object
Specify a namespace if a node and all its children are all namespaced elements. This is simpler than passing the :namespace option to each defined element.
213 214 215 216 |
# File 'lib/happymapper.rb', line 213 def namespace(namespace = nil) @namespace = namespace if namespace @namespace if defined? @namespace end |
#parse(xml, options = {}) ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/happymapper.rb', line 293 def parse(xml, = {}) # Capture any provided namespaces and merge in any namespaces that have # been registered on the object. namespaces = [:namespaces] || {} namespaces = namespaces.merge(@registered_namespaces) # If the XML specified is an Node then we have what we need. if xml.is_a?(Nokogiri::XML::Node) && !xml.is_a?(Nokogiri::XML::Document) node = xml else unless xml.is_a?(Nokogiri::XML::Document) # Attempt to parse the xml value with Nokogiri XML as a document # and select the root element xml = Nokogiri::XML( xml, nil, nil, Nokogiri::XML::ParseOptions::STRICT, &nokogiri_config_callback ) end # Now xml is certainly an XML document: Select the root node of the document node = xml.root # merge any namespaces found on the xml node into the namespace hash namespaces = namespaces.merge(xml.collect_namespaces) # if the node name is equal to the tag name then the we are parsing the # root element and that is important to record so that we can apply # the correct xpath on the elements of this document. root = node.name == tag_name end # If the :single option has been specified or we are at the root element # then we are going to return a single element or nil if no nodes are found single = root || [:single] # if a namespace has been provided then set the current namespace to it # or use the namespace provided by the class # or use the 'xmlns' namespace if defined namespace = [:namespace] || self.namespace || namespaces.key?('xmlns') && 'xmlns' # from the options grab any nodes present and if none are present then # perform the following to find the nodes for the given class nodes = .fetch(:nodes) do find_nodes_to_parse(, namespace, tag_name, namespaces, node, root) end # Nothing matching found, we can go ahead and return return (single ? nil : []) if nodes.empty? # If the :limit option has been specified then we are going to slice # our node results by that amount to allow us the ability to deal with # a large result set of data. limit = [:in_groups_of] || nodes.size # If the limit of 0 has been specified then the user obviously wants # none of the nodes that we are serving within this batch of nodes. return [] if limit == 0 collection = [] nodes.each_slice(limit) do |slice| part = slice.map do |n| parse_node(n, , namespace, namespaces) end # If a block has been provided and the user has requested that the objects # be handled in groups then we should yield the slice of the objects to them # otherwise continue to lump them together if block_given? && [:in_groups_of] yield part else collection += part end end # If we're parsing a single element then we are going to return the first # item in the collection. Otherwise the return response is going to be an # entire array of items. if single collection.first else collection end end |
#register_namespace(name, href) ⇒ Object
Register a namespace that is used to persist the object namespace back to XML.
90 91 92 |
# File 'lib/happymapper.rb', line 90 def register_namespace(name, href) @registered_namespaces.merge!(name => href) end |
#tag(new_tag_name) ⇒ Object
221 222 223 |
# File 'lib/happymapper.rb', line 221 def tag(new_tag_name) @tag_name = new_tag_name.to_s unless new_tag_name.nil? || new_tag_name.to_s.empty? end |
#tag_name ⇒ String
The name of the tag
230 231 232 |
# File 'lib/happymapper.rb', line 230 def tag_name @tag_name ||= name && name.to_s.split('::')[-1].downcase end |
#with_nokogiri_config(&blk) ⇒ Object
Register a config callback according to the block Nokogori expects when calling Nokogiri::XML::Document.parse().
280 281 282 |
# File 'lib/happymapper.rb', line 280 def with_nokogiri_config(&blk) @nokogiri_config_callback = blk end |
#wrap(name, &blk) ⇒ Object
There is an XML tag that needs to be known for parsing and should be generated during a to_xml. But it doesn’t need to be a class and the contained elements should be made available on the parent class
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/happymapper.rb', line 241 def wrap(name, &blk) # Get an anonymous HappyMapper that has 'name' as its tag and defined # in '&blk'. Then save that to a class instance variable for later use wrapper = AnonymousWrapperClassFactory.get(name, &blk) wrapper_key = wrapper.inspect @wrapper_anonymous_classes[wrapper_key] = wrapper # Create getter/setter for each element and attribute defined on the anonymous HappyMapper # onto this class. They get/set the value by passing thru to the anonymous class. passthrus = wrapper.attributes + wrapper.elements passthrus.each do |item| class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{item.method_name} @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper_key}'].new @#{name}.#{item.method_name} end def #{item.method_name}=(value) @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper_key}'].new @#{name}.#{item.method_name} = value end RUBY end has_one name, wrapper end |