facebook_wall 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ .DS_Store
7
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in facebook_wall.gemspec
4
+ gemspec
@@ -0,0 +1,66 @@
1
+ = facebook_wall
2
+
3
+ facebook_wall is a very simple library that fetches the latest wall-posts for a Facebook page without having to log in -
4
+ wall posts are taken from the page's RSS feed. The markup in posts is filtered to help ensure standards-compliance and
5
+ prevent errors when inserted into your own Web pages.
6
+
7
+ == Requirements
8
+
9
+ facebook_wall was written and tested on Ruby 1.9.2 but is likely to work on other versions. It requires no 3rd-party
10
+ libraries - it uses the open-uri and RSS libs from the Standard Library.
11
+
12
+ == Installation
13
+
14
+ Using Bundler:
15
+
16
+ gem 'facebook_wall'
17
+
18
+ or:
19
+
20
+ gem 'facebook_wall', :git => 'git://github.com/archaichorizon/ruby-facebook-wall.git'
21
+
22
+ == Usage
23
+
24
+ The following example prints the latest wall-post from
25
+ {Archaic Horizon's Facebook page}[http://www.facebook.com/archaichorizon].
26
+
27
+ require 'facebook_wall'
28
+
29
+ facebook_wall_posts = FacebookWall::posts_by 260041833284
30
+ latest_wall_post = facebook_wall_posts.first
31
+
32
+ puts latest_wall_post.description
33
+
34
+ <tt>FacebookWall::posts_by</tt> returns an <tt>Array</tt> containing instances of <tt>FacebookWall::Post</tt>.
35
+ <tt>FacebookWall::Post</tt> decorates <tt>RSS::Rss::Channel::Item</tt>, which means you can easily access all
36
+ sub-elements of <tt>item</tt>s published in a page's feed.
37
+ For example:
38
+
39
+ post.title # => A title automatically generated by Facebook
40
+ post.link # => The URL of the wall post
41
+ post.description # => The content of the wall post
42
+ post.pubDate # => The date the post was published
43
+ post.author # => The author of the post
44
+
45
+ == Filters
46
+
47
+ The library applies two filters to each item in the feed:
48
+
49
+ * <tt>FacebookWall::FeedEntryFilters::LinkRewriter</tt> completely rewrites HTML links in items, removing superfluous
50
+ attributes added by Facebook.
51
+ * <tt>FacebookWall::FeedEntryFilters::Paragraphizer</tt> wraps 'plain' paragraphs with <tt>P</tt> tags to create
52
+ semantically-correct HTML.
53
+
54
+ You can insert your own filters into the chain by adding subclasses of
55
+ <tt>FacebookWall::FeedEntryFilters::FeedEntryFilter</tt> to the <tt>FacebookWall::FeedEntryFilters</tt> module. The
56
+ following filter, for example, would append the word "foo" to the description of each item.
57
+
58
+ module FacebookWall
59
+ module FeedEntryFilters
60
+ class CustomFilter < FeedEntryFilter
61
+ def apply!(feed_entry)
62
+ feed_entry.description << 'foo'
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = Dir.glob("#{File.dirname(__FILE__)}/test/**/*_test.rb").sort
10
+ t.warning = true
11
+ t.verbose = true
12
+ end
13
+
14
+ Rake::RDocTask.new do |rd|
15
+ rd.main = 'README.rdoc'
16
+ rd.rdoc_files.include 'README.rdoc', 'lib/**/*.rb'
17
+ rd.rdoc_dir = 'doc'
18
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "facebook_wall/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "facebook_wall"
7
+ s.version = FacebookWall::VERSION
8
+ s.authors = ["Dan Bettles"]
9
+ s.email = ["dan@archaichorizon.com"]
10
+ s.homepage = "http://www.archaichorizon.com/"
11
+ s.summary = %q{facebook_wall is a very simple library that fetches the latest wall-posts for a Facebook page without having to log in - wall posts are taken from the page's RSS feed.}
12
+ s.description = %q{facebook_wall is a very simple library that fetches the latest wall-posts for a Facebook page without having to log in - wall posts are taken from the page's RSS feed. The markup in posts is filtered to help ensure standards-compliance and prevent errors when inserted into your own Web pages.}
13
+
14
+ s.rubyforge_project = "facebook_wall"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ #s.add_runtime_dependency 'feedzirra', '~> 0.1.3'
24
+ end
@@ -0,0 +1,12 @@
1
+ require 'open-uri'
2
+ require 'rss/2.0'
3
+
4
+ require 'facebook_wall/std_lib_ext'
5
+ require 'facebook_wall/version'
6
+ require 'facebook_wall/methods'
7
+ require 'facebook_wall/post'
8
+ require 'facebook_wall/feed_entry_filters/feed_entry_filter'
9
+ require 'facebook_wall/feed_entry_filters/paragraphizer'
10
+ require 'facebook_wall/feed_entry_filters/link_rewriter'
11
+ require 'facebook_wall/feed_entry_filters/chain'
12
+ require 'facebook_wall/factories/methods'
@@ -0,0 +1,34 @@
1
+ module FacebookWall
2
+ module Factories
3
+ #Creates a filter chain containing instances of all feed-entry filters (subclasses of
4
+ #FacebookWall::FeedEntryFilters::FeedEntryFilter) in FacebookWall::FeedEntryFilters.
5
+ #=== Returns
6
+ #FacebookWall::FeedEntryFilters::Chain
7
+ def self.create_feed_entry_filter_chain
8
+ feed_entry_filters_module = FacebookWall::FeedEntryFilters
9
+
10
+ chain = feed_entry_filters_module::Chain.new
11
+
12
+ feed_entry_filters_module.constants.each do |name|
13
+ constant = feed_entry_filters_module.const_get name
14
+ chain << constant.new if constant < feed_entry_filters_module::FeedEntryFilter
15
+ end
16
+
17
+ chain
18
+ end
19
+
20
+ #Creates wall posts from the <tt>item</tt>s in the specified RSS feed.
21
+ #=== Parameters
22
+ #[feed - RSS::Rss] A RSS feed
23
+ #[feed_entry_filter_chain - FacebookWall::FeedEntryFilters::Chain] A filter chain
24
+ #=== Returns
25
+ #Array of FacebookWall::Post objects
26
+ def self.create_posts(feed, feed_entry_filter_chain)
27
+ feed.items.collect do |entry|
28
+ entry_clone = entry.clone #TODO Remove this?
29
+ feed_entry_filter_chain.apply_filters_to! entry_clone
30
+ FacebookWall::Post.new entry_clone
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ module FacebookWall
2
+ module FeedEntryFilters
3
+ class Chain < Array
4
+ #Applies the filters in the chain to the specified RSS item.
5
+ #=== Parameters
6
+ #[feed_entry - RSS::Rss::Channel::Item] A RSS item
7
+ def apply_filters_to!(feed_entry)
8
+ each do |feed_entry_filter|
9
+ feed_entry_filter.apply! feed_entry
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module FacebookWall
2
+ module FeedEntryFilters
3
+ class FeedEntryFilter
4
+ #Applies the filter to the specified RSS item. This method should be overridden in subclasses.
5
+ #=== Parameters
6
+ #[feed_entry - RSS::Rss::Channel::Item] A RSS item
7
+ def apply!(feed_entry); end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ module FacebookWall
2
+ module FeedEntryFilters
3
+ #Completely rewrites HTML links in <tt>item</tt>s, removing superfluous attributes added by Facebook. For example,
4
+ # <a href="http://example.com" target="_blank" onmousedown="doSomething()" rel="nofollow" id="link">example.com</a>
5
+ #would be replaced with:
6
+ # <a href="http://example.com">example.com</a>
7
+ class LinkRewriter < FeedEntryFilter
8
+ def apply!(feed_entry)
9
+ feed_entry.description.scan(/<a\s+[^>]+>/).each do |link_tag|
10
+ href_matches = link_tag.match(/\s+(href="[^"]*")/)
11
+ feed_entry.description.gsub! link_tag, "<a #{href_matches[1]}>" if href_matches
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module FacebookWall
2
+ module FeedEntryFilters
3
+ #Builds HTML paragraphs from groups of text separated by multiple +BR+ tags. For example:
4
+ # First paragraph<br /> <br /> Second paragraph<br/><br/><br/>Something inserted<br/>by Facebook
5
+ #would be replaced with:
6
+ # <p>First paragraph</p><p>Second paragraph</p><p>Something inserted<br/>by Facebook</p>
7
+ class Paragraphizer < FeedEntryFilter
8
+ def apply!(feed_entry)
9
+ plain_paragraphs = Paragraphizer.normalize_line_breaks(feed_entry.description).split(/(?:<br\/>\s*){2,}/)
10
+ paragraphized = plain_paragraphs.collect{|plain_paragraph| "<p>#{plain_paragraph}</p>"}.join
11
+ feed_entry.description = paragraphized
12
+ end
13
+
14
+ private
15
+
16
+ def self.normalize_line_breaks(str)
17
+ str.gsub(/<br\s*\/>/, '<br/>')
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module FacebookWall
2
+ #Returns the URL of the RSS feed for the specified Facebook page's wall.
3
+ #=== Parameters
4
+ #[id - Fixnum] The ID of the Facebook page
5
+ #=== Returns
6
+ #String
7
+ def self.feed_url(id)
8
+ "http://www.facebook.com/feeds/page.php?id=#{id.to_s}&format=rss20"
9
+ end
10
+
11
+ #Returns the most recent posts from the specified Facebook page's wall.
12
+ #=== Parameters
13
+ #[id - Fixnum] The ID of the Facebook page
14
+ #=== Returns
15
+ #Array of FacebookWall::Post objects
16
+ def self.posts_by(id)
17
+ feed = RSS::Parser.fetch_and_parse feed_url id
18
+ feed_entry_filter_chain = Factories::create_feed_entry_filter_chain
19
+ Factories::create_posts feed, feed_entry_filter_chain
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module FacebookWall
2
+ #A Facebook wall post.
3
+ #
4
+ #FacebookWall::Post decorates RSS::Rss::Channel::Item, which means you can easily access all sub-elements of
5
+ #<tt>item</tt>s published in a page's feed. For example:
6
+ #
7
+ # post.title # => A title automatically generated by Facebook
8
+ # post.link # => The URL of the wall post
9
+ # post.description # => The content of the wall post
10
+ # post.pubDate # => The date the post was published
11
+ # post.author # => The author of the post
12
+ class Post
13
+ attr_reader :feed_entry
14
+
15
+ def initialize(feed_entry)
16
+ @feed_entry = feed_entry
17
+ end
18
+
19
+ def method_missing(method_id) #:nodoc:
20
+ feed_entry.send method_id.id2name
21
+ end
22
+ end
23
+ end
@@ -0,0 +1 @@
1
+ require 'facebook_wall/std_lib_ext/rss/parser'
@@ -0,0 +1,15 @@
1
+ #TODO Blog post
2
+ module RSS
3
+ class Parser
4
+ #Fetches, and then parses, the RSS feed at the specified URL
5
+ #=== Parameters
6
+ #[url - String] The URL of the RSS feed
7
+ #=== Returns
8
+ #RSS::Rss
9
+ def self.fetch_and_parse(url)
10
+ open url do |http|
11
+ RSS::Parser.parse http.read
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module FacebookWall
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,33 @@
1
+ require 'test/unit'
2
+
3
+ lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
4
+ $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
5
+
6
+ require 'facebook_wall'
7
+
8
+ def create_feed(xml)
9
+ RSS::Parser.parse xml
10
+ end
11
+
12
+ def create_feed_entry(attributes = {})
13
+ feed_entry = RSS::Rss::Channel::Item.new
14
+
15
+ attributes.each do |name, value|
16
+ feed_entry.send("#{name}=", value)
17
+ end
18
+
19
+ feed_entry
20
+ end
21
+
22
+ module FacebookWall
23
+ class Post
24
+ def eql?(other)
25
+ #This will hold for as long as the feed entry is the only source of data
26
+ other.instance_of?(self.class) && feed_entry.to_s.eql?(other.feed_entry.to_s)
27
+ end
28
+ end
29
+ end
30
+
31
+ def create_post(attributes)
32
+ FacebookWall::Post.new create_feed_entry(attributes)
33
+ end
@@ -0,0 +1,14 @@
1
+ require 'abstract_unit'
2
+
3
+ class FacebookWallTest < Test::Unit::TestCase
4
+ def test_feed_url_returns_the_url_of_the_wall_feed_for_the_specified_page
5
+ assert_equal 'http://www.facebook.com/feeds/page.php?id=260041833284&format=rss20', FacebookWall::feed_url(260041833284)
6
+ end
7
+
8
+ def test_posts_returns_an_array_of_posts
9
+ posts = FacebookWall::posts_by 260041833284
10
+ assert posts.instance_of?(Array)
11
+ assert posts.length > 0
12
+ assert posts.first.instance_of?(FacebookWall::Post)
13
+ end
14
+ end
@@ -0,0 +1,112 @@
1
+ require 'abstract_unit'
2
+
3
+ class FactoriesTest < Test::Unit::TestCase
4
+ def test_create_feed_entry_filter_chain_creates_a_chain_containing_all_filters_in_the_feed_entry_filters_module
5
+ feed_entry_filters_module = FacebookWall::FeedEntryFilters
6
+
7
+ feed_entry_filter_chain = FacebookWall::Factories::create_feed_entry_filter_chain
8
+
9
+ assert feed_entry_filter_chain.instance_of?(feed_entry_filters_module::Chain)
10
+ assert_equal 2, feed_entry_filter_chain.length
11
+
12
+ expected_classes = [feed_entry_filters_module::Paragraphizer, feed_entry_filters_module::LinkRewriter]
13
+
14
+ feed_entry_filter_chain.each{|feed_entry_filter| assert expected_classes.include?(feed_entry_filter.class)}
15
+ end
16
+
17
+ def test_create_posts_creates_an_array_containing_posts
18
+ feed_xml = <<END
19
+ <?xml version="1.0" encoding="utf-8"?>
20
+ <rss version="2.0">
21
+ <channel>
22
+ <title>Channel title</title>
23
+ <link>http://example.com/</link>
24
+ <description>Channel description</description>
25
+ <item>
26
+ <title><![CDATA[Item 1 title]]></title>
27
+ <link>http://example.com/blog_posts/1</link>
28
+ <description><![CDATA[Item 1 description]]></description>
29
+ </item>
30
+ <item>
31
+ <title><![CDATA[Item 2 title]]></title>
32
+ <link>http://example.com/blog_posts/2</link>
33
+ <description><![CDATA[Item 2 description]]></description>
34
+ </item>
35
+ </channel>
36
+ </rss>
37
+ END
38
+
39
+ feed = create_feed feed_xml
40
+ feed_entry_filter_chain = FacebookWall::FeedEntryFilters::Chain.new
41
+ posts = FacebookWall::Factories::create_posts feed, feed_entry_filter_chain
42
+
43
+ assert posts.instance_of?(Array)
44
+ assert_equal 2, posts.length
45
+ posts.each{|post| assert post.instance_of?(FacebookWall::Post)}
46
+
47
+ assert posts.first.eql?(create_post('title' => 'Item 1 title', 'link' => 'http://example.com/blog_posts/1', 'description' => 'Item 1 description'))
48
+ assert posts.last.eql?(create_post('title' => 'Item 2 title', 'link' => 'http://example.com/blog_posts/2', 'description' => 'Item 2 description'))
49
+
50
+ feed = create_feed feed_xml
51
+ feed_entry_filter_chain = FacebookWall::FeedEntryFilters::Chain.new
52
+ feed_entry_filter_chain << FactoriesTestDoubles::FeedEntryFilter01.new()
53
+ feed_entry_filter_chain << FactoriesTestDoubles::FeedEntryFilter02.new()
54
+ posts = FacebookWall::Factories::create_posts feed, feed_entry_filter_chain
55
+
56
+ assert posts.instance_of?(Array)
57
+ assert_equal 2, posts.length
58
+ posts.each{|post| assert post.instance_of?(FacebookWall::Post)}
59
+
60
+ assert posts.first.eql?(create_post('title' => 'Item 1 title', 'link' => 'http://example.com/blog_posts/1', 'description' => 'Item 1 description foo bar'))
61
+ assert posts.last.eql?(create_post('title' => 'Item 2 title', 'link' => 'http://example.com/blog_posts/2', 'description' => 'Item 2 description foo bar'))
62
+
63
+ feed_xml = <<END
64
+ <?xml version="1.0" encoding="utf-8"?>
65
+ <rss version="2.0">
66
+ <channel>
67
+ <title>Archaic Horizon&apos;s Facebook Wall</title>
68
+ <link>http://www.facebook.com/</link>
69
+ <description>Archaic Horizon&apos;s Facebook Wall</description>
70
+ <item>
71
+ <title><![CDATA[ More of Jeremy Morgan&#039;s work here: http://jphmorgan.com]]></title>
72
+ <link>http://www.facebook.com/archaichorizon/posts/262512677162510</link>
73
+ <description><![CDATA[More of Jeremy Morgan&#039;s work here: <a href="http://jphmorgan.com/" target="_blank" rel="nofollow nofollow" onmousedown="UntrustedLink.bootstrap($(this), &quot;4AQEEBrT_&quot;, event, bagof(&#123;&#125;));">http://jphmorgan.com/</a><br/><br/><a href="http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg" id="" title="" target="" onclick="" style="" onmousedown="UntrustedLink.bootstrap($(this), &quot;PAQGoceG_&quot;, event, bagof(&#123;&#125;));" rel="nofollow"><img class="img" src="http://external.ak.fbcdn.net/safe_image.php?d=AQDzaFjOqqk40sEl&amp;w=90&amp;h=90&amp;url=http%3A%2F%2F27.media.tumblr.com%2Ftumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg" alt="" /></a><br/><a href="http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg" id="" target="_blank" style="" onmousedown="UntrustedLink.bootstrap($(this), &quot;eAQE2srCn&quot;, event, bagof(&#123;&#125;));" rel="nofollow"><a href="http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg" target="_blank" rel="nofollow nofollow" onmousedown="UntrustedLink.bootstrap($(this), &quot;yAQFp-Snl&quot;, event, bagof(&#123;&#125;));">http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg</a></a><br/>27.media.tumblr.com]]></description>
74
+ </item>
75
+ <item>
76
+ <title><![CDATA[ A generative ambient sound instrument created by Batuhan Bozkurt, a sound artist...]]></title>
77
+ <link>http://www.facebook.com/archaichorizon/posts/377150222297415</link>
78
+ <description><![CDATA[A generative ambient sound instrument created by Batuhan Bozkurt, a sound artist, computer programmer, performer and overall a curious person currently living in Istanbul, Turkey.<br /> <br /> <a href="http://www.earslap.com/projectslab/circuli?q=2608v4564v1o_2o66564k1k7_2o4o063442262o" target="_blank" rel="nofollow nofollow" onmousedown="UntrustedLink.bootstrap($(this), &quot;CAQHV5LbD&quot;, event, bagof(&#123;&#125;));">http://www.earslap.com/projectslab/circuli?q=2608v4564v1o_2o66564k1k7_2o4o063442262o</a><br/><br/><br/><a href="http://www.earslap.com/projectslab/circuli?q=2608v4564v1o_2o66564k1k7_2o4o063442262o" id="" target="_blank" style="" onmousedown="UntrustedLink.bootstrap($(this), &quot;mAQGmvWic&quot;, event, bagof(&#123;&#125;));" rel="nofollow">Circuli</a><br/>www.earslap.com]]></description>
79
+ </item>
80
+ </channel>
81
+ </rss>
82
+ END
83
+
84
+ feed = create_feed feed_xml
85
+ feed_entry_filter_chain = FacebookWall::Factories::create_feed_entry_filter_chain
86
+ posts = FacebookWall::Factories::create_posts feed, feed_entry_filter_chain
87
+
88
+ assert_equal(
89
+ '<p>More of Jeremy Morgan&#039;s work here: <a href="http://jphmorgan.com/">http://jphmorgan.com/</a></p><p><a href="http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg"><img class="img" src="http://external.ak.fbcdn.net/safe_image.php?d=AQDzaFjOqqk40sEl&amp;w=90&amp;h=90&amp;url=http%3A%2F%2F27.media.tumblr.com%2Ftumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg" alt="" /></a><br/><a href="http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg"><a href="http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg">http://27.media.tumblr.com/tumblr_m09mfxU8kE1qdrgo9o9_r8_500.jpg</a></a><br/>27.media.tumblr.com</p>',
90
+ posts.first.description
91
+ )
92
+
93
+ assert_equal(
94
+ '<p>A generative ambient sound instrument created by Batuhan Bozkurt, a sound artist, computer programmer, performer and overall a curious person currently living in Istanbul, Turkey.</p><p><a href="http://www.earslap.com/projectslab/circuli?q=2608v4564v1o_2o66564k1k7_2o4o063442262o">http://www.earslap.com/projectslab/circuli?q=2608v4564v1o_2o66564k1k7_2o4o063442262o</a></p><p><a href="http://www.earslap.com/projectslab/circuli?q=2608v4564v1o_2o66564k1k7_2o4o063442262o">Circuli</a><br/>www.earslap.com</p>',
95
+ posts.last.description
96
+ )
97
+ end
98
+ end
99
+
100
+ module FactoriesTestDoubles
101
+ class FeedEntryFilter01 < FacebookWall::FeedEntryFilters::FeedEntryFilter
102
+ def apply!(feed_entry)
103
+ feed_entry.description << ' foo'
104
+ end
105
+ end
106
+
107
+ class FeedEntryFilter02 < FacebookWall::FeedEntryFilters::FeedEntryFilter
108
+ def apply!(feed_entry)
109
+ feed_entry.description << ' bar'
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,38 @@
1
+ require 'abstract_unit'
2
+
3
+ class ChainTest < Test::Unit::TestCase
4
+ def test_is_an_array
5
+ assert FacebookWall::FeedEntryFilters::Chain < Array
6
+ end
7
+
8
+ def test_apply_filters_to_applies_the_filters_to_the_specified_feed_entry
9
+ feed_entry_filter_chain = FacebookWall::FeedEntryFilters::Chain.new
10
+ feed_entry = create_feed_entry 'description' => 'Description'
11
+ feed_entry_filter_chain.apply_filters_to! feed_entry
12
+
13
+ assert_equal 'Description', feed_entry.description
14
+
15
+ feed_entry_filter_chain = FacebookWall::FeedEntryFilters::Chain.new
16
+ feed_entry_filter_chain << ChainTestDoubles::FeedEntryFilter01.new
17
+ feed_entry_filter_chain << ChainTestDoubles::FeedEntryFilter02.new
18
+ feed_entry = create_feed_entry 'description' => 'Description'
19
+ feed_entry_filter_chain.apply_filters_to! feed_entry
20
+
21
+ assert_equal 'Description foo bar', feed_entry.description
22
+ end
23
+ end
24
+
25
+ #TODO Blog post
26
+ module ChainTestDoubles
27
+ class FeedEntryFilter01 < FacebookWall::FeedEntryFilters::FeedEntryFilter
28
+ def apply!(feed_entry)
29
+ feed_entry.description << ' foo'
30
+ end
31
+ end
32
+
33
+ class FeedEntryFilter02 < FacebookWall::FeedEntryFilters::FeedEntryFilter
34
+ def apply!(feed_entry)
35
+ feed_entry.description << ' bar'
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ require 'abstract_unit'
2
+
3
+ class FeedEntryFilterTest < Test::Unit::TestCase
4
+ def test_has_an_instance_method_called_apply
5
+ assert FacebookWall::FeedEntryFilters::FeedEntryFilter.new.respond_to?(:apply!)
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ require 'abstract_unit'
2
+
3
+ class LinkRewriterTest < Test::Unit::TestCase
4
+ def test_is_a_feed_entry_filter
5
+ assert FacebookWall::FeedEntryFilters::LinkRewriter < FacebookWall::FeedEntryFilters::FeedEntryFilter
6
+ end
7
+
8
+ def test_apply_rewrites_links_in_the_description_in_the_feed_entry
9
+ expected_description = '<a href="http://example.com">example.com</a>'
10
+
11
+ feed_entry = create_feed_entry(
12
+ 'description' => '<a href="http://example.com" target="_blank" onmousedown="doSomething()" rel="nofollow" id="link">example.com</a>'
13
+ )
14
+
15
+ link_rewriter = FacebookWall::FeedEntryFilters::LinkRewriter.new
16
+ link_rewriter.apply! feed_entry
17
+
18
+ assert_equal expected_description, feed_entry.description
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'abstract_unit'
2
+
3
+ class ParagraphizerTest < Test::Unit::TestCase
4
+ def test_is_a_feed_entry_filter
5
+ assert FacebookWall::FeedEntryFilters::Paragraphizer < FacebookWall::FeedEntryFilters::FeedEntryFilter
6
+ end
7
+
8
+ def test_apply_paragraphizes_the_description_in_the_feed_entry
9
+ expected_description = '<p>First paragraph</p><p>Second paragraph</p><p>Something inserted<br/>by Facebook</p>'
10
+
11
+ rss_entry = create_feed_entry(
12
+ 'description' => 'First paragraph<br /> <br /> Second paragraph<br/><br/><br/>Something inserted<br/>by Facebook'
13
+ )
14
+
15
+ paragraphizer = FacebookWall::FeedEntryFilters::Paragraphizer.new
16
+ paragraphizer.apply! rss_entry
17
+
18
+ assert_equal expected_description, rss_entry.description
19
+ end
20
+ end
@@ -0,0 +1,39 @@
1
+ require 'abstract_unit'
2
+
3
+ class PostTest < Test::Unit::TestCase
4
+ def test_is_initialized_with_a_feed_entry
5
+ feed_entry = create_feed_entry
6
+ post = FacebookWall::Post.new feed_entry
7
+
8
+ assert_same feed_entry, post.feed_entry
9
+ end
10
+
11
+ def test_decorates_the_feed_entry
12
+ feed_entry = create_feed_entry 'title' => 'Foo', 'description' => 'Bar baz bip'
13
+ post = FacebookWall::Post.new feed_entry
14
+
15
+ assert_same feed_entry.title, post.title
16
+ assert_same feed_entry.description, post.description
17
+ end
18
+
19
+ #eql?() is added, for testing purposes only, by abstract_unit
20
+ def test_eql_returns_true_if_the_specified_object_is_a_post_with_the_same_value
21
+ attributes = {'title' => 'Item 1 title', 'link' => 'http://example.com/blog_posts/1', 'description' => 'Item 1 description'}
22
+
23
+ post = FacebookWall::Post.new create_feed_entry(attributes)
24
+ another_post = FacebookWall::Post.new create_feed_entry(attributes)
25
+
26
+ assert post.eql?(another_post)
27
+
28
+ almost_a_feed_entry = "<item>\n <title>Item 1 title</title>\n <link>http://example.com/blog_posts/1</link>\n <description>Item 1 description</description>\n</item>"
29
+ post = FacebookWall::Post.new create_feed_entry(attributes)
30
+
31
+ assert_equal almost_a_feed_entry, post.feed_entry.to_s
32
+ assert ! post.eql?(almost_a_feed_entry)
33
+
34
+ not_a_post = 123
35
+ post = FacebookWall::Post.new create_feed_entry(attributes)
36
+
37
+ assert ! post.eql?(not_a_post)
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ require 'abstract_unit'
2
+
3
+ class ParserTest < Test::Unit::TestCase
4
+ def test_fetch_and_parse_fetches_and_parses_the_feed_at_the_specified_url
5
+ feed = RSS::Parser.fetch_and_parse 'http://www.facebook.com/feeds/page.php?id=260041833284&format=rss20'
6
+ assert feed.instance_of?(RSS::Rss)
7
+ assert feed.items.length > 0
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facebook_wall
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Bettles
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-20 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: facebook_wall is a very simple library that fetches the latest wall-posts
15
+ for a Facebook page without having to log in - wall posts are taken from the page's
16
+ RSS feed. The markup in posts is filtered to help ensure standards-compliance and
17
+ prevent errors when inserted into your own Web pages.
18
+ email:
19
+ - dan@archaichorizon.com
20
+ executables: []
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - .gitignore
25
+ - Gemfile
26
+ - README.rdoc
27
+ - Rakefile
28
+ - facebook_wall.gemspec
29
+ - lib/facebook_wall.rb
30
+ - lib/facebook_wall/factories/methods.rb
31
+ - lib/facebook_wall/feed_entry_filters/chain.rb
32
+ - lib/facebook_wall/feed_entry_filters/feed_entry_filter.rb
33
+ - lib/facebook_wall/feed_entry_filters/link_rewriter.rb
34
+ - lib/facebook_wall/feed_entry_filters/paragraphizer.rb
35
+ - lib/facebook_wall/methods.rb
36
+ - lib/facebook_wall/post.rb
37
+ - lib/facebook_wall/std_lib_ext.rb
38
+ - lib/facebook_wall/std_lib_ext/rss/parser.rb
39
+ - lib/facebook_wall/version.rb
40
+ - test/abstract_unit.rb
41
+ - test/facebook_wall_test.rb
42
+ - test/factories/factories_test.rb
43
+ - test/feed_entry_filters/chain_test.rb
44
+ - test/feed_entry_filters/feed_entry_filter_test.rb
45
+ - test/feed_entry_filters/link_rewriter_test.rb
46
+ - test/feed_entry_filters/paragraphizer_test.rb
47
+ - test/post_test.rb
48
+ - test/std_lib_ext/rss/parser_test.rb
49
+ homepage: http://www.archaichorizon.com/
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project: facebook_wall
69
+ rubygems_version: 1.8.15
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: facebook_wall is a very simple library that fetches the latest wall-posts
73
+ for a Facebook page without having to log in - wall posts are taken from the page's
74
+ RSS feed.
75
+ test_files:
76
+ - test/abstract_unit.rb
77
+ - test/facebook_wall_test.rb
78
+ - test/factories/factories_test.rb
79
+ - test/feed_entry_filters/chain_test.rb
80
+ - test/feed_entry_filters/feed_entry_filter_test.rb
81
+ - test/feed_entry_filters/link_rewriter_test.rb
82
+ - test/feed_entry_filters/paragraphizer_test.rb
83
+ - test/post_test.rb
84
+ - test/std_lib_ext/rss/parser_test.rb