diff --git a/lib/microformats2.rb b/lib/microformats2.rb index 7f2f751..a7618c5 100644 --- a/lib/microformats2.rb +++ b/lib/microformats2.rb @@ -18,7 +18,7 @@ module Microformats2 def parse(html) html = read_html(html) document = Nokogiri::HTML(html) - Collection.new.parse(document) + Collection.new(document).parse end def read_html(html) diff --git a/lib/microformats2/collection.rb b/lib/microformats2/collection.rb index 867a4d7..6f70da2 100644 --- a/lib/microformats2/collection.rb +++ b/lib/microformats2/collection.rb @@ -1,15 +1,36 @@ module Microformats2 class Collection - attr_accessor :formats + attr_reader :all - def parse(document) - @formats = FormatParser.parse(document) + def initialize(element) + @element = element + @format_names = [] + end + + def parse + all self end + def all + @all ||= FormatParser.parse(@element).each do |format| + save_format_name(format.method_name) + define_method(format.method_name) + set_value(format.method_name, format) + end + end + + def first + all.first + end + + def last + all.last + end + def to_hash hash = { items: [] } - formats.each do |format| + all.each do |format| hash[:items] << format.to_hash end hash @@ -18,5 +39,27 @@ module Microformats2 def to_json to_hash.to_json end + + private + + def save_format_name(format_name) + unless @format_names.include?(format_name) + @format_names << format_name + end + end + + def define_method(mn) + unless respond_to?(mn) + self.class.class_eval { attr_accessor mn } + end + end + + def set_value(mn, value) + if current = send(mn) + current << value + else + send("#{mn}=", [value]) + end + end end end diff --git a/lib/microformats2/format.rb b/lib/microformats2/format.rb index 18789bc..4bd53f2 100644 --- a/lib/microformats2/format.rb +++ b/lib/microformats2/format.rb @@ -2,62 +2,38 @@ module Microformats2 class Format CLASS_REG_EXP = /^(h-)/ - attr_reader :element + attr_reader :method_name def initialize(element) @element = element - @added_methods = [] + @method_name = to_method_name(format_types.first) + @property_names = [] end def parse - properties format_types + properties self 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 - @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 end end + def properties + @properties ||= PropertyParser.parse(@element.children).each do |property| + save_property_name(property.method_name) + define_method(property.method_name) + set_value(property.method_name, property) + end + end + def to_hash hash = { type: format_types, properties: {} } - @added_methods.each do |method_name| - value = send(method_name) - value = value.is_a?(Array) ? value : [value] - hash[:properties][method_name.to_sym] = value.map(&:to_hash) + @property_names.each do |method_name| + hash[:properties][method_name.to_sym] = send(method_name).map(&:to_hash) end hash end @@ -65,5 +41,35 @@ module Microformats2 def to_json to_hash.to_json end + + private + + 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.class.class_eval { attr_accessor mn } + end + end + + def set_value(mn, value) + if current = send(mn) + current << value + else + send("#{mn}=", [value]) + end + end end end diff --git a/lib/microformats2/format_parser.rb b/lib/microformats2/format_parser.rb index 760e8b9..32f349d 100644 --- a/lib/microformats2/format_parser.rb +++ b/lib/microformats2/format_parser.rb @@ -54,6 +54,6 @@ module Microformats2 end klass end - end + end # class << self end end diff --git a/lib/microformats2/property/date_time.rb b/lib/microformats2/property/date_time.rb index ce6775b..f7b7c00 100644 --- a/lib/microformats2/property/date_time.rb +++ b/lib/microformats2/property/date_time.rb @@ -7,6 +7,8 @@ module Microformats2 super end + protected + def attr_map @attr_map ||= { "time" => "datetime", diff --git a/lib/microformats2/property/foundation.rb b/lib/microformats2/property/foundation.rb index fa781fe..6682f4c 100644 --- a/lib/microformats2/property/foundation.rb +++ b/lib/microformats2/property/foundation.rb @@ -1,60 +1,26 @@ module Microformats2 module Property class Foundation - attr_accessor :element, :name, :value, :formats + attr_reader :method_name def initialize(element, html_class) @element = element - @name = to_method_name(html_class) + @method_name = to_method_name(html_class) 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 - formats value + formats self end - def formats - @formats ||= format_classes.length >=1 ? FormatParser.parse(element) : [] - end - - def format_classes - @format_classes = element.attribute("class").to_s.split.select do |html_class| - html_class =~ Format::CLASS_REG_EXP - end - end - def value @value ||= value_class_pattern || element_value || text_value end - def value_class_pattern - # TODO - end - - def element_value - element.attribute(attribute).to_s if attribute - end - - def text_value - element.inner_text.gsub(/\n+/, " ").gsub(/\s+/, " ").strip - end - - def attribute - attr_map[element.name] - end - - def attr_map - {} - end + def formats + @formats ||= format_classes.length >=1 ? FormatParser.parse(@element) : [] + end def to_hash if formats.empty? @@ -63,6 +29,48 @@ module Microformats2 { value: value.to_s }.merge(formats.first.to_hash) end end + + def to_json + to_hash.to_json + end + + protected + + def value_class_pattern + # TODO + end + + def element_value + @element.attribute(attribute).to_s if attribute + end + + def text_value + @element.inner_text.gsub(/\n+/, " ").gsub(/\s+/, " ").strip + end + + def attribute + attr_map[@element.name] + end + + def attr_map + {} + end + + private + + 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 format_classes + @format_classes = @element.attribute("class").to_s.split.select do |html_class| + html_class =~ Format::CLASS_REG_EXP + end + end end end end diff --git a/lib/microformats2/property/text.rb b/lib/microformats2/property/text.rb index ebecc59..5252ee9 100644 --- a/lib/microformats2/property/text.rb +++ b/lib/microformats2/property/text.rb @@ -1,6 +1,9 @@ module Microformats2 module Property class Text < Foundation + + protected + def attr_map @attr_map = { "abbr" => "title", diff --git a/lib/microformats2/property/url.rb b/lib/microformats2/property/url.rb index 0771e1a..dbbec49 100644 --- a/lib/microformats2/property/url.rb +++ b/lib/microformats2/property/url.rb @@ -1,6 +1,9 @@ module Microformats2 module Property class Url < Foundation + + protected + def attr_map @attr_map = { "a" => "href", diff --git a/lib/microformats2/property_parser.rb b/lib/microformats2/property_parser.rb index 45f8558..2da472a 100644 --- a/lib/microformats2/property_parser.rb +++ b/lib/microformats2/property_parser.rb @@ -8,7 +8,7 @@ module Microformats2 def parse_node(node) case when node.is_a?(Nokogiri::XML::NodeSet) then parse_nodeset(node) - when node.is_a?(Nokogiri::XML::Element) then parse_for_properties(node) + when node.is_a?(Nokogiri::XML::Element) then [parse_for_properties(node)] end end @@ -40,6 +40,6 @@ module Microformats2 html_class =~ Property::CLASS_REG_EXP end end - end + end # class << self end end diff --git a/spec/lib/microformats2/collection_spec.rb b/spec/lib/microformats2/collection_spec.rb index 45f6b00..839bb80 100644 --- a/spec/lib/microformats2/collection_spec.rb +++ b/spec/lib/microformats2/collection_spec.rb @@ -25,21 +25,23 @@ describe Microformats2::Collection do describe "#parse" do it "creates ruby class HCard" do - @collection.formats.first.should be_kind_of HCard + @collection.all.first.should be_kind_of HCard + @collection.first.should be_kind_of HCard + @collection.card.first.should be_kind_of HCard end it "assigns .h-card .p-name to HCard#name" do - @collection.formats.first.name.first.value.should == "Jessica Lynn Suttles" + @collection.first.name.first.value.should == "Jessica Lynn Suttles" end it "assigns both .h-card .u-url to HCard#url" do urls = ["http://flickr.com/jlsuttles", "http://twitter.com/jlsuttles"] - @collection.formats.first.url.map(&:value).should == urls + @collection.first.url.map(&:value).should == urls end it "assings .h-card .dt-bday to HCard#bday" do - @collection.formats.first.bday.first.value.should be_kind_of DateTime - @collection.formats.first.bday.first.value.to_s.should == "1990-10-15T20:45:33-08:00" + @collection.first.bday.first.value.should be_kind_of DateTime + @collection.first.bday.first.value.to_s.should == "1990-10-15T20:45:33-08:00" end it "assigns .h-card .e-content to HCard#content" do - @collection.formats.first.content.first.value.should == "Vegan. Cat lover. Coder." + @collection.first.content.first.value.should == "Vegan. Cat lover. Coder." end end @@ -69,10 +71,12 @@ describe Microformats2::Collection do describe "#parse" do it "creates ruby class HEntry" do - @collection.formats.first.should be_kind_of HEntry + @collection.all.first.should be_kind_of HEntry + @collection.first.should be_kind_of HEntry + @collection.entry.first.should be_kind_of HEntry end it "assigns .h-entry .p-author to HEntry#author" do - @collection.formats.first.author.value.should == "Jessica Lynn Suttles" + @collection.first.author.first.value.should == "Jessica Lynn Suttles" end end