lib/gepub/meta.rb
require 'rubygems'
require 'nokogiri'
module GEPUB
# Holds one metadata with refine meta elements.
class Meta
include DSLUtil
attr_accessor :content
attr_reader :name
def initialize(name, content, parent, attributes= {}, refiners = {})
@parent = parent
@name = name
@content = content
@attributes = attributes
@refiners = refiners
@parent.register_meta(self) unless @parent.nil?
end
# get +attribute+
def [](attribute)
@attributes[attribute]
end
# set +attribute+
def []=(attribute, value)
@attributes[attribute] = value
end
def refiner_list(name)
return @refiners[name].dup
end
def refiner_clear(name)
if !@refiners[name].nil?
@refiners[name].each {
|refiner|
@parent.unregister_meta(refiner)
}
end
@refiners[name]= []
end
def refiner(name)
refiner = @refiners[name]
if refiner.nil? || refiner.size == 0
nil
else
refiner[0]
end
end
# add a refiner.
def add_refiner(property, content, attributes = {})
(@refiners[property] ||= []) << Meta.new('meta', content, @parent, { 'property' => property }.merge(attributes)) unless content.nil?
self
end
# set a 'unique' refiner. all other refiners with same property will be removed.
def refine(property, content, attributes = {})
if !content.nil?
refiner_clear(property)
add_refiner(property, content, attributes)
end
self
end
REFINERS = ['title-type', 'identifier-type', 'display-seq', 'file-as', 'group-position', 'role'].each {
|name|
methodbase = name.sub('-','_')
define_method(methodbase + '=') { |val| refine(name, val) }
define_method('set_' + methodbase) { |val|
warn "set_#{methodbase} is obsolete. use #{methodbase} instead."
refine(name, val)
}
define_method(methodbase, ->(value = UNASSIGNED) {
if unassigned?(value)
refiner(name)
else
refine(name,value)
end
})
}
def lang=(lang)
@attributes['xml:lang'] = lang
end
def lang(lang = UNASSIGNED)
if unassigned?(lang)
@attributes['xml:lang']
else
self.lang=(lang)
end
end
# add alternate script refiner.
def add_alternates(alternates = {})
alternates.each {
|locale, content|
add_refiner('alternate-script', content, { 'xml:lang' => locale })
}
self
end
def list_alternates
list = refiner_list('alternate-script').map {
|refiner|
[ refiner['xml:lang'], refiner.content ]
}
Hash[*list.flatten]
end
def to_xml(builder, id_pool, ns = nil, additional_attr = {}, opf_version = '3.0')
additional_attr ||= {}
if @refiners.size > 0 && opf_version.to_f >= 3.0
@attributes['id'] = id_pool.generate_key(:prefix => name) if @attributes['id'].nil?
end
# using __send__ to parametarize Namespace and content.
target = ns.nil? || @name == 'meta' ? builder : builder[ns]
attr = @attributes.reject{|_k,v| v.nil?}.merge(additional_attr)
if @content.nil?
target.__send__(@name, attr)
else
target.__send__(@name, attr, self.to_s)
end
if @refiners.size > 0 && opf_version.to_f >= 3.0
additional_attr['refines'] = "##{@attributes['id']}"
@refiners.each {
|_k, ref_list|
ref_list.each {
|ref|
ref.to_xml(builder, id_pool, nil, additional_attr)
}
}
end
end
def to_s(locale=nil)
localized = nil
if !locale.nil?
prefix = locale.sub(/^(.+?)-.*/, '\1')
regex = Regexp.new("^((" + locale.split('-').join(')?-?(') + ")?)")
candidates = @refiners['alternate-script'].select {
|refiner|
refiner['xml:lang'] =~ /^#{prefix}-?.*/
}.sort_by {
|x|
x['xml:lang'] =~ regex; $1.size
}.reverse
localized = candidates[0].content if candidates.size > 0
end
(localized || self.content || super()).to_s
end
end
end