Class: Atom::Element

Inherits:
Object show all
Extended by:
Converters, Parsers
Defined in:
lib/atom/element.rb

Overview

The Class’ methods provide a DSL for describing Atom’s structure

(and more generally for describing simple namespaced XML)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Parsers

on_parse, on_parse_attr, on_parse_many, on_parse_root, parse_plain

Methods included from Converters

atom_attrb, atom_element, atom_elements, atom_link, atom_string, atom_time, attrb, build_plain, element, elements, strings, time

Constructor Details

#initialize(defaults = {}) ⇒ Element

be sure to call #super if you override this method!



495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/atom/element.rb', line 495

def initialize defaults = {}
  @extensions = []

  @extensions.instance_variable_set('@attrs', {})
  def @extensions.attributes
    @attrs
  end

  self.class.initters do |init|
    self.instance_eval &init
  end

  defaults.each do |k,v|
    set(k, v)
  end
end

Instance Attribute Details

#baseObject

this element’s xml:base



325
326
327
# File 'lib/atom/element.rb', line 325

def base
  @base
end

#extensionsObject (readonly)

xml elements and attributes that have been parsed, but are unknown



328
329
330
# File 'lib/atom/element.rb', line 328

def extensions
  @extensions
end

Class Method Details

.attributesObject



499
500
501
# File 'lib/atom/element.rb', line 499

def @extensions.attributes
  @attrs
end

.builders(&block) ⇒ Object



389
390
391
392
393
394
395
396
# File 'lib/atom/element.rb', line 389

def self.builders &block
  if ancestors[1].respond_to? :builders
    ancestors[1].builders &block
  end

  @on_build ||= []
  @on_build.each &block
end

.def_get(name, &block) ⇒ Object

defines a getter that calls ‘block’



485
486
487
# File 'lib/atom/element.rb', line 485

def self.def_get(name, &block)
  define_method name.to_sym, &block
end

.def_set(name, &block) ⇒ Object

defines a setter that calls ‘block’



490
491
492
# File 'lib/atom/element.rb', line 490

def self.def_set(name, &block)
  define_method "#{name}=".to_sym, &block
end

.do_parsing(e, root) ⇒ Object



380
381
382
383
384
385
386
387
# File 'lib/atom/element.rb', line 380

def self.do_parsing e, root
  if ancestors[1].respond_to? :do_parsing
    ancestors[1].do_parsing e, root
  end

  @on_parse ||= []
  @on_parse.each { |p| p.call e, root }
end

.initters(&block) ⇒ Object



517
518
519
520
# File 'lib/atom/element.rb', line 517

def self.initters &block
  @on_init ||= []
  @on_init.each &block
end

.is_atom_element(name) ⇒ Object

wrapper for #is_element



338
339
340
# File 'lib/atom/element.rb', line 338

def self.is_atom_element name
  self.is_element Atom::NS, name
end

.is_element(ns, name) ⇒ Object

attaches a name and a namespace to an element this needs to be called on any new element



332
333
334
335
# File 'lib/atom/element.rb', line 332

def self.is_element ns, name
  meta_def :self_namespace do; ns; end
  meta_def :self_name do; name.to_s; end
end

.on_build(&block) ⇒ Object



375
376
377
378
# File 'lib/atom/element.rb', line 375

def self.on_build &block
  @on_build ||= []
  @on_build << block
end

.on_init(&block) ⇒ Object



512
513
514
515
# File 'lib/atom/element.rb', line 512

def self.on_init &block
  @on_init ||= []
  @on_init << block
end

.parse(xml, base = '', element = nil) ⇒ Object

turns a String, an IO-like, a REXML::Element, etc. into an Atom::Element

the ‘base’ base URL parameter should be supplied if you know where this XML was fetched from

if you want to parse into an existing Atom::Element, it can be passed in as ‘element’



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/atom/element.rb', line 405

def self.parse xml, base = '', element = nil
  if xml.respond_to? :elements
     root = xml.dup
   else
     xml = xml.read if xml.respond_to? :read

     begin
       root = REXML::Document.new(xml.to_s).root
     rescue REXML::ParseException => e
       raise Atom::ParseError, e.message
     end
   end

  unless root.local_name == self.self_name
    raise Atom::ParseError, "expected element named #{self.self_name}, not #{root.local_name}"
  end

  unless root.namespace == self.self_namespace
    raise Atom::ParseError, "expected element in namespace #{self.self_namespace}, not #{root.namespace}"
  end

  if root.attributes['xml:base']
    base = (base.to_uri + root.attributes['xml:base'])
  end

  e = element ? element : self.new
  e.base = base

  # extension elements
  root.elements.each do |c|
    e.extensions << c
  end

  # extension attributes
  root.attributes.each do |k,v|
    e.extensions.attributes[k] = v
  end

  # as things are parsed, they're removed from e.extensions. whatever's
  # left over is stored so it can be round-tripped

  self.do_parsing e, root

  e
end

Instance Method Details

#append_elem(root, ns, name) ⇒ Object

appends an element named ‘name’ in namespace ‘ns’ to ‘root’ ns is either [prefix, namespace] or just a String containing the namespace



524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/atom/element.rb', line 524

def append_elem(root, ns, name)
  if ns.is_a? Array
    prefix, uri = ns
  else
    prefix, uri = nil, ns
  end

  name = name.to_s

  existing_prefix = root.namespaces.find do |k,v|
    v == uri
  end

  root << if existing_prefix
            prefix = existing_prefix[0]

            if prefix != 'xmlns'
              name = prefix + ':' + name
            end

            REXML::Element.new(name)
          elsif prefix
            e = REXML::Element.new(prefix + ':' + name)
            e.add_namespace(prefix, uri)
            e
          else
            e = REXML::Element.new(name)
            e.add_namespace(uri)
            e
          end
end

#build(root) ⇒ Object

fill a REXML::Element with the data from this Atom::Element



462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/atom/element.rb', line 462

def build root
  if self.base and not self.base.empty?
    root.attributes['xml:base'] = self.base
  end

  self.class.builders do |builder|
    builder.call self, root
  end

  @extensions.each do |e|
    root << e.dup
  end

  @extensions.attributes.each do |k,v|
    root.attributes[k] = v
  end
end

#get(name) ⇒ Object

calls a getter



561
562
563
# File 'lib/atom/element.rb', line 561

def get name
  send "#{name}".to_sym
end

#get_atom_attrb(xml, name) ⇒ Object

gets an attribute on xml



363
364
365
# File 'lib/atom/element.rb', line 363

def get_atom_attrb xml, name
  xml.attributes[name.to_s]
end

#get_atom_elem(xml, name) ⇒ Object

gets a child element in the Atom namespace



353
354
355
# File 'lib/atom/element.rb', line 353

def get_atom_elem xml, name
  get_elem xml, Atom::NS, name
end

#get_atom_elems(xml, name) ⇒ Object

gets multiple child elements in the Atom namespace



358
359
360
# File 'lib/atom/element.rb', line 358

def get_atom_elems xml, name
  get_elems Atom::NS, name
end

#get_elem(xml, ns, name) ⇒ Object

gets a single namespaced child element



343
344
345
# File 'lib/atom/element.rb', line 343

def get_elem xml, ns, name
  REXML::XPath.first xml, "./ns:#{name}", { 'ns' => ns }
end

#get_elems(xml, ns, name) ⇒ Object

gets multiple namespaced child elements



348
349
350
# File 'lib/atom/element.rb', line 348

def get_elems xml, ns, name
  REXML::XPath.match xml, "./ns:#{name}", { 'ns' => ns }
end

#set(name, value) ⇒ Object

calls a setter



566
567
568
# File 'lib/atom/element.rb', line 566

def set name, value
  send "#{name}=", value
end

#set_atom_attrb(xml, name, value) ⇒ Object

sets an attribute on xml



368
369
370
# File 'lib/atom/element.rb', line 368

def set_atom_attrb xml, name, value
  xml.attributes[name.to_s] = value
end

#to_sObject



480
481
482
# File 'lib/atom/element.rb', line 480

def to_s
  to_xml.to_s
end

#to_xmlObject

converts to a REXML::Element



452
453
454
455
456
457
458
459
# File 'lib/atom/element.rb', line 452

def to_xml
  root = REXML::Element.new self.class.self_name
  root.add_namespace self.class.self_namespace

  build root

  root
end