microformats2/lib/microformats2/format.rb

111 lines
2.8 KiB
Ruby

module Microformats2
class Format
CLASS_REG_EXP = /^(h-)/
attr_reader :method_name
def initialize(element, base)
@element = element
@base = base
@method_name = to_method_name(format_types.first)
@property_names = []
end
def parse
format_types
properties
self
end
def format_types
@format_types ||= @element.attribute("class").to_s.split.select do |html_class|
html_class =~ Format::CLASS_REG_EXP
end
end
def properties
@properties ||= parse_properties.concat parse_implied_properties
end
def parse_properties
PropertyParser.parse(@element.children, @base).each do |property|
assign_property(property)
end
end
def add_property(property_class, value)
property = Property.new(nil, property_class, value, @base)
assign_property(property)
end
def parse_implied_properties
ip = []
ip << ImpliedProperty::Name.new(@element).parse unless property_present?(:name)
ip << ImpliedProperty::Url.new(@element, @base).parse unless property_present?(:url)
ip << ImpliedProperty::Photo.new(@element).parse unless property_present?(:photo)
ip.compact.each do |property|
save_property_name(property.method_name)
define_method(property.method_name)
set_value(property.method_name, property)
end
end
def property_present?(property)
!! respond_to?(property) && send(property)
end
def to_hash
hash = { type: format_types, properties: {} }
@property_names.each do |method_name|
hash[:properties][method_name.to_sym] = send(method_name.pluralize).map(&:to_hash)
end
hash
end
def to_json
to_hash.to_json
end
private
def assign_property(property)
save_property_name(property.method_name)
define_method(property.method_name)
set_value(property.method_name, property)
end
def to_method_name(html_class)
# p-class-name -> class_name
mn = html_class.downcase.split("-")[1..-1].join("_")
# avoid overriding Object#class
mn = "klass" if mn == "class"
mn
end
def save_property_name(property_name)
unless @property_names.include?(property_name)
@property_names << property_name
end
end
def define_method(mn)
unless respond_to?(mn)
self.singleton_class.class_eval { attr_accessor mn }
end
unless respond_to?(mn.pluralize)
self.singleton_class.class_eval { attr_accessor mn.pluralize }
end
end
def set_value(mn, value)
unless current = send(mn)
send("#{mn}=", value)
end
if current = send(mn.pluralize)
current << value
else
send("#{mn.pluralize}=", [value])
end
end
end
end