disqus 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ module Disqus
2
+
3
+ class BaseAuthor
4
+ attr_reader :url, :email_hash
5
+ end
6
+
7
+ class Author < BaseAuthor
8
+ attr_reader :id, :username, :display_name, :has_avatar
9
+ def initialize(id, username, display_name, url, email_hash, has_avatar)
10
+ @id, @username, @display_name, @url, @email_hash, @has_avatar = id, username, display_name, url, email_hash, has_avatar
11
+ end
12
+
13
+ # Returns the user's <tt>display_name</tt> or <tt>username</tt> if <tt>display_name</tt> is blank.
14
+ def name
15
+ @display_name.blank? ? @username : @display_name
16
+ end
17
+
18
+ end
19
+
20
+ class AnonymousAuthor < BaseAuthor
21
+ attr_reader :name
22
+ def initialize(name, url, email_hash)
23
+ @name, @url, @email_hash = name, url, email_hash
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,126 @@
1
+ module Disqus
2
+
3
+ class Forum
4
+ attr_reader :id, :shortname, :name, :created_at, :threads
5
+
6
+ def initialize(id, shortname, name, created_at, include_threads = false)
7
+ @id, @shortname, @name, @created_at = id.to_i, shortname, name, Time.parse(created_at.to_s)
8
+ @key = nil
9
+ @forum_threads = include_threads ? load_threads : []
10
+ end
11
+
12
+ def ==(other_forum)
13
+ id == other_forum.id &&
14
+ shortname == other_forum.shortname &&
15
+ name == other_forum.name &&
16
+ key == other_forum.key
17
+ end
18
+
19
+ # Returns an array of Forum objects belonging to the user indicated by the API key.
20
+ def self.list(user_api_key = nil)
21
+ opts = user_api_key ? {:api_key => user_api_key} : {}
22
+ response = Disqus::Api::get_forum_list(opts)
23
+ if response["succeeded"]
24
+ return response["message"].map{|forum| Forum.new(forum["id"], forum["shortname"], forum["name"], forum["created_at"])}
25
+ else
26
+ raise_api_error(response)
27
+ end
28
+ end
29
+
30
+ # Returns a Forum object corresponding to the given forum_id or nil if it was not found.
31
+ def self.find(forum_id, user_api_key = nil)
32
+ opts = user_api_key ? {:api_key => user_api_key} : {}
33
+ list = Forum.list(opts)
34
+ if list
35
+ list.select{|f| f.id == forum_id}.first
36
+ end
37
+ end
38
+
39
+ # Returns the forum API Key for this forum.
40
+ def key(user_api_key = nil)
41
+ @key ||= load_key(user_api_key)
42
+ end
43
+
44
+ # Returns an array of threads belonging to this forum.
45
+ def forum_threads(force_update = false)
46
+ if (@forum_threads.nil? or @forum_threads.empty? or force_update)
47
+ @forum_threads = Disqus::Thread.list(self)
48
+ end
49
+ @forum_threads
50
+ end
51
+
52
+ # Returns a thread associated with the given URL.
53
+ #
54
+ # A thread will only have an associated URL if it was automatically
55
+ # created by Disqus javascript embedded on that page.
56
+ def get_thread_by_url(url)
57
+ response = Disqus::Api::get_thread_by_url(:url => url, :forum_api_key => key)
58
+ if response["succeeded"]
59
+ t = response["message"]
60
+ Thread.new(t["id"], self, t["slug"], t["title"], t["created_at"], t["allow_comments"], t["url"], t["identifier"])
61
+ else
62
+ raise_api_error(response)
63
+ end
64
+ end
65
+
66
+ # Create or retrieve a thread by an arbitrary identifying string of your
67
+ # choice. For example, you could use your local database's ID for the
68
+ # thread. This method allows you to decouple thread identifiers from the
69
+ # URL's on which they might be appear. (Disqus would normally use a
70
+ # thread's URL to identify it, which is problematic when URL's do not
71
+ # uniquely identify a resource.) If no thread exists for the given
72
+ # identifier (paired with the forum) yet, one will be created.
73
+ #
74
+ # Returns a Thread object representing the thread that was created or
75
+ # retrieved.
76
+ def thread_by_identifier(identifier, title)
77
+ # TODO - should we separate thread retrieval from thread creation? The API to me seems confusing here.
78
+ response = Disqus::Api::thread_by_identifier(:identifier => identifier, :title => title, :forum_api_key => key)
79
+ if response["succeeded"]
80
+ t = response["message"]["thread"]
81
+ Thread.new(t["id"], self, t["slug"], t["title"], t["created_at"], t["allow_comments"], t["url"], t["identifier"])
82
+ else
83
+ raise_api_error(response)
84
+ end
85
+ end
86
+
87
+ # Sets the provided values on the thread object.
88
+ #
89
+ # Returns an empty success message.
90
+ #
91
+ # Options:
92
+ #
93
+ # * <tt>:title</tt> - the title of the thread
94
+ # * <tt>:slug</tt> - the per-forum-unique string used for identifying this thread in disqus.com URL's relating to this thread. Composed of underscore-separated alphanumeric strings.
95
+ # * <tt>:url</tt> - the URL this thread is on, if known.
96
+ # * <tt>:allow_comment</tt> - whether this thread is open to new comments
97
+ def update_thread(thread_id, opts = {})
98
+ result = Disqus::Api::update_thread(
99
+ :forum_api_key => key,
100
+ :thread_id => thread_id,
101
+ :title => opts[:title],
102
+ :slug => opts[:slug],
103
+ :url => opts[:url],
104
+ :allow_comments => opts[:allow_comments]
105
+ )
106
+ return result["succeeded"]
107
+ end
108
+
109
+ private
110
+
111
+ def raise_api_error(response)
112
+ raise "Error: #{response['code']}: #{response['message']}"
113
+ end
114
+
115
+ def load_key(user_api_key = nil)
116
+ opts = user_api_key ? {:api_key => user_api_key} : {}
117
+ response = Disqus::Api::get_forum_api_key(opts.merge(:forum_id => self.id))
118
+ if response["succeeded"]
119
+ return @key = response["message"]
120
+ else
121
+ raise_api_error(response)
122
+ end
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,51 @@
1
+ module Disqus
2
+
3
+ class Post
4
+ attr_reader :id, :forum, :thread, :created_at, :message, :parent_post, :shown, :is_anonymous, :author
5
+
6
+ def initialize(id, forum, thread, created_at, message, parent_post, shown, is_anonymous, author)
7
+ @id, @forum, @thread, @created_at, @message, @parent_post, @shown, @is_anonymous, @author = id.to_i, forum, thread, Time.parse(created_at.to_s), message, parent_post, shown, is_anonymous, author
8
+ end
9
+
10
+ # Returns an array of Post objects representing all posts belonging to the
11
+ # given thread. The array is sorted by the "created_at" date descending.
12
+ def self.list(thread)
13
+ response = Disqus::Api::get_thread_posts(:thread_id =>thread.id, :forum_api_key => thread.forum.key)
14
+ if response["succeeded"]
15
+ posts = response["message"].map do |post|
16
+ author = nil
17
+ if post["is_anonymous"]
18
+ author = AnonymousAuthor.new(
19
+ post["anonymous_author"]["name"],
20
+ post["anonymous_author"]["url"],
21
+ post["anonymous_author"]["email_hash"]
22
+ )
23
+ else
24
+ author = Author.new(
25
+ post["author"]["id"].to_i,
26
+ post["author"]["username"],
27
+ post["author"]["display_name"],
28
+ post["author"]["url"],
29
+ post["author"]["email_hash"],
30
+ post["author"]["has_avatar"]
31
+ )
32
+ end
33
+ Post.new(
34
+ post["id"],
35
+ thread.forum,
36
+ thread,
37
+ post["created_at"],
38
+ post["message"],
39
+ post["parent_post"],
40
+ post["shown"],
41
+ post["is_anonymous"],
42
+ author
43
+ )
44
+ end
45
+ posts.sort!{|a,b| a.created_at <=> b.created_at}
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+
@@ -0,0 +1,73 @@
1
+ module Disqus
2
+
3
+ class Thread
4
+ attr_reader :id, :forum, :slug, :title, :created_at, :allow_comments, :url, :identifier, :forum
5
+
6
+ def initialize(id, forum, slug, title, created_at, allow_comments, url, identifier)
7
+ @id, @forum, @slug, @title, @created_at, @allow_comments, @url, @identifier = id.to_i, forum, slug, title, Time.parse(created_at.to_s), allow_comments, url, identifier
8
+ @posts = []
9
+ end
10
+
11
+ # Threads are equal if all their attributes are equal.
12
+ def ==(other_thread)
13
+ id == other_thread.id &&
14
+ forum == other_thread.forum &&
15
+ slug == other_thread.slug &&
16
+ title == other_thread.title &&
17
+ created_at == other_thread.created_at &&
18
+ allow_comments == other_thread.allow_comments &&
19
+ url == other_thread.url &&
20
+ identifier == other_thread.identifier
21
+ end
22
+
23
+ # Returns an array of Thread objects representing the threads belonging to the given Forum.
24
+ def self.list(forum, opts = {})
25
+ response = Disqus::Api::get_thread_list(opts.merge(:forum_id =>forum.id, :forum_api_key => forum.key))
26
+ if response["succeeded"]
27
+ list = response["message"].map do |thread|
28
+ Thread.new(
29
+ thread["id"],
30
+ forum,
31
+ thread["slug"],
32
+ thread["title"],
33
+ thread["created_at"],
34
+ thread["allow_comments"],
35
+ thread["url"],
36
+ thread["identifier"]
37
+ )
38
+ end
39
+ end
40
+ end
41
+
42
+ # Returns an array of posts belonging to this thread.
43
+ def posts(force_update = false)
44
+ if (@posts.nil? or @posts.empty? or force_update)
45
+ @posts = Disqus::Post.list(self)
46
+ end
47
+ @posts
48
+ end
49
+
50
+ # Sets the provided values on the thread object.
51
+ #
52
+ # Options:
53
+ #
54
+ # * :thread_id
55
+ # * :title
56
+ # * :slug
57
+ # * :url
58
+ # * :allow_comments
59
+ def update(opts = {})
60
+ result = Disqus::Api::update_thread(opts.merge(
61
+ :forum_api_key => forum.key,
62
+ :thread_id => id,
63
+ :title => title,
64
+ :slug => slug,
65
+ :url => url,
66
+ :allow_comments => allow_comments)
67
+ )
68
+ return result["succeeded"]
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,8 @@
1
+ module Disqus #:nodoc:
2
+ module Version #:nodoc:
3
+ MAJOR = 1
4
+ MINOR = 0
5
+ TINY = 0
6
+ STRING = [MAJOR, MINOR, TINY].join('.')
7
+ end
8
+ end
data/lib/disqus/widget.rb CHANGED
@@ -59,15 +59,15 @@ module Disqus
59
59
  <script type="text/javascript">
60
60
  //<[CDATA[
61
61
  (function() {
62
- var links = document.getElementsByTagName('a');
63
- var query = '?';
64
- for(var i = 0; i < links.length; i++) {
65
- if(links[i].href.indexOf('#disqus_thread') >= 0) {
66
- query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
67
- }
68
- }
69
- document.write('<script type="text/javascript" src="#{ROOT_PATH}get_num_replies.js' + query + '"></' + 'script>');
70
- })();
62
+ var links = document.getElementsByTagName('a');
63
+ var query = '?';
64
+ for(var i = 0; i < links.length; i++) {
65
+ if(links[i].href.indexOf('#disqus_thread') >= 0) {
66
+ query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
67
+ }
68
+ }
69
+ document.write('<' + 'script type="text/javascript" src="#{ROOT_PATH}get_num_replies.js' + query + '"></' + 'script>');
70
+ })();
71
71
  //]]>
72
72
  </script>
73
73
  WHIMPER
data/tasks/rcov.rake ADDED
@@ -0,0 +1,23 @@
1
+ desc "Run RCov"
2
+ task :rcov do
3
+ run_coverage Dir["test/**/*_test.rb"]
4
+ end
5
+
6
+ def run_coverage(files)
7
+ rm_f "coverage"
8
+ rm_f "coverage.data"
9
+ if files.length == 0
10
+ puts "No files were specified for testing"
11
+ return
12
+ end
13
+ files = files.join(" ")
14
+ if PLATFORM =~ /darwin/
15
+ exclude = '--exclude "gems/"'
16
+ else
17
+ exclude = '--exclude "rubygems"'
18
+ end
19
+ rcov = "rcov -Ilib:test --sort coverage --text-report #{exclude} --no-validator-links"
20
+ cmd = "#{rcov} #{files}"
21
+ puts cmd
22
+ sh cmd
23
+ end
data/test/api_test.rb ADDED
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ApiTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ require 'disqus'
7
+ Disqus.defaults[:api_key] = DISQUS_TEST["api_key"]
8
+ end
9
+
10
+ def test_create_post
11
+ mock_post_response('create_post.json')
12
+ the_post = Disqus::Api::create_post()
13
+ assert_equal "This is a mock post", the_post["message"]["message"]
14
+ end
15
+
16
+ def test_get_forum_list
17
+ mock_get_response('get_forum_list.json')
18
+ forum_list = Disqus::Api::get_forum_list
19
+ assert_equal "Disqus Test", forum_list["message"][0]["name"]
20
+ end
21
+
22
+ def test_get_forum_api_key
23
+ mock_get_response('get_forum_api_key.json')
24
+ forum_api_key = Disqus::Api::get_forum_api_key(:forum_id => 1234, :user_api_key=>"FAKE_KEY")
25
+ assert_equal "FAKE_FORUM_API_KEY", forum_api_key["message"]
26
+ end
27
+
28
+ def test_get_thread_list
29
+ mock_get_response('get_thread_list.json')
30
+ thread_list = Disqus::Api::get_thread_list(:forum_api_key=>"FAKE_KEY")
31
+ assert_equal "this_is_the_thread_identifier", thread_list["message"].first["identifier"]
32
+ end
33
+
34
+ def test_get_num_posts
35
+ mock_get_response('get_num_posts.json')
36
+ nums = Disqus::Api::get_num_posts(:thread_ids => [123,456], :forum_api_key=>"FAKE_KEY")
37
+ assert_equal [10,12], nums["message"][nums["message"].keys.first]
38
+ end
39
+
40
+ def test_get_thread_by_url
41
+ mock_get_response('get_thread_by_url.json')
42
+ thread = Disqus::Api::get_thread_by_url(:url => "FAKE_URL", :forum_api_key=>"FAKE_KEY")
43
+ assert_equal "test_thread", thread["message"]["slug"]
44
+ end
45
+
46
+ def test_get_thread_posts
47
+ mock_get_response('get_thread_posts.json')
48
+ thread_posts = Disqus::Api::get_thread_posts(:thread_id =>1234, :forum_api_key => "FAKE_KEY")
49
+ assert_equal "This is a mock post", thread_posts["message"].first["message"]
50
+ end
51
+
52
+ def test_thread_by_identifier
53
+ mock_post_response('thread_by_identifier.json')
54
+ thread = Disqus::Api::thread_by_identifier(:identifier =>'foo_bar', :title => "Foo Bar", :forum_api_key => "FAKE_KEY")
55
+ assert_equal "Test thread", thread["message"]["thread"]["title"]
56
+ end
57
+
58
+ def test_update_thread
59
+ mock_post_response('update_thread.json')
60
+ result = Disqus::Api::thread_by_identifier(:thread_id =>123, :title => "Foo Bar", :forum_api_key => "FAKE_KEY")
61
+ assert result["succeeded"]
62
+ end
63
+
64
+ def test_comment_form
65
+ c = Disqus::Api::comment_form("myforum", "mythread")
66
+ assert_match(/myforum/, c)
67
+ assert_match(/mythread/, c)
68
+ end
69
+
70
+ private
71
+
72
+ def mock_get_response(file)
73
+ Disqus::Api.expects(:get).returns(File.read(File.dirname(__FILE__) + "/responses/#{file}"))
74
+ end
75
+
76
+ def mock_post_response(file)
77
+ Disqus::Api.expects(:post).returns(File.read(File.dirname(__FILE__) + "/responses/#{file}"))
78
+ end
79
+
80
+ end
data/test/config.yml ADDED
@@ -0,0 +1,3 @@
1
+ # This can be used to do actual calls to the API rather than use mocks during
2
+ # testing. This can be useful to verify tests against API changes.
3
+ api_key: 'YOUR DISQUS USER API KEY GOES HERE'
@@ -0,0 +1,3 @@
1
+ # This can be used to do actual calls to the API rather than use mocks during
2
+ # testing. This can be useful to verify tests against API changes.
3
+ api_key: 'YOUR DISQUS USER API KEY GOES HERE'
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ForumTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ require 'disqus'
7
+ Disqus.defaults[:api_key] = DISQUS_TEST["api_key"]
8
+ stub_api_call(:get_forum_api_key).returns("FAKE_FORUM_API_KEY")
9
+ end
10
+
11
+ def test_forum_list
12
+ mock_api_call(:get_forum_list)
13
+ list = Disqus::Forum.list
14
+ expected = [create_forum]
15
+ assert_equal 1, list.size
16
+ assert_equal expected, list
17
+ end
18
+
19
+ def test_forum_find
20
+ mock_api_call(:get_forum_list)
21
+ forum = Disqus::Forum.find(1234)
22
+ assert_equal "disqus-test", forum.shortname
23
+ end
24
+
25
+ def test_forum_find_bad_id
26
+ mock_api_call(:get_forum_list)
27
+ forum = Disqus::Forum.find(666)
28
+ assert_equal nil, forum
29
+ end
30
+
31
+ def test_forum_find_no_forums
32
+ Disqus::Api.expects(:get_forum_list).returns({"succeeded"=>true, "code"=>"", "message" => []})
33
+ forum = Disqus::Forum.find(1234)
34
+ assert_equal nil, forum
35
+ end
36
+
37
+ def test_key
38
+ mock_api_call(:get_forum_api_key)
39
+ forum = Disqus::Forum.new(1234, "disqus-test", "Disqus Test", "2008-01-03 14:44:07.627492")
40
+ assert_equal "FAKE_FORUM_API_KEY", forum.key
41
+ end
42
+
43
+ def test_forum_threads
44
+ forum = create_forum
45
+ Disqus::Thread.expects(:list).with(forum).returns([thread = mock()])
46
+ assert_equal [thread], forum.forum_threads
47
+ end
48
+
49
+ def test_get_thread_by_url
50
+ mock_api_call(:get_thread_by_url)
51
+ forum = create_forum
52
+ thread = forum.get_thread_by_url("http://www.example.com")
53
+ expected = Disqus::Thread.new("7651269", forum, "test_thread", "Test thread", "2008-11-28T01:47", true, "FAKE_URL", nil)
54
+ assert_equal expected, thread
55
+ end
56
+
57
+ def test_thread_by_identifier
58
+ mock_api_call(:thread_by_identifier)
59
+ forum = create_forum
60
+ thread = forum.thread_by_identifier("FAKE_IDENTIFIER", "")
61
+ expected = Disqus::Thread.new("7651269", forum, "test_thread", "Test thread", "2008-11-28T01:47", true, "FAKE_URL", "FAKE_IDENTIFIER")
62
+ assert_equal expected, thread
63
+ end
64
+
65
+ def test_update_thread
66
+ Disqus::Api.expects(:update_thread).with({:thread_id => 1234, :forum_api_key => "FAKE_FORUM_API_KEY", :title => 'Title', :slug => "a_slug", :url => "http://www.example.com", :allow_comments => true}).returns({"succeeded" => true})
67
+ forum = create_forum
68
+ forum.update_thread(1234, :title => 'Title', :slug => "a_slug", :url => "http://www.example.com", :allow_comments => true)
69
+ end
70
+ end