Class: Atom::Element

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

Overview

Atom::Element

Base Element Object Class

You don’t use this class directly. This is a base class of each element classes used in Atom Syndication Format.

Constant Summary collapse

@@ns =
Namespace::ATOM

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = {}) ⇒ Element

Setup element.



441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'lib/atomutil.rb', line 441

def initialize(params={})
  @ns = params.has_key?(:namespace) ? params[:namespace] \
      : self.class.element_ns       ? self.class.element_ns \
      :                               self.class.ns
  @elem = params.has_key?(:elem) ? params[:elem] : REXML::Element.new(self.class.element_name)
  if @ns.is_a?(Namespace)
    unless @ns.prefix.nil?
      @elem.add_namespace @ns.prefix, @ns.uri
    else
      @elem.add_namespace @ns.uri
    end
  else
    @elem.add_namespace @ns
  end
  params.keys.each do |key|
    setter = "#{key}=";
    send(setter.to_sym, params[key]) if respond_to?(setter.to_sym)
  end
end

Instance Attribute Details

#elemObject (readonly)

accessor for xml-element(REXML::Element) object.



461
462
463
# File 'lib/atomutil.rb', line 461

def elem
  @elem
end

Class Method Details

.element_attr_accessor(name) ⇒ Object

Attribute accessor generator



423
424
425
426
427
428
429
430
431
432
433
434
# File 'lib/atomutil.rb', line 423

def self.element_attr_accessor(name)
  name = name.to_s
  name.tr!('-', '_')
  class_eval(<<-EOS, __FILE__, __LINE__)
    def #{name}
      get_attr('#{name}')
    end
    def #{name}=(value)
      set_attr('#{name}', value)
    end
  EOS
end

.element_attr_accessors(*names) ⇒ Object

You can generate attribute accessor at once.



436
437
438
# File 'lib/atomutil.rb', line 436

def self.element_attr_accessors(*names)
  names.each{ |n| element_attr_accessor(n) }
end

.element_datetime_accessor(name) ⇒ Object

Generate datetime element accessor for indicated name.

Example:

class Entry < BaseEntry
  element_datetime_accessor :updated
  element_datetime_accessor :published
end
entry = Entry.new
entry.updated = Time.now
puts entry.updated.year
puts entry.updated.month


321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/atomutil.rb', line 321

def self.element_datetime_accessor(name)
  name = name.to_s
  name.tr!('-', '_')
  class_eval(<<-EOS, __FILE__, __LINE__)
    def #{name}
      dt = get(@ns, '#{name}')
      dt.nil? ? nil : Time.iso8601(dt.text)
    end
    def #{name}=(value, attributes=nil)
      case value
        when Time
          date = value.iso8601
        else
          date = value
      end
      set(@ns, '#{name}', date, attributes)
    end
  EOS
end

.element_datetime_accessors(*names) ⇒ Object

You can set datetime accessor at once with this method

Example:

class Entry < BaseEntry
  element_datetime_accessor :updated, :published
end
entry = Entry.new
entry.updated = Time.now
puts entry.updated.year
puts entry.updated.month


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

def self.element_datetime_accessors(*names)
  names.each{ |n| element_datetime_accessor(n) }
end

.element_name(name = nil) ⇒ Object



248
249
250
251
252
253
# File 'lib/atomutil.rb', line 248

def self.element_name(name=nil)
  unless name.nil?
    @element_name = name.to_s
  end
  @element_name
end

.element_ns(ns = nil) ⇒ Object



255
256
257
258
259
260
# File 'lib/atomutil.rb', line 255

def self.element_ns(ns=nil)
  unless ns.nil?
    @element_ns = ns.is_a?(Namespace) ? ns : Namespace.new(:uri => ns) 
  end
  @element_ns
end

.element_object_list_accessor(name, ext_class, moniker = nil) ⇒ Object

Generate useful accessor for the multiple element

Example:

class Entry < Element
  element_object_list_accessors :author, Author, :authors
  element_object_list_accessors :contributor, Contributor, :contributors
end


394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/atomutil.rb', line 394

def self.element_object_list_accessor(name, ext_class, moniker=nil)
  name = name.to_s
  name.tr!('-', '_')
  unless moniker.nil?
    moniker = moniker.to_s
    moniker.tr!('-', '_') 
  end
  elem_ns = ext_class.element_ns || ns
  class_eval(<<-EOS, __FILE__, __LINE__)
    def #{name}
      get_object('#{elem_ns}', '#{name}', #{ext_class})
    end
    def #{name}=(stuff)
      set('#{elem_ns}', '#{name}', stuff)
    end
    def add_#{name}(stuff)
      add('#{elem_ns}', '#{name}', stuff)
    end
  EOS
  class_eval(<<-EOS, __FILE__, __LINE__) unless moniker.nil?
    def #{moniker}
      get_objects('#{elem_ns}', '#{name}', #{ext_class})
    end
    def #{moniker}=(stuff)
      #{name} = stuff
    end
  EOS
end

.element_text_accessor(name) ⇒ Object

Generate element accessor for indicated name The generated accessors can deal with elements which has only simple text-node, such as title, summary, rights, and etc. Of course, these elements should handle more complex data. In such a case, you can control them directly with ‘set’ and ‘get’ method.

Example:

class Entry < Element
  element_text_accessor 'title'
  element_text_accessor 'summary'
end

elem = MyElement.new
elem.title   = "foo"
elem.summary = "bar"
puts elem.title #foo
puts elem.summary #bar

div = REXML::Element.new("<div><p>hoge</p></div>")
elem.set('http://www.w3.org/2005/Atom', 'title', div, { :type => 'xhtml' })


283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/atomutil.rb', line 283

def self.element_text_accessor(name)
  name = name.to_s
  name.tr!('-', '_')
  class_eval(<<-EOS, __FILE__, __LINE__)
    def #{name}
      value = get(@ns, '#{name}')
      value.nil? ? nil : value.text
    end
    def #{name}=(value, attributes=nil)
      set(@ns, '#{name}', value, attributes)
    end
  EOS
end

.element_text_accessors(*names) ⇒ Object

You can set text_accessor at once with this method

Example:

class Entry < BaseEntry
  element_text_accessors :title, :summary
end
entry = Entry.new
entry.title = "hoge"
puts entry.title #hoge


306
307
308
# File 'lib/atomutil.rb', line 306

def self.element_text_accessors(*names)
  names.each{ |n| element_text_accessor(n) }
end

.element_text_list_accessor(name, moniker = nil) ⇒ Object

Generates text accessor for multiple value.

Example:



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
385
# File 'lib/atomutil.rb', line 357

def self.element_text_list_accessor(name, moniker=nil)
  name = name.to_s
  name.tr!('-', '_')
  unless moniker.nil?
    moniker = moniker.to_s
    moniker.tr!('-', '_') 
  end
  elem_ns = element_ns || ns
  class_eval(<<-EOS, __FILE__, __LINE__)
    def #{name}
      value = getlist('#{elem_ns}', '#{name}')
      value.empty?? nil : value.first
    end
    def #{name}=(stuff)
      set('#{elem_ns}', '#{name}', stuff)
    end
    def add_#{name}(stuff)
      add('#{elem_ns}', '#{name}', stuff)
    end
  EOS
  class_eval(<<-EOS, __FILE__, __LINE__) unless moniker.nil?
    def #{moniker}
      getlist('#{elem_ns}', '#{name}')
    end
    def #{moniker}=(stuff)
      #{name} = stuff
    end
  EOS
end

.new(params = {}) {|obj| ... } ⇒ Object

Yields:

  • (obj)


235
236
237
238
239
# File 'lib/atomutil.rb', line 235

def self.new(params={})
  obj = super(params)
  yield(obj) if block_given?
  obj
end

.ns(ns = nil) ⇒ Object



241
242
243
244
245
246
# File 'lib/atomutil.rb', line 241

def self.ns(ns=nil)
  unless ns.nil?
    @@ns = ns.is_a?(Namespace) ? ns : Namespace.new(:uri => ns)
  end
  @@ns
end

Instance Method Details

#add(ns, element_name, value, attributes = {}) ⇒ Object

Same as ‘set’, but when a element-name confliction occurs, append new element without overriding.



505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
# File 'lib/atomutil.rb', line 505

def add(ns, element_name, value, attributes={})
  element = REXML::Element.new(element_name)
  if ns.is_a?(Namespace)
    unless ns.prefix.nil? || ns.prefix.empty?
      element.name = "#{ns.prefix}:#{element_name}"
      element.add_namespace ns.prefix, ns.uri unless @ns == ns || @ns == ns.uri
    else
      element.add_namespace ns.uri unless @ns == ns || @ns == ns.uri
    end
  else
    element.add_namespace ns unless @ns == ns || @ns.to_s == ns
  end
  if value.is_a?(Element)
    value.elem.each_element do |e|
      element.add e.deep_clone
    end
    value.elem.attributes.each_attribute do |a|
      unless a.name =~ /^xmlns(?:\:)?/
        element.add_attribute a
      end
    end
    element.text = value.elem.text unless value.elem.text.nil?
  else
    if value.is_a?(REXML::Element)
      element.add_element value.deep_clone
    else
      element.add_text value.to_s
    end
  end
  element.add_attributes attributes unless attributes.nil?
  @elem.add_element element
end

#get(ns, element_name) ⇒ Object

Get indicated element. If it matches multiple, returns first one.

elem = entry.get('http://example/2007/mynamespace', 'foo')

ns = Atom::Namespace.new(:prefix => 'dc', :uri => 'http://purl.org/dc/elements/1.1/')
elem = entry.get(ns, 'subject')


545
546
547
# File 'lib/atomutil.rb', line 545

def get(ns, element_name)
  getlist(ns, element_name).first
end

#get_attr(name) ⇒ Object

Get attribute value for indicated key



583
584
585
# File 'lib/atomutil.rb', line 583

def get_attr(name)
  @elem.attributes[name.to_s]
end

#get_object(ns, element_name, ext_class) ⇒ Object

Get indicated elements as an object of the class you passed as thrid argument.

ns = Atom::Namespace.new(:uri => 'http://example.com/ns#')
obj = entry.get_object(ns, 'mytag', MyClass)
puts obj.class #MyClass

MyClass should inherit Atom::Element



564
565
566
567
568
# File 'lib/atomutil.rb', line 564

def get_object(ns, element_name, ext_class)
  elements = getlist(ns, element_name)
  return nil if elements.empty?
  ext_class.new(:namespace => ns, :elem => elements.first) 
end

#get_objects(ns, element_name, ext_class) ⇒ Object

Get all indicated elements as an object of the class you passed as thrid argument.

entry.get_objects(ns, 'mytag', MyClass).each{ |obj|
  p obj.class #MyClass
}


575
576
577
578
579
580
581
# File 'lib/atomutil.rb', line 575

def get_objects(ns, element_name, ext_class)
  elements = getlist(ns, element_name)
  return [] if elements.empty?
  elements.collect do |e|
    ext_class.new(:namespace => ns, :elem => e) 
  end
end

#getlist(ns, element_name) ⇒ Object

Get indicated elements as array

ns = Atom::Namespace.new(:prefix => 'dc', :uri => 'http://purl.org/dc/elements/1.1/')
elems = entry.getlist(ns, 'subject')


553
554
555
# File 'lib/atomutil.rb', line 553

def getlist(ns, element_name)
  @elem.get_elements(child_xpath(ns, element_name))
end

#set(ns, element_name, value = "", attributes = nil) ⇒ Object

This method allows you to handle extra-element such as you can’t represent with elements defined in Atom namespace.

entry = Atom::Entry.new
entry.set('http://example/2007/mynamespace', 'foo', 'bar')

Now your entry includes new element. <foo xmlns=“example/2007/mynamespace”>bar</foo>

You also can add attributes

entry.set('http://example/2007/mynamespace', 'foo', 'bar', { :myattr => 'attr1', :myattr2 => 'attr2' })

And you can get following element from entry

<foo xmlns="http://example/2007/mynamespace" myattr="attr1" myattr2="attr2">bar</foo>

Or using prefix,

entry = Atom::Entry.new
ns = Atom::Namespace.new(:prefix => 'dc', :uri => 'http://purl.org/dc/elements/1.1/')
entry.set(ns, 'subject', 'buz')

Then your element contains

<dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/">buz</dc:subject>

And in case you need to handle more complex element, pass the REXML::Element object which you customized as third argument instead of text-value.

custom_element = REXML::Element.new
custom_child = REXML::Element.new('mychild')
custom_child.add_text = 'child!'
custom_element.add_element custom_child
entry.set(ns, 'mynamespace', costom_element)


498
499
500
501
502
# File 'lib/atomutil.rb', line 498

def set(ns, element_name, value="", attributes=nil)
  xpath = child_xpath(ns, element_name)
  @elem.elements.delete_all(xpath)
  add(ns, element_name, value, attributes)
end

#set_attr(name, value) ⇒ Object

Set attribute value for indicated key



587
588
589
# File 'lib/atomutil.rb', line 587

def set_attr(name, value)
  @elem.attributes[name.to_s] = value
end

#to_sObject

Convert to XML-Document and return it as string



591
592
593
594
595
596
597
# File 'lib/atomutil.rb', line 591

def to_s(*)
  doc = REXML::Document.new
  decl = REXML::XMLDecl.new("1.0", "utf-8")
  doc.add decl
  doc.add_element @elem
  doc.to_s
end