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!



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

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



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

def base
  @base
end

#extensionsObject (readonly)

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



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

def extensions
  @extensions
end

Class Method Details

.attributesObject



502
503
504
# File 'lib/atom/element.rb', line 502

def @extensions.attributes
  @attrs
end

.builders(&block) ⇒ Object



392
393
394
395
396
397
398
399
# File 'lib/atom/element.rb', line 392

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’



488
489
490
# File 'lib/atom/element.rb', line 488

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

.def_set(name, &block) ⇒ Object

defines a setter that calls ‘block’



493
494
495
# File 'lib/atom/element.rb', line 493

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

.do_parsing(e, root) ⇒ Object



383
384
385
386
387
388
389
390
# File 'lib/atom/element.rb', line 383

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



520
521
522
523
# File 'lib/atom/element.rb', line 520

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

.is_atom_element(name) ⇒ Object

wrapper for #is_element



341
342
343
# File 'lib/atom/element.rb', line 341

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



335
336
337
338
# File 'lib/atom/element.rb', line 335

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



378
379
380
381
# File 'lib/atom/element.rb', line 378

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

.on_init(&block) ⇒ Object



515
516
517
518
# File 'lib/atom/element.rb', line 515

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’



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
450
451
452
# File 'lib/atom/element.rb', line 408

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



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
555
556
557
# File 'lib/atom/element.rb', line 527

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



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

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



564
565
566
# File 'lib/atom/element.rb', line 564

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

#get_atom_attrb(xml, name) ⇒ Object

gets an attribute on xml



366
367
368
# File 'lib/atom/element.rb', line 366

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



356
357
358
# File 'lib/atom/element.rb', line 356

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



361
362
363
# File 'lib/atom/element.rb', line 361

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

#get_elem(xml, ns, name) ⇒ Object

gets a single namespaced child element



346
347
348
# File 'lib/atom/element.rb', line 346

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



351
352
353
# File 'lib/atom/element.rb', line 351

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

#set(name, value) ⇒ Object

calls a setter



569
570
571
# File 'lib/atom/element.rb', line 569

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

#set_atom_attrb(xml, name, value) ⇒ Object

sets an attribute on xml



371
372
373
# File 'lib/atom/element.rb', line 371

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

#to_sObject



483
484
485
# File 'lib/atom/element.rb', line 483

def to_s
  to_xml.to_s
end

#to_xmlObject

converts to a REXML::Element



455
456
457
458
459
460
461
462
# File 'lib/atom/element.rb', line 455

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

  build root

  root
end