microformats2 1.0.2 → 2.0.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +5 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +117 -26
  8. data/Rakefile +65 -9
  9. data/lib/microformats2.rb +30 -115
  10. data/lib/microformats2/collection.rb +71 -0
  11. data/lib/microformats2/format.rb +101 -0
  12. data/lib/microformats2/format_parser.rb +59 -0
  13. data/lib/microformats2/implied_property/foundation.rb +58 -0
  14. data/lib/microformats2/implied_property/name.rb +34 -0
  15. data/lib/microformats2/implied_property/photo.rb +24 -0
  16. data/lib/microformats2/implied_property/url.rb +20 -0
  17. data/lib/microformats2/property.rb +10 -0
  18. data/lib/microformats2/property/date_time.rb +31 -0
  19. data/lib/microformats2/property/embedded.rb +9 -0
  20. data/lib/microformats2/property/foundation.rb +80 -0
  21. data/lib/microformats2/property/text.rb +16 -0
  22. data/lib/microformats2/property/url.rb +18 -0
  23. data/lib/microformats2/property_parser.rb +54 -0
  24. data/lib/microformats2/version.rb +3 -0
  25. data/microformats2.gemspec +30 -0
  26. data/spec/lib/microformats2/collection_spec.rb +181 -0
  27. data/spec/lib/microformats2/implied_property/name_spec.rb +31 -0
  28. data/spec/lib/microformats2/implied_property/photo_spec.rb +31 -0
  29. data/spec/lib/microformats2/implied_property/url_spec.rb +31 -0
  30. data/spec/lib/microformats2_spec.rb +30 -0
  31. data/spec/spec_helper.rb +10 -0
  32. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-0.html +3 -0
  33. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-0.js +10 -0
  34. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-1.html +10 -0
  35. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-1.js +16 -0
  36. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-2.html +12 -0
  37. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-2.js +16 -0
  38. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-3.html +6 -0
  39. data/spec/support/cases/microformat2-node.jit.su/h-adr/h-adr-3.js +12 -0
  40. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-0.html +3 -0
  41. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-0.js +10 -0
  42. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-1.html +3 -0
  43. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-1.js +11 -0
  44. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-2.html +4 -0
  45. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-2.js +12 -0
  46. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-3.html +11 -0
  47. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-3.js +15 -0
  48. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-4.html +6 -0
  49. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-4.js +26 -0
  50. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-5.html +6 -0
  51. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-5.js +30 -0
  52. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-6.html +6 -0
  53. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-6.js +29 -0
  54. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-7.html +16 -0
  55. data/spec/support/cases/microformat2-node.jit.su/h-card/h-card-7.js +15 -0
  56. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-0.html +4 -0
  57. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-0.js +10 -0
  58. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-1.html +3 -0
  59. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-1.js +11 -0
  60. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-2.html +21 -0
  61. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-2.js +28 -0
  62. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-3.html +22 -0
  63. data/spec/support/cases/microformat2-node.jit.su/h-entry/h-entry-3.js +21 -0
  64. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-0.html +3 -0
  65. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-0.js +10 -0
  66. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-1.html +3 -0
  67. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-1.js +11 -0
  68. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-2.html +14 -0
  69. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-2.js +57 -0
  70. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-3.html +15 -0
  71. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-3.js +35 -0
  72. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-4.html +9 -0
  73. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-4.js +12 -0
  74. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-5.html +45 -0
  75. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-5.js +22 -0
  76. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-6.html +51 -0
  77. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-6.js +21 -0
  78. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-7.html +22 -0
  79. data/spec/support/cases/microformat2-node.jit.su/h-event/h-event-7.js +20 -0
  80. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-0.html +5 -0
  81. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-0.js +10 -0
  82. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-1.html +7 -0
  83. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-1.js +12 -0
  84. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-2.html +10 -0
  85. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-2.js +13 -0
  86. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-3.html +12 -0
  87. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-3.js +12 -0
  88. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-4.html +12 -0
  89. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-4.js +12 -0
  90. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-5.html +6 -0
  91. data/spec/support/cases/microformat2-node.jit.su/h-geo/h-geo-5.js +12 -0
  92. data/spec/support/cases/microformat2-node.jit.su/h-news/h-news-0.html +26 -0
  93. data/spec/support/cases/microformat2-node.jit.su/h-news/h-news-0.js +37 -0
  94. data/spec/support/cases/microformat2-node.jit.su/h-news/h-news-1.html +37 -0
  95. data/spec/support/cases/microformat2-node.jit.su/h-news/h-news-1.js +48 -0
  96. data/spec/support/cases/microformat2-node.jit.su/h-org/h-org-0.html +3 -0
  97. data/spec/support/cases/microformat2-node.jit.su/h-org/h-org-0.js +10 -0
  98. data/spec/support/cases/microformat2-node.jit.su/h-org/h-org-1.html +3 -0
  99. data/spec/support/cases/microformat2-node.jit.su/h-org/h-org-1.js +11 -0
  100. data/spec/support/cases/microformat2-node.jit.su/h-org/h-org-2.html +6 -0
  101. data/spec/support/cases/microformat2-node.jit.su/h-org/h-org-2.js +12 -0
  102. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-0.html +3 -0
  103. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-0.js +10 -0
  104. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-1.html +3 -0
  105. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-1.js +11 -0
  106. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-2.html +11 -0
  107. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-2.js +23 -0
  108. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-3.html +22 -0
  109. data/spec/support/cases/microformat2-node.jit.su/h-product/h-product-3.js +42 -0
  110. data/spec/support/cases/microformat2-node.jit.su/h-recipe/h-recipe-0.html +9 -0
  111. data/spec/support/cases/microformat2-node.jit.su/h-recipe/h-recipe-0.js +11 -0
  112. data/spec/support/cases/microformat2-node.jit.su/h-recipe/h-recipe-1.html +67 -0
  113. data/spec/support/cases/microformat2-node.jit.su/h-recipe/h-recipe-1.js +51 -0
  114. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-0.html +3 -0
  115. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-0.js +10 -0
  116. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-1.html +20 -0
  117. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-1.js +39 -0
  118. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-2.html +17 -0
  119. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-2.js +54 -0
  120. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-3.html +15 -0
  121. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-3.js +54 -0
  122. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-4.html +15 -0
  123. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-4.js +12 -0
  124. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-5.html +13 -0
  125. data/spec/support/cases/microformat2-node.jit.su/h-resume/h-resume-5.js +27 -0
  126. data/spec/support/cases/microformat2-node.jit.su/h-review-aggregate/h-review-aggregate-0.html +10 -0
  127. data/spec/support/cases/microformat2-node.jit.su/h-review-aggregate/h-review-aggregate-0.js +19 -0
  128. data/spec/support/cases/microformat2-node.jit.su/h-review-aggregate/h-review-aggregate-1.html +20 -0
  129. data/spec/support/cases/microformat2-node.jit.su/h-review-aggregate/h-review-aggregate-1.js +26 -0
  130. data/spec/support/cases/microformat2-node.jit.su/h-review-aggregate/h-review-aggregate-2.html +15 -0
  131. data/spec/support/cases/microformat2-node.jit.su/h-review-aggregate/h-review-aggregate-2.js +23 -0
  132. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-0.html +3 -0
  133. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-0.js +10 -0
  134. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-1.html +3 -0
  135. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-1.js +11 -0
  136. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-2.html +3 -0
  137. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-2.js +11 -0
  138. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-3.html +6 -0
  139. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-3.js +19 -0
  140. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-4.html +8 -0
  141. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-4.js +20 -0
  142. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-5.html +24 -0
  143. data/spec/support/cases/microformat2-node.jit.su/h-review/h-review-5.js +37 -0
  144. data/spec/support/cases/microformat2-node.jit.su/includes/includes-0.html +18 -0
  145. data/spec/support/cases/microformat2-node.jit.su/includes/includes-0.js +43 -0
  146. data/spec/support/cases/microformat2-node.jit.su/includes/includes-1.html +26 -0
  147. data/spec/support/cases/microformat2-node.jit.su/includes/includes-1.js +54 -0
  148. data/spec/support/cases/microformat2-node.jit.su/includes/includes-2.html +13 -0
  149. data/spec/support/cases/microformat2-node.jit.su/includes/includes-2.js +20 -0
  150. data/spec/support/cases/microformat2-node.jit.su/includes/includes-3.html +20 -0
  151. data/spec/support/cases/microformat2-node.jit.su/includes/includes-3.js +40 -0
  152. data/spec/support/cases/microformat2-node.jit.su/includes/includes-4.html +23 -0
  153. data/spec/support/cases/microformat2-node.jit.su/includes/includes-4.js +42 -0
  154. data/spec/support/cases/microformat2-node.jit.su/rel/rel-0.html +3 -0
  155. data/spec/support/cases/microformat2-node.jit.su/rel/rel-0.js +10 -0
  156. data/spec/support/cases/microformat2-node.jit.su/rel/rel-1.html +3 -0
  157. data/spec/support/cases/microformat2-node.jit.su/rel/rel-1.js +10 -0
  158. data/spec/support/cases/microformat2-node.jit.su/rel/rel-2.html +12 -0
  159. data/spec/support/cases/microformat2-node.jit.su/rel/rel-2.js +19 -0
  160. data/spec/support/cases/microformat2-node.jit.su/rel/rel-3.html +21 -0
  161. data/spec/support/cases/microformat2-node.jit.su/rel/rel-3.js +26 -0
  162. data/spec/support/cases/microformat2-node.jit.su/rel/rel-4.html +15 -0
  163. data/spec/support/cases/microformat2-node.jit.su/rel/rel-4.js +42 -0
  164. data/spec/support/cases/microformats.org/microformats-2/microformats-2-0.html +2 -0
  165. data/spec/support/cases/microformats.org/microformats-2/microformats-2-0.js +9 -0
  166. data/spec/support/cases/microformats.org/microformats-2/microformats-2-1.html +2 -0
  167. data/spec/support/cases/microformats.org/microformats-2/microformats-2-1.js +10 -0
  168. data/spec/support/cases/microformats.org/microformats-2/microformats-2-2.html +5 -0
  169. data/spec/support/cases/microformats.org/microformats-2/microformats-2-2.js +11 -0
  170. data/spec/support/cases/microformats.org/microformats-2/microformats-2-3.html +17 -0
  171. data/spec/support/cases/microformats.org/microformats-2/microformats-2-3.js +20 -0
  172. data/spec/support/cases/microformats.org/microformats-2/microformats-2-4.html +16 -0
  173. data/spec/support/cases/microformats.org/microformats-2/microformats-2-4.js +24 -0
  174. data/spec/support/cases/microformats.org/microformats-2/microformats-2-5.html +7 -0
  175. data/spec/support/cases/microformats.org/microformats-2/microformats-2-5.js +11 -0
  176. data/spec/support/cases/microformats.org/microformats-2/microformats-2-6.html +9 -0
  177. data/spec/support/cases/microformats.org/microformats-2/microformats-2-6.js +18 -0
  178. data/spec/support/cases/microformats.org/microformats-2/microformats-2-7.html +9 -0
  179. data/spec/support/cases/microformats.org/microformats-2/microformats-2-7.js +18 -0
  180. data/spec/support/cases/microformats.org/microformats-2/microformats-2-8.html +9 -0
  181. data/spec/support/cases/microformats.org/microformats-2/microformats-2-8.js +17 -0
  182. data/spec/support/cases/microformats.org/microformats-2/microformats-2-9.html +9 -0
  183. data/spec/support/cases/microformats.org/microformats-2/microformats-2-9.js +17 -0
  184. data/spec/support/lib/microformats2/implied_property/name-fail.html +60 -0
  185. data/spec/support/lib/microformats2/implied_property/name-pass.html +30 -0
  186. data/spec/support/lib/microformats2/implied_property/photo-fail.html +60 -0
  187. data/spec/support/lib/microformats2/implied_property/photo-pass.html +30 -0
  188. data/spec/support/lib/microformats2/implied_property/url-fail.html +18 -0
  189. data/spec/support/lib/microformats2/implied_property/url-pass.html +12 -0
  190. data/spec/support/lib/microformats2/nested-format-with-property.html +12 -0
  191. data/spec/support/lib/microformats2/nested-format-with-property.js +15 -0
  192. data/spec/support/lib/microformats2/nested-format-without-property.html +13 -0
  193. data/spec/support/lib/microformats2/nested-property.html +12 -0
  194. data/spec/support/lib/microformats2/nested-property.js +9 -0
  195. data/spec/support/lib/microformats2/simple.html +19 -0
  196. data/spec/support/lib/microformats2/simple.js +10 -0
  197. metadata +535 -85
  198. data/.autotest +0 -23
  199. data/.gemtest +0 -0
  200. data/History.txt +0 -19
  201. data/Manifest.txt +0 -10
  202. data/bin/microformats2 +0 -3
  203. data/test/IndieWebCamp.html +0 -351
  204. data/test/simple.html +0 -30
  205. data/test/test_microformats2.rb +0 -185
@@ -0,0 +1,71 @@
1
+ module Microformats2
2
+ class Collection
3
+ attr_reader :all
4
+
5
+ def initialize(element)
6
+ @element = element
7
+ @format_names = []
8
+ end
9
+
10
+ def parse
11
+ all
12
+ self
13
+ end
14
+
15
+ def all
16
+ @all ||= FormatParser.parse(@element).each do |format|
17
+ save_format_name(format.method_name)
18
+ define_method(format.method_name)
19
+ set_value(format.method_name, format)
20
+ end
21
+ end
22
+
23
+ def first
24
+ all.first
25
+ end
26
+
27
+ def last
28
+ all.last
29
+ end
30
+
31
+ def to_hash
32
+ hash = { items: [] }
33
+ all.each do |format|
34
+ hash[:items] << format.to_hash
35
+ end
36
+ hash
37
+ end
38
+
39
+ def to_json
40
+ to_hash.to_json
41
+ end
42
+
43
+ private
44
+
45
+ def save_format_name(format_name)
46
+ unless @format_names.include?(format_name)
47
+ @format_names << format_name
48
+ end
49
+ end
50
+
51
+ def define_method(mn)
52
+ unless respond_to?(mn)
53
+ self.class.class_eval { attr_accessor mn }
54
+ end
55
+ unless respond_to?(mn.pluralize)
56
+ self.class.class_eval { attr_accessor mn.pluralize }
57
+ end
58
+ end
59
+
60
+ def set_value(mn, value)
61
+ unless current = send(mn)
62
+ send("#{mn}=", value)
63
+ end
64
+ if current = send(mn.pluralize)
65
+ current << value
66
+ else
67
+ send("#{mn.pluralize}=", [value])
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,101 @@
1
+ module Microformats2
2
+ class Format
3
+ CLASS_REG_EXP = /^(h-)/
4
+
5
+ attr_reader :method_name
6
+
7
+ def initialize(element)
8
+ @element = element
9
+ @method_name = to_method_name(format_types.first)
10
+ @property_names = []
11
+ end
12
+
13
+ def parse
14
+ format_types
15
+ properties
16
+ self
17
+ end
18
+
19
+ def format_types
20
+ @format_types ||= @element.attribute("class").to_s.split.select do |html_class|
21
+ html_class =~ Format::CLASS_REG_EXP
22
+ end
23
+ end
24
+
25
+ def properties
26
+ @properties ||= parse_properties.concat parse_implied_properties
27
+ end
28
+
29
+ def parse_properties
30
+ PropertyParser.parse(@element.children).each do |property|
31
+ save_property_name(property.method_name)
32
+ define_method(property.method_name)
33
+ set_value(property.method_name, property)
34
+ end
35
+ end
36
+
37
+ def parse_implied_properties
38
+ ip = []
39
+ ip << ImpliedProperty::Name.new(@element).parse unless property_present?(:name)
40
+ ip << ImpliedProperty::Url.new(@element).parse unless property_present?(:url)
41
+ ip << ImpliedProperty::Photo.new(@element).parse unless property_present?(:photo)
42
+ ip.compact.each do |property|
43
+ save_property_name(property.method_name)
44
+ define_method(property.method_name)
45
+ set_value(property.method_name, property)
46
+ end
47
+ end
48
+
49
+ def property_present?(property)
50
+ !! respond_to?(property) && send(property)
51
+ end
52
+
53
+ def to_hash
54
+ hash = { type: format_types, properties: {} }
55
+ @property_names.each do |method_name|
56
+ hash[:properties][method_name.to_sym] = send(method_name.pluralize).map(&:to_hash)
57
+ end
58
+ hash
59
+ end
60
+
61
+ def to_json
62
+ to_hash.to_json
63
+ end
64
+
65
+ private
66
+
67
+ def to_method_name(html_class)
68
+ # p-class-name -> class_name
69
+ mn = html_class.downcase.split("-")[1..-1].join("_")
70
+ # avoid overriding Object#class
71
+ mn = "klass" if mn == "class"
72
+ mn
73
+ end
74
+
75
+ def save_property_name(property_name)
76
+ unless @property_names.include?(property_name)
77
+ @property_names << property_name
78
+ end
79
+ end
80
+
81
+ def define_method(mn)
82
+ unless respond_to?(mn)
83
+ self.class.class_eval { attr_accessor mn }
84
+ end
85
+ unless respond_to?(mn.pluralize)
86
+ self.class.class_eval { attr_accessor mn.pluralize }
87
+ end
88
+ end
89
+
90
+ def set_value(mn, value)
91
+ unless current = send(mn)
92
+ send("#{mn}=", value)
93
+ end
94
+ if current = send(mn.pluralize)
95
+ current << value
96
+ else
97
+ send("#{mn.pluralize}=", [value])
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,59 @@
1
+ module Microformats2
2
+ class FormatParser
3
+ class << self
4
+ def parse(element)
5
+ parse_node(element).flatten.compact
6
+ end
7
+
8
+ def parse_node(node)
9
+ case
10
+ when node.is_a?(Nokogiri::HTML::Document) then parse_node(node.children)
11
+ when node.is_a?(Nokogiri::XML::NodeSet) then parse_nodeset(node)
12
+ when node.is_a?(Nokogiri::XML::Element) then [parse_for_microformats(node)]
13
+ end
14
+ end
15
+
16
+ def parse_nodeset(nodeset)
17
+ nodeset.map { |node| parse_node(node) }
18
+ end
19
+
20
+ def parse_for_microformats(element)
21
+ if format_classes(element).length >= 1
22
+ parse_microformat(element)
23
+ else
24
+ parse_nodeset(element.children)
25
+ end
26
+ end
27
+
28
+ def parse_microformat(element)
29
+ # only create ruby object for first format class
30
+ html_class = format_classes(element).first
31
+ const_name = constant_name(html_class)
32
+ klass = find_or_create_ruby_class(const_name)
33
+
34
+ klass.new(element).parse
35
+ end
36
+
37
+ def format_classes(element)
38
+ element.attribute("class").to_s.split.select do |html_class|
39
+ html_class =~ Format::CLASS_REG_EXP
40
+ end
41
+ end
42
+
43
+ def constant_name(html_class)
44
+ # html-Class -> html-class -> html_class -> Html_class -> HtmlClass
45
+ html_class.downcase.gsub("-","_").gsub(/^([a-z])/){$1.upcase}.gsub(/_(.)/){$1.upcase}
46
+ end
47
+
48
+ def find_or_create_ruby_class(const_name)
49
+ if Object.const_defined?(const_name)
50
+ klass = Object.const_get(const_name)
51
+ else
52
+ klass = Class.new(Microformats2::Format)
53
+ Object.const_set const_name, klass
54
+ end
55
+ klass
56
+ end
57
+ end # class << self
58
+ end
59
+ end
@@ -0,0 +1,58 @@
1
+ module Microformats2
2
+ module ImpliedProperty
3
+ class Foundation
4
+
5
+ def initialize(element)
6
+ @element = element
7
+ end
8
+
9
+ def parse
10
+ self if to_s
11
+ end
12
+
13
+ def method_name
14
+ "foundation"
15
+ end
16
+
17
+ def to_s
18
+ @to_s ||= element_value || selector_value
19
+ end
20
+
21
+ def to_hash
22
+ to_s
23
+ end
24
+
25
+ def to_json
26
+ to_hash.to_json
27
+ end
28
+
29
+ protected
30
+
31
+ def element_value
32
+ name_map.each_pair do |elname, attr|
33
+ if elname == @element.name && @element.attribute(attr)
34
+ return @element.attribute(attr).to_s
35
+ end
36
+ end
37
+ nil
38
+ end
39
+
40
+ def name_map
41
+ {}
42
+ end
43
+
44
+ def selector_value
45
+ selector_map.each_pair do |sel, attr|
46
+ if selected_element = @element.css(sel).first
47
+ return selected_element.attribute(attr).to_s
48
+ end
49
+ end
50
+ nil
51
+ end
52
+
53
+ def selector_map
54
+ {}
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ module Microformats2
2
+ module ImpliedProperty
3
+ class Name < Foundation
4
+
5
+ def method_name
6
+ "name"
7
+ end
8
+
9
+ def to_s
10
+ @to_s ||= element_value || selector_value || text_value
11
+ end
12
+
13
+ protected
14
+
15
+ def name_map
16
+ { "img" => "alt",
17
+ "abbr" => "title" }
18
+ end
19
+
20
+ def selector_map
21
+ { ">img[alt]:only-of-type" => "alt",
22
+ ">abbr[title]:only-of-type" => "title",
23
+ ">:only-of-type>img[alt]:only-of-type" => "alt",
24
+ ">:only-of-type>abbr[title]:only-of-type" => "title" }
25
+ end
26
+
27
+ private
28
+
29
+ def text_value
30
+ @element.inner_text.gsub(/\n+/, " ").gsub(/\s+/, " ").strip
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ module Microformats2
2
+ module ImpliedProperty
3
+ class Photo < Foundation
4
+
5
+ def method_name
6
+ "photo"
7
+ end
8
+
9
+ protected
10
+
11
+ def name_map
12
+ { "img" => "src",
13
+ "object" => "data" }
14
+ end
15
+
16
+ def selector_map
17
+ { ">img[src]:only-of-type" => "src",
18
+ ">object[data]:only-of-type" => "data",
19
+ ">:only-child>img[src]:only-of-type" => "src",
20
+ ">:only-child>object[data]:only-of-type" => "data" }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module Microformats2
2
+ module ImpliedProperty
3
+ class Url < Foundation
4
+
5
+ def method_name
6
+ "url"
7
+ end
8
+
9
+ protected
10
+
11
+ def name_map
12
+ { "a" => "href" }
13
+ end
14
+
15
+ def selector_map
16
+ { ">a[href]:only-of-type" => "href" }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module Microformats2
2
+ module Property
3
+ CLASS_REG_EXP = /^(p-|u-|dt-|e-)/
4
+ PREFIX_CLASS_MAP = {
5
+ "p" => Text,
6
+ "u" => Url,
7
+ "dt" => DateTime,
8
+ "e" => Embedded }
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ module Microformats2
2
+ module Property
3
+ class DateTime < Foundation
4
+ def to_s
5
+ @to_s ||= value_class_pattern || element_value || text_value
6
+ end
7
+
8
+ def value
9
+ ::DateTime.parse(to_s)
10
+ end
11
+
12
+ def to_hash
13
+ if formats.empty?
14
+ to_s
15
+ else
16
+ { value: to_s }.merge(formats.first.to_hash)
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ def attr_map
23
+ @attr_map ||= {
24
+ "time" => "datetime",
25
+ "ins" => "datetime",
26
+ "abbr" => "title",
27
+ "data" => "value" }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ module Microformats2
2
+ module Property
3
+ class Embedded < Foundation
4
+ def to_s
5
+ @to_s ||= @element.inner_html.strip
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,80 @@
1
+ module Microformats2
2
+ module Property
3
+ class Foundation
4
+ attr_reader :method_name
5
+
6
+ def initialize(element, html_class)
7
+ @element = element
8
+ @method_name = to_method_name(html_class)
9
+ end
10
+
11
+ def parse
12
+ to_s
13
+ formats
14
+ self
15
+ end
16
+
17
+ def to_s
18
+ @to_s ||= value_class_pattern || element_value || text_value
19
+ end
20
+
21
+ def format
22
+ formats.first
23
+ end
24
+
25
+ def formats
26
+ @formats ||= format_classes.length >=1 ? FormatParser.parse(@element) : []
27
+ end
28
+
29
+ def to_hash
30
+ if formats.empty?
31
+ to_s
32
+ else
33
+ { value: to_s }.merge(formats.first.to_hash)
34
+ end
35
+ end
36
+
37
+ def to_json
38
+ to_hash.to_json
39
+ end
40
+
41
+ protected
42
+
43
+ def value_class_pattern
44
+ # TODO
45
+ end
46
+
47
+ def element_value
48
+ @element.attribute(attribute).to_s if attribute && @element.attribute(attribute)
49
+ end
50
+
51
+ def text_value
52
+ @element.inner_text.gsub(/\n+/, " ").gsub(/\s+/, " ").strip
53
+ end
54
+
55
+ def attribute
56
+ attr_map[@element.name]
57
+ end
58
+
59
+ def attr_map
60
+ {}
61
+ end
62
+
63
+ private
64
+
65
+ def to_method_name(html_class)
66
+ # p-class-name -> class_name
67
+ mn = html_class.downcase.split("-")[1..-1].join("_")
68
+ # avoid overriding Object#class
69
+ mn = "klass" if mn == "class"
70
+ mn
71
+ end
72
+
73
+ def format_classes
74
+ @format_classes = @element.attribute("class").to_s.split.select do |html_class|
75
+ html_class =~ Format::CLASS_REG_EXP
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end