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!



502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/atom/element.rb', line 502

def initialize defaults = {}
  @extensions = []

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

  self.class.run_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



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

def base
  @base
end

#extensionsObject (readonly)

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



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

def extensions
  @extensions
end

Class Method Details

.attributesObject



506
507
508
# File 'lib/atom/element.rb', line 506

def @extensions.attributes
  @attrs
end

.builders(&block) ⇒ Object



396
397
398
399
400
401
402
403
# File 'lib/atom/element.rb', line 396

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’



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

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

.def_set(name, &block) ⇒ Object

defines a setter that calls ‘block’



497
498
499
# File 'lib/atom/element.rb', line 497

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

.do_parsing(e, root) ⇒ Object



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

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

.is_atom_element(name) ⇒ Object

wrapper for #is_element



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

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



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

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



382
383
384
385
# File 'lib/atom/element.rb', line 382

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

.on_init(&block) ⇒ Object



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

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’



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
453
454
455
456
# File 'lib/atom/element.rb', line 412

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

.run_initters(&block) ⇒ Object



524
525
526
# File 'lib/atom/element.rb', line 524

def self.run_initters &block
  @on_init.each(&block) if @on_init
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



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
558
559
560
# File 'lib/atom/element.rb', line 530

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



469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/atom/element.rb', line 469

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



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

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

#get_atom_attrb(xml, name) ⇒ Object

gets an attribute on xml



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

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



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

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



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

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

#get_elem(xml, ns, name) ⇒ Object

gets a single namespaced child element



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

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



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

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

#set(name, value) ⇒ Object

calls a setter



572
573
574
# File 'lib/atom/element.rb', line 572

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

#set_atom_attrb(xml, name, value) ⇒ Object

sets an attribute on xml



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

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

#to_sObject



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

def to_s
  to_xml.to_s
end

#to_xmlObject

converts to a REXML::Element



459
460
461
462
463
464
465
466
# File 'lib/atom/element.rb', line 459

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

  build root

  root
end