microformats 0.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +75 -23
- data/Rakefile +14 -2
- data/lib/address.rb +79 -14
- data/lib/calendar.rb +40 -0
- data/lib/event.rb +156 -0
- data/lib/formatting_helpers.rb +57 -0
- data/lib/helpers.rb +68 -15
- data/lib/microformats.rb +5 -0
- data/lib/vcard.rb +140 -33
- metadata +7 -8
- data/spec/address_spec.rb +0 -57
- data/spec/helpers_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -1
- data/spec/vcard_spec.rb +0 -110
data/README.rdoc
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
=
|
1
|
+
= Microformats
|
2
|
+
|
3
|
+
<b>STILL IN DEVELOPMENT, IT SHOULD WORK, BUT USE AT YOUR OWN RISK!</b>
|
2
4
|
|
3
5
|
<em>Created by Chris Powers, September 11, 2010</em>
|
4
6
|
|
@@ -11,7 +13,7 @@ the new HTML5 Microdata standard.
|
|
11
13
|
|
12
14
|
By using microformats, you are opening your data up to Google
|
13
15
|
and other consumers for easy and intelligent consumption. In
|
14
|
-
the future, Google plans on
|
16
|
+
the future, Google plans on making consumed microdata
|
15
17
|
directly searchable, which yields all sorts of new potential
|
16
18
|
for relevant results.
|
17
19
|
|
@@ -21,27 +23,33 @@ Install the Microformats gem as usual:
|
|
21
23
|
|
22
24
|
gem install microformats
|
23
25
|
|
24
|
-
==
|
26
|
+
== Getting Started
|
27
|
+
|
28
|
+
To use Microformats, first include the Microformats::Helper
|
29
|
+
mixin into your view layer, like this in Rails:
|
30
|
+
|
31
|
+
# in app/helpers/application_helper.rb
|
32
|
+
module Application Helper
|
33
|
+
include Microformats::Helpers
|
34
|
+
end
|
35
|
+
|
36
|
+
== Usage: vCards and Addresses
|
25
37
|
|
26
38
|
You can easily markup a person and/or organization using the
|
27
|
-
|
28
|
-
and the http://www.data-vocabulary.org/Person
|
39
|
+
<tt>vcard</tt> helper method. This will use both the hCard Microformat
|
40
|
+
and the http://www.data-vocabulary.org/Person microdata.
|
29
41
|
|
30
|
-
<
|
42
|
+
<b>PLEASE NOTE:</b> These two microdata standards do
|
31
43
|
not support the same fields. For example, hCard gives a person
|
32
44
|
telephone numbers and email addresses. The Person microdata only
|
33
|
-
gives organizations a single telephone number and has no
|
34
|
-
|
35
|
-
from hCard.
|
45
|
+
gives organizations a single telephone number and has no support
|
46
|
+
for email.
|
36
47
|
|
37
|
-
|
38
|
-
|
48
|
+
vCards can embed addresses using the Microformats::Vcard#address
|
49
|
+
method, which gives you a block to run with a new
|
50
|
+
Microformats::Address object.
|
39
51
|
|
40
|
-
|
41
|
-
include Microformats::Helpers
|
42
|
-
end
|
43
|
-
|
44
|
-
Then, you can do something like this in your view (using ERB here):
|
52
|
+
EXAMPLE (using ERB):
|
45
53
|
|
46
54
|
<% vcard do |card| %>
|
47
55
|
<%= card.photo "/images/me.jpg", :size => '200x300' %>
|
@@ -52,7 +60,7 @@ Then, you can do something like this in your view (using ERB here):
|
|
52
60
|
<%= card.email "me@mydomain.com", :type => 'Home' %>
|
53
61
|
|
54
62
|
I work at <%= card.company "Acme Co." %>
|
55
|
-
<%
|
63
|
+
<% card.address(:type => 'Work') do |adr| %>
|
56
64
|
<%= adr.street "123 Main" %>
|
57
65
|
<%= adr.city "Chicago" %>, <%= adr.state 'IL' %> <%= adr.zip '60010' %>
|
58
66
|
<% end %>
|
@@ -62,16 +70,16 @@ Then, you can do something like this in your view (using ERB here):
|
|
62
70
|
This will output the following markup:
|
63
71
|
|
64
72
|
<div class='vcard' itemscope='itemscope' itemtype='http://data-vocabulary.org/Person'>
|
65
|
-
<img itemprop='photo' src='/images/me.jpg' width='200' height='300' />
|
73
|
+
<img class='photo' itemprop='photo' src='/images/me.jpg' width='200' height='300' />
|
66
74
|
<span class='fn' itemprop='name'>John Doe</span>
|
67
75
|
<a class='url' href='http://mydomain.com' itemprop='url'>Visit my Site</a>
|
68
|
-
<span class='tel'><span class='type'
|
69
|
-
<span class='tel'><span class='type'
|
70
|
-
<
|
76
|
+
<span class='tel'><span class='type'><span class='value-title' title='Home'></span></span>999.888.7766</span>
|
77
|
+
<span class='tel'><span class='type'><span class='value-title' title='Work'></span></span> 111.222.3344</span>
|
78
|
+
<a class='email' href='mailto:me@mydomain.com'><span class='value-title' title='Home'></span>me@mydomain.com</span>
|
71
79
|
|
72
80
|
I work at <span class='org' itemprop='affiliation'>Acme Co.</span>
|
73
81
|
<div class='adr' itemscope='itemscope' itemtype='http://data-vocabulary.org/Address'>
|
74
|
-
<span class='type'
|
82
|
+
<span class='type'><span class='value-title' title='Work'></span></span>
|
75
83
|
<span class='street-address' itemprop='street-address'>123 Main</span>
|
76
84
|
<span class='locality' itemprop='locality'>Chicago</span>, <span class='region' itemprop='region'>IL</span> <span class='postal-code' itemprop='postal-code'>60010</span>
|
77
85
|
</div>
|
@@ -81,7 +89,7 @@ This will output the following markup:
|
|
81
89
|
While these helper methods default to using <span> tags
|
82
90
|
(and <a> tags as appropriate), you can easily customize
|
83
91
|
the tag used for any given piece of microdata by using the
|
84
|
-
<tt>:tag</tt>
|
92
|
+
<tt>:tag</tt> option:
|
85
93
|
|
86
94
|
<%= card.name "John Doe", :tag => :h1 %>
|
87
95
|
|
@@ -93,3 +101,47 @@ currently on, so this is a quick way to do this in Rails:
|
|
93
101
|
|
94
102
|
<%= card.download_link request.request_uri %>
|
95
103
|
|
104
|
+
== Usage: Calendars and Events
|
105
|
+
|
106
|
+
Calendars with many events can be represented using the
|
107
|
+
Microformats::Calendar and Microformats::Event classes.
|
108
|
+
This employs the hCal and hEvent microformats along with the
|
109
|
+
http://www.data-vocabulary.org/Event microdata.
|
110
|
+
|
111
|
+
<b>NOTE:</b> An Event can use a nested vCard to represent
|
112
|
+
its location information.
|
113
|
+
|
114
|
+
EXAMPLE:
|
115
|
+
|
116
|
+
<% vcalendar :id => "my_calendar" do |cal| %>
|
117
|
+
<h1>Upcoming Events</h1>
|
118
|
+
<% cal.event do |event| %>
|
119
|
+
<h2><%= event.url(event.name("Happy Hour"), :href => "http://meetup.com/happyhour") %></h2>
|
120
|
+
<%= event.photo "/images/happy_hour.jpg", :size => "250x150" %>
|
121
|
+
<%= event.description "Come hang out with us for half price drinks at lots of fun!" %>
|
122
|
+
<span class='time_range'>
|
123
|
+
From <%= event.starts_at "October 30, 2010 at 7:30PM" %> -
|
124
|
+
<%= event.ends_at "October 30, 2010 at 10:00PM", :text => "10:00PM" %>
|
125
|
+
</span>
|
126
|
+
<% event.location do |card| %>
|
127
|
+
<%= card.url(card.company("Frank's Bar", :is_company => true), :href => "http://franksbar.com") %>
|
128
|
+
<% card.address do |adr| %>
|
129
|
+
<%= adr.street "784 N Main St" %><br />
|
130
|
+
<%= adr.city "Chicago" %>, <%= adr.state "IL" %> <%= adr.zip "60016" %>
|
131
|
+
<% end %>
|
132
|
+
<% end %>
|
133
|
+
<% end %>
|
134
|
+
<!-- More events could be added... -->
|
135
|
+
<% end %>
|
136
|
+
|
137
|
+
== Resources
|
138
|
+
|
139
|
+
* http://www.data-vocabulary.org
|
140
|
+
* http://microformats.org
|
141
|
+
|
142
|
+
== Care to Help?
|
143
|
+
|
144
|
+
There are still a lot of standards that need to be implemented into
|
145
|
+
this library, including but not limited to: Events, Products, Reviews,
|
146
|
+
Organizations. I will continue to work on these, but I'd be happy to
|
147
|
+
accept pull requests!
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
-
|
3
|
+
require 'rake/rdoctask'
|
4
4
|
# require 'rake/gempackagetask'
|
5
5
|
# require 'rcov/rcovtask'
|
6
6
|
# require 'date'
|
@@ -12,4 +12,16 @@ task :default => :spec
|
|
12
12
|
|
13
13
|
Spec::Rake::SpecTask.new do |t|
|
14
14
|
t.warning = true
|
15
|
-
end
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace :doc do
|
18
|
+
desc "Generate documentation for the gem."
|
19
|
+
Rake::RDocTask.new("gem") { |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'doc'
|
21
|
+
rdoc.title = "Microformats"
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.options << '--charset' << 'utf-8'
|
24
|
+
rdoc.rdoc_files.include('README.rdoc')
|
25
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
26
|
+
}
|
27
|
+
end
|
data/lib/address.rb
CHANGED
@@ -1,32 +1,97 @@
|
|
1
1
|
class Microformats::Address
|
2
|
+
include Microformats::FormattingHelpers
|
3
|
+
|
4
|
+
def initialize(template)
|
5
|
+
@template = template
|
6
|
+
@default_tag = :span
|
7
|
+
end
|
8
|
+
|
9
|
+
# You can directly initialize and run this class, but it's easier
|
10
|
+
# to use the Microformats::Helpers#vaddress helper method or the
|
11
|
+
# Microformats::Vcard#address method.
|
12
|
+
#
|
13
|
+
# OPTIONS:
|
14
|
+
# * :type - A string that specifies the type of address('home', 'work', etc)
|
15
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
16
|
+
# * Any other passed options will be treated as HTML attributes.
|
17
|
+
#
|
18
|
+
def run(opts = {}, &block)
|
19
|
+
type = opts[:type] ? self.type(opts.delete(:type)) : nil
|
20
|
+
opts[:class] = combine_class_names('adr', opts[:class])
|
21
|
+
opts[:itemscope] = 'itemscope'
|
22
|
+
opts[:itemtype] = 'http://data-vocabulary.org/Address'
|
23
|
+
opts[:tag] ||= :div
|
24
|
+
concat_tag(opts) do
|
25
|
+
concat type if type
|
26
|
+
block.call(self)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Outputs markup for the type of address ('work', 'home', etc.)
|
31
|
+
# There will be no visible text unless provided with the :text option.
|
32
|
+
#
|
33
|
+
# <em>NOTE: You get this for free with the :type option of
|
34
|
+
# Microformats::Helpers#vaddress, Microformats::Vcard#address and #run methods.</em>
|
35
|
+
#
|
36
|
+
# OPTIONS
|
37
|
+
# * :text - String, the text you want displayed as a text node (default is '')
|
38
|
+
# * Any other passed options will be treated as HTML attributes.
|
39
|
+
#
|
40
|
+
def type(str, opts = {})
|
41
|
+
inner = content_tag('', :class => 'value-title', :title => str)
|
42
|
+
text = opts.delete(:text) || ''
|
43
|
+
content_tag(inner + text, merge_html_attrs({:class => 'type'}, opts))
|
44
|
+
end
|
45
|
+
|
46
|
+
# Outputs the passed string as a street address.
|
47
|
+
#
|
48
|
+
# OPTIONS
|
49
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
50
|
+
# * Any other passed options will be treated as HTML attributes.
|
51
|
+
#
|
2
52
|
def street(str, opts = {})
|
3
|
-
content_tag(
|
53
|
+
content_tag(str, merge_html_attrs({:class => 'street-address', :itemprop => 'street-address'}, opts))
|
4
54
|
end
|
5
55
|
|
56
|
+
# Outputs the passed string as a city.
|
57
|
+
#
|
58
|
+
# OPTIONS
|
59
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
60
|
+
# * Any other passed options will be treated as HTML attributes.
|
61
|
+
#
|
6
62
|
def city(str, opts = {})
|
7
|
-
content_tag(
|
63
|
+
content_tag(str, merge_html_attrs({:class => 'locality', :itemprop => 'locality'}, opts))
|
8
64
|
end
|
9
65
|
|
66
|
+
# Outputs the passed string as a state.
|
67
|
+
#
|
68
|
+
# OPTIONS
|
69
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
70
|
+
# * Any other passed options will be treated as HTML attributes.
|
71
|
+
#
|
10
72
|
def state(str, opts = {})
|
11
|
-
content_tag(
|
73
|
+
content_tag(str, merge_html_attrs({:class => 'region', :itemprop => 'region'}, opts))
|
12
74
|
end
|
13
75
|
|
76
|
+
# Outputs the passed string as a postal code.
|
77
|
+
#
|
78
|
+
# OPTIONS
|
79
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
80
|
+
# * Any other passed options will be treated as HTML attributes.
|
81
|
+
#
|
14
82
|
def zip(str, opts = {})
|
15
|
-
content_tag(
|
83
|
+
content_tag(str, merge_html_attrs({:class => 'postal-code', :itemprop => 'postal-code'}, opts))
|
16
84
|
end
|
17
85
|
alias_method :postal_code, :zip
|
18
86
|
|
87
|
+
# Outputs the passed string as a country.
|
88
|
+
#
|
89
|
+
# OPTIONS
|
90
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
91
|
+
# * Any other passed options will be treated as HTML attributes.
|
92
|
+
#
|
19
93
|
def country(str, opts = {})
|
20
|
-
content_tag(
|
94
|
+
content_tag(str, merge_html_attrs({:class => 'country-name', :itemprop => 'country-name'}, opts))
|
21
95
|
end
|
22
96
|
|
23
|
-
def content_tag(tag, content, opts={})
|
24
|
-
attrs = opts.inject([]) do |out, tuple|
|
25
|
-
k,v = tuple
|
26
|
-
out << "#{k}='#{v}'"
|
27
|
-
end
|
28
|
-
attr_string = attrs.sort.join(' ')
|
29
|
-
open_tag = attr_string == '' ? tag : "#{tag} #{attr_string}"
|
30
|
-
"<#{open_tag}>#{content}</#{tag}>"
|
31
|
-
end
|
32
97
|
end
|
data/lib/calendar.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
class Microformats::Calendar
|
2
|
+
include Microformats::FormattingHelpers
|
3
|
+
|
4
|
+
def initialize(template)
|
5
|
+
@template = template
|
6
|
+
@default_tag = :span
|
7
|
+
end
|
8
|
+
|
9
|
+
# You can directly initialize and run this class, but it's easier
|
10
|
+
# to use the Microformats::Helpers#vcalendar helper method.
|
11
|
+
#
|
12
|
+
# OPTIONS:
|
13
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
14
|
+
# * Any other passed options will be treated as HTML attributes.
|
15
|
+
#
|
16
|
+
def run(opts = {}, &block)
|
17
|
+
opts[:class] = combine_class_names('vcalendar', opts[:class])
|
18
|
+
opts[:tag] ||= :div
|
19
|
+
concat_tag(opts) do
|
20
|
+
block.call(self)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Creates a vEvent with the given options and a block.
|
25
|
+
#
|
26
|
+
# OPTIONS:
|
27
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
28
|
+
# * Any other passed options will be treated as HTML attributes.
|
29
|
+
#
|
30
|
+
# EXAMPLE:
|
31
|
+
# <% calendar.event :id => 'my_event' do |event| %>
|
32
|
+
# This event is called <%= event.name "Cool Event" %>.
|
33
|
+
# <% end %>
|
34
|
+
#
|
35
|
+
def event(opts = {}, &block)
|
36
|
+
ev = Microformats::Event.new(@template)
|
37
|
+
opts[:class] = combine_class_names('vevent', opts[:class])
|
38
|
+
ev.run(opts, &block)
|
39
|
+
end
|
40
|
+
end
|
data/lib/event.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
class Microformats::Event
|
2
|
+
include Microformats::FormattingHelpers
|
3
|
+
|
4
|
+
def initialize(template)
|
5
|
+
@template = template
|
6
|
+
@default_tag = :span
|
7
|
+
end
|
8
|
+
|
9
|
+
# You can directly initialize and run this class, but it's easier
|
10
|
+
# to use the Microformats::Helpers#vevent helper method or the
|
11
|
+
# Microformats::Calendar#event method.
|
12
|
+
#
|
13
|
+
# OPTIONS:
|
14
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
15
|
+
# * Any other passed options will be treated as HTML attributes.
|
16
|
+
#
|
17
|
+
def run(opts = {}, &block)
|
18
|
+
opts[:class] = combine_class_names('vevent', opts[:class])
|
19
|
+
opts[:itemscope] = 'itemscope'
|
20
|
+
opts[:itemtype] = 'http://data-vocabulary.org/Event'
|
21
|
+
opts[:tag] ||= :div
|
22
|
+
concat_tag(opts) do
|
23
|
+
block.call(self)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Marks up an event's name.
|
28
|
+
#
|
29
|
+
# OPTIONS:
|
30
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
31
|
+
# * Any other passed options will be treated as HTML attributes.
|
32
|
+
#
|
33
|
+
def name(str, opts={})
|
34
|
+
content_tag(str, merge_html_attrs({:itemprop => 'summary', :class => 'summary'}, opts))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Marks up the event's URL. By default, it will output an <a> tag using
|
38
|
+
# the passed in string as both the href and the text. If the :href option
|
39
|
+
# is passed, then the string argument is treated as text.
|
40
|
+
#
|
41
|
+
# OPTIONS:
|
42
|
+
# * :href - If passed, the string argument will be treated as the text node.
|
43
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
44
|
+
# * Any other passed options will be treated as HTML attributes.
|
45
|
+
#
|
46
|
+
# EXAMPLES:
|
47
|
+
# event.url('http://google.com') #=> <a class='url' href='http://google.com' itemprop='url'>http://google.com</a>
|
48
|
+
# event.url('Google', :href => 'http://google.com') #=> <a class='url' href='http://google.com' itemprop='url'>Google</a>
|
49
|
+
# event.url('http://google.com', :tag => :span) #=> <span class='url' itemprop='url'>http://google.com</span>
|
50
|
+
#
|
51
|
+
def url(str, opts = {})
|
52
|
+
if opts[:href]
|
53
|
+
content_tag(str, merge_html_attrs({:tag => :a, :class => 'url', :itemprop => 'url'}, opts))
|
54
|
+
elsif opts[:tag]
|
55
|
+
content_tag(str, merge_html_attrs({:class => 'url', :itemprop => 'url'}, opts))
|
56
|
+
else
|
57
|
+
content_tag(str, merge_html_attrs({:tag => :a, :class => 'url', :href => str, :itemprop => 'url'}, opts))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Marks up the event photo as an <img> tag. Takes the image URL as the first argument.
|
62
|
+
#
|
63
|
+
# OPTIONS
|
64
|
+
# * :size - Pass a string with WIDTHxHEIGHT like "200x100" in lieu of the :width and :height options.
|
65
|
+
# * Any other passed options will be treated as HTML attributes.
|
66
|
+
#
|
67
|
+
def photo(str, opts = {})
|
68
|
+
if size = opts.delete(:size)
|
69
|
+
opts[:width], opts[:height] = size.split('x')
|
70
|
+
end
|
71
|
+
content_tag(nil, merge_html_attrs({:tag => :img, :class => 'photo', :itemprop => 'photo', :src => str}, opts))
|
72
|
+
end
|
73
|
+
|
74
|
+
# Marks up an event's description.
|
75
|
+
#
|
76
|
+
# OPTIONS:
|
77
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
78
|
+
# * Any other passed options will be treated as HTML attributes.
|
79
|
+
#
|
80
|
+
def description(str, opts={})
|
81
|
+
content_tag(str, merge_html_attrs({:itemprop => 'description', :class => 'description'}, opts))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Marks up the event's start time/date. Accepts either a Time object
|
85
|
+
# or a time String as the first argument. By default, the text node
|
86
|
+
# will be the date and time output like "Oct 20, 2010 at 7:30PM", but
|
87
|
+
# this can be overridden by the :text option.
|
88
|
+
#
|
89
|
+
# OPTIONS:
|
90
|
+
# * :text - String, will be displayed as the text node.
|
91
|
+
# * Any other passed options will be treated as HTML attributes.
|
92
|
+
#
|
93
|
+
def starts_at(time_or_str, opts={})
|
94
|
+
if time_or_str.is_a?(String)
|
95
|
+
time = Time.parse(time_or_str)
|
96
|
+
encoded_time = encode_time(time)
|
97
|
+
humanized_time = opts.delete(:text) || time_or_str
|
98
|
+
else
|
99
|
+
encoded_time = encode_time(time_or_str)
|
100
|
+
humanized_time = opts.delete(:text) || humanize_time(time_or_str)
|
101
|
+
end
|
102
|
+
inner_span = content_tag('', :class => 'value-title', :title => encoded_time)
|
103
|
+
content_tag(inner_span + humanized_time, merge_html_attrs({:tag => :time, :itemprop => 'startDate', :class => 'dtstart', :datetime => encoded_time}, opts))
|
104
|
+
end
|
105
|
+
|
106
|
+
# Marks up the event's end time/date. Accepts either a Time object
|
107
|
+
# or a time String as the first argument. By default, the text node
|
108
|
+
# will be the date and time output like "Oct 20, 2010 at 7:30PM", but
|
109
|
+
# this can be overridden by the :text option.
|
110
|
+
#
|
111
|
+
# OPTIONS:
|
112
|
+
# * :text - String, will be displayed as the text node.
|
113
|
+
# * Any other passed options will be treated as HTML attributes.
|
114
|
+
#
|
115
|
+
def ends_at(time_or_str, opts={})
|
116
|
+
if time_or_str.is_a?(String)
|
117
|
+
time = Time.parse(time_or_str)
|
118
|
+
encoded_time = encode_time(time)
|
119
|
+
humanized_time = opts.delete(:text) || time_or_str
|
120
|
+
else
|
121
|
+
encoded_time = encode_time(time_or_str)
|
122
|
+
humanized_time = opts.delete(:text) || humanize_time(time_or_str)
|
123
|
+
end
|
124
|
+
inner_span = content_tag('', :class => 'value-title', :title => encoded_time)
|
125
|
+
content_tag(inner_span + humanized_time, merge_html_attrs({:tag => :time, :itemprop => 'endDate', :class => 'dtend', :datetime => encoded_time}, opts))
|
126
|
+
end
|
127
|
+
|
128
|
+
# Marks up an event's category name.
|
129
|
+
#
|
130
|
+
# OPTIONS:
|
131
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
132
|
+
# * Any other passed options will be treated as HTML attributes.
|
133
|
+
#
|
134
|
+
def category(str, opts = {})
|
135
|
+
content_tag(str, merge_html_attrs({:itemprop => 'eventType', :class => 'category'}, opts))
|
136
|
+
end
|
137
|
+
|
138
|
+
# Creates a vCard with the given options and a block to represent
|
139
|
+
# the event's location.
|
140
|
+
#
|
141
|
+
# OPTIONS:
|
142
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
143
|
+
# * Any other passed options will be treated as HTML attributes.
|
144
|
+
#
|
145
|
+
# EXAMPLE:
|
146
|
+
# <% event.location :id => 'my_location' do |card| %>
|
147
|
+
# We will be meeting at the <%= card.company "Obtiva" %> office.
|
148
|
+
# <% end %>
|
149
|
+
#
|
150
|
+
def location(opts = {}, &block)
|
151
|
+
card = Microformats::Vcard.new(@template)
|
152
|
+
opts[:class] = combine_class_names('location', opts[:class])
|
153
|
+
card.run(opts, &block)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# These are all internal methods used for formatting, no need
|
2
|
+
# to use any of them explicitly.
|
3
|
+
#
|
4
|
+
module Microformats::FormattingHelpers # :nodoc:
|
5
|
+
def content_tag(content, opts={}) # :nodoc:
|
6
|
+
tag = opts.delete(:tag) || @default_tag
|
7
|
+
attrs = opts.inject([]) do |out, tuple|
|
8
|
+
k,v = tuple
|
9
|
+
out << "#{k}='#{v}'" if v
|
10
|
+
out
|
11
|
+
end
|
12
|
+
attr_string = attrs.sort.join(' ')
|
13
|
+
open_tag = attr_string == '' ? tag : "#{tag} #{attr_string}"
|
14
|
+
if [:img].include?(tag)
|
15
|
+
"<#{open_tag} />"
|
16
|
+
else
|
17
|
+
"<#{open_tag}>#{content}</#{tag}>"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def concat_tag(opts={}) # :nodoc:
|
22
|
+
tag = opts.delete(:tag) || @default_tag
|
23
|
+
attrs = opts.inject([]) do |out, tuple|
|
24
|
+
k,v = tuple
|
25
|
+
out << "#{k}='#{v}'"
|
26
|
+
end
|
27
|
+
attr_string = attrs.sort.join(' ')
|
28
|
+
open_tag = attr_string == '' ? tag : "#{tag} #{attr_string}"
|
29
|
+
concat "<#{open_tag}>\n"
|
30
|
+
yield
|
31
|
+
concat "</#{tag}>\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
def merge_html_attrs(base_attrs, overriding_attrs) # :nodoc:
|
35
|
+
classes = combine_class_names(base_attrs.delete(:class), overriding_attrs.delete(:class))
|
36
|
+
attrs = base_attrs.merge(overriding_attrs)
|
37
|
+
attrs[:class] = classes unless classes == ''
|
38
|
+
attrs
|
39
|
+
end
|
40
|
+
|
41
|
+
def concat(str) # :nodoc:
|
42
|
+
@template.concat(str)
|
43
|
+
end
|
44
|
+
|
45
|
+
def encode_time(t) # :nodoc:
|
46
|
+
t.strftime("%Y-%m-%dT%H:%M%z").gsub(/00$/, ":00")
|
47
|
+
end
|
48
|
+
|
49
|
+
def humanize_time(t) # :nodoc:
|
50
|
+
t.strftime("%b %d, %Y at %I:%M%p").gsub(/\s0/, ' ')
|
51
|
+
end
|
52
|
+
|
53
|
+
def combine_class_names(*classes) # :nodoc:
|
54
|
+
str = classes.flatten.compact.sort.join(' ').gsub(/\s+/, ' ')
|
55
|
+
(str =~ /\w/) ? str : nil
|
56
|
+
end
|
57
|
+
end
|
data/lib/helpers.rb
CHANGED
@@ -1,21 +1,74 @@
|
|
1
|
+
# Include this file into your view layer. For example, in Rails:
|
2
|
+
#
|
3
|
+
# module ApplicationHelper
|
4
|
+
# include Microformats::Helpers
|
5
|
+
# end
|
6
|
+
#
|
1
7
|
module Microformats::Helpers
|
2
|
-
#
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
# Creates a vCard with the given options and a block.
|
9
|
+
#
|
10
|
+
# OPTIONS:
|
11
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
12
|
+
# * Any other passed options will be treated as HTML attributes.
|
13
|
+
#
|
14
|
+
# EXAMPLE:
|
15
|
+
# <% vcard :id => 'my_vcard' do |card| %>
|
16
|
+
# Hello, my name is <%= card.name "Chris" %>!
|
17
|
+
# <% end %>
|
18
|
+
#
|
19
|
+
def vcard(opts = {}, &block)
|
20
|
+
card = Microformats::Vcard.new(self)
|
21
|
+
card.run(opts, &block)
|
8
22
|
end
|
9
23
|
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
24
|
+
# Creates a vAddress with the given options and a block.
|
25
|
+
#
|
26
|
+
# OPTIONS:
|
27
|
+
# * :type - A string that specifies the type of address('home', 'work', etc)
|
28
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
29
|
+
# * Any other passed options will be treated as HTML attributes.
|
30
|
+
#
|
31
|
+
# EXAMPLE:
|
32
|
+
# <% vaddress :type => 'work', :id => 'my_adr' do |adr| %>
|
33
|
+
# I live at <%= adr.street "123 Main St" %>.
|
34
|
+
# <% end %>
|
35
|
+
#
|
36
|
+
def vaddress(opts = {}, &block)
|
37
|
+
address = Microformats::Address.new(self)
|
38
|
+
address.run(opts, &block)
|
19
39
|
end
|
20
40
|
|
41
|
+
# Creates a vEvent with the given options and a block.
|
42
|
+
#
|
43
|
+
# OPTIONS:
|
44
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
45
|
+
# * Any other passed options will be treated as HTML attributes.
|
46
|
+
#
|
47
|
+
# EXAMPLE:
|
48
|
+
# <% vevent :id => 'my_event' do |event| %>
|
49
|
+
# This event is called <%= event.name "Cool Event" %>.
|
50
|
+
# <% end %>
|
51
|
+
#
|
52
|
+
def vevent(opts = {}, &block)
|
53
|
+
event = Microformats::Event.new(self)
|
54
|
+
event.run(opts, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates a vCalendar with the given options and a block.
|
58
|
+
#
|
59
|
+
# OPTIONS:
|
60
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
61
|
+
# * Any other passed options will be treated as HTML attributes.
|
62
|
+
#
|
63
|
+
# EXAMPLE:
|
64
|
+
# <% vcalendar :id => 'my_cal' do |cal| %>
|
65
|
+
# <% cal.event :id => 'my_event' do |event| %>
|
66
|
+
# This event is called <%= event.name "Cool Event" %>.
|
67
|
+
# <% end %>
|
68
|
+
# <% end %>
|
69
|
+
#
|
70
|
+
def vcalendar(opts = {}, &block)
|
71
|
+
cal = Microformats::Calendar.new(self)
|
72
|
+
cal.run(opts, &block)
|
73
|
+
end
|
21
74
|
end
|
data/lib/microformats.rb
CHANGED
data/lib/vcard.rb
CHANGED
@@ -1,70 +1,177 @@
|
|
1
1
|
class Microformats::Vcard
|
2
|
-
|
2
|
+
include Microformats::FormattingHelpers
|
3
|
+
|
4
|
+
# You can directly initialize and runthis class, but it's easier
|
5
|
+
# to use the Microformats::Helpers#vcard helper method.
|
6
|
+
def initialize(template)
|
7
|
+
@template = template
|
3
8
|
@default_tag = :span
|
4
9
|
end
|
5
10
|
|
11
|
+
# You can directly initialize and runthis class, but it's easier
|
12
|
+
# to use the Microformats::Helpers#vcard helper method.
|
13
|
+
#
|
14
|
+
# OPTIONS:
|
15
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
16
|
+
# * Any other passed options will be treated as HTML attributes.
|
17
|
+
#
|
18
|
+
def run(opts = {}, &block)
|
19
|
+
opts[:class] = combine_class_names('vcard', opts[:class])
|
20
|
+
opts[:itemscope] = 'itemscope'
|
21
|
+
opts[:itemtype] = 'http://data-vocabulary.org/Person'
|
22
|
+
opts[:tag] ||= :div
|
23
|
+
concat_tag(opts) do
|
24
|
+
block.call(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Marks up a person's name.
|
29
|
+
#
|
30
|
+
# OPTIONS:
|
31
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
32
|
+
# * Any other passed options will be treated as HTML attributes.
|
33
|
+
#
|
6
34
|
def name(str, opts = {})
|
7
|
-
content_tag(
|
35
|
+
content_tag(str, merge_html_attrs({:class => 'fn', :itemprop => 'name'}, opts))
|
8
36
|
end
|
9
37
|
|
38
|
+
# Marks up a company name. If this vCard represents a company
|
39
|
+
# rather than an individual person that works at a company, set
|
40
|
+
# the :is_company option to true.
|
41
|
+
#
|
42
|
+
# OPTIONS:
|
43
|
+
# * :is_company - Boolean, true if this is a company vCard (defaults to false)
|
44
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
45
|
+
# * Any other passed options will be treated as HTML attributes.
|
46
|
+
#
|
10
47
|
def company(str, opts = {})
|
11
|
-
|
48
|
+
classes = opts.delete(:is_company) ? 'fn org' : 'org'
|
49
|
+
content_tag(str, merge_html_attrs({:class => classes, :itemprop => 'affiliation'}, opts))
|
12
50
|
end
|
13
51
|
alias_method :organization, :company
|
14
52
|
|
53
|
+
# Marks up the person's URL. By default, it will output an <a> tag using
|
54
|
+
# the passed in string as both the href and the text. If the :href option
|
55
|
+
# is passed, then the string argument is treated as text.
|
56
|
+
#
|
57
|
+
# OPTIONS:
|
58
|
+
# * :href - If passed, the string argument will be treated as the text node.
|
59
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
60
|
+
# * Any other passed options will be treated as HTML attributes.
|
61
|
+
#
|
62
|
+
# EXAMPLES:
|
63
|
+
# card.url('http://google.com') #=> <a class='url' href='http://google.com' itemprop='url'>http://google.com</a>
|
64
|
+
# card.url('Google', :href => 'http://google.com') #=> <a class='url' href='http://google.com' itemprop='url'>Google</a>
|
65
|
+
# card.url('http://google.com', :tag => :span) #=> <span class='url' itemprop='url'>http://google.com</span>
|
66
|
+
#
|
15
67
|
def url(str, opts = {})
|
16
68
|
if opts[:href]
|
17
|
-
content_tag(
|
69
|
+
content_tag(str, merge_html_attrs({:tag => :a, :class => 'url', :itemprop => 'url'}, opts))
|
18
70
|
elsif opts[:tag]
|
19
|
-
content_tag(
|
71
|
+
content_tag(str, merge_html_attrs({:class => 'url', :itemprop => 'url'}, opts))
|
20
72
|
else
|
21
|
-
content_tag(:a,
|
73
|
+
content_tag(str, merge_html_attrs({:tag => :a, :class => 'url', :href => str, :itemprop => 'url'}, opts))
|
22
74
|
end
|
23
75
|
end
|
24
76
|
|
77
|
+
# Marks up the vCard photo as an <img> tag. Takes the image URL as the first argument.
|
78
|
+
#
|
79
|
+
# OPTIONS
|
80
|
+
# * :size - Pass a string with WIDTHxHEIGHT like "200x100" in lieu of the :width and :height options.
|
81
|
+
# * Any other passed options will be treated as HTML attributes.
|
82
|
+
#
|
25
83
|
def photo(str, opts = {})
|
26
|
-
|
84
|
+
if size = opts.delete(:size)
|
85
|
+
opts[:width], opts[:height] = size.split('x')
|
86
|
+
end
|
87
|
+
content_tag(nil, merge_html_attrs({:tag => :img, :class => 'photo', :itemprop => 'photo', :src => str}, opts))
|
27
88
|
end
|
28
89
|
|
90
|
+
# Marks up a phone number, takes the phone number as a string.
|
91
|
+
#
|
92
|
+
# OPTIONS
|
93
|
+
# * :type - A string that specifies the type of phone number ('home', 'work', etc)
|
94
|
+
# * :tag - The HTML wrapper element (defaults to :span)
|
95
|
+
# * Any other passed options will be treated as HTML attributes.
|
96
|
+
#
|
29
97
|
def phone(str, opts = {})
|
30
|
-
type =
|
31
|
-
|
98
|
+
type = if opts[:type].to_s != ''
|
99
|
+
type_inner_span = content_tag('', :class => 'value-title', :title => opts.delete(:type))
|
100
|
+
content_tag(type_inner_span, :class => 'type')
|
101
|
+
else
|
102
|
+
''
|
103
|
+
end
|
104
|
+
content_tag(type + str, merge_html_attrs({:class => 'tel'}, opts))
|
32
105
|
end
|
33
106
|
|
107
|
+
# Marks up an email address, takes the email as a string.
|
108
|
+
#
|
109
|
+
# OPTIONS
|
110
|
+
# * :type - A string that specifies the type of phone number ('home', 'work', etc)
|
111
|
+
# * :tag - The HTML wrapper element (defaults to :a)
|
112
|
+
# * Any other passed options will be treated as HTML attributes.
|
113
|
+
#
|
34
114
|
def email(str, opts = {})
|
35
|
-
|
115
|
+
opts[:tag] ||= :a
|
116
|
+
type = if opts[:type].to_s != ''
|
117
|
+
type_inner_span = content_tag('', :class => 'value-title', :title => opts.delete(:type))
|
118
|
+
content_tag(type_inner_span, :class => 'type')
|
119
|
+
else
|
120
|
+
''
|
121
|
+
end
|
36
122
|
if opts[:tag] == :a
|
37
|
-
content_tag(
|
123
|
+
content_tag(type + str, merge_html_attrs({:class => 'email', :href => "mailto:#{str}"}, opts))
|
38
124
|
else
|
39
|
-
content_tag(
|
125
|
+
content_tag(type + str, merge_html_attrs({:class => 'email'}, opts))
|
40
126
|
end
|
41
127
|
end
|
42
128
|
|
129
|
+
# Accepts latitude and longitude as arguments. It will only output a
|
130
|
+
# visible text node if you provide the :text option.
|
131
|
+
#
|
132
|
+
# OPTIONS
|
133
|
+
# * :text - String, the text will be be displayed inside the 'geo' wrapper
|
134
|
+
#
|
135
|
+
def coordinates(lat, lng, opts = {})
|
136
|
+
lat_meta = content_tag('', :tag => :meta, :itemprop => 'latitude', :content => lat)
|
137
|
+
lng_meta = content_tag('', :tag => :meta, :itemprop => 'longitude', :content => lng)
|
138
|
+
lat_span = content_tag(content_tag('', :class => 'value-title', :title => lat), :class => 'latitude')
|
139
|
+
lng_span = content_tag(content_tag('', :class => 'value-title', :title => lng), :class => 'longitude')
|
140
|
+
text = opts[:text] || ''
|
141
|
+
content_tag(lat_meta + lng_meta + lat_span + lng_span + text, :class => 'geo', :itemprop => 'geo', :itemscope => 'itemscope', :itemtype => 'http://data-vocabulary.org/Geo')
|
142
|
+
end
|
143
|
+
|
144
|
+
# Outputs a link to h2vx.com that will let the user download the vcard
|
145
|
+
# at the passed URL.
|
146
|
+
#
|
147
|
+
# OPTIONS
|
148
|
+
# * :text - The link text (default is "Download vCard")
|
149
|
+
# * Any other passed options will be treated as HTML attributes.
|
150
|
+
#
|
151
|
+
# EXAMPLE
|
152
|
+
# <%# In Rails, request.request_uri returns the URL of this page %>
|
153
|
+
# <%= card.download_link request.request_uri %>
|
154
|
+
#
|
43
155
|
def download_link(url, opts = {})
|
44
156
|
str = opts.delete(:text) || "Download vCard"
|
45
157
|
new_url = "http://h2vx.com/vcf/" + url.gsub("http://", '')
|
46
|
-
content_tag(:a,
|
47
|
-
end
|
48
|
-
|
49
|
-
def content_tag(tag, content, opts={})
|
50
|
-
attrs = opts.inject([]) do |out, tuple|
|
51
|
-
k,v = tuple
|
52
|
-
out << "#{k}='#{v}'"
|
53
|
-
end
|
54
|
-
attr_string = attrs.sort.join(' ')
|
55
|
-
open_tag = attr_string == '' ? tag : "#{tag} #{attr_string}"
|
56
|
-
if [:img].include?(tag)
|
57
|
-
"<#{open_tag} />"
|
58
|
-
else
|
59
|
-
"<#{open_tag}>#{content}</#{tag}>"
|
60
|
-
end
|
158
|
+
content_tag(str, merge_html_attrs({:tag => :a, :href => new_url, :type => 'text/directory'}, opts))
|
61
159
|
end
|
62
160
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
161
|
+
# Opens a new block for a nested vAddress.
|
162
|
+
#
|
163
|
+
# OPTIONS:
|
164
|
+
# * :type - A string that specifies the type of address('home', 'work', etc)
|
165
|
+
# * :tag - The HTML wrapper element (defaults to :div)
|
166
|
+
# * Any other passed options will be treated as HTML attributes.
|
167
|
+
#
|
168
|
+
# EXAMPLE:
|
169
|
+
# <% card.address :type => 'work', :id => 'my_adr' do |adr| %>
|
170
|
+
# I live at <%= adr.street "123 Main St" %>.
|
171
|
+
# <% end %>
|
172
|
+
#
|
173
|
+
def address(opts = {}, &block)
|
174
|
+
adr = Microformats::Address.new(@template)
|
175
|
+
adr.run(opts, &block)
|
69
176
|
end
|
70
177
|
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: microformats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 3
|
9
|
+
version: "0.3"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Chris Powers
|
@@ -31,14 +31,13 @@ files:
|
|
31
31
|
- CHANGELOG.rdoc
|
32
32
|
- LICENSE
|
33
33
|
- Rakefile
|
34
|
-
- lib/microformats.rb
|
35
34
|
- lib/address.rb
|
35
|
+
- lib/calendar.rb
|
36
|
+
- lib/event.rb
|
37
|
+
- lib/formatting_helpers.rb
|
36
38
|
- lib/helpers.rb
|
39
|
+
- lib/microformats.rb
|
37
40
|
- lib/vcard.rb
|
38
|
-
- spec/address_spec.rb
|
39
|
-
- spec/helpers_spec.rb
|
40
|
-
- spec/spec_helper.rb
|
41
|
-
- spec/vcard_spec.rb
|
42
41
|
has_rdoc: true
|
43
42
|
homepage: http://github.com/chrisjpowers/microformats
|
44
43
|
licenses: []
|
data/spec/address_spec.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Microformats::Address do
|
4
|
-
before(:each) do
|
5
|
-
@address = Microformats::Address.new
|
6
|
-
end
|
7
|
-
|
8
|
-
describe "street" do
|
9
|
-
it "should wrap the string with street-address" do
|
10
|
-
@address.street("123 Main").should == "<span class='street-address' itemprop='street-address'>123 Main</span>"
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should use the given tag" do
|
14
|
-
@address.street("123 Main", :tag => :strong).should == "<strong class='street-address' itemprop='street-address'>123 Main</strong>"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "city" do
|
19
|
-
it "should wrap the string with locality" do
|
20
|
-
@address.city("Chicago").should == "<span class='locality' itemprop='locality'>Chicago</span>"
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should use the given tag" do
|
24
|
-
@address.city("Chicago", :tag => :strong).should == "<strong class='locality' itemprop='locality'>Chicago</strong>"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "state" do
|
29
|
-
it "should wrap the string with region" do
|
30
|
-
@address.state("IL").should == "<span class='region' itemprop='region'>IL</span>"
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should use the given tag" do
|
34
|
-
@address.state("IL", :tag => :strong).should == "<strong class='region' itemprop='region'>IL</strong>"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "zip" do
|
39
|
-
it "should wrap the string with postal-code" do
|
40
|
-
@address.zip("60085").should == "<span class='postal-code' itemprop='postal-code'>60085</span>"
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should use the given tag" do
|
44
|
-
@address.zip("60085", :tag => :strong).should == "<strong class='postal-code' itemprop='postal-code'>60085</strong>"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "country" do
|
49
|
-
it "should wrap the string with country-name" do
|
50
|
-
@address.country("USA").should == "<span class='country-name' itemprop='country-name'>USA</span>"
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should use the given tag" do
|
54
|
-
@address.country("USA", :tag => :strong).should == "<strong class='country-name' itemprop='country-name'>USA</strong>"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/spec/helpers_spec.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Microformats::Helpers do
|
4
|
-
class MyTester
|
5
|
-
include Microformats::Helpers
|
6
|
-
|
7
|
-
def concat(str)
|
8
|
-
@output ||= ''
|
9
|
-
@output << str
|
10
|
-
end
|
11
|
-
|
12
|
-
def output
|
13
|
-
@output
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
before(:each) do
|
18
|
-
@tester = MyTester.new
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "vcard" do
|
22
|
-
it "should wrap a block in a vcard div" do
|
23
|
-
@tester.should_receive(:do_something)
|
24
|
-
@tester.vcard do
|
25
|
-
@tester.do_something
|
26
|
-
end
|
27
|
-
@tester.output.should == "<div class='vcard' itemscope='itemscope' itemtype='http://data-vocabulary.org/Person'>\n</div>\n"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "vcard_address" do
|
32
|
-
context "with type" do
|
33
|
-
it "should wrap the block in an adr div and output the type" do
|
34
|
-
@tester.should_receive(:do_something)
|
35
|
-
@tester.vcard_address :type => 'Work' do
|
36
|
-
@tester.do_something
|
37
|
-
end
|
38
|
-
@tester.output.should == "<div class='adr' itemscope='itemscope' itemtype='http://data-vocabulary.org/Address'>\n<span class='type'>Work</span></div>\n"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context "without type" do
|
43
|
-
it "should wrap the block in an adr div" do
|
44
|
-
@tester.should_receive(:do_something)
|
45
|
-
@tester.vcard_address do
|
46
|
-
@tester.do_something
|
47
|
-
end
|
48
|
-
@tester.output.should == "<div class='adr' itemscope='itemscope' itemtype='http://data-vocabulary.org/Address'>\n</div>\n"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'microformats.rb')
|
data/spec/vcard_spec.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Microformats::Vcard do
|
4
|
-
before(:each) do
|
5
|
-
@vcard = Microformats::Vcard.new
|
6
|
-
end
|
7
|
-
|
8
|
-
describe "name" do
|
9
|
-
it "should wrap a string with fn class, default to span" do
|
10
|
-
@vcard.name("John Doe").should == "<span class='fn' itemprop='name'>John Doe</span>"
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should use the given tag" do
|
14
|
-
@vcard.name("John Doe", :tag => :strong).should == "<strong class='fn' itemprop='name'>John Doe</strong>"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "company" do
|
19
|
-
it "should wrap a string with org class, default to span" do
|
20
|
-
@vcard.company("Acme Co.").should == "<span class='org' itemprop='affiliation'>Acme Co.</span>"
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should use the given tag" do
|
24
|
-
@vcard.company("Acme Co.", :tag => :strong).should == "<strong class='org' itemprop='affiliation'>Acme Co.</strong>"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "url" do
|
29
|
-
it "should default to a tag with url class, using the URL for text and href" do
|
30
|
-
@vcard.url("http://google.com").should == "<a class='url' href='http://google.com' itemprop='url'>http://google.com</a>"
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should use given href" do
|
34
|
-
@vcard.url('Google', :href => "http://google.com").should == "<a class='url' href='http://google.com' itemprop='url'>Google</a>"
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should use given tag" do
|
38
|
-
@vcard.url('http://google.com', :tag => :strong).should == "<strong class='url' itemprop='url'>http://google.com</strong>"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "photo" do
|
43
|
-
it "should create an image tag using the passed string as the src, adding itemprop photo" do
|
44
|
-
@vcard.photo("/images/me.png").should == "<img itemprop='photo' src='/images/me.png' />"
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should use :size option to set width and height" do
|
48
|
-
@vcard.photo("/images/me.png", :size => "200x100").should == "<img height='100' itemprop='photo' src='/images/me.png' width='200' />"
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should pass through options" do
|
52
|
-
@vcard.photo("/images/me.png", :height => 100, :width => 200).should == "<img height='100' itemprop='photo' src='/images/me.png' width='200' />"
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "phone" do
|
58
|
-
it "should wrap string with a tel class" do
|
59
|
-
@vcard.phone('123.456.7890').should == "<span class='tel'>123.456.7890</span>"
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should add a type span if given" do
|
63
|
-
out = @vcard.phone('123.456.7890', :type => 'Work')
|
64
|
-
out.should == "<span class='tel'><span class='type'>Work</span> 123.456.7890</span>"
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should use the given tag" do
|
68
|
-
out = @vcard.phone('123.456.7890', :type => 'Work', :tag => :strong)
|
69
|
-
out.should == "<strong class='tel'><span class='type'>Work</span> 123.456.7890</strong>"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe "email" do
|
74
|
-
it "should wrap string with a email class" do
|
75
|
-
@vcard.email('john@doe.com').should == "<span class='email'>john@doe.com</span>"
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should add a type span if given" do
|
79
|
-
out = @vcard.email('john@doe.com', :type => 'Work')
|
80
|
-
out.should == "<span class='email'><span class='type'>Work</span> john@doe.com</span>"
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should use the given tag" do
|
84
|
-
out = @vcard.email('john@doe.com', :type => 'Work', :tag => :strong)
|
85
|
-
out.should == "<strong class='email'><span class='type'>Work</span> john@doe.com</strong>"
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should use mailto if using an 'a' tag" do
|
89
|
-
out = @vcard.email('john@doe.com', :type => 'Work', :tag => :a)
|
90
|
-
out.should == "<a class='email' href='mailto:john@doe.com'><span class='type'>Work</span> john@doe.com</a>"
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
describe "download_link" do
|
95
|
-
it "should output a link to h2vx.com using the passed url" do
|
96
|
-
out = @vcard.download_link('mydomain.com/page')
|
97
|
-
out.should == "<a href='http://h2vx.com/vcf/mydomain.com/page' type='text/directory'>Download vCard</a>"
|
98
|
-
end
|
99
|
-
|
100
|
-
it "should strip the protocol from a passed url" do
|
101
|
-
out = @vcard.download_link('http://mydomain.com/page')
|
102
|
-
out.should == "<a href='http://h2vx.com/vcf/mydomain.com/page' type='text/directory'>Download vCard</a>"
|
103
|
-
end
|
104
|
-
|
105
|
-
it "should use :text option as text node if present" do
|
106
|
-
out = @vcard.download_link('mydomain.com/page', :text => "Download Me Now")
|
107
|
-
out.should == "<a href='http://h2vx.com/vcf/mydomain.com/page' type='text/directory'>Download Me Now</a>"
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|