├── .gitignore ├── CHANGELOG.rdoc ├── lib ├── microformats.rb ├── calendar.rb ├── formatting_helpers.rb ├── helpers.rb ├── address.rb ├── event.rb └── vcard.rb ├── README.md ├── spec ├── spec_helper.rb ├── formatting_helpers_spec.rb ├── calendar_spec.rb ├── helpers_spec.rb ├── address_spec.rb ├── event_spec.rb └── vcard_spec.rb ├── microformats.gemspec ├── Rakefile └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | doc -------------------------------------------------------------------------------- /CHANGELOG.rdoc: -------------------------------------------------------------------------------- 1 | = Microformats CHANGELOG 2 | 3 | == Version 0.1 4 | * Initial Implementation of Vcard 5 | * Implements hCard microformat 6 | * Implements Google's Person microdata http://www.data-vocabulary.org/Person/ -------------------------------------------------------------------------------- /lib/microformats.rb: -------------------------------------------------------------------------------- 1 | module Microformats 2 | 3 | end 4 | 5 | require 'time' 6 | 7 | require 'formatting_helpers' 8 | require 'vcard' 9 | require 'address' 10 | require 'calendar' 11 | require 'event' 12 | require 'helpers' -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # END OF LIFE : 2010-10-25 2 | # Microformats Tag Rails Helper 3 | 4 | **NO LONGER IN DEVELOPMENT. As of 2017-05-16, this repo is archived and unsupported. Use at your own risk.** 5 | 6 | **If you're looking for the Microformats Ruby Parser, you're in the wrong place. Go here instead: [https://github.com/indieweb/microformats2-ruby](github.com/indieweb/microformats2-ruby)** 7 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require File.join(File.dirname(__FILE__), '..', 'lib', 'microformats.rb') 3 | 4 | # We need to be able to test what Vcard is outputting using the 5 | # concat method. The output method just lets us check this. 6 | class MockTemplate 7 | def concat(str) 8 | @output ||= '' 9 | @output << str 10 | end 11 | 12 | def output 13 | @output 14 | end 15 | end -------------------------------------------------------------------------------- /microformats.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'microformats' 3 | s.version = '0.3' 4 | s.author = 'Chris Powers' 5 | s.date = "2010-09-11" 6 | s.homepage = 'http://github.com/chrisjpowers/microformats' 7 | s.email = 'chrisjpowers@gmail.com' 8 | s.summary = 'The Microformats gem gives you helper methods for richly marking up your HTML with microformats and HTML5 microdata.' 9 | s.files = [ 'README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'Rakefile', 'lib/address.rb', 10 | 'lib/calendar.rb', 'lib/event.rb', 'lib/formatting_helpers.rb', 11 | 'lib/helpers.rb', 'lib/microformats.rb', 'lib/vcard.rb'] 12 | s.require_paths = ["lib"] 13 | s.has_rdoc = true 14 | end 15 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | require 'rake/rdoctask' 4 | # require 'rake/gempackagetask' 5 | # require 'rcov/rcovtask' 6 | # require 'date' 7 | 8 | require 'spec/rake/spectask' 9 | 10 | desc 'Default: run the specs.' 11 | task :default => :spec 12 | 13 | Spec::Rake::SpecTask.new do |t| 14 | t.warning = true 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 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Chris Powers 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /lib/calendar.rb: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /spec/formatting_helpers_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe Microformats::FormattingHelpers do 4 | class Tester 5 | include Microformats::FormattingHelpers 6 | def initialize 7 | @default_tag = :span 8 | end 9 | end 10 | 11 | before(:each) do 12 | @tester = Tester.new 13 | end 14 | 15 | describe "combine_class_names" do 16 | it "should join the args with spaces alphebetized" do 17 | @tester.combine_class_names('one', 'two', 'three').should == "one three two" 18 | end 19 | 20 | it "should join arrays of class names" do 21 | out = @tester.combine_class_names(['one', 'two'], 'three', ['four', 'five']) 22 | out.should == "five four one three two" 23 | end 24 | 25 | it "should not include nils" do 26 | @tester.combine_class_names('one', [nil, 'two']).should == "one two" 27 | end 28 | 29 | it "should return nil if no classes" do 30 | @tester.combine_class_names(nil, nil).should == nil 31 | end 32 | end 33 | 34 | describe "content_tag" do 35 | it "should output default tag with attrs in alphabetical order" do 36 | out = @tester.content_tag('hello', :id => 'my_id', :class => 'klass') 37 | out.should == "hello" 38 | end 39 | 40 | it "should not include attrs with nil values" do 41 | out = @tester.content_tag('hello', :id => 'my_id', :class => nil) 42 | out.should == "hello" 43 | end 44 | end 45 | end -------------------------------------------------------------------------------- /lib/formatting_helpers.rb: -------------------------------------------------------------------------------- 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}" 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 "\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 -------------------------------------------------------------------------------- /spec/calendar_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe Microformats::Calendar do 4 | before(:each) do 5 | @template = MockTemplate.new 6 | @cal = Microformats::Calendar.new(@template) 7 | end 8 | 9 | describe "run" do 10 | it "should wrap the block with a .vcalendar div" do 11 | @cal.run do |cal| 12 | cal.concat "Hello" 13 | end 14 | @template.output.should == "
\nHello
\n" 15 | end 16 | 17 | it "should add passed attributes to .vcalendar element" do 18 | @cal.run(:id => 'my_cal', :class => 'extra', :tag => 'section') do |cal| 19 | cal.concat "Hello" 20 | end 21 | @template.output.should == "
\nHello
\n" 22 | end 23 | end 24 | 25 | describe "event" do 26 | before(:each) do 27 | @event = Microformats::Event.new(@template) 28 | Microformats::Event.should_receive(:new).with(@template).and_return(@event) 29 | end 30 | 31 | it "should run the block on a new event" do 32 | @event.should_receive(:run).with(:class => 'vevent') 33 | @cal.event do |e| 34 | # won't get run in test because #run is stubbed 35 | end 36 | end 37 | 38 | it "should use the given tag" do 39 | @event.should_receive(:run).with(:class => 'vevent', :tag => :section) 40 | @cal.event(:tag => :section) do |e| 41 | # won't get run in test because #run is stubbed 42 | end 43 | end 44 | 45 | it "should pass along html opts" do 46 | @event.should_receive(:run).with(:class => 'extra vevent', :id => 'my_event') 47 | @cal.event(:class => 'extra', :id => 'my_event') do |e| 48 | # won't get run in test because #run is stubbed 49 | end 50 | end 51 | end 52 | end -------------------------------------------------------------------------------- /lib/helpers.rb: -------------------------------------------------------------------------------- 1 | # Include this file into your view layer. For example, in Rails: 2 | # 3 | # module ApplicationHelper 4 | # include Microformats::Helpers 5 | # end 6 | # 7 | module Microformats::Helpers 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) 22 | end 23 | 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) 39 | end 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 74 | end -------------------------------------------------------------------------------- /lib/address.rb: -------------------------------------------------------------------------------- 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 | # NOTE: You get this for free with the :type option of 34 | # Microformats::Helpers#vaddress, Microformats::Vcard#address and #run methods. 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 | # 52 | def street(str, opts = {}) 53 | content_tag(str, merge_html_attrs({:class => 'street-address', :itemprop => 'street-address'}, opts)) 54 | end 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 | # 62 | def city(str, opts = {}) 63 | content_tag(str, merge_html_attrs({:class => 'locality', :itemprop => 'locality'}, opts)) 64 | end 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 | # 72 | def state(str, opts = {}) 73 | content_tag(str, merge_html_attrs({:class => 'region', :itemprop => 'region'}, opts)) 74 | end 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 | # 82 | def zip(str, opts = {}) 83 | content_tag(str, merge_html_attrs({:class => 'postal-code', :itemprop => 'postal-code'}, opts)) 84 | end 85 | alias_method :postal_code, :zip 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 | # 93 | def country(str, opts = {}) 94 | content_tag(str, merge_html_attrs({:class => 'country-name', :itemprop => 'country-name'}, opts)) 95 | end 96 | 97 | end -------------------------------------------------------------------------------- /spec/helpers_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Microformats::Helpers do 4 | 5 | class MockTemplateWithHelpers < MockTemplate 6 | include Microformats::Helpers 7 | end 8 | 9 | before(:each) do 10 | @template = MockTemplateWithHelpers.new 11 | end 12 | 13 | describe "vcard" do 14 | it "should wrap a block in a vcard div" do 15 | @template.should_receive(:do_something) 16 | @template.vcard do |card| 17 | card.is_a?(Microformats::Vcard).should be_true 18 | @template.do_something 19 | end 20 | @template.output.should == "
\n
\n" 21 | end 22 | 23 | it "should use passed html attrs" do 24 | @template.should_receive(:do_something) 25 | @template.vcard(:class => 'extra', :id => 'my_card') do |card| 26 | card.is_a?(Microformats::Vcard).should be_true 27 | @template.do_something 28 | end 29 | @template.output.should == "
\n
\n" 30 | end 31 | end 32 | 33 | describe "vaddress" do 34 | context "with type" do 35 | it "should wrap the block in an adr div and output the type" do 36 | @template.should_receive(:do_something) 37 | @template.vaddress :type => 'work' do 38 | @template.do_something 39 | end 40 | @template.output.should == "
\n
\n" 41 | end 42 | 43 | it "should use passed html attrs" do 44 | @template.should_receive(:do_something) 45 | @template.vaddress :type => 'work', :class => 'extra', :id => 'my_address' do 46 | @template.do_something 47 | end 48 | @template.output.should == "
\n
\n" 49 | end 50 | end 51 | 52 | context "without type" do 53 | it "should wrap the block in an adr div" do 54 | @template.should_receive(:do_something) 55 | @template.vaddress do |adr| 56 | adr.is_a?(Microformats::Address).should be_true 57 | @template.do_something 58 | end 59 | @template.output.should == "
\n
\n" 60 | end 61 | end 62 | end 63 | 64 | describe "vevent" do 65 | it "should wrap the block with a .vevent div" do 66 | @template.should_receive(:do_something) 67 | @template.vevent do |event| 68 | event.is_a?(Microformats::Event).should be_true 69 | @template.do_something 70 | end 71 | @template.output.should == "
\n
\n" 72 | end 73 | 74 | it "should add passed attributes to .vevent element" do 75 | @template.should_receive(:do_something) 76 | @template.vevent(:id => 'my_event', :class => 'extra', :tag => 'section') do |event| 77 | @template.do_something 78 | end 79 | @template.output.should == "
\n
\n" 80 | end 81 | end 82 | 83 | describe "vcalendar" do 84 | it "should wrap the block with a .vcalendar div" do 85 | @template.should_receive(:do_something) 86 | @template.vcalendar do |cal| 87 | cal.is_a?(Microformats::Calendar).should be_true 88 | @template.do_something 89 | end 90 | @template.output.should == "
\n
\n" 91 | end 92 | 93 | it "should add passed attributes to .vcalendar element" do 94 | @template.should_receive(:do_something) 95 | @template.vcalendar(:id => 'my_cal', :class => 'extra', :tag => 'section') do |cal| 96 | @template.do_something 97 | end 98 | @template.output.should == "
\n
\n" 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /spec/address_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Microformats::Address do 4 | before(:each) do 5 | @template = MockTemplate.new 6 | @address = Microformats::Address.new(@template) 7 | end 8 | 9 | describe "run" do 10 | it "should wrap the block with an .adr div" do 11 | @address.run do |adr| 12 | adr.concat "Hello" 13 | end 14 | @template.output.should == "
\nHello
\n" 15 | end 16 | 17 | it "should add passed attributes to .adr div" do 18 | @address.run(:id => 'my_address', :class => 'extra') do |adr| 19 | adr.concat "Hello" 20 | end 21 | @template.output.should == "
\nHello
\n" 22 | end 23 | end 24 | 25 | describe "type" do 26 | it "should output the type string as a hidden value" do 27 | @address.type('home').should == "" 28 | end 29 | 30 | it "should include text passed with :text option" do 31 | @address.type('home', :text => "Where I Live").should == "Where I Live" 32 | end 33 | end 34 | 35 | describe "street" do 36 | it "should wrap the string with street-address" do 37 | e = "123 Main" 38 | @address.street("123 Main").should == e 39 | end 40 | 41 | it "should use passed html attrs" do 42 | e = "123 Main" 43 | @address.street("123 Main", :class => 'extra', :id => 'my_street').should == e 44 | end 45 | 46 | it "should use the given tag" do 47 | e = "123 Main" 48 | @address.street("123 Main", :tag => :strong).should == e 49 | end 50 | end 51 | 52 | describe "city" do 53 | it "should wrap the string with locality" do 54 | @address.city("Chicago").should == "Chicago" 55 | end 56 | 57 | it "should use passed html attrs" do 58 | e = "Chicago" 59 | @address.city("Chicago", :class => 'extra', :id => 'my_city').should == e 60 | end 61 | 62 | it "should use the given tag" do 63 | @address.city("Chicago", :tag => :strong).should == "Chicago" 64 | end 65 | end 66 | 67 | describe "state" do 68 | it "should wrap the string with region" do 69 | @address.state("IL").should == "IL" 70 | end 71 | 72 | it "should use passed html attrs" do 73 | e = "IL" 74 | @address.state("IL", :class => 'extra', :id => 'my_state').should == e 75 | end 76 | 77 | it "should use the given tag" do 78 | @address.state("IL", :tag => :strong).should == "IL" 79 | end 80 | end 81 | 82 | describe "zip" do 83 | it "should wrap the string with postal-code" do 84 | @address.zip("60085").should == "60085" 85 | end 86 | 87 | it "should use passed html attrs" do 88 | e = "60085" 89 | @address.zip("60085", :class => 'extra', :id => 'my_zip').should == e 90 | end 91 | 92 | it "should use the given tag" do 93 | @address.zip("60085", :tag => :strong).should == "60085" 94 | end 95 | end 96 | 97 | describe "country" do 98 | it "should wrap the string with country-name" do 99 | @address.country("USA").should == "USA" 100 | end 101 | 102 | it "should use passed html attrs" do 103 | e = "USA" 104 | @address.country("USA", :class => 'extra', :id => 'my_country').should == e 105 | end 106 | 107 | it "should use the given tag" do 108 | @address.country("USA", :tag => :strong).should == "USA" 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /lib/event.rb: -------------------------------------------------------------------------------- 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 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') #=> 48 | # event.url('Google', :href => 'http://google.com') #=> 49 | # event.url('http://google.com', :tag => :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 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 -------------------------------------------------------------------------------- /lib/vcard.rb: -------------------------------------------------------------------------------- 1 | class Microformats::Vcard 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 8 | @default_tag = :span 9 | end 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 | # 34 | def name(str, opts = {}) 35 | content_tag(str, merge_html_attrs({:class => 'fn', :itemprop => 'name'}, opts)) 36 | end 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 | # 47 | def company(str, opts = {}) 48 | classes = opts.delete(:is_company) ? 'fn org' : 'org' 49 | content_tag(str, merge_html_attrs({:class => classes, :itemprop => 'affiliation'}, opts)) 50 | end 51 | alias_method :organization, :company 52 | 53 | # Marks up the person's URL. By default, it will output an 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') #=> 64 | # card.url('Google', :href => 'http://google.com') #=> 65 | # card.url('http://google.com', :tag => :span) #=> 66 | # 67 | def url(str, opts = {}) 68 | if opts[:href] 69 | content_tag(str, merge_html_attrs({:tag => :a, :class => 'url', :itemprop => 'url'}, opts)) 70 | elsif opts[:tag] 71 | content_tag(str, merge_html_attrs({:class => 'url', :itemprop => 'url'}, opts)) 72 | else 73 | content_tag(str, merge_html_attrs({:tag => :a, :class => 'url', :href => str, :itemprop => 'url'}, opts)) 74 | end 75 | end 76 | 77 | # Marks up the vCard photo as an 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 | # 83 | def photo(str, opts = {}) 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)) 88 | end 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 | # 97 | def phone(str, opts = {}) 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)) 105 | end 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 | # 114 | def email(str, opts = {}) 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 122 | if opts[:tag] == :a 123 | content_tag(type + str, merge_html_attrs({:class => 'email', :href => "mailto:#{str}"}, opts)) 124 | else 125 | content_tag(type + str, merge_html_attrs({:class => 'email'}, opts)) 126 | end 127 | end 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 | # 155 | def download_link(url, opts = {}) 156 | str = opts.delete(:text) || "Download vCard" 157 | new_url = "http://h2vx.com/vcf/" + url.gsub("http://", '') 158 | content_tag(str, merge_html_attrs({:tag => :a, :href => new_url, :type => 'text/directory'}, opts)) 159 | end 160 | 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) 176 | end 177 | end -------------------------------------------------------------------------------- /spec/event_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe Microformats::Event do 4 | before(:each) do 5 | @template = MockTemplate.new 6 | @event = Microformats::Event.new(@template) 7 | end 8 | 9 | describe "run" do 10 | it "should wrap the block with a .vevent div" do 11 | @event.run do |event| 12 | event.concat "Hello" 13 | end 14 | @template.output.should == "
\nHello
\n" 15 | end 16 | 17 | it "should add passed attributes to .vevent element" do 18 | @event.run(:id => 'my_event', :class => 'extra', :tag => 'section') do |event| 19 | event.concat "Hello" 20 | end 21 | @template.output.should == "
\nHello
\n" 22 | end 23 | end 24 | 25 | describe "name" do 26 | it "should wrap the string with summary" do 27 | @event.name("My Event").should == "My Event" 28 | end 29 | 30 | it "should use arbitrary html attrs" do 31 | e = "My Event" 32 | @event.name("My Event", :class => 'extra', :id => 'my_event').should == e 33 | end 34 | 35 | it "should use the given tag" do 36 | @event.name("My Event", :tag => :strong).should == "My Event" 37 | end 38 | end 39 | 40 | describe "url" do 41 | it "should default to a tag with url class, using the URL for text and href" do 42 | @event.url("http://google.com").should == "" 43 | end 44 | 45 | it "should take arbitrary html attrs" do 46 | e = "" 47 | @event.url("http://google.com", :class => 'extra', :id => 'my_url').should == e 48 | end 49 | 50 | it "should use given href" do 51 | @event.url('Google', :href => "http://google.com").should == "" 52 | end 53 | 54 | it "should use given tag" do 55 | @event.url('http://google.com', :tag => :strong).should == "" 56 | end 57 | end 58 | 59 | describe "photo" do 60 | it "should create an image tag using the passed string as the src, adding itemprop photo" do 61 | @event.photo("/images/event.png").should == "" 62 | end 63 | 64 | it "should use arbitrary html attrs" do 65 | e = "" 66 | @event.photo("/images/event.png", :class => 'extra', :id => 'my_photo').should == e 67 | end 68 | 69 | it "should use :size option to set width and height" do 70 | @event.photo("/images/event.png", :size => "200x100").should == "" 71 | end 72 | 73 | it "should pass through options" do 74 | @event.photo("/images/event.png", :height => 100, :width => 200).should == "" 75 | end 76 | end 77 | 78 | describe "description" do 79 | it "should wrap the string with description" do 80 | @event.description("My Event").should == "My Event" 81 | end 82 | 83 | it "should use arbitrary html attrs" do 84 | e = "My Event" 85 | @event.description("My Event", :class => 'extra', :id => 'my_desc').should == e 86 | end 87 | 88 | it "should use the given tag" do 89 | @event.description("My Event", :tag => :strong).should == "My Event" 90 | end 91 | end 92 | 93 | describe "starts_at" do 94 | it "should output the time wrapped in a time tag with encoded time" do 95 | t = Time.local(2010, 10, 20, 19, 30) # Oct 20, 2010 at 7:30pm 96 | @event.starts_at(t).should == "" 97 | end 98 | 99 | it "should use arbitrary html attrs" do 100 | t = Time.local(2010, 10, 20, 19, 30) # Oct 20, 2010 at 7:30pm 101 | e = "" 102 | @event.starts_at(t, :class => 'extra', :id => 'my_start').should == e 103 | end 104 | 105 | it "should accept a datetime string instead of a time object" do 106 | @event.starts_at("October 20, 2010 7:30pm").should == "" 107 | end 108 | 109 | it "should accept a time object with a display string as :text" do 110 | t = Time.local(2010, 10, 20, 19, 30) # Oct 20, 2010 at 7:30pm 111 | @event.starts_at(t, :text => "Sometime").should == "" 112 | end 113 | end 114 | 115 | describe "ends_at" do 116 | it "should output the time wrapped in a time tag with encoded time" do 117 | t = Time.local(2010, 10, 20, 19, 30) # Oct 20, 2010 at 7:30pm 118 | @event.ends_at(t).should == "" 119 | end 120 | 121 | it "should use arbitrary html attrs" do 122 | t = Time.local(2010, 10, 20, 19, 30) # Oct 20, 2010 at 7:30pm 123 | e = "" 124 | @event.ends_at(t, :class => 'extra', :id => 'my_end').should == e 125 | end 126 | 127 | it "should accept a datetime string instead of a time object" do 128 | @event.ends_at("October 20, 2010 7:30pm").should == "" 129 | end 130 | 131 | it "should accept a time object with a display string as :text" do 132 | t = Time.local(2010, 10, 20, 19, 30) # Oct 20, 2010 at 7:30pm 133 | @event.ends_at(t, :text => "Sometime").should == "" 134 | end 135 | end 136 | 137 | describe "category" do 138 | it "should wrap the string with category class and eventType itemprop" do 139 | @event.category("Geekfest").should == "Geekfest" 140 | end 141 | 142 | it "should should use arbitrary html attrs" do 143 | e = "Geekfest" 144 | @event.category("Geekfest", :class => 'extra', :id => 'my_category').should == e 145 | end 146 | 147 | it "should use the given tag" do 148 | @event.category("Geekfest", :tag => :strong).should == "Geekfest" 149 | end 150 | end 151 | 152 | describe "location" do 153 | before(:each) do 154 | @card = Microformats::Vcard.new(@template) 155 | Microformats::Vcard.should_receive(:new).with(@template).and_return(@card) 156 | end 157 | it "should run the block on a new vcard" do 158 | @card.should_receive(:run).with(:class => 'location') 159 | @event.location do |card| 160 | # won't get run in test because #run is stubbed 161 | end 162 | end 163 | 164 | it "should pass along html opts" do 165 | @card.should_receive(:run).with(:class => 'extra location', :id => 'my_location') 166 | @event.location(:class => 'extra', :id => 'my_location') do |card| 167 | # won't get run in test because #run is stubbed 168 | end 169 | end 170 | end 171 | 172 | end -------------------------------------------------------------------------------- /spec/vcard_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Microformats::Vcard do 4 | before(:each) do 5 | @template = MockTemplate.new 6 | @vcard = Microformats::Vcard.new(@template) 7 | end 8 | 9 | describe "run" do 10 | it "should wrap the block in a .vcard div" do 11 | @vcard.run do |card| 12 | card.concat "Hello" 13 | end 14 | @template.output.should == "
\nHello
\n" 15 | end 16 | 17 | it "should should apply id and extra classes to .vcard div" do 18 | @vcard.run(:id => 'my_vcard', :class => 'extra') do |card| 19 | card.concat "Hello" 20 | end 21 | @template.output.should == "
\nHello
\n" 22 | end 23 | end 24 | 25 | describe "name" do 26 | it "should wrap a string with fn class, default to span" do 27 | @vcard.name("John Doe").should == "John Doe" 28 | end 29 | 30 | it "should use arbitrary html attrs" do 31 | e = "John Doe" 32 | @vcard.name("John Doe", :class => 'extra', :id => 'my_name').should == e 33 | end 34 | 35 | it "should use the given tag" do 36 | @vcard.name("John Doe", :tag => :strong).should == "John Doe" 37 | end 38 | end 39 | 40 | describe "company" do 41 | it "should wrap a string with org class, default to span" do 42 | @vcard.company("Acme Co.").should == "Acme Co." 43 | end 44 | 45 | it "should use arbitrary html attrs" do 46 | e = "Acme Co." 47 | @vcard.company("Acme Co.", :class => 'extra', :id => 'my_company').should == e 48 | end 49 | 50 | it "should use the given tag" do 51 | @vcard.company("Acme Co.", :tag => :strong).should == "Acme Co." 52 | end 53 | 54 | it "should have fn class if passed :is_company => true" do 55 | @vcard.company("Acme Co.", :is_company => true).should == "Acme Co." 56 | end 57 | end 58 | 59 | describe "url" do 60 | it "should default to a tag with url class, using the URL for text and href" do 61 | @vcard.url("http://google.com").should == "" 62 | end 63 | 64 | it "should use arbitrary html attrs" do 65 | e = "" 66 | @vcard.url("http://google.com", :class => 'extra', :id => 'my_url').should == e 67 | end 68 | 69 | it "should use given href" do 70 | @vcard.url('Google', :href => "http://google.com").should == "" 71 | end 72 | 73 | it "should use given tag" do 74 | @vcard.url('http://google.com', :tag => :strong).should == "" 75 | end 76 | end 77 | 78 | describe "photo" do 79 | it "should create an image tag using the passed string as the src, adding itemprop photo" do 80 | @vcard.photo("/images/me.png").should == "" 81 | end 82 | 83 | it "should use arbitrary html attrs" do 84 | e = "" 85 | @vcard.photo("/images/me.png", :class => 'extra', :id => 'my_photo').should == e 86 | end 87 | 88 | it "should use :size option to set width and height" do 89 | @vcard.photo("/images/me.png", :size => "200x100").should == "" 90 | end 91 | 92 | it "should pass through options" do 93 | @vcard.photo("/images/me.png", :height => 100, :width => 200).should == "" 94 | end 95 | end 96 | 97 | describe "phone" do 98 | it "should wrap string with a tel class" do 99 | @vcard.phone('123.456.7890').should == "123.456.7890" 100 | end 101 | 102 | it "should use arbitrary html attrs" do 103 | e = "123.456.7890" 104 | @vcard.phone('123.456.7890', :class => 'extra', :id => 'my_phone').should == e 105 | end 106 | 107 | it "should add a type span if given" do 108 | out = @vcard.phone('123.456.7890', :type => 'work') 109 | out.should == "123.456.7890" 110 | end 111 | 112 | it "should use the given tag" do 113 | out = @vcard.phone('123.456.7890', :type => 'work', :tag => :strong) 114 | out.should == "123.456.7890" 115 | end 116 | end 117 | 118 | describe "email" do 119 | it "should use mailto and default to 'a' tag" do 120 | out = @vcard.email('john@doe.com') 121 | out.should == "john@doe.com" 122 | end 123 | 124 | it "should wrap string with passed tag" do 125 | @vcard.email('john@doe.com', :tag => :span).should == "john@doe.com" 126 | end 127 | 128 | it "should use arbitrary html attrs" do 129 | e = "john@doe.com" 130 | @vcard.email('john@doe.com', :class => 'extra', :id => 'my_email').should == e 131 | end 132 | 133 | it "should add a type span if given" do 134 | out = @vcard.email('john@doe.com', :type => 'work') 135 | out.should == "john@doe.com" 136 | end 137 | 138 | it "should use the given tag" do 139 | out = @vcard.email('john@doe.com', :type => 'work', :tag => :strong) 140 | out.should == "john@doe.com" 141 | end 142 | end 143 | 144 | describe "coordinates" do 145 | it "should output a geo container with meta and spans for lat and long" do 146 | out = @vcard.coordinates(37.774929, -122.419416) 147 | out.should == "" 148 | end 149 | 150 | it "should output text in .geo span if in options" do 151 | out = @vcard.coordinates(37.774929, -122.419416, :text => "My Location") 152 | out.should == "My Location" 153 | end 154 | end 155 | 156 | describe "download_link" do 157 | it "should output a link to h2vx.com using the passed url" do 158 | out = @vcard.download_link('mydomain.com/page') 159 | out.should == "Download vCard" 160 | end 161 | 162 | it "should use arbitrary html attrs" do 163 | out = @vcard.download_link('mydomain.com/page', :class => 'extra', :id => 'my_link') 164 | out.should == "Download vCard" 165 | end 166 | 167 | it "should strip the protocol from a passed url" do 168 | out = @vcard.download_link('http://mydomain.com/page') 169 | out.should == "Download vCard" 170 | end 171 | 172 | it "should use :text option as text node if present" do 173 | out = @vcard.download_link('mydomain.com/page', :text => "Download Me Now") 174 | out.should == "Download Me Now" 175 | end 176 | end 177 | 178 | describe "address" do 179 | before(:each) do 180 | @adr = Microformats::Address.new(@template) 181 | Microformats::Address.should_receive(:new).with(@template).and_return(@adr) 182 | end 183 | 184 | it "should run the block on a new vaddress" do 185 | @adr.should_receive(:run) 186 | @vcard.address do |adr| 187 | # won't get run in test because #run is stubbed 188 | end 189 | end 190 | 191 | it "should pass along html opts" do 192 | @adr.should_receive(:run).with(:class => 'extra', :id => 'my_address') 193 | @vcard.address(:class => 'extra', :id => 'my_address') do |adr| 194 | # won't get run in test because #run is stubbed 195 | end 196 | end 197 | end 198 | end 199 | --------------------------------------------------------------------------------