mofo 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/CHANGELOG +6 -0
  2. data/Manifest.txt +55 -0
  3. data/Rakefile +32 -0
  4. data/init.rb +2 -0
  5. data/lib/microformat.rb +39 -6
  6. data/lib/mofo/hentry.rb +4 -0
  7. data/site/index.html +382 -0
  8. data/site/mofo-logo.png +0 -0
  9. data/site/mootools.v1.00.js +2 -0
  10. data/site/style.css +159 -0
  11. data/test/base_url_test.rb +22 -0
  12. data/test/fixtures/corkd.html +1 -1
  13. data/test/hatom_test.rb +1 -1
  14. data/test/hreview_test.rb +4 -3
  15. data/test/include_pattern_test.rb +1 -1
  16. data/test/test_helper.rb +17 -6
  17. metadata +63 -115
  18. data/test/format_test.rb +0 -230
  19. data/vendor/testspec-0.3.0/ChangeLog +0 -177
  20. data/vendor/testspec-0.3.0/README +0 -289
  21. data/vendor/testspec-0.3.0/ROADMAP +0 -1
  22. data/vendor/testspec-0.3.0/Rakefile +0 -151
  23. data/vendor/testspec-0.3.0/SPECS +0 -108
  24. data/vendor/testspec-0.3.0/TODO +0 -2
  25. data/vendor/testspec-0.3.0/bin/specrb +0 -104
  26. data/vendor/testspec-0.3.0/doc/classes/Kernel.html +0 -140
  27. data/vendor/testspec-0.3.0/doc/classes/Object.html +0 -155
  28. data/vendor/testspec-0.3.0/doc/classes/Test/Spec.html +0 -128
  29. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/CustomShould.html +0 -236
  30. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/DefinitionError.html +0 -111
  31. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/Should.html +0 -884
  32. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/ShouldNot.html +0 -487
  33. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/TestCase.html +0 -220
  34. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/TestCase/ClassMethods.html +0 -318
  35. data/vendor/testspec-0.3.0/doc/classes/Test/Spec/TestCase/InstanceMethods.html +0 -195
  36. data/vendor/testspec-0.3.0/doc/classes/Test/Unit/UI/RDox/TestRunner.html +0 -222
  37. data/vendor/testspec-0.3.0/doc/classes/Test/Unit/UI/SpecDox/TestRunner.html +0 -476
  38. data/vendor/testspec-0.3.0/doc/created.rid +0 -1
  39. data/vendor/testspec-0.3.0/doc/files/README.html +0 -516
  40. data/vendor/testspec-0.3.0/doc/files/ROADMAP.html +0 -109
  41. data/vendor/testspec-0.3.0/doc/files/SPECS.html +0 -386
  42. data/vendor/testspec-0.3.0/doc/files/lib/test/spec/dox_rb.html +0 -108
  43. data/vendor/testspec-0.3.0/doc/files/lib/test/spec/rdox_rb.html +0 -108
  44. data/vendor/testspec-0.3.0/doc/files/lib/test/spec/should-output_rb.html +0 -115
  45. data/vendor/testspec-0.3.0/doc/files/lib/test/spec_rb.html +0 -123
  46. data/vendor/testspec-0.3.0/doc/fr_class_index.html +0 -38
  47. data/vendor/testspec-0.3.0/doc/fr_file_index.html +0 -33
  48. data/vendor/testspec-0.3.0/doc/fr_method_index.html +0 -102
  49. data/vendor/testspec-0.3.0/doc/index.html +0 -24
  50. data/vendor/testspec-0.3.0/doc/rdoc-style.css +0 -208
  51. data/vendor/testspec-0.3.0/examples/stack.rb +0 -38
  52. data/vendor/testspec-0.3.0/examples/stack_spec.rb +0 -119
  53. data/vendor/testspec-0.3.0/lib/test/spec.rb +0 -490
  54. data/vendor/testspec-0.3.0/lib/test/spec/dox.rb +0 -122
  55. data/vendor/testspec-0.3.0/lib/test/spec/rdox.rb +0 -25
  56. data/vendor/testspec-0.3.0/lib/test/spec/should-output.rb +0 -49
  57. data/vendor/testspec-0.3.0/test/spec_dox.rb +0 -39
  58. data/vendor/testspec-0.3.0/test/spec_flexmock.rb +0 -210
  59. data/vendor/testspec-0.3.0/test/spec_mocha.rb +0 -118
  60. data/vendor/testspec-0.3.0/test/spec_nestedcontexts.rb +0 -26
  61. data/vendor/testspec-0.3.0/test/spec_should-output.rb +0 -26
  62. data/vendor/testspec-0.3.0/test/spec_testspec.rb +0 -522
  63. data/vendor/testspec-0.3.0/test/spec_testspec_order.rb +0 -26
  64. data/vendor/testspec-0.3.0/test/test_testunit.rb +0 -21
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ = 0.2.3
2
+ - Moved to Echoe
3
+ - Added feature of figuring out the base URL for relative URLs
4
+ - Removed vendor/, now has test/spec 0.3 gem dependency
5
+ - Added after_find callbacks to run arbitrary code after a uformat is found
6
+
1
7
  = 0.2.2
2
8
  - Proper ISO8601 date handling and cleanup of String#coerce
3
9
 
data/Manifest.txt ADDED
@@ -0,0 +1,55 @@
1
+ ./CHANGELOG
2
+ ./init.rb
3
+ ./lib/microformat/array.rb
4
+ ./lib/microformat/simple.rb
5
+ ./lib/microformat/string.rb
6
+ ./lib/microformat/time.rb
7
+ ./lib/microformat.rb
8
+ ./lib/mofo/adr.rb
9
+ ./lib/mofo/geo.rb
10
+ ./lib/mofo/hcalendar.rb
11
+ ./lib/mofo/hcard.rb
12
+ ./lib/mofo/hentry.rb
13
+ ./lib/mofo/hfeed.rb
14
+ ./lib/mofo/hresume.rb
15
+ ./lib/mofo/hreview.rb
16
+ ./lib/mofo/rel_bookmark.rb
17
+ ./lib/mofo/rel_tag.rb
18
+ ./lib/mofo/xfn.rb
19
+ ./lib/mofo/xoxo.rb
20
+ ./lib/mofo.rb
21
+ ./LICENSE
22
+ ./Manifest.txt
23
+ ./Rakefile
24
+ ./README
25
+ ./site/index.html
26
+ ./site/mofo-logo.png
27
+ ./site/mootools.v1.00.js
28
+ ./site/style.css
29
+ ./test/base_url_test.rb
30
+ ./test/ext_test.rb
31
+ ./test/fixtures/bob.html
32
+ ./test/fixtures/chowhound.html
33
+ ./test/fixtures/corkd.html
34
+ ./test/fixtures/event_addr.html
35
+ ./test/fixtures/events.html
36
+ ./test/fixtures/fake.html
37
+ ./test/fixtures/fauxtank.html
38
+ ./test/fixtures/hatom.html
39
+ ./test/fixtures/hresume.html
40
+ ./test/fixtures/include_pattern_single_attribute.html
41
+ ./test/fixtures/simple.html
42
+ ./test/fixtures/stoneship.html
43
+ ./test/fixtures/upcoming.html
44
+ ./test/fixtures/upcoming_single.html
45
+ ./test/fixtures/xfn.html
46
+ ./test/hatom_test.rb
47
+ ./test/hcalendar_test.rb
48
+ ./test/hcard_test.rb
49
+ ./test/hresume_test.rb
50
+ ./test/hreview_test.rb
51
+ ./test/include_pattern_test.rb
52
+ ./test/reltag_test.rb
53
+ ./test/test_helper.rb
54
+ ./test/xfn_test.rb
55
+ ./test/xoxo_test.rb
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ version = '0.2.3'
5
+ svn_repo = 'svn+ssh://chris@errtheblog.com/svn/projects/mofo'
6
+
7
+ begin
8
+ require 'echoe'
9
+
10
+ Echoe.new('mofo', version) do |p|
11
+ p.rubyforge_name = 'mofo'
12
+ p.summary = "mofo is a ruby microformat parser"
13
+ p.description = "mofo is a ruby microformat parser"
14
+ p.url = "http://mofo.rubyforge.org/"
15
+ p.author = 'Chris Wanstrath'
16
+ p.email = "chris@ozmm.org"
17
+ p.extra_deps << ['hpricot', '>=0.4.59']
18
+ p.test_globs = 'test/*_test.rb'
19
+ end
20
+
21
+ rescue LoadError => boom
22
+ puts "You are missing a dependency required for meta-operations on this gem."
23
+ puts "#{boom.to_s.capitalize}."
24
+ end
25
+
26
+ desc "Tag the current trunk with the current release version"
27
+ task :tag do
28
+ warn "WARNING: this will tag #{svn_repo}/trunk using the tag REL_#{version.gsub!('.','_')}"
29
+ warn "If you do not wish to continue, you have 5 seconds to cancel by pressing CTRL-C..."
30
+ 5.times { |i| print "#{5-i} "; $stdout.flush; sleep 1 }
31
+ system %[svn copy #{svn_repo}/trunk #{svn_repo}/tags/REL_#{version} -m "Tagging the #{version} release"]
32
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Rails Plugin
2
+ require 'mofo'
data/lib/microformat.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  %w(rubygems hpricot microformat/string microformat/array open-uri ostruct timeout).each { |f| require f }
2
- gem 'hpricot', '>= 0.4.59'
2
+ gem 'hpricot', '>=0.4.59'
3
3
 
4
4
  class Microformat
5
5
  module Base
@@ -10,6 +10,8 @@ class Microformat
10
10
  target, @options = args
11
11
  @options ||= target.is_a?(Hash) ? target : {}
12
12
  [:first, :all].each { |key| target = @options[key] if @options[key] }
13
+
14
+ extract_base_url! target, @options
13
15
 
14
16
  @doc = build_doc(@options[:text] ? @options : target)
15
17
 
@@ -49,9 +51,16 @@ class Microformat
49
51
  ##
50
52
  # DSL Related
51
53
  #
54
+ def after_find(&block)
55
+ @after_find_procs ||= Hash.new { |h,k| h[k] = [] }
56
+ @after_find_procs[name] << block if block_given?
57
+ @after_find_procs[name]
58
+ end
59
+ alias :after_finds :after_find
60
+
52
61
  def inherited(klass)
53
- klass.instance_variable_set("@container", klass.name.downcase)
54
- klass.instance_variable_set("@attributes", Hash.new([]))
62
+ klass.instance_variable_set(:@container, klass.name.downcase)
63
+ klass.instance_variable_set(:@attributes, Hash.new([]))
55
64
  end
56
65
 
57
66
  def collector
@@ -119,14 +128,31 @@ class Microformat
119
128
  def build_class(microformat)
120
129
  hash = build_hash(microformat)
121
130
  class_eval { attr_reader *(hash.keys << :properties) }
131
+
122
132
  klass = new
123
- klass.instance_variable_set("@properties", hash.keys.map { |i| i.to_s } )
133
+ klass.instance_variable_set(:@properties, hash.keys.map { |i| i.to_s } )
134
+
124
135
  hash.each do |key, value|
125
136
  klass.instance_variable_set("@#{key}", prepare_value(value) )
126
137
  end
138
+
139
+ after_find_callbacks! klass
140
+
127
141
  klass
128
142
  end
129
143
 
144
+ def after_find_callbacks!(object)
145
+ original_ivars = object.instance_variables.dup
146
+
147
+ after_finds.each do |block|
148
+ object.instance_eval &block
149
+ end
150
+
151
+ Array(object.instance_variables - original_ivars).each do |ivar|
152
+ object.properties << ivar.gsub('@','')
153
+ end
154
+ end
155
+
130
156
  def build_hash(doc, attributes = @attributes)
131
157
  hash = {}
132
158
 
@@ -203,11 +229,12 @@ class Microformat
203
229
 
204
230
  def parse_element(element, target = nil)
205
231
  if target == :url
206
- case element.name
232
+ url = case element.name
207
233
  when 'img' then element['src']
208
234
  when 'a' then element['href']
209
235
  when 'object' then element['value']
210
236
  end
237
+ url[/^http/] ? url : @base_url.to_s + url
211
238
  elsif target.is_a? Array
212
239
  target.inject(nil) do |found, klass|
213
240
  klass = klass.respond_to?(:find) ? klass : nil
@@ -215,7 +242,7 @@ class Microformat
215
242
  found || parse_element(element, klass)
216
243
  end
217
244
  elsif target.is_a? Class
218
- target.find(:first => element)
245
+ target.find({:first => element}.merge(@options))
219
246
  else
220
247
  value = case element.name
221
248
  when 'abbr' then element['title']
@@ -229,6 +256,12 @@ class Microformat
229
256
  def prepare_value(value)
230
257
  value.is_a?(Hash) ? OpenStruct.new(value) : value
231
258
  end
259
+
260
+ def extract_base_url!(target, options)
261
+ @base_url = nil
262
+ @base_url ||= options[:base] || options[:url]
263
+ @base_url ||= target[/^(http:\/\/[^\/]+)/] if target.respond_to?(:scan)
264
+ end
232
265
  end
233
266
 
234
267
  def method_missing(method, *args, &block)
data/lib/mofo/hentry.rb CHANGED
@@ -8,4 +8,8 @@ class HEntry < Microformat
8
8
  :author => HCard, :tags => RelTag
9
9
 
10
10
  many :entry_content
11
+
12
+ after_find do
13
+ @updated = @published unless @updated if @published
14
+ end
11
15
  end
data/site/index.html ADDED
@@ -0,0 +1,382 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7
+
8
+ <title>mofo - a ruby microformat parser</title>
9
+ <link href="style.css" rel="stylesheet" type="text/css" />
10
+ <script type="text/javascript" src="mootools.v1.00.js"></script>
11
+ <script type="text/javascript">function sc(el) { new Fx.Scroll(window).toElement(el); }</script>
12
+ </head>
13
+
14
+ <body>
15
+ <div id="container">
16
+ <div id="header">
17
+ <img src="mofo-logo.png" alt="mofo!" />
18
+ <br /><hr />
19
+ </div>
20
+
21
+ <div id="left">
22
+ <h3>mofo</h3>
23
+
24
+ <ul class="xoxo">
25
+ <li><a href="#" onclick="sc('get_started')">Get Started</a></li>
26
+ <li><a href="#" onclick="sc('microwhozit')">Microwhozit?</a></li>
27
+ <li><a href="#" onclick="sc('find')">Mofo#find</a></li>
28
+ <li><a href="#" onclick="sc('supported')">Supported Microformats</a></li>
29
+ <li><a href="#" onclick="sc('rails')">Ruby on Rails</a></li>
30
+ <li><a href="#" onclick="sc('touch')">Get in Touch</a></li>
31
+ </ul>
32
+
33
+ <h3>Points of Interest</h3>
34
+
35
+ <ul class="xoxo">
36
+ <li><a href="http://errtheblog.com/post/37">Me and uFormats</a></li>
37
+ <li><a href="http://microformats.org">Microformats HQ</a></li>
38
+ <li><a href="http://microformatique.com">Microformatique</a></li>
39
+ <li><a href="http://labnotes.org">Assaf Arkin</a></li>
40
+ <li><a href="http://allinthehead.com">Drew McClellan</a></li>
41
+ <li><a href="http://tantek.com">Tantek Çelik</a></li>
42
+ <li><a href="http://theryanking.com/blog">Ryan King</a></li>
43
+ </ul>
44
+
45
+ <h3>Other Parsers</h3>
46
+
47
+ <ul class="xoxo">
48
+ <li><a href="http://rubyforge.org/projects/scrapi">Scrapi</a> [ruby]</li>
49
+ <li><a href="http://rubyforge.org/projects/uformats">uFormats</a> [ruby]</li>
50
+ <li><a href="http://allinthehead.com/hkit">hKit</a> [php]</li>
51
+ <li><a href="http://www.danwebb.net/2007/2/9/sumo-a-generic-microformats-parser-for-javascript">Sumo</a> [js]</li>
52
+ <li><a href="https://addons.mozilla.org/en-US/firefox/addon/4106">Operator</a> [firefox]</li>
53
+ </ul>
54
+ </div>
55
+
56
+ <div id="main">
57
+ <h3 id="get_started">Get Started Immediately</h3>
58
+ <br/>
59
+ <pre>
60
+ $ sudo gem install mofo -y
61
+ ... install mofo and hpricot dependency ...
62
+ $ irb -rubygems
63
+ &gt;&gt; require 'mofo'
64
+ =&gt; true
65
+ &gt;&gt; fireball = HCard.find 'http://flickr.com/people/gruber/'
66
+ =&gt; #&lt;HCard:0x6db898 ...&gt;
67
+ &gt;&gt; fireball.properties
68
+ =&gt; ["fn", "logo", "url", "n", "adr", "title", "nickname"]
69
+ &gt;&gt; fireball.nickname
70
+ =&gt; "gruber"
71
+ &gt;&gt; fireball.url
72
+ =&gt; "http://daringfireball.net/"
73
+ &gt;&gt; fireball.n.family_name
74
+ =&gt; "Gruber"
75
+ &gt;&gt; fireball.title
76
+ =&gt; "Raconteur"
77
+ &gt;&gt; fireball.adr.locality
78
+ =&gt; "Philadelphia"
79
+ &gt;&gt; fireball.logo
80
+ =&gt; "http://static.flickr.com/9/buddyicons/44621776@N00.jpg?1117572751"
81
+ </pre>
82
+
83
+ <h3 id="microwhozit">Microwhozit?</h3>
84
+
85
+ <p>
86
+ Microformats are tiny little markup definitions built on top of, usually,
87
+ HTML or XHTML.
88
+ </p>
89
+ <p>
90
+ You have a blog. You have recent posts on your blog's index page. You have
91
+ an Atom feed. You have recent posts on your blog's Atom feed. See where I'm
92
+ going with this?
93
+ </p>
94
+ <p>
95
+ The hAtom microformat (or uformat) can be embedded in your existing HTML by
96
+ setting CSS classes with semantic meaning inside of your posts. A class to signify
97
+ a post is contained within this div, a class to signify the contents of this
98
+ h3 are the post's title, a class to signify the contents of this span is the
99
+ blog post's author, etc.
100
+ </p>
101
+ <p>
102
+ You can then use a microformat parser (like, say, mofo) to extract this information
103
+ as you would from an Atom feed. Hell, you can even convert hAtom to Atom. It's an
104
+ insta-feed! No extra code required!
105
+ </p>
106
+ <p>
107
+ You're already doing the work, you see. Microformats are everywhere. We just need
108
+ to set them free.
109
+ </p>
110
+ <p>
111
+ Check it:</p>
112
+
113
+ <pre>
114
+ &lt;div class="post"&gt;
115
+ &lt;h3&gt;Megadeth Show Last Night&lt;/h3&gt;
116
+ &lt;span class="subtitle"&gt;Posted by Chris on June 4th&lt;/span&gt;
117
+ &lt;div class="content"&gt;Went to a show last night. Megadeth. It was alright.&lt;/div&gt;
118
+ &lt;/div&gt;
119
+ </pre>
120
+
121
+ <p>Right? Normal. Here's the same post marked up with hAtom:</p>
122
+
123
+ <pre>
124
+ &lt;div class="post <strong>hentry</strong>"&gt;
125
+ &lt;h3 class="<strong>entry-title</strong>"&gt;Megadeth Show Last Night&lt;/h3&gt;
126
+ &lt;span class="subtitle"&gt;Posted by &lt;span class="<strong>author vcard fn</strong>"&gt;Chris&lt;/span&gt; on
127
+ &lt;abbr class="<strong>updated</strong>" title="2006-06-04T10:32:10Z"&gt;June 4th&lt;/abbr&gt;&lt;/span&gt;
128
+ &lt;div class="content <strong>entry-content</strong>"&gt;
129
+ Went to a show last night. Megadeth. It was alright.
130
+ &lt;/div&gt;
131
+ &lt;/div&gt;
132
+ </pre>
133
+
134
+ <p>
135
+ All I did was add the hentry, entry-title, and entry-content classes to existing containers. Then I
136
+ went ahead and wrapped the date in an &lt;abbr&gt; tag giving it a title in the microformat-standard way. Finally
137
+ I put a div around Chris signifying it as the author field of the hEntry and making it a valid hCard by
138
+ including the vcard and fn classes. It's really not all that hard. Did I mess it up? Maybe, but I'm sure I got
139
+ close. And I didn't even use a reference. Practice.
140
+ </p>
141
+
142
+ <p>
143
+ How'd we parse this, tho?
144
+ </p>
145
+
146
+ <pre>
147
+ $ irb -rubygems
148
+ &gt;&gt; require 'mofo'
149
+ =&gt; true
150
+ &gt;&gt; post = HEntry.find 'http://milesofstyle.org/posts/351-megadeth-show-last-night'
151
+ =&gt; #&lt;HEntry:0x6db898 ... &gt;
152
+ &gt;&gt; post.entry_title
153
+ =&gt; "Megadeth Show Last Night"
154
+ &gt;&gt; post.properties
155
+ =&gt; ["entry_content", "updated", "author", "entry_title"]
156
+ &gt;&gt; post.updated
157
+ =&gt; Sun Jun 04 10:32:10 UTC 2006
158
+ &gt;&gt; post.updated.class
159
+ =&gt; Time
160
+ &gt;&gt; post.author
161
+ =&gt; #&lt;HCard:0x6e7b98 @properties=["fn"], @fn="Chris"&gt;
162
+ &gt;&gt; post.author.fn
163
+ =&gt; "Chris"
164
+ &gt;&gt; post.entry_content
165
+ =&gt; "Went to a show last night. Megadeth. It was alright."
166
+ </pre>
167
+ <p>
168
+ That's, like, stupid easy. If HEntry.find gets back more than one hEntry, you'll get an array.
169
+ </p>
170
+
171
+ <h3 id="find">Mofo#find</h3>
172
+
173
+ <p>Everything revolves around the #find method. Sound familiar? Yeah.</p>
174
+
175
+ <pre>
176
+ &gt;&gt; Microformat.find "http://valid-url.com"
177
+ &gt;&gt; Microformat.find "/path/to/existing/file"
178
+ &gt;&gt; Microformat.find :text =&gt; "microformat text"
179
+ </pre>
180
+
181
+ <p>
182
+ Also, #find can be told explicitly to find all (returning an array on failure) or only find
183
+ the first (returning nil on failure).
184
+ </p>
185
+
186
+ <pre>
187
+ &gt;&gt; Microformat.find :all =&gt; "/existing/file"
188
+ =&gt; [ array of microformat objects ]
189
+ &gt;&gt; Microformat.find :first =&gt; "/existing/file"
190
+ =&gt; microformat object
191
+ &gt;&gt; Microformat.find "/existing/file"
192
+ =&gt; either an array of objects or just one object
193
+ </pre>
194
+
195
+ <p>When parsing a string, use :all and :first go outside of :text.</p>
196
+
197
+ <pre>
198
+ &gt;&gt; Microformat.find :all =&gt; { :text =&gt; 'mfin text' }
199
+ </pre>
200
+
201
+ <p>
202
+ That's it.
203
+ </p>
204
+
205
+ <h3 id="supported">Supported Microformats</h3>
206
+
207
+ <p><strong>hCard</strong> - <a href="http://microformats.org/wiki/hcard">http://microformats.org/wiki/hcard</a></p>
208
+ <pre>
209
+ &gt;&gt; messina = HCard.find 'http://www.flickr.com/people/factoryjoe/'
210
+ =&gt; #&lt;HCard:0x125eb5c ...&gt;
211
+ &gt;&gt; messina.properties
212
+ =&gt; ["fn", "note", "logo", "url", "n", "adr", "title", "nickname"]
213
+ &gt;&gt; messina.title
214
+ =&gt; "Citizen Provocateur, Open Source Ambassador"
215
+ &gt;&gt; messina.logo
216
+ =&gt; "http://farm1.static.flickr.com/1/buddyicons/25419820@N00.jpg?1167346106"
217
+ &gt;&gt; messina.n
218
+ =&gt; #&lt;OpenStruct given_name="Chris", family_name="Messina"&gt;
219
+ &gt;&gt; messina.fn
220
+ =&gt; "Chris Messina"
221
+ &gt;&gt; messina.url
222
+ =&gt; "http://factoryjoe.com/blog"
223
+ &gt;&gt; messina.nickname
224
+ =&gt; "factoryjoe"
225
+ </pre>
226
+
227
+ <p><strong>hCalendar</strong> - <a href="http://microformats.org/wiki/hcalendar">http://microformats.org/wiki/hcalendar</a></p>
228
+ <pre>
229
+ &gt;&gt; events = HCalendar.find 'http://upcoming.org'
230
+ =&gt; [#&lt;HCalendar:0x131d304 ...&gt; ... ]
231
+ &gt;&gt; events.size
232
+ =&gt; 17
233
+ &gt;&gt; events.first.properties
234
+ =&gt; ["summary", "url", "location"]
235
+ &gt;&gt; events.first.location
236
+ =&gt; "Neumo&amp;#39;s, Seattle, WA"
237
+ &gt;&gt; events.first.summary
238
+ =&gt; "Ratatat + 120 Days"
239
+ </pre>
240
+
241
+ <p><strong>hReview</strong> - <a href="http://microformats.org/wiki/hreview">http://microformats.org/wiki/hreview</a></p>
242
+ <pre>
243
+ &gt;&gt; wine = HReview.find 'http://corkd.com/wine/view/1772'
244
+ =&gt; [#&lt;HReview:0x156c3f8 ...&gt; ...]
245
+ &gt;&gt; wine.size
246
+ =&gt; 7
247
+ &gt;&gt; wine.first.properties
248
+ =&gt; ["rating", "description", "item", "reviewer", "tags", "dtreviewed"]
249
+ &gt;&gt; wine.first.rating
250
+ =&gt; 3
251
+ &gt;&gt; wine.first.tags
252
+ =&gt; ["fresh", "lime", "pear"]
253
+ &gt;&gt; wine.first.dtreviewed
254
+ =&gt; Fri Jun 02 00:00:00 -0700 2006
255
+ </pre>
256
+
257
+ <p><strong>hEntry</strong> - <a href="http://microformats.org/wiki/hatom">http://microformats.org/wiki/hatom</a></p>
258
+ <pre>
259
+ &gt;&gt; post = HEntry.find 'http://errtheblog.com'
260
+ =&gt; #&lt;HEntry:0x169309c ...&gt;
261
+ &gt;&gt; post.properties
262
+ =&gt; ["published", "entry_title", "author", "entry_content", "bookmark", "tags"]
263
+ &gt;&gt; post.author.class
264
+ =&gt; HCard
265
+ &gt;&gt; post.author.fn
266
+ =&gt; "Chris"
267
+ &gt;&gt; post.published
268
+ =&gt; Mon Mar 26 09:21:00 UTC 2007
269
+ &gt;&gt; post.entry_content.length
270
+ =&gt; 4737
271
+ </pre>
272
+
273
+ <p><strong>hResume</strong> - <a href="http://microformats.org/wiki/hresume">http://microformats.org/wiki/hresume</a></p>
274
+ <pre>
275
+ &gt;&gt; crunch = HResume.find 'http://www.linkedin.com/in/michaelarrington'
276
+ =&gt; #&lt;HResume:0x129d370 ...&gt;
277
+ &gt;&gt; crunch.properties
278
+ =&gt; ["summary", "education", "experience", "contact"]
279
+ &gt;&gt; crunch.experience.first.class
280
+ =&gt; HCalendar
281
+ &gt;&gt; crunch.contact
282
+ =&gt; #&lt;HCard:0x36614 ...&gt;
283
+ &gt;&gt; crunch.contact.title
284
+ =&gt; "Editor - TechCrunch"
285
+ </pre>
286
+
287
+ <p><strong>XOXO</strong> - <a href="http://microformats.org/wiki/xoxo">http://microformats.org/wiki/xoxo</a></p>
288
+ <pre>
289
+ &gt;&gt; mofo = XOXO.find 'http://mofo.rubyforge.org', :class =&gt; true
290
+ =&gt; [["Get Started", "Microwhozit?", "Mofo#find", ...]
291
+ &gt;&gt; mofo.first
292
+ =&gt; ["Get Started", "Microwhozit?", "Mofo#find", "Supported Microformats", ...]
293
+ &gt;&gt; mofo[1]
294
+ =&gt; ["Me and uFormats", "Microformats HQ", "Microformatique", "Assaf Arkin", ...]
295
+ &gt;&gt; mofo[1].first
296
+ =&gt; "Me and uFormats"
297
+ &gt;&gt; mofo[1].first.class
298
+ =&gt; XOXO::Label
299
+ &gt;&gt; mofo[1].first.url
300
+ =&gt; "http://errtheblog.com/post/37"
301
+ </pre>
302
+
303
+ <p><strong>Geo</strong> - <a href="http://microformats.org/wiki/geo">http://microformats.org/wiki/geo</a></p>
304
+ <pre>
305
+ &gt;&gt; somewhere = Geo.find 'http://www.geograph.org.uk/photo/1234'
306
+ =&gt; #&lt;Geo:0x12337a4 ...&gt;
307
+ &gt;&gt; somewhere.latitude
308
+ =&gt; 54.05836
309
+ &gt;&gt; somewhere.longitude
310
+ =&gt; -2.14662
311
+ </pre>
312
+
313
+ <p><strong>Adr</strong> - <a href="http://microformats.org/wiki/adr">http://microformats.org/wiki/adr</a></p>
314
+ <pre>
315
+ ...coming soon...
316
+ </pre>
317
+
318
+ <p><strong>XFN</strong> - <a href="http://microformats.org/wiki/xfn">http://microformats.org/wiki/xfn</a></p>
319
+ <pre>
320
+ &gt;&gt; tons = XFN.find 'http://deliciouslymeta.com/projects/xfn/test_data.html'
321
+ =&gt; #&lt;XFN:0x157f200 ...&gt;
322
+ &gt;&gt; tons.first
323
+ =&gt; #&lt;XFN::Link name="friend - contact", relation="contact", link="#contact"&gt;
324
+ &gt;&gt; tons.me_and_parent
325
+ =&gt; #&lt;XFN::Link name="me + parent", relation=["me", "parent"], link="#parent"&gt;
326
+ &gt;&gt; tons.me_and_parent.name
327
+ =&gt; "me + parent
328
+ &gt;&gt; tons.neighbor
329
+ =&gt; [#&lt;XFN::Link ...&gt; ...]
330
+ &gt;&gt; tons.neighbor.size
331
+ =&gt; 5
332
+ &gt;&gt; tons.parent_and_kin.link
333
+ =&gt; "#parent"
334
+ </pre>
335
+
336
+
337
+ <h3 id="rails">Ruby on Rails</h3>
338
+
339
+ <p>
340
+ mofo doubles as a Rails plugin. Just drop it into vendor/plugins and you are good to go, with all the
341
+ available microformat parsers loaded into your application.
342
+
343
+ mofo classes are YAML and Marshal approved, meaning you can cache them with memcached (or DRb) or store
344
+ them in a session.
345
+ </p>
346
+
347
+ <p>
348
+ Install with <a href="http://www.rubyinside.com/advent2006/12-piston.html">Piston</a>:
349
+ </p>
350
+
351
+ <pre>
352
+ $ piston import svn://errtheblog.com/svn/mofo/trunk vendor/plugins/mofo
353
+ </pre>
354
+
355
+ <p>
356
+ Install with SVN:
357
+ </p>
358
+
359
+ <pre>
360
+ $ ./script/plugin install -x svn://errtheblog.com/svn/mofo/trunk
361
+ </pre>
362
+
363
+ <h3 id="touch">Get in Touch</h3>
364
+
365
+ <ul>
366
+ <li>Me: chris[at]ozmm[dot]org (chris wanstrath)</li>
367
+ <li>Trac: <a href="http://require.errtheblog.com/mofo/browser">http://require.errtheblog.com/mofo/browser</a></li>
368
+ <li>SVN: svn://errtheblog.com/svn/mofo/trunk</li>
369
+ </ul>
370
+ </div>
371
+
372
+ <div id="footer">
373
+ <hr />
374
+ <p class="left">| <a href="http://jigsaw.w3.org/css-validator/">CSS</a> | <a href="http://validator.w3.org/check?uri=referer">XHTML 1.1</a> |</p>
375
+ <p class="right">Designed by <a href="mailto:support@syndicateme.net">syndicateme.net</a>. Hosted by <a href="http://rubyforge.org">Rubyforge</a>. Birthed by <a href="http://errtheblog.com">Err</a>.</p>
376
+ <p>&nbsp;</p>
377
+ </div>
378
+ </div>
379
+ <script src="http://static.getclicky.com/4581.js" type="text/javascript"></script>
380
+ <noscript><p><img alt="Clicky" src="http://static.getclicky.com/4581ns.gif" /></p></noscript>
381
+ </body>
382
+ </html>