fixes the world minus nested formats

This commit is contained in:
Jessica Lynn Suttles 2013-02-13 16:16:45 -08:00
parent 081d0e5000
commit 40fcdf22d9
7 changed files with 91 additions and 50 deletions

View file

@ -3,7 +3,8 @@ module Microformats2
attr_accessor :formats attr_accessor :formats
def parse(document) def parse(document)
formats = FormatParser.parse(document) @formats = FormatParser.parse(document)
self
end end
def to_hash def to_hash

View file

@ -2,20 +2,50 @@ module Microformats2
class Format class Format
CLASS_REG_EXP = /^(h-)/ CLASS_REG_EXP = /^(h-)/
attr_reader :element, :properties, :format_types attr_reader :element
def initialize(element) def initialize(element)
@element = element @element = element
@format_types = [] @added_methods = []
@properties = []
end end
def parse def parse
properties << PropertyParser.parse(element) properties
format_types format_types
self self
end end
def properties
@properties ||= create_properties
end
def create_properties
PropertyParser.parse(element).map do |property|
save_method_name(property.name)
define_method(property.name)
set_value(property.name, property)
end
end
def save_method_name(method_name)
unless @added_methods.include?(method_name)
@added_methods << method_name
end
end
def define_method(method_name)
unless respond_to?(method_name)
self.class.class_eval { attr_accessor method_name }
end
end
def set_value(method_name, value)
if current = send(method_name)
current << value
else
send("#{method_name}=", [value])
end
end
def format_types def format_types
@format_types ||= element.attribute("class").to_s.split.select do |html_class| @format_types ||= element.attribute("class").to_s.split.select do |html_class|
html_class =~ Format::CLASS_REG_EXP html_class =~ Format::CLASS_REG_EXP
@ -23,8 +53,8 @@ module Microformats2
end end
def to_hash def to_hash
hash = { type: @format_types, properties: {} } hash = { type: format_types, properties: {} }
properties.each do |method_name| @added_methods.each do |method_name|
value = send(method_name) value = send(method_name)
value = value.is_a?(Array) ? value : [value] value = value.is_a?(Array) ? value : [value]
hash[:properties][method_name.to_sym] = value.map(&:to_hash) hash[:properties][method_name.to_sym] = value.map(&:to_hash)

View file

@ -2,13 +2,14 @@ module Microformats2
class FormatParser class FormatParser
class << self class << self
def parse(element) def parse(element)
parse_node(element) parse_node(element).flatten.compact
end end
def parse_node(node) def parse_node(node)
case case
when node.is_a?(Nokogiri::XML::NodeSet) then parse_nodeset(node) when node.is_a?(Nokogiri::HTML::Document) then parse_node(node.children)
when node.is_a?(Nokogiri::XML::Element) then parse_for_microformats(node) when node.is_a?(Nokogiri::XML::NodeSet) then parse_nodeset(node)
when node.is_a?(Nokogiri::XML::Element) then [parse_for_microformats(node)]
end end
end end
@ -25,22 +26,11 @@ module Microformats2
end end
def parse_microformat(element) def parse_microformat(element)
# only worry about the first format for now # only create ruby object for first format class
html_class = format_classes(element).first html_class = format_classes(element).first
# class-name -> class_name const_name = constant_name(html_class)
method_name = html_class.downcase.gsub("-","_") klass = find_or_create_ruby_class(const_name)
# class_name -> Class_name -> ClassName
constant_name = method_name.gsub(/^([a-z])/){$1.upcase}.gsub(/_(.)/){$1.upcase}
# find or create ruby class for microformat
if Object.const_defined?(constant_name)
klass = Object.const_get(constant_name)
else
klass = Class.new(Microformats2::Format)
Object.const_set constant_name, klass
end
# parse microformat
klass.new(element).parse klass.new(element).parse
end end
@ -49,6 +39,21 @@ module Microformats2
html_class =~ Format::CLASS_REG_EXP html_class =~ Format::CLASS_REG_EXP
end end
end end
def constant_name(html_class)
# html-Class -> html-class -> html_class -> Html_class -> HtmlClass
html_class.downcase.gsub("-","_").gsub(/^([a-z])/){$1.upcase}.gsub(/_(.)/){$1.upcase}
end
def find_or_create_ruby_class(const_name)
if Object.const_defined?(const_name)
klass = Object.const_get(const_name)
else
klass = Class.new(Microformats2::Format)
Object.const_set const_name, klass
end
klass
end
end end
end end
end end

View file

@ -5,7 +5,6 @@ module Microformats2
"p" => Text, "p" => Text,
"u" => Url, "u" => Url,
"dt" => DateTime, "dt" => DateTime,
"e" => Embedded "e" => Embedded }
}
end end
end end

View file

@ -1,21 +1,33 @@
module Microformats2 module Microformats2
module Property module Property
class Foundation class Foundation
attr_accessor :element, :value, :formats attr_accessor :element, :name, :value, :formats
def initialize(element) def initialize(element, html_class)
@element = element @element = element
@formats = [] @name = to_method_name(html_class)
end end
def to_method_name(html_class)
# p-class-name -> class_name
method_name = html_class.downcase.split("-")[1..-1].join("_")
# avoid overriding Object#class
method_name = "klass" if method_name == "class"
method_name
end
def parse def parse
formats << FormatParser.parse(element) if format_classes.length >=1 formats
value value
self self
end end
def formats
@formats ||= format_classes.length >=1 ? FormatParser.parse(element) : []
end
def format_classes def format_classes
element.attribute("class").to_s.split.select do |html_class| @format_classes = element.attribute("class").to_s.split.select do |html_class|
html_class =~ Format::CLASS_REG_EXP html_class =~ Format::CLASS_REG_EXP
end end
end end

View file

@ -2,7 +2,7 @@ module Microformats2
class PropertyParser class PropertyParser
class << self class << self
def parse(element) def parse(element)
parse_node(element) parse_node(element).flatten.compact
end end
def parse_node(node) def parse_node(node)
@ -24,24 +24,18 @@ module Microformats2
end end
end end
def parse_property(element, html_classes) def parse_property(element)
property_classes(element).each do |property_class| property_classes(element).map do |property_class|
# p-class-name -> p # p-class-name -> p
prefix = property_class.split("-").first prefix = property_class.split("-").first
# p-class-name -> class_name
method_name = property_class.split("-")[1..-1].join("_")
# avoid overriding Object#class
method_name = "klass" if method_name == "class"
# find ruby class for kind of property # find ruby class for kind of property
klass = Microformats2::Property::PREFIX_CLASS_MAP[prefix] klass = Microformats2::Property::PREFIX_CLASS_MAP[prefix]
# parse property klass.new(element, property_class).parse
klass.new(element).parse
end end
end end
def property_classes(element, regexp) def property_classes(element)
element.attribute("class").to_s.split.select do |html_class| element.attribute("class").to_s.split.select do |html_class|
html_class =~ Property::CLASS_REG_EXP html_class =~ Property::CLASS_REG_EXP
end end

View file

@ -25,21 +25,21 @@ describe Microformats2::Collection do
describe "#parse" do describe "#parse" do
it "creates ruby class HCard" do it "creates ruby class HCard" do
@collection.first.should be_kind_of HCard @collection.formats.first.should be_kind_of HCard
end end
it "assigns .h-card .p-name to HCard#name" do it "assigns .h-card .p-name to HCard#name" do
@collection.first.name.value.should == "Jessica Lynn Suttles" @collection.formats.first.name.first.value.should == "Jessica Lynn Suttles"
end end
it "assigns both .h-card .u-url to HCard#url" do it "assigns both .h-card .u-url to HCard#url" do
urls = ["http://flickr.com/jlsuttles", "http://twitter.com/jlsuttles"] urls = ["http://flickr.com/jlsuttles", "http://twitter.com/jlsuttles"]
@collection.first.url.map(&:value).should == urls @collection.formats.first.url.map(&:value).should == urls
end end
it "assings .h-card .dt-bday to HCard#bday" do it "assings .h-card .dt-bday to HCard#bday" do
@collection.first.bday.value.should be_kind_of DateTime @collection.formats.first.bday.first.value.should be_kind_of DateTime
@collection.first.bday.value.to_s.should == "1990-10-15T20:45:33-08:00" @collection.formats.first.bday.first.value.to_s.should == "1990-10-15T20:45:33-08:00"
end end
it "assigns .h-card .e-content to HCard#content" do it "assigns .h-card .e-content to HCard#content" do
@collection.first.content.value.should == "Vegan. Cat lover. Coder." @collection.formats.first.content.first.value.should == "Vegan. Cat lover. Coder."
end end
end end
@ -69,10 +69,10 @@ describe Microformats2::Collection do
describe "#parse" do describe "#parse" do
it "creates ruby class HEntry" do it "creates ruby class HEntry" do
@collection.first.should be_kind_of HEntry @collection.formats.first.should be_kind_of HEntry
end end
it "assigns .h-entry .p-author to HEntry#author" do it "assigns .h-entry .p-author to HEntry#author" do
@collection.first.author.value.should == "Jessica Lynn Suttles" @collection.formats.first.author.value.should == "Jessica Lynn Suttles"
end end
end end