disqussion 0.0.1

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.
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