feedjira 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +8 -0
  5. data/CHANGELOG.md +162 -0
  6. data/Gemfile +17 -0
  7. data/Guardfile +5 -0
  8. data/README.md +242 -0
  9. data/Rakefile +6 -0
  10. data/benchmarks/README.md +90 -0
  11. data/benchmarks/basic.rb +31 -0
  12. data/benchmarks/feed_list.txt +10 -0
  13. data/benchmarks/feed_xml/apple.xml +149 -0
  14. data/benchmarks/feed_xml/cnn.xml +278 -0
  15. data/benchmarks/feed_xml/daring_fireball.xml +1697 -0
  16. data/benchmarks/feed_xml/engadget.xml +604 -0
  17. data/benchmarks/feed_xml/feedjira_commits.xml +370 -0
  18. data/benchmarks/feed_xml/gizmodo.xml +2 -0
  19. data/benchmarks/feed_xml/loop.xml +441 -0
  20. data/benchmarks/feed_xml/rails.xml +1938 -0
  21. data/benchmarks/feed_xml/white_house.xml +951 -0
  22. data/benchmarks/feed_xml/xkcd.xml +2 -0
  23. data/benchmarks/fetching_systems.rb +23 -0
  24. data/benchmarks/other_libraries.rb +73 -0
  25. data/feedjira.gemspec +27 -0
  26. data/lib/feedjira.rb +16 -0
  27. data/lib/feedjira/core_ext.rb +3 -0
  28. data/lib/feedjira/core_ext/date.rb +19 -0
  29. data/lib/feedjira/core_ext/string.rb +9 -0
  30. data/lib/feedjira/core_ext/time.rb +31 -0
  31. data/lib/feedjira/feed.rb +459 -0
  32. data/lib/feedjira/feed_entry_utilities.rb +66 -0
  33. data/lib/feedjira/feed_utilities.rb +103 -0
  34. data/lib/feedjira/parser.rb +20 -0
  35. data/lib/feedjira/parser/atom.rb +61 -0
  36. data/lib/feedjira/parser/atom_entry.rb +34 -0
  37. data/lib/feedjira/parser/atom_feed_burner.rb +22 -0
  38. data/lib/feedjira/parser/atom_feed_burner_entry.rb +35 -0
  39. data/lib/feedjira/parser/google_docs_atom.rb +28 -0
  40. data/lib/feedjira/parser/google_docs_atom_entry.rb +29 -0
  41. data/lib/feedjira/parser/itunes_rss.rb +50 -0
  42. data/lib/feedjira/parser/itunes_rss_item.rb +41 -0
  43. data/lib/feedjira/parser/itunes_rss_owner.rb +12 -0
  44. data/lib/feedjira/parser/rss.rb +24 -0
  45. data/lib/feedjira/parser/rss_entry.rb +37 -0
  46. data/lib/feedjira/parser/rss_feed_burner.rb +23 -0
  47. data/lib/feedjira/parser/rss_feed_burner_entry.rb +43 -0
  48. data/lib/feedjira/version.rb +3 -0
  49. data/spec/feedjira/feed_entry_utilities_spec.rb +62 -0
  50. data/spec/feedjira/feed_spec.rb +762 -0
  51. data/spec/feedjira/feed_utilities_spec.rb +273 -0
  52. data/spec/feedjira/parser/atom_entry_spec.rb +86 -0
  53. data/spec/feedjira/parser/atom_feed_burner_entry_spec.rb +47 -0
  54. data/spec/feedjira/parser/atom_feed_burner_spec.rb +56 -0
  55. data/spec/feedjira/parser/atom_spec.rb +76 -0
  56. data/spec/feedjira/parser/google_docs_atom_entry_spec.rb +22 -0
  57. data/spec/feedjira/parser/google_docs_atom_spec.rb +31 -0
  58. data/spec/feedjira/parser/itunes_rss_item_spec.rb +63 -0
  59. data/spec/feedjira/parser/itunes_rss_owner_spec.rb +18 -0
  60. data/spec/feedjira/parser/itunes_rss_spec.rb +58 -0
  61. data/spec/feedjira/parser/rss_entry_spec.rb +85 -0
  62. data/spec/feedjira/parser/rss_feed_burner_entry_spec.rb +85 -0
  63. data/spec/feedjira/parser/rss_feed_burner_spec.rb +57 -0
  64. data/spec/feedjira/parser/rss_spec.rb +57 -0
  65. data/spec/sample_feeds/AmazonWebServicesBlog.xml +797 -0
  66. data/spec/sample_feeds/AmazonWebServicesBlogFirstEntryContent.xml +63 -0
  67. data/spec/sample_feeds/AtomFeedWithSpacesAroundEquals.xml +61 -0
  68. data/spec/sample_feeds/FeedBurnerUrlNoAlternate.xml +28 -0
  69. data/spec/sample_feeds/GoogleDocsList.xml +188 -0
  70. data/spec/sample_feeds/HREFConsideredHarmful.xml +314 -0
  71. data/spec/sample_feeds/HREFConsideredHarmfulFirstEntry.xml +22 -0
  72. data/spec/sample_feeds/ITunesWithSpacesInAttributes.xml +63 -0
  73. data/spec/sample_feeds/PaulDixExplainsNothing.xml +175 -0
  74. data/spec/sample_feeds/PaulDixExplainsNothingAlternate.xml +175 -0
  75. data/spec/sample_feeds/PaulDixExplainsNothingFirstEntryContent.xml +19 -0
  76. data/spec/sample_feeds/PaulDixExplainsNothingWFW.xml +174 -0
  77. data/spec/sample_feeds/SamRuby.xml +583 -0
  78. data/spec/sample_feeds/TechCrunch.xml +1515 -0
  79. data/spec/sample_feeds/TechCrunchFirstEntry.xml +9 -0
  80. data/spec/sample_feeds/TechCrunchFirstEntryDescription.xml +3 -0
  81. data/spec/sample_feeds/TenderLovemaking.xml +516 -0
  82. data/spec/sample_feeds/TenderLovemakingFirstEntry.xml +66 -0
  83. data/spec/sample_feeds/TrotterCashionHome.xml +611 -0
  84. data/spec/sample_feeds/TypePadNews.xml +368 -0
  85. data/spec/sample_feeds/atom_with_link_tag_for_url_unmarked.xml +31 -0
  86. data/spec/sample_feeds/itunes.xml +67 -0
  87. data/spec/sample_feeds/pet_atom.xml +497 -0
  88. data/spec/spec_helper.rb +88 -0
  89. metadata +229 -0
@@ -0,0 +1,76 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Feedjira::Parser::Atom do
4
+ describe "#will_parse?" do
5
+ it "should return true for an atom feed" do
6
+ Feedjira::Parser::Atom.should be_able_to_parse(sample_atom_feed)
7
+ end
8
+
9
+ it "should return false for an rdf feed" do
10
+ Feedjira::Parser::Atom.should_not be_able_to_parse(sample_rdf_feed)
11
+ end
12
+
13
+ it "should return false for an rss feedburner feed" do
14
+ Feedjira::Parser::Atom.should_not be_able_to_parse(sample_rss_feed_burner_feed)
15
+ end
16
+
17
+ it "should return true for an atom feed that has line breaks in between attributes in the <feed> node" do
18
+ Feedjira::Parser::Atom.should be_able_to_parse(sample_atom_feed_line_breaks)
19
+ end
20
+ end
21
+
22
+ describe "parsing" do
23
+ before(:each) do
24
+ @feed = Feedjira::Parser::Atom.parse(sample_atom_feed)
25
+ end
26
+
27
+ it "should parse the title" do
28
+ @feed.title.should == "Amazon Web Services Blog"
29
+ end
30
+
31
+ it "should parse the description" do
32
+ @feed.description.should == "Amazon Web Services, Products, Tools, and Developer Information..."
33
+ end
34
+
35
+ it "should parse the url" do
36
+ @feed.url.should == "http://aws.typepad.com/aws/"
37
+ end
38
+
39
+ it "should parse the url even when it doesn't have the type='text/html' attribute" do
40
+ Feedjira::Parser::Atom.parse(load_sample("atom_with_link_tag_for_url_unmarked.xml")).url.should == "http://www.innoq.com/planet/"
41
+ end
42
+
43
+ it "should parse the feed_url even when it doesn't have the type='application/atom+xml' attribute" do
44
+ Feedjira::Parser::Atom.parse(load_sample("atom_with_link_tag_for_url_unmarked.xml")).feed_url.should == "http://www.innoq.com/planet/atom.xml"
45
+ end
46
+
47
+ it "should parse the feed_url" do
48
+ @feed.feed_url.should == "http://aws.typepad.com/aws/atom.xml"
49
+ end
50
+
51
+ it "should parse no hub urls" do
52
+ @feed.hubs.count.should == 0
53
+ end
54
+
55
+ it "should parse the hub urls" do
56
+ feed_with_hub = Feedjira::Parser::Atom.parse(load_sample("SamRuby.xml"))
57
+ feed_with_hub.hubs.count.should == 1
58
+ feed_with_hub.hubs.first.should == "http://pubsubhubbub.appspot.com/"
59
+ end
60
+
61
+ it "should parse entries" do
62
+ @feed.entries.size.should == 10
63
+ end
64
+ end
65
+
66
+ describe "preprocessing" do
67
+ it "retains markup in xhtml content" do
68
+ Feedjira::Parser::Atom.preprocess_xml = true
69
+
70
+ feed = Feedjira::Parser::Atom.parse sample_atom_xhtml_feed
71
+ entry = feed.entries.first
72
+
73
+ entry.content.should match /\<div/
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,22 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Feedjira::Parser::GoogleDocsAtomEntry do
4
+ describe 'parsing' do
5
+ before do
6
+ @feed = Feedjira::Parser::GoogleDocsAtom.parse(sample_google_docs_list_feed)
7
+ @entry = @feed.entries.first
8
+ end
9
+
10
+ it 'should have the custom checksum element' do
11
+ @entry.checksum.should eql '2b01142f7481c7b056c4b410d28f33cf'
12
+ end
13
+
14
+ it 'should have the custom filename element' do
15
+ @entry.original_filename.should eql "MyFile.pdf"
16
+ end
17
+
18
+ it 'should have the custom suggested filename element' do
19
+ @entry.suggested_filename.should eql "TaxDocument.pdf"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Feedjira::Parser::GoogleDocsAtom do
4
+ describe '.able_to_parser?' do
5
+ it 'should return true for Google Docs feed' do
6
+ Feedjira::Parser::GoogleDocsAtom.should be_able_to_parse(sample_google_docs_list_feed)
7
+ end
8
+
9
+ it 'should not be able to parse another Atom feed' do
10
+ Feedjira::Parser::GoogleDocsAtom.should_not be_able_to_parse(sample_atom_feed)
11
+ end
12
+ end
13
+
14
+ describe 'parsing' do
15
+ before do
16
+ @feed = Feedjira::Parser::GoogleDocsAtom.parse(sample_google_docs_list_feed)
17
+ end
18
+
19
+ it 'should return a bunch of objects' do
20
+ @feed.entries.should_not be_empty
21
+ end
22
+
23
+ it 'should populate a title, interhited from the Atom entry' do
24
+ @feed.title.should_not be_nil
25
+ end
26
+
27
+ it 'should return a bunch of entries of type GoogleDocsAtomEntry' do
28
+ @feed.entries.first.should be_a Feedjira::Parser::GoogleDocsAtomEntry
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Feedjira::Parser::ITunesRSSItem do
4
+ before(:each) do
5
+ # I don't really like doing it this way because these unit test should only rely on ITunesRssItem,
6
+ # but this is actually how it should work. You would never just pass entry xml straight to the ITunesRssItem
7
+ @item = Feedjira::Parser::ITunesRSS.parse(sample_itunes_feed).entries.first
8
+ end
9
+
10
+ it "should parse the title" do
11
+ @item.title.should == "Shake Shake Shake Your Spices"
12
+ end
13
+
14
+ it "should parse the author" do
15
+ @item.itunes_author.should == "John Doe"
16
+ end
17
+
18
+ it "should parse the subtitle" do
19
+ @item.itunes_subtitle.should == "A short primer on table spices"
20
+ end
21
+
22
+ it "should parse the summary" do
23
+ @item.itunes_summary.should == "This week we talk about salt and pepper shakers, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!"
24
+ end
25
+
26
+ it "should parse the enclosure" do
27
+ @item.enclosure_length.should == "8727310"
28
+ @item.enclosure_type.should == "audio/x-m4a"
29
+ @item.enclosure_url.should == "http://example.com/podcasts/everything/AllAboutEverythingEpisode3.m4a"
30
+ end
31
+
32
+ it "should parse the guid as id" do
33
+ @item.id.should == "http://example.com/podcasts/archive/aae20050615.m4a"
34
+ end
35
+
36
+ it "should parse the published date" do
37
+ @item.published.should == Time.parse_safely("Wed Jun 15 19:00:00 UTC 2005")
38
+ end
39
+
40
+ it "should parse the duration" do
41
+ @item.itunes_duration.should == "7:04"
42
+ end
43
+
44
+ it "should parse the keywords" do
45
+ @item.itunes_keywords.should == "salt, pepper, shaker, exciting"
46
+ end
47
+
48
+ it "should parse the image" do
49
+ @item.itunes_image.should == "http://example.com/podcasts/everything/AllAboutEverything.jpg"
50
+ end
51
+
52
+ it "should parse the order" do
53
+ @item.itunes_order.should eq '12'
54
+ end
55
+
56
+ it "should parse the closed captioned flag" do
57
+ @item.itunes_closed_captioned.should eq 'yes'
58
+ end
59
+
60
+ it "should parse the encoded content" do
61
+ @item.content.should == "<p><strong>TOPIC</strong>: Gooseneck Options</p>"
62
+ end
63
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Feedjira::Parser::ITunesRSSOwner do
4
+ before(:each) do
5
+ # I don't really like doing it this way because these unit test should only rely on RSSEntry,
6
+ # but this is actually how it should work. You would never just pass entry xml straight to the ITunesRssOwner
7
+ @owner = Feedjira::Parser::ITunesRSS.parse(sample_itunes_feed).itunes_owners.first
8
+ end
9
+
10
+ it "should parse the name" do
11
+ @owner.name.should == "John Doe"
12
+ end
13
+
14
+ it "should parse the email" do
15
+ @owner.email.should == "john.doe@example.com"
16
+ end
17
+
18
+ end
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
2
+
3
+ describe Feedjira::Parser::ITunesRSS do
4
+ describe "#will_parse?" do
5
+ it "should return true for an itunes RSS feed" do
6
+ Feedjira::Parser::ITunesRSS.should be_able_to_parse(sample_itunes_feed)
7
+ end
8
+
9
+ it "should return true for an itunes RSS feed with spaces between attribute names, equals sign, and values" do
10
+ Feedjira::Parser::ITunesRSS.should be_able_to_parse(sample_itunes_feed_with_spaces)
11
+ end
12
+
13
+ it "should return fase for an atom feed" do
14
+ Feedjira::Parser::ITunesRSS.should_not be_able_to_parse(sample_atom_feed)
15
+ end
16
+
17
+ it "should return false for an rss feedburner feed" do
18
+ Feedjira::Parser::ITunesRSS.should_not be_able_to_parse(sample_rss_feed_burner_feed)
19
+ end
20
+ end
21
+
22
+ describe "parsing" do
23
+ before(:each) do
24
+ @feed = Feedjira::Parser::ITunesRSS.parse(sample_itunes_feed)
25
+ end
26
+
27
+ it "should parse the subtitle" do
28
+ @feed.itunes_subtitle.should == "A show about everything"
29
+ end
30
+
31
+ it "should parse the author" do
32
+ @feed.itunes_author.should == "John Doe"
33
+ end
34
+
35
+ it "should parse an owner" do
36
+ @feed.itunes_owners.size.should == 1
37
+ end
38
+
39
+ it "should parse an image" do
40
+ @feed.itunes_image.should == "http://example.com/podcasts/everything/AllAboutEverything.jpg"
41
+ end
42
+
43
+ it "should parse categories" do
44
+ @feed.itunes_categories.size == 3
45
+ @feed.itunes_categories[0] == "Technology"
46
+ @feed.itunes_categories[1] == "Gadgets"
47
+ @feed.itunes_categories[2] == "TV &amp; Film"
48
+ end
49
+
50
+ it "should parse the summary" do
51
+ @feed.itunes_summary.should == "All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our Podcast in the iTunes Music Store"
52
+ end
53
+
54
+ it "should parse entries" do
55
+ @feed.entries.size.should == 3
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,85 @@
1
+ # coding: utf-8
2
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
3
+
4
+ describe Feedjira::Parser::RSSEntry do
5
+ before(:each) do
6
+ # I don't really like doing it this way because these unit test should only rely on RSSEntry,
7
+ # but this is actually how it should work. You would never just pass entry xml straight to the AtomEnry
8
+ @entry = Feedjira::Parser::RSS.parse(sample_rss_feed).entries.first
9
+ end
10
+
11
+ after(:each) do
12
+ # We change the title in one or more specs to test []=
13
+ if @entry.title != "Nokogiri’s Slop Feature"
14
+ @entry.title = Feedjira::Parser::RSS.parse(sample_rss_feed).entries.first.title
15
+ end
16
+ end
17
+
18
+ it "should parse the title" do
19
+ @entry.title.should == "Nokogiri’s Slop Feature"
20
+ end
21
+
22
+ it "should parse the url" do
23
+ @entry.url.should == "http://tenderlovemaking.com/2008/12/04/nokogiris-slop-feature/"
24
+ end
25
+
26
+ it "should parse the author" do
27
+ @entry.author.should == "Aaron Patterson"
28
+ end
29
+
30
+ it "should parse the content" do
31
+ @entry.content.should == sample_rss_entry_content
32
+ end
33
+
34
+ it "should provide a summary" do
35
+ @entry.summary.should == "Oops! When I released nokogiri version 1.0.7, I totally forgot to talk about Nokogiri::Slop() feature that was added. Why is it called \"slop\"? It lets you sloppily explore documents. Basically, it decorates your document with method_missing() that allows you to search your document via method calls.\nGiven this document:\n\ndoc = Nokogiri::Slop&#40;&#60;&#60;-eohtml&#41;\n&#60;html&#62;\n&#160; &#60;body&#62;\n&#160; [...]"
36
+ end
37
+
38
+ it "should parse the published date" do
39
+ @entry.published.should == Time.parse_safely("Thu Dec 04 17:17:49 UTC 2008")
40
+ end
41
+
42
+ it "should parse the categories" do
43
+ @entry.categories.should == ['computadora', 'nokogiri', 'rails']
44
+ end
45
+
46
+ it "should parse the guid as id" do
47
+ @entry.id.should == "http://tenderlovemaking.com/?p=198"
48
+ end
49
+
50
+ it "should support each" do
51
+ @entry.respond_to? :each
52
+ end
53
+
54
+ it "should be able to list out all fields with each" do
55
+ all_fields = []
56
+ @entry.each do |field, value|
57
+ all_fields << field
58
+ end
59
+ all_fields.sort == ['author', 'categories', 'content', 'id', 'published', 'summary', 'title', 'url']
60
+ end
61
+
62
+ it "should be able to list out all values with each" do
63
+ title_value = ''
64
+ @entry.each do |field, value|
65
+ title_value = value if field == 'title'
66
+ end
67
+ title_value.should == "Nokogiri’s Slop Feature"
68
+ end
69
+
70
+ it "should support checking if a field exists in the entry" do
71
+ @entry.include?('title') && @entry.include?('author')
72
+ end
73
+
74
+ it "should allow access to fields with hash syntax" do
75
+ @entry['title'] == @entry.title
76
+ @entry['title'].should == "Nokogiri’s Slop Feature"
77
+ @entry['author'] == @entry.author
78
+ @entry['author'].should == "Aaron Patterson"
79
+ end
80
+
81
+ it "should allow setting field values with hash syntax" do
82
+ @entry['title'] = "Foobar"
83
+ @entry.title.should == "Foobar"
84
+ end
85
+ end
@@ -0,0 +1,85 @@
1
+ # coding: utf-8
2
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
3
+
4
+ describe Feedjira::Parser::RSSFeedBurnerEntry do
5
+ before(:each) do
6
+ # I don't really like doing it this way because these unit test should only rely on RSSEntry,
7
+ # but this is actually how it should work. You would never just pass entry xml straight to the AtomEnry
8
+ @entry = Feedjira::Parser::RSSFeedBurner.parse(sample_rss_feed_burner_feed).entries.first
9
+ end
10
+
11
+ after(:each) do
12
+ # We change the title in one or more specs to test []=
13
+ if @entry.title != "Angie’s List Sets Price Range IPO At $11 To $13 Per Share; Valued At Over $600M"
14
+ @entry.title = Feedjira::Parser::RSS.parse(sample_rss_feed_burner_feed).entries.first.title
15
+ end
16
+ end
17
+
18
+ it "should parse the title" do
19
+ @entry.title.should == "Angie’s List Sets Price Range IPO At $11 To $13 Per Share; Valued At Over $600M"
20
+ end
21
+
22
+ it "should parse the original url" do
23
+ @entry.url.should == "http://techcrunch.com/2011/11/02/angies-list-prices-ipo-at-11-to-13-per-share-valued-at-over-600m/"
24
+ end
25
+
26
+ it "should parse the author" do
27
+ @entry.author.should == "Leena Rao"
28
+ end
29
+
30
+ it "should parse the content" do
31
+ @entry.content.should == sample_rss_feed_burner_entry_content
32
+ end
33
+
34
+ it "should provide a summary" do
35
+ @entry.summary.should == sample_rss_feed_burner_entry_description
36
+ end
37
+
38
+ it "should parse the published date" do
39
+ @entry.published.should == Time.parse_safely("Wed Nov 02 17:25:27 UTC 2011")
40
+ end
41
+
42
+ it "should parse the categories" do
43
+ @entry.categories.should == ["TC", "angie\\'s list"]
44
+ end
45
+
46
+ it "should parse the guid as id" do
47
+ @entry.id.should == "http://techcrunch.com/?p=446154"
48
+ end
49
+
50
+ it "should support each" do
51
+ @entry.respond_to? :each
52
+ end
53
+
54
+ it "should be able to list out all fields with each" do
55
+ all_fields = []
56
+ @entry.each do |field, value|
57
+ all_fields << field
58
+ end
59
+ all_fields.sort == ['author', 'categories', 'content', 'id', 'published', 'summary', 'title', 'url']
60
+ end
61
+
62
+ it "should be able to list out all values with each" do
63
+ title_value = ''
64
+ @entry.each do |field, value|
65
+ title_value = value if field == 'title'
66
+ end
67
+ title_value.should == "Angie’s List Sets Price Range IPO At $11 To $13 Per Share; Valued At Over $600M"
68
+ end
69
+
70
+ it "should support checking if a field exists in the entry" do
71
+ @entry.include?('title') && @entry.include?('author')
72
+ end
73
+
74
+ it "should allow access to fields with hash syntax" do
75
+ @entry['title'] == @entry.title
76
+ @entry['title'].should == "Angie’s List Sets Price Range IPO At $11 To $13 Per Share; Valued At Over $600M"
77
+ @entry['author'] == @entry.author
78
+ @entry['author'].should == "Leena Rao"
79
+ end
80
+
81
+ it "should allow setting field values with hash syntax" do
82
+ @entry['title'] = "Foobar"
83
+ @entry.title.should == "Foobar"
84
+ end
85
+ end