disqussion 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.gitignore +9 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +80 -0
  4. data/HISTORY.mkd +5 -0
  5. data/LICENSE.mkd +20 -0
  6. data/README.mkd +139 -0
  7. data/Rakefile +23 -0
  8. data/disqussion.gemspec +37 -0
  9. data/lib/disqussion/api.rb +21 -0
  10. data/lib/disqussion/client/.DS_Store +0 -0
  11. data/lib/disqussion/client/applications.rb +20 -0
  12. data/lib/disqussion/client/blacklists.rb +4 -0
  13. data/lib/disqussion/client/categories.rb +4 -0
  14. data/lib/disqussion/client/exports.rb +4 -0
  15. data/lib/disqussion/client/forums.rb +122 -0
  16. data/lib/disqussion/client/imports.rb +4 -0
  17. data/lib/disqussion/client/posts.rb +217 -0
  18. data/lib/disqussion/client/reactions.rb +79 -0
  19. data/lib/disqussion/client/reports.rb +4 -0
  20. data/lib/disqussion/client/threads.rb +199 -0
  21. data/lib/disqussion/client/trends.rb +23 -0
  22. data/lib/disqussion/client/users.rb +103 -0
  23. data/lib/disqussion/client/utils.rb +90 -0
  24. data/lib/disqussion/client/whitelists.rb +4 -0
  25. data/lib/disqussion/client.rb +46 -0
  26. data/lib/disqussion/configuration.rb +121 -0
  27. data/lib/disqussion/connection.rb +36 -0
  28. data/lib/disqussion/error.rb +51 -0
  29. data/lib/disqussion/request.rb +38 -0
  30. data/lib/disqussion/version.rb +3 -0
  31. data/lib/disqussion/view_helpers.rb +9 -0
  32. data/lib/disqussion/widget.rb +183 -0
  33. data/lib/disqussion.rb +25 -0
  34. data/lib/faraday/response/raise_http_4xx.rb +41 -0
  35. data/lib/faraday/response/raise_http_5xx.rb +20 -0
  36. data/spec/disqussion/api_spec.rb +63 -0
  37. data/spec/disqussion/client/.DS_Store +0 -0
  38. data/spec/disqussion/client/applications_spec.rb +24 -0
  39. data/spec/disqussion/client/forums_spec.rb +80 -0
  40. data/spec/disqussion/client/posts_spec.rb +154 -0
  41. data/spec/disqussion/client/reactions_spec.rb +63 -0
  42. data/spec/disqussion/client/threads_spec.rb +128 -0
  43. data/spec/disqussion/client/trends_spec.rb +24 -0
  44. data/spec/disqussion/client/users_spec.rb +33 -0
  45. data/spec/disqussion/client_spec.rb +15 -0
  46. data/spec/disqussion_spec.rb +101 -0
  47. data/spec/faraday/response_spec.rb +30 -0
  48. data/spec/fixtures/applications/listUsage.json +129 -0
  49. data/spec/fixtures/forums/create.json +12 -0
  50. data/spec/fixtures/forums/details.json +12 -0
  51. data/spec/fixtures/forums/listCategories.json +21 -0
  52. data/spec/fixtures/forums/listPosts.json +859 -0
  53. data/spec/fixtures/forums/listThreads.json +533 -0
  54. data/spec/fixtures/posts/approve.json +6 -0
  55. data/spec/fixtures/posts/create.json +6 -0
  56. data/spec/fixtures/posts/details.json +35 -0
  57. data/spec/fixtures/posts/highlight.json +6 -0
  58. data/spec/fixtures/posts/list.json +247 -0
  59. data/spec/fixtures/posts/remove.json +6 -0
  60. data/spec/fixtures/posts/report.json +6 -0
  61. data/spec/fixtures/posts/restore.json +6 -0
  62. data/spec/fixtures/posts/spam.json +6 -0
  63. data/spec/fixtures/posts/unhighlight.json +6 -0
  64. data/spec/fixtures/posts/vote.json +6 -0
  65. data/spec/fixtures/reactions/domains.json +4 -0
  66. data/spec/fixtures/reactions/ips.json +131 -0
  67. data/spec/fixtures/reactions/threads.json +4 -0
  68. data/spec/fixtures/reactions/users.json +124 -0
  69. data/spec/fixtures/threads/close.json +4 -0
  70. data/spec/fixtures/threads/create.json +22 -0
  71. data/spec/fixtures/threads/details.json +24 -0
  72. data/spec/fixtures/threads/list.json +531 -0
  73. data/spec/fixtures/threads/listMostLiked.json +530 -0
  74. data/spec/fixtures/threads/listPosts.json +87 -0
  75. data/spec/fixtures/threads/open.json +8 -0
  76. data/spec/fixtures/threads/remove.json +4 -0
  77. data/spec/fixtures/threads/restore.json +4 -0
  78. data/spec/fixtures/threads/vote.json +4 -0
  79. data/spec/fixtures/trends/listTreads.json +283 -0
  80. data/spec/fixtures/users/details.json +19 -0
  81. data/spec/fixtures/users/follow.json +4 -0
  82. data/spec/helper.rb +47 -0
  83. metadata +348 -0
@@ -0,0 +1,90 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Disqussion
3
+ class Client
4
+ # @private
5
+ module Utils
6
+ private
7
+
8
+ # Take a single user ID or screen name and merge it into an options hash with the correct key
9
+ #
10
+ # @param user_id_or_username [Integer, String] A Disqus user ID or username.
11
+ # @param options [Hash] A customizable set of options.
12
+ # @return [Hash]
13
+ def merge_user_into_options!(user_id_or_username, options={})
14
+ case user_id_or_username
15
+ when Fixnum
16
+ options[:user] = user_id_or_username
17
+ when String
18
+ options[:"user:username"] = user_id_or_username
19
+ end
20
+ options
21
+ end
22
+
23
+ # Take a single user ID or screen name and merge it into an options hash with the correct key
24
+ #
25
+ # @param user_id_or_username [Integer, String] A Disqus user ID or username.
26
+ # @param options [Hash] A customizable set of options.
27
+ # @return [Hash]
28
+ def merge_target_into_options!(user_id_or_username, options={})
29
+ case user_id_or_username
30
+ when Fixnum
31
+ options[:target] = user_id_or_username
32
+ when String
33
+ options[:"target:username"] = user_id_or_username
34
+ end
35
+ options
36
+ end
37
+
38
+ # Take a multiple user IDs and screen names and merge them into an options hash with the correct keys
39
+ #
40
+ # @param users_id_or_usernames [Array] An array of Disqus user IDs or usernames.
41
+ # @param options [Hash] A customizable set of options.
42
+ # @return [Hash]
43
+ def merge_users_into_options!(user_ids_or_usernames, options={})
44
+ user_ids, usernames = [], []
45
+ user_ids_or_usernames.flatten.each do |user_id_or_username|
46
+ case user_id_or_username
47
+ when Fixnum
48
+ user_ids << user_id_or_username
49
+ when String
50
+ usernames << user_id_or_username
51
+ end
52
+ end
53
+ options[:user_id] = user_ids.join(',') unless user_ids.empty?
54
+ options[:username] = usernames.join(',') unless usernames.empty?
55
+ options
56
+ end
57
+
58
+ # Take a single owner ID or owner screen name and merge it into an options hash with the correct key
59
+ # (for Disqus API endpoints that want :owner_id and :owner_username)
60
+ #
61
+ # @param owner_id_or_owner_username [Integer, String] A Disqus user ID or username.
62
+ # @param options [Hash] A customizable set of options.
63
+ # @return [Hash]
64
+ def merge_owner_into_options!(owner_id_or_owner_username, options={})
65
+ case owner_id_or_owner_username
66
+ when Fixnum
67
+ options[:owner_id] = owner_id_or_owner_username
68
+ when String
69
+ options[:owner_username] = owner_id_or_owner_username
70
+ end
71
+ options
72
+ end
73
+
74
+ # Take a single list ID or slug and merge it into an options hash with the correct key
75
+ #
76
+ # @param list_id_or_slug [Integer, String] A Disqus list ID or slug.
77
+ # @param options [Hash] A customizable set of options.
78
+ # @return [Hash]
79
+ def merge_list_into_options!(list_id_or_username, options={})
80
+ case list_id_or_username
81
+ when Fixnum
82
+ options[:list_id] = list_id_or_username
83
+ when String
84
+ options[:slug] = list_id_or_username
85
+ end
86
+ options
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,4 @@
1
+ module Disqussion
2
+ class Whitelists < Client
3
+ end
4
+ end
@@ -0,0 +1,46 @@
1
+ module Disqussion
2
+ # Wrapper for the Disqussion REST API
3
+ #
4
+ # @note All methods have been separated into client classes and follow the same grouping used in {http://disqus.com/api/docs/ the Disqus API Documentation}.
5
+ # @see http://docs.disqus.com/developers/api/
6
+ class Client < API
7
+ require 'disqussion/client/applications.rb'
8
+ require 'disqussion/client/blacklists.rb'
9
+ require 'disqussion/client/categories.rb'
10
+ require 'disqussion/client/exports.rb'
11
+ require 'disqussion/client/forums.rb'
12
+ require 'disqussion/client/imports.rb'
13
+ require 'disqussion/client/posts.rb'
14
+ require 'disqussion/client/reactions.rb'
15
+ require 'disqussion/client/reports.rb'
16
+ require 'disqussion/client/threads.rb'
17
+ require 'disqussion/client/trends.rb'
18
+ require 'disqussion/client/users.rb'
19
+ require 'disqussion/client/utils.rb'
20
+ require 'disqussion/client/whitelists.rb'
21
+
22
+ alias :api_endpoint :endpoint
23
+
24
+ include Disqussion::Client::Utils
25
+
26
+ ['applications',
27
+ 'blacklists',
28
+ 'categories',
29
+ 'exports',
30
+ 'forums',
31
+ 'imports',
32
+ 'posts',
33
+ 'reactions',
34
+ 'reports',
35
+ 'threads',
36
+ 'trends',
37
+ 'users',
38
+ 'whitelists'].each do |classname|
39
+ class_eval <<-END
40
+ def self.#{classname}
41
+ Disqussion::#{classname.capitalize}.new
42
+ end
43
+ END
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,121 @@
1
+ require 'faraday'
2
+ require 'disqussion/version'
3
+
4
+ module Disqussion
5
+ # Defines constants and methods related to configuration
6
+ module Configuration
7
+ # An array of valid keys in the options hash when configuring a {Disqussion::API}
8
+ VALID_OPTIONS_KEYS = [
9
+ :adapter,
10
+ :endpoint,
11
+ :api_key,
12
+ :api_secret,
13
+ :developer,
14
+ :container_id,
15
+ :avatar_size,
16
+ :color,
17
+ :default_tab,
18
+ :hide_avatars,
19
+ :hide_mods,
20
+ :num_items,
21
+ :show_powered_by,
22
+ :orientation,
23
+ :format,
24
+ :proxy,
25
+ :user_agent].freeze
26
+
27
+ # An array of valid request/response formats
28
+ #
29
+ # @note only json for now
30
+ VALID_FORMATS = [:json].freeze
31
+
32
+ # The adapter that will be used to connect if none is set
33
+ #
34
+ # @note The default faraday adapter is Net::HTTP.
35
+ DEFAULT_ADAPTER = if defined?(EventMachine) && EM.reactor_running?
36
+ EMSynchrony
37
+ else
38
+ Faraday.default_adapter
39
+ end
40
+
41
+ # By default, don't set an application key
42
+ DEFAULT_API_KEY = nil
43
+
44
+ # By default, don't set an application secret
45
+ DEFAULT_API_SECRET = nil
46
+
47
+ # The endpoint that will be used to connect if none is set
48
+ #
49
+ # @note This is configurable in case you want to use HTTP instead of HTTPS, specify a different API version, or use a Disqussion-compatible endpoint.
50
+ # @see http://status.net/wiki/Disqussion-compatible_API
51
+ # @see http://en.blog.wordpress.com/2009/12/12/disqussion-api/
52
+ # @see http://staff.tumblr.com/post/287703110/api
53
+ # @see http://developer.typepad.com/typepad-disqussion-api/disqussion-api.html
54
+ DEFAULT_API_VERSION = '3.0'.freeze
55
+ DEFAULT_ENDPOINT = "https://disqus.com/api/#{DEFAULT_API_VERSION}/".freeze
56
+
57
+ # The response format appended to the path and sent in the 'Accept' header if none is set
58
+ #
59
+ # @note JSON is preferred over XML because it is more concise and faster to parse.
60
+ DEFAULT_FORMAT = :json
61
+
62
+ # By default, don't use a proxy server
63
+ DEFAULT_PROXY = nil
64
+
65
+ # The user agent that will be sent to the API endpoint if none is set
66
+ DEFAULT_USER_AGENT = "Disqussion Ruby Gem #{Disqussion::VERSION}".freeze
67
+
68
+ DEFAULT_DEVELOPER = false
69
+ DEFAULT_CONTAINER_ID = 'disqus_thread'
70
+ DEFAULT_AVATAR_SIZE = 48
71
+ DEFAULT_COLOR = "grey"
72
+ DEFAULT_DEFAULT_TAB = "popular"
73
+ DEFAULT_HIDE_AVATARS = false
74
+ DEFAULT_HIDE_MODS = true
75
+ DEFAULT_NUM_ITEMS = 15
76
+ DEFAULT_SHOW_POWERED_BY = true
77
+ DEFAULT_ORIENTATION = "horizontal"
78
+
79
+ # @private
80
+ attr_accessor *VALID_OPTIONS_KEYS
81
+
82
+ # When this module is extended, set all configuration options to their default values
83
+ def self.extended(base)
84
+ base.reset
85
+ end
86
+
87
+ # Convenience method to allow configuration options to be set in a block
88
+ def configure
89
+ yield self
90
+ end
91
+
92
+ # Create a hash of options and their values
93
+ def options
94
+ options = {}
95
+ VALID_OPTIONS_KEYS.each{|k| options[k] = send(k) }
96
+ options
97
+ end
98
+
99
+ # Reset all configuration options to defaults
100
+ def reset
101
+ self.adapter = DEFAULT_ADAPTER
102
+ self.endpoint = DEFAULT_ENDPOINT
103
+ self.api_key = DEFAULT_API_KEY
104
+ self.api_secret = DEFAULT_API_SECRET
105
+ self.developer = DEFAULT_DEVELOPER
106
+ self.container_id = DEFAULT_CONTAINER_ID
107
+ self.avatar_size = DEFAULT_AVATAR_SIZE
108
+ self.color = DEFAULT_COLOR
109
+ self.default_tab = DEFAULT_DEFAULT_TAB
110
+ self.hide_avatars = DEFAULT_HIDE_AVATARS
111
+ self.hide_mods = DEFAULT_HIDE_MODS
112
+ self.num_items = DEFAULT_NUM_ITEMS
113
+ self.show_powered_by = DEFAULT_SHOW_POWERED_BY
114
+ self.orientation = DEFAULT_ORIENTATION
115
+ self.format = DEFAULT_FORMAT
116
+ self.proxy = DEFAULT_PROXY
117
+ self.user_agent = DEFAULT_USER_AGENT
118
+ self
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,36 @@
1
+ require 'faraday_middleware'
2
+ require 'faraday/response/raise_http_4xx'
3
+ require 'faraday/response/raise_http_5xx'
4
+
5
+ module Disqussion
6
+ # @private
7
+ module Connection
8
+ private
9
+
10
+ def connection(raw=false)
11
+ options = {
12
+ :headers => {'Accept' => "application/#{format}", 'User-Agent' => user_agent},
13
+ :proxy => proxy,
14
+ :ssl => {:verify => false},
15
+ :url => api_endpoint,
16
+ }
17
+
18
+ Faraday.new(options) do |builder|
19
+ builder.use Faraday::Request::Multipart
20
+ builder.use Faraday::Request::UrlEncoded
21
+ builder.use Faraday::Response::RaiseHttp4xx
22
+ builder.use Faraday::Response::Rashify unless raw
23
+ unless raw
24
+ case format.to_s.downcase
25
+ when 'json'
26
+ builder.use Faraday::Response::ParseJson
27
+ when 'xml'
28
+ builder.use Faraday::Response::ParseXml
29
+ end
30
+ end
31
+ builder.use Faraday::Response::RaiseHttp5xx
32
+ builder.adapter(adapter)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ module Disqussion
2
+ # Custom error class for rescuing from all Disqus errors
3
+ class Error < StandardError
4
+ attr_reader :http_headers
5
+
6
+ def initialize(message, http_headers)
7
+ @http_headers = Hash[http_headers]
8
+ super message
9
+ end
10
+
11
+ def ratelimit_reset
12
+ Time.at(@http_headers.values_at('x-ratelimit-reset', 'X-RateLimit-Reset').detect{|value| value}.to_i)
13
+ end
14
+
15
+ def ratelimit_limit
16
+ @http_headers.values_at('x-ratelimit-limit', 'X-RateLimit-Limit').detect{|value| value}.to_i
17
+ end
18
+
19
+ def ratelimit_remaining
20
+ @http_headers.values_at('x-ratelimit-remaining', 'X-RateLimit-Remaining').detect{|value| value}.to_i
21
+ end
22
+
23
+ def retry_after
24
+ [(ratelimit_reset - Time.now).ceil, 0].max
25
+ end
26
+ end
27
+
28
+ # Raised when Disqus returns the HTTP status code 400
29
+ class BadRequest < Error; end
30
+
31
+ # Raised when Disqus returns the HTTP status code 401
32
+ class Unauthorized < Error; end
33
+
34
+ # Raised when Disqus returns the HTTP status code 403
35
+ class Forbidden < Error; end
36
+
37
+ # Raised when Disqus returns the HTTP status code 404
38
+ class NotFound < Error; end
39
+
40
+ # Raised when Disqus returns the HTTP status code 406
41
+ class NotAcceptable < Error; end
42
+
43
+ # Raised when Disqus returns the HTTP status code 500
44
+ class InternalServerError < Error; end
45
+
46
+ # Raised when Disqus returns the HTTP status code 502
47
+ class BadGateway < Error; end
48
+
49
+ # Raised when Disqus returns the HTTP status code 503
50
+ class ServiceUnavailable < Error; end
51
+ end
@@ -0,0 +1,38 @@
1
+ module Disqussion
2
+ # Defines HTTP request methods
3
+ module Request
4
+ # Perform an HTTP GET request
5
+ def get(path, options={}, raw=false)
6
+ request(:get, path, options, raw)
7
+ end
8
+
9
+ # Perform an HTTP POST request
10
+ def post(path, options={}, raw=false)
11
+ request(:post, path, options, raw)
12
+ end
13
+
14
+ private
15
+
16
+ # Perform an HTTP request
17
+ def request(method, path, options, raw=false)
18
+ # identify our request
19
+ # @see: http://docs.disqus.com/help/52/
20
+ options ||= {}
21
+ options.merge!(:api_secret => self.api_secret) unless options.has_key?(:api_secret)
22
+ response = connection(raw).send(method) do |request|
23
+ case method
24
+ when :get
25
+ request.url(formatted_path(path), options)
26
+ when :post
27
+ request.path = formatted_path(path)
28
+ request.body = options unless options.empty?
29
+ end
30
+ end
31
+ raw ? response : response.body
32
+ end
33
+
34
+ def formatted_path(path)
35
+ [path, format].compact.join('.')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ module Disqussion
2
+ VERSION = '0.0.1'.freeze unless defined?(::Disqussion::VERSION)
3
+ end
@@ -0,0 +1,9 @@
1
+ # Shortcuts to access the widgets as simple functions as opposed to using
2
+ # their full qualified names.
3
+ %w[combo comment_counts popular_threads recent_comments thread top_commenters].each do |method|
4
+ eval(<<-EOM)
5
+ def disqus_#{method}(options = {})
6
+ Disqus::Widget.#{method}(options)
7
+ end
8
+ EOM
9
+ end
@@ -0,0 +1,183 @@
1
+ module EventMachine
2
+ module Disqus
3
+ # Disqus Widget generator.
4
+ #
5
+ # All of the methods accept various options, and "account" is required for
6
+ # all of them. You can avoid having to pass in the account each time by
7
+ # setting it in the defaults like this:
8
+ #
9
+ # Disqus::defaults[:account] = "my_account"
10
+ class Widget
11
+
12
+ VALID_COLORS = ['blue', 'grey', 'green', 'red', 'orange']
13
+ VALID_NUM_ITEMS = 5..20
14
+ VALID_DEFAULT_TABS = ['people', 'recent', 'popular']
15
+ VALID_AVATAR_SIZES = [24, 32, 48, 92, 128]
16
+ VALID_ORIENTATIONS = ['horizontal', 'vertical']
17
+
18
+ ROOT_PATH = 'http://disqus.com/forums/%s/'
19
+ THREAD = ROOT_PATH + 'embed.js'
20
+ COMBO = ROOT_PATH + 'combination_widget.js?num_items=%d&color=%s&default_tab=%s'
21
+ RECENT = ROOT_PATH + 'recent_comments_widget.js?num_items=%d&avatar_size=%d'
22
+ POPULAR = ROOT_PATH + 'popular_threads_widget.js?num_items=%d'
23
+ TOP = ROOT_PATH + 'top_commenters_widget.js?num_items=%d&avatar_size=%d&orientation=%s'
24
+ class << self
25
+
26
+ # Show the main Disqus thread widget.
27
+ # Options:
28
+ # * <tt>account:</tt> Your Discus account (required).
29
+ def thread(opts = {})
30
+ opts = Disqus::defaults.merge(opts)
31
+ opts[:view_thread_text] ||= "View the discussion thread"
32
+ validate_opts!(opts)
33
+ s = ''
34
+ if opts[:developer]
35
+ s << '<script type="text/javascript">var disqus_developer = 1;</script>'
36
+ end
37
+ s << '<div id="disqus_thread"></div>'
38
+ s << '<script type="text/javascript" src="' + THREAD + '"></script>'
39
+ s << '<noscript><a href="http://%s.disqus.com/?url=ref">'
40
+ s << opts[:view_thread_text]
41
+ s << '</a></noscript>'
42
+ if opts[:show_powered_by]
43
+ s << '<a href="http://disqus.com" class="dsq-brlink">blog comments '
44
+ s << 'powered by <span class="logo-disqus">Disqus</span></a>'
45
+ end
46
+ s % [opts[:account], opts[:account]]
47
+ end
48
+
49
+ # Loads Javascript to show the number of comments for the page.
50
+ #
51
+ # The Javascript sets the inner html to the comment count for any links
52
+ # on the page that have the anchor "disqus_thread". For example, "View
53
+ # Comments" below would be replaced by "1 comment" or "23 comments" etc.
54
+ #
55
+ # <a href="http://my.website/article-permalink#disqus_thread">View Comments</a>
56
+ # <a href="http://my.website/different-permalink#disqus_thread">View Comments</a>
57
+ # Options:
58
+ # * <tt>account:</tt> Your Discus account (required).
59
+ def comment_counts(opts = {})
60
+ opts = Disqus::defaults.merge(opts)
61
+ validate_opts!(opts)
62
+ s = <<-WHIMPER
63
+ <script type="text/javascript">
64
+ //<![CDATA[
65
+ (function() {
66
+ var links = document.getElementsByTagName('a');
67
+ var query = '?';
68
+ for(var i = 0; i < links.length; i++) {
69
+ if(links[i].href.indexOf('#disqus_thread') >= 0) {
70
+ query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
71
+ }
72
+ }
73
+ document.write('<' + 'script type="text/javascript" src="#{ROOT_PATH}get_num_replies.js' + query + '"></' + 'script>');
74
+ })();
75
+ //]]>
76
+ </script>
77
+ WHIMPER
78
+ s % opts[:account]
79
+ end
80
+
81
+ # Show the top commenters Disqus thread widget.
82
+ # Options:
83
+ # * <tt>account:</tt> Your Discus account (required).
84
+ # * <tt>header:</tt> HTML snipper with header (default h2) tag and text.
85
+ # * <tt>show_powered_by:</tt> Show or hide the powered by Disqus text.
86
+ # * <tt>num_items:</tt>: How many items to show.
87
+ # * <tt>hide_mods:</tt> Don't show moderators.
88
+ # * <tt>hide_avatars:</tt> Don't show avatars.
89
+ # * <tt>avatar_size:</tt> Avatar size.
90
+ def top_commenters(opts = {})
91
+ opts = Disqus::defaults.merge(opts)
92
+ opts[:header] ||= '<h2 class="dsq-widget-title">Top Commenters</h2>'
93
+ validate_opts!(opts)
94
+ s = '<div id="dsq-topcommenters" class="dsq-widget">'
95
+ s << opts[:header]
96
+ s << '<script type="text/javascript" src="'
97
+ s << TOP
98
+ s << '&hide_avatars=1' if opts[:hide_avatars]
99
+ s << '&hide_mods=1' if opts[:hide_mods]
100
+ s << '"></script>'
101
+ s << '</div>'
102
+ if opts[:show_powered_by]
103
+ s << '<a href="http://disqus.com">Powered by Disqus</a>'
104
+ end
105
+ s % [opts[:account], opts[:num_items], opts[:avatar_size], opts[:orientation]]
106
+ end
107
+
108
+ # Show the popular threads Disqus widget.
109
+ # Options:
110
+ # * <tt>account:</tt> Your Discus account (required).
111
+ # * <tt>header:</tt> HTML snipper with header (default h2) tag and text.
112
+ # * <tt>num_items:</tt>: How many items to show.
113
+ # * <tt>hide_mods:</tt> Don't show moderators.
114
+ def popular_threads(opts = {})
115
+ opts = Disqus::defaults.merge(opts)
116
+ opts[:header] ||= '<h2 class="dsq-widget-title">Popular Threads</h2>'
117
+ validate_opts!(opts)
118
+ s = '<div id="dsq-popthreads" class="dsq-widget">'
119
+ s << opts[:header]
120
+ s << '<script type="text/javascript" src="'
121
+ s << POPULAR
122
+ s << '&hide_mods=1' if opts[:hide_mods]
123
+ s << '"></script>'
124
+ s << '</div>'
125
+ s << '<a href="http://disqus.com">Powered by Disqus</a>' if opts[:show_powered_by]
126
+ s % [opts[:account], opts[:num_items]]
127
+ end
128
+
129
+ # Show the recent comments Disqus widget.
130
+ # Options:
131
+ # * <tt>account:</tt> Your Discus account (required).
132
+ # * <tt>header:</tt> HTML snipper with header (default h2) tag and text.
133
+ # * <tt>num_items:</tt>: How many items to show.
134
+ # * <tt>hide_avatars:</tt> Don't show avatars.
135
+ # * <tt>avatar_size:</tt> Avatar size.
136
+ def recent_comments(opts = {})
137
+ opts = Disqus::defaults.merge(opts)
138
+ opts[:header] ||= '<h2 class="dsq-widget-title">Recent Comments</h2>'
139
+ validate_opts!(opts)
140
+ s = '<div id="dsq-recentcomments" class="dsq-widget">'
141
+ s << opts[:header]
142
+ s << '<script type="text/javascript" src="'
143
+ s << RECENT
144
+ s << '&hide_avatars=1' if opts[:hide_avatars]
145
+ s << '"></script>'
146
+ s << '</div>'
147
+ if opts[:show_powered_by]
148
+ s << '<a href="http://disqus.com">Powered by Disqus</a>'
149
+ end
150
+ s % [opts[:account], opts[:num_items], opts[:avatar_size]]
151
+ end
152
+
153
+ # Show the Disqus combo widget. This is a three-tabbed box with links
154
+ # popular threads, top posters, and recent threads.
155
+ # Options:
156
+ # * <tt>:account:</tt> Your Discus account (required).
157
+ # * <tt>:num_items:</tt> How many items to show.
158
+ # * <tt>:hide_mods:</tt> Don't show moderators.
159
+ # * <tt>:default_tab:</tt> Should be 'people', 'recent', or 'popular'.
160
+ def combo(opts = {})
161
+ opts = Disqus::defaults.merge(opts)
162
+ validate_opts!(opts)
163
+ s = '<script type="text/javascript" src="'
164
+ s << COMBO
165
+ s << '&hide_mods=1' if opts[:hide_mods]
166
+ s << '"></script>'
167
+ s % [opts[:account], opts[:num_items], opts[:color], opts[:default_tab]]
168
+ end
169
+
170
+ private
171
+
172
+ def validate_opts!(opts)
173
+ raise ArgumentError.new("You must specify an :account") if !opts[:account]
174
+ raise ArgumentError.new("Invalid color") if opts[:color] && !VALID_COLORS.include?(opts[:color])
175
+ raise ArgumentError.new("Invalid num_items") if opts[:num_items] && !VALID_NUM_ITEMS.include?(opts[:num_items])
176
+ raise ArgumentError.new("Invalid default_tab") if opts[:default_tab] && !VALID_DEFAULT_TABS.include?(opts[:default_tab])
177
+ raise ArgumentError.new("Invalid avatar size") if opts[:avatar_size] && !VALID_AVATAR_SIZES.include?(opts[:avatar_size])
178
+ raise ArgumentError.new("Invalid orientation") if opts[:orientation] && !VALID_ORIENTATIONS.include?(opts[:orientation])
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
data/lib/disqussion.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'disqussion/error'
2
+ require 'disqussion/configuration'
3
+ require 'disqussion/api'
4
+ require 'disqussion/client'
5
+
6
+ module Disqussion
7
+ extend Configuration
8
+
9
+ # Alias for Disqussion::Client.new
10
+ #
11
+ # @return [Disqussion::Client]
12
+ def self.client(options={})
13
+ Disqussion::Client.new(options)
14
+ end
15
+
16
+ # Delegate to Disqussion::Client
17
+ def self.method_missing(method, *args, &block)
18
+ return super unless client.respond_to?(method)
19
+ client.send(method, *args, &block)
20
+ end
21
+
22
+ def self.respond_to?(method, include_private = false)
23
+ client.respond_to?(method, include_private) || super(method, include_private)
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ require 'faraday'
2
+
3
+ # @private
4
+ module Faraday
5
+ # @private
6
+ class Response::RaiseHttp4xx < Response::Middleware
7
+ def on_complete(env)
8
+ case env[:status].to_i
9
+ when 400
10
+ raise Disqussion::BadRequest.new(error_message(env), env[:response_headers])
11
+ when 401
12
+ raise Disqussion::Unauthorized.new(error_message(env), env[:response_headers])
13
+ when 403
14
+ raise Disqussion::Forbidden.new(error_message(env), env[:response_headers])
15
+ when 404
16
+ raise Disqussion::NotFound.new(error_message(env), env[:response_headers])
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def error_message(env)
23
+ "#{env[:method].to_s.upcase} #{env[:url].to_s}: #{env[:status]}#{error_body(env[:body])}"
24
+ end
25
+
26
+ def error_body(body)
27
+ if body.nil?
28
+ nil
29
+ elsif body['error']
30
+ ": #{body['error']}"
31
+ elsif body['errors']
32
+ first = body['errors'].to_a.first
33
+ if first.kind_of? Hash
34
+ ": #{first['message'].chomp}"
35
+ else
36
+ ": #{first.chomp}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ require 'faraday'
2
+
3
+ # @private
4
+ module Faraday
5
+ # @private
6
+ class Response::RaiseHttp5xx < Response::Middleware
7
+ def on_complete(env)
8
+ case env[:status].to_i
9
+ when 500
10
+ raise Disqussion::InternalServerError.new(error_message(env, "Something is technically wrong."), env[:response_headers])
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def error_message(env, body=nil)
17
+ "#{env[:method].to_s.upcase} #{env[:url].to_s}: #{[env[:status].to_s + ':', body].compact.join(' ')} Check http://status.disqus.com/ for updates on the status of the Disqus service."
18
+ end
19
+ end
20
+ end