microformats 0.1 → 0.3
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.
- 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
|