spec/item_spec.rb in mida-0.2.0 vs spec/item_spec.rb in mida-0.3.0

- old
+ new

@@ -1,584 +1,275 @@ -require_relative 'spec_helper' -require_relative '../lib/mida' +require 'spec_helper' +require 'mida/item' +require 'mida/vocabulary' -describe Mida::Item, 'when initialized with an itemscope containing just itemprops' do +describe Mida::Item, 'when initialized with an incomplete itemscope' do before do - # The first_name element - @fn = mock_element('span', {'itemprop' => 'first_name'}, 'Lorry') - - # The last_name element - @ln = mock_element('span', {'itemprop' => 'last_name'}, 'Woodman') + itemscope = mock(Mida::Itemscope) + itemscope.stub!(:type).and_return(nil) + itemscope.stub!(:id).and_return(nil) + itemscope.stub!(:properties).and_return({}) + @item = Mida::Item.new(itemscope) end - context 'when there is no itemtype' do - before do - # The surrounding reviewer itemscope element - itemscope_el = mock_element('div', {'itemprop' => 'reviewer', 'itemscope' => true}, nil, [@fn,@ln]) - @item = Mida::Item.new(itemscope_el) - end - - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic - end - - it '#type should return the correct type' do - @item.type.should == nil - end - - it '#id should return the correct id' do - @item.id.should == nil - end - - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'] - } - end - - it '#to_h should return the correct type and properties' do - @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, type: nil, id: nil, properties: { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'] - } - } - end + it '#type should return the same type as the itemscope' do + @item.type.should == nil end - context 'when there is an itemtype' do - before do - # The surrounding reviewer itemscope element - itemscope_el = mock_element('div', {'itemprop' => 'reviewer', 'itemtype' => 'person', 'itemscope' => true}, nil, [@fn,@ln]) - @item = Mida::Item.new(itemscope_el) - end - - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic - end - - it '#type should return the correct type' do - @item.type.should == 'person' - end - - it '#id should return the correct id' do - @item.id.should == nil - end - - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'] - } - end - - it '#to_h should return the correct type and properties' do - @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: 'person', - id: nil, - properties: { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'] - } - } - end - end -end - -describe Mida::Item, 'when initialized with an itemscope containing an itemprop with a relative url' do - before do - @url = mock_element('a', {'itemprop' => 'url', 'href' => 'home/lorry'}) - itemscope_el = mock_element('div', {'itemscope' => true}, nil, [@url]) - @item = Mida::Item.new(itemscope_el, "http://example.com") - end - - it 'should return the url as an absolute url' do - @item.properties['url'].should == ['http://example.com/home/lorry'] - end -end - -describe Mida::Item, 'when initialized with an itemscope containing itemprops surrounded by a non microdata element' do - before do - # The first_name element - fn = mock_element('span', {'itemprop' => 'first_name'}, 'Lorry') - - # The last_name element - ln = mock_element('span', {'itemprop' => 'last_name'}, 'Woodman') - - # A non microdata element surrounding last_name - surround = mock_element('span', {}, nil, [ln]) - - # The surrounding reviewer itemscope element - itemscope_el = mock_element('div', {'itemprop' => 'reviewer', - 'itemtype' => 'person', - 'itemscope' => true}, - nil, [fn,surround]) - @item = Mida::Item.new(itemscope_el) - end - - it '#type should return the correct type' do - @item.type.should == 'person' - end - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic + @item.vocabulary.should == Mida::GenericVocabulary end - it '#id should return the correct id' do + it '#id should return the same id as the itemscope' do @item.id.should == nil end - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'] - } + it '#properties should return the same properties as the itemscope' do + @item.properties.should == {} end it '#to_h should return the correct type and properties' do @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: 'person', + type: nil, id: nil, - properties: { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'] - } + properties: {} } end - end -describe Mida::Item, "when initialized with an itemscope containing itemprops - who's inner text is surrounded by non-microdata elements" do +describe Mida::Item, 'when initialized with a complete itemscope of an unknown type' do before do - html = '<div itemscope><span itemprop="reviewer">Lorry <em>Woodman</em></span></div>' - doc = Nokogiri(html) - itemscope = doc.search('./*').first + itemscope = mock(Mida::Itemscope) + itemscope.stub!(:type).and_return("book") + itemscope.stub!(:id).and_return("urn:isbn:978-1-849510-50-9") + itemscope.stub!(:properties).and_return( + {'first_name' => ['Lorry'], 'last_name' => ['Woodman']} + ) @item = Mida::Item.new(itemscope) end - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic + it '#type should return the same type as the itemscope' do + @item.type.should == "book" end - it '#type should return the correct type' do - @item.type.should == nil + it '#vocabulary should return the correct vocabulary' do + @item.vocabulary.should == Mida::GenericVocabulary end - it '#id should return the correct id' do - @item.id.should == nil + it '#id should return the same id as the itemscope' do + @item.id.should == "urn:isbn:978-1-849510-50-9" end - it '#properties should return the correct name/value pairs' do + it '#properties should return the same properties as the itemscope' do @item.properties.should == { - 'reviewer' => ['Lorry Woodman'] + 'first_name' => ['Lorry'], + 'last_name' => ['Woodman'] } end it '#to_h should return the correct type and properties' do @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: nil, - id: nil, + type: 'book', + id: "urn:isbn:978-1-849510-50-9", properties: { - 'reviewer' => ['Lorry Woodman'] + 'first_name' => ['Lorry'], + 'last_name' => ['Woodman'] } } end - end -describe Mida::Item, "when initialized with an itemscope containing an itemprop - nested within another itemprop" do +describe Mida::Item, 'when initialized with an itemscope of a known type' do before do - html = ' - <div itemscope> - <span itemprop="description">The animal is a <span itemprop="colour">green</span> parrot.</span> - </div> - ' - doc = Nokogiri(html) - itemscope = doc.search('./*').first - @item = Mida::Item.new(itemscope) - end + class Person < Mida::Vocabulary + itemtype %r{http://example.com/vocab/person} + has_one 'name' + has_many 'date' do + extract Mida::DataType::ISO8601Date, Mida::DataType::Text + end + has_many 'url' + end - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic - end - - it '#type should return the correct type' do - @item.type.should == nil - end - - it '#id should return the correct id' do - @item.id.should == nil - end - - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'description' => ['The animal is a green parrot.'], - 'colour' => ['green'] - } - end - - it '#to_h should return the correct type and properties' do - @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: nil, - id: nil, - properties: { - 'description' => ['The animal is a green parrot.'], - 'colour' => ['green'] + itemscope = mock(Mida::Itemscope) + itemscope.stub!(:type).and_return("http://example.com/vocab/person") + itemscope.stub!(:id).and_return(nil) + itemscope.stub!(:properties).and_return( + { 'name' => ['Lorry Woodman'], + 'date' => ['2nd October 2009', '2009-10-02'], + 'url' => ['http://example.com/user/lorry'] } - } + ) + @item = Mida::Item.new(itemscope) end -end - -describe Mida::Item, 'when initialized with an itemscope containing itemprops with the same name' do - before do - # Lemon Sorbet flavour - ls_flavour = mock_element('span', {'itemprop' => 'flavour'}, 'Lemon Sorbet') - - # Apricot Sorbet flavour - as_flavour = mock_element('span', {'itemprop' => 'flavour'}, 'Apricot Sorbet') - - # Strawberry icecream - fruit = mock_element('span', {'itemprop' => 'fruit'}, 'Strawberry') - - # Homemade icecream - style = mock_element('span', {'itemprop' => 'style'}, 'Homemade') - - # The surrounding icecreame-type itemscope - @sb_flavour = mock_element('div', {'itemprop' => 'flavour', - 'itemtype' => 'icecream-type', - 'itemscope' => true}, - nil, [fruit,style]) - - # The surrounding icecreams itemscope element - icecreams = mock_element('div', {'itemtype' => 'icecreams', - 'itemscope' => true}, - nil, [ls_flavour, as_flavour, @sb_flavour]) - @item = Mida::Item.new(icecreams) - end - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic + @item.vocabulary.should == Person end - it '#type should return the correct type' do - @item.type.should == 'icecreams' + it 'should return has_one properties as a single value' do + @item.properties['name'].should == 'Lorry Woodman' end - it '#id should return the correct id' do - @item.id.should == nil + it 'should return has_many properties as an array' do + @item.properties['url'].should == ['http://example.com/user/lorry'] end - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'flavour' => [ - 'Lemon Sorbet', - 'Apricot Sorbet', - Mida::Item.new(@sb_flavour) - ] - } + it 'should reject datatypes that are not valid' do + @item.properties['date'][0].should == '2nd October 2009' end - it '#to_h should return the correct type and properties' do - @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: 'icecreams', - id: nil, - properties: { - 'flavour' => [ - 'Lemon Sorbet', - 'Apricot Sorbet', - { vocabulary: Mida::Vocabulary::Generic, - type: 'icecream-type', - id: nil, - properties: { - 'fruit' => ['Strawberry'], - 'style' => ['Homemade'] - } - } - ] - } - } + it 'should accept datatypes that are valid' do + @item.properties['date'][1].should == Date.iso8601('2009-10-02') end -end - -describe Mida::Item, 'when initialized with an itemscope containing itemrefs' do - - before do - - name = mock_element('span', {'itemprop' => 'name'}, 'Amanda') - name_p = mock_element('p', {'id' => 'a'}, nil, [name]) - - band_name = mock_element('span', {'itemprop' => 'band_name'}, 'Jazz Band') - band_size = mock_element('span', {'itemprop' => 'band_size'}, '12') - band_div = mock_element('div', {'id' => 'c'}, nil, [band_name, band_size]) - @empty_band_div = mock_element('div', {'id' => 'b', - 'itemprop' => 'band', - 'itemref' => 'c', - 'itemscope' => true}, - nil, [], - {'c' => band_div}) - - - age = mock_element('span', {'itemprop' => 'age'}, '30') - age_div = mock_element('div', {'itemref' => 'a b', - 'itemscope' => true}, - nil, [age], - {'a' => name_p, 'b' => @empty_band_div}) - - @item = Mida::Item.new(age_div) + it 'should reject datatypes that are not valid' do + @item.properties['date'][1].should == Date.iso8601('2009-10-02') end - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic - end - - it '#type should return the correct type' do - @item.type.should == nil - end - - it '#id should return the correct id' do - @item.id.should == nil - end - - it '#properties should return the correct name/value pairs' do + it '#properties should return the same properties as the itemscope' do @item.properties.should == { - 'age' => ['30'], - 'name' => ['Amanda'], - 'band' => [Mida::Item.new(@empty_band_div)] + 'name' => 'Lorry Woodman', + 'date' => ['2nd October 2009', Date.iso8601('2009-10-02')], + 'url' => ['http://example.com/user/lorry'] } end it '#to_h should return the correct type and properties' do @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: nil, + type: 'http://example.com/vocab/person', id: nil, properties: { - 'age' => ['30'], - 'name' => ['Amanda'], - 'band' => [{ - vocabulary: Mida::Vocabulary::Generic, - type: nil, - id: nil, - properties: { - 'band_name' => ['Jazz Band'], - 'band_size' => ['12'] - } - }] + 'name' => 'Lorry Woodman', + 'date' => ['2nd October 2009', Date.iso8601('2009-10-02')], + 'url' => ['http://example.com/user/lorry'] } } end end -describe Mida::Item, 'when initialized with an itemscope containing an itemid' do - +describe Mida::Item, 'when initialized with an itemscope of a known type that does not fully match vocabulary' do before do + # Make sure the class is redefined afresh to make sure that + # inherited() hook is called + Mida::Vocabulary.unregister(Person) + Object.send(:remove_const, :Person) + class Person < Mida::Vocabulary + itemtype %r{http://example.com/vocab/person} + has_one 'name', 'tel' + has_many 'url', 'city' + end - title = mock_element('span', {'itemprop' => 'title'}, 'Hacking Vim 7.2') - author = mock_element('span', {'itemprop' => 'author'}, 'Kim Schulz') - book = mock_element('div', { - 'itemtype' => 'book', - 'itemid' => 'urn:isbn:978-1-849510-50-9', - 'itemscope' => true}, - nil, [title,author]) - - @item = Mida::Item.new(book) - end - - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic - end - - it '#type should return the correct type' do - @item.type.should == 'book' - end - - it '#id should return the correct id' do - @item.id.should == 'urn:isbn:978-1-849510-50-9' - end - - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'title' => ['Hacking Vim 7.2'], - 'author' => ['Kim Schulz'] - } - end - - it '#to_h should return the correct type and properties' do - @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: 'book', - id: 'urn:isbn:978-1-849510-50-9', - properties: { - 'title' => ['Hacking Vim 7.2'], - 'author' => ['Kim Schulz'] + itemscope = mock(Mida::Itemscope) + itemscope.stub!(:type).and_return("http://example.com/vocab/person") + itemscope.stub!(:id).and_return(nil) + itemscope.stub!(:properties).and_return( + { 'name' => ['Lorry Woodman'], + 'tel' => ['000004847582', '111111857485'], + 'url' => ['http://example.com/user/lorry'], + 'city' => ['Bristol'] } - } + ) + @item = Mida::Item.new(itemscope) end -end - -describe Mida::Item, 'when initialized with an itemscope containing itemscopes as properties nested two deep' do - before do - - # The name of the item reviewed - @item_name = mock_element('span', {'itemprop' => 'item_name'}, 'Acme Anvil') - - # The rating of the item - @rating = mock_element('span', {'itemprop' => 'rating'}, '5') - - # The first_name - @fn = mock_element('span', {'itemprop' => 'first_name'}, 'Lorry') - - # The last_name - @ln = mock_element('span', {'itemprop' => 'last_name'}, 'Woodman') - - # The organization name - @org_name = mock_element('span', {'itemprop' => 'name'}, 'Acme') - - # The surrounding organization itemscope - @org_el = mock_element('div', {'itemprop' => 'represents', - 'itemtype' => 'organization', - 'itemscope' => true}, nil, [@org_name]) - - # The surrounding reviewer itemscope - @reviewer_el = mock_element('div', {'itemprop' => 'reviewer', - 'itemtype' => 'person', - 'itemscope' => true}, - nil, [@fn,@ln, @org_el]) - - # The surrounding reviewer itemscope - @review_el = mock_element('div', {'itemtype' => 'review', 'itemscope' => true}, nil, [@item_name, @rating, @reviewer_el]) - - @item = Mida::Item.new(@review_el) - - end - - before do - end - it '#vocabulary should return the correct vocabulary' do - @item.vocabulary.should == Mida::Vocabulary::Generic + @item.vocabulary.should == Person end - it '#type should return the correct type' do - @item.type.should == 'review' + it 'should not keep properties that have too many values' do + @item.properties.should_not have_key('tel') end - it '#id should return the correct id' do - @item.id.should == nil + it 'should keep have_many properties even if they have only one value' do + @item.properties.should have_key('city') end - it '#properties should return the correct name/value pairs' do - @item.properties.should == { - 'item_name' => ['Acme Anvil'], - 'rating' => ['5'], - 'reviewer' => [Mida::Item.new(@reviewer_el)] - } - end - - it '#to_h should return the correct type and properties' do - @item.to_h.should == { - vocabulary: Mida::Vocabulary::Generic, - type: 'review', - id: nil, - properties: { - 'item_name' => ['Acme Anvil'], - 'rating' => ['5'], - 'reviewer' => [{ - vocabulary: Mida::Vocabulary::Generic, - type: 'person', - id: nil, - properties: { - 'first_name' => ['Lorry'], - 'last_name' => ['Woodman'], - 'represents' => [{ - vocabulary: Mida::Vocabulary::Generic, - type: 'organization', - id: nil, - properties: { - 'name' => ['Acme'] - } - }] - } - }] - } - } - end end -describe Mida::Item, 'when initialized with an itemscope that matches a non-generic registered vocabulary' do +describe Mida::Item, 'when initialized with an itemscope containing another correct itemscope' do before do - - class Colour < Mida::VocabularyDesc - itemtype %r{http://example.com/vocab/colour} - has_one 'red', 'green', 'blue' + class Tel < Mida::Vocabulary + itemtype %r{http://example.com/vocab/tel} + has_one 'dial_code', 'number' end - Mida::Vocabulary.register(Colour) - class Person < Mida::VocabularyDesc + class Person < Mida::Vocabulary itemtype %r{http://example.com/vocab/person} has_one 'name' - has_one 'url' - has_many 'limbs' - has_many 'favourite-colours' do - types Colour + has_many 'tel' do + extract Tel, Mida::DataType::Text end end - Mida::Vocabulary.register(Person) - red = mock_element('span', {'itemprop' => 'red'}, '0xFF') - green = mock_element('span', {'itemprop' => 'green'}, '0x00') - blue = mock_element('span', {'itemprop' => 'blue'}, '0xFF') - purple = mock_element('div', {'itemscope' => true, - 'itemtype' => 'http://example.com/vocab/colour', - 'itemprop' => 'favourite-colours'}, - nil, [red, green, blue]) - orange = mock_element('span', {'itemprop' => 'favourite-colours'}, 'Orange') - - name1 = mock_element('span', {'itemprop' => 'name'}, 'Lawrence Woodman') - name2 = mock_element('span', {'itemprop' => 'name'}, 'Lorry Woodman') - url = mock_element('a', {'itemprop' => 'url', 'href' => 'http://example.com/myhomepage'}) - arm = mock_element('span', {'itemprop' => 'limbs'}, 'Arm') - leg = mock_element('span', {'itemprop' => 'limbs'}, 'Leg') - robert_wilson = mock_element('span', {'itemprop' => 'favourite-author'}, 'Robert Wilson') - itemscope_el = mock_element('div', {'itemscope' => true, - 'itemtype' =>'http://example.com/vocab/person' - }, nil, [name1, name2, url, arm, leg, purple, orange, robert_wilson]) - @item = Mida::Item.new(itemscope_el, "http://example.com") + tel_itemscope = mock(Mida::Itemscope) + tel_itemscope.stub!(:kind_of?).any_number_of_times.with(Mida::Itemscope).and_return(true) + tel_itemscope.stub!(:type).and_return("http://example.com/vocab/tel") + tel_itemscope.stub!(:id).and_return(nil) + tel_itemscope.stub!(:properties).and_return( + { 'dial_code' => ['0248583'], + 'number' => ['000004847582'], + } + ) + person_itemscope = mock(Mida::Itemscope) + person_itemscope.stub!(:type).and_return("http://example.com/vocab/person") + person_itemscope.stub!(:id).and_return(nil) + person_itemscope.stub!(:properties).and_return( + { 'name' => ['Lorry Woodman'], + 'tel' => ['000004847582', tel_itemscope], + } + ) + @item = Mida::Item.new(person_itemscope) end it '#vocabulary should return the correct vocabulary' do @item.vocabulary.should == Person end - it 'should reject properties that have multiple values if has_one specified' do - @item.properties.should_not have_key('name') + it 'should validate and convert the nested itemscope' do + @item.properties['tel'][1].vocabulary.should == Tel + @item.properties['tel'][1].properties.should == { + 'dial_code' => '0248583', + 'number' => '000004847582', + } end - it 'should accept properties that have a single value if has_one specified' do - @item.properties['url'].should == ['http://example.com/myhomepage'] + it 'should accept the text tel' do + @item.properties['tel'][0].should == '000004847582' end - it 'should accept properties that have a many values if has_many specified' do - @item.properties['limbs'].should == ['Arm', 'Leg'] - end +end - it 'should register properties using the specified types' do - @item.properties['favourite-colours'].size.should == 1 - @item.properties['favourite-colours'].first.vocabulary.should == Colour +describe Mida::Item, 'when initialized with an itemscope containing another invalid itemscope' do + before do + class Person < Mida::Vocabulary + itemtype %r{http://example.com/vocab/person} + has_one 'name' + has_many 'tel' + end + + tel_itemscope = mock(Mida::Itemscope) + tel_itemscope.stub!(:kind_of?).any_number_of_times.with(Mida::Itemscope).and_return(true) + tel_itemscope.stub!(:type).and_return("http://example.com/vocab/tel") + tel_itemscope.stub!(:id).and_return(nil) + tel_itemscope.stub!(:properties).and_return( + { 'dial_code' => ['0248583'], + 'number' => ['000004847582'], + } + ) + person_itemscope = mock(Mida::Itemscope) + person_itemscope.stub!(:type).and_return("http://example.com/vocab/person") + person_itemscope.stub!(:id).and_return(nil) + person_itemscope.stub!(:properties).and_return( + { 'name' => ['Lorry Woodman'], + 'tel' => ['000004847582', tel_itemscope], + } + ) + @item = Mida::Item.new(person_itemscope) end - it 'should reject properties that are not specified' do - @item.properties.should_not have_key('favourite-author') + it 'should only accept values of the correct type' do + @item.properties['tel'].size.should == 1 + @item.properties['tel'][0].should == '000004847582' end + end