ruby-satisfaction 0.4.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS.txt CHANGED
@@ -1,7 +1,6 @@
1
1
  John Duff
2
- Pius Uzamere
3
2
 
4
3
  Awards
5
4
  ======
6
5
 
7
- John Duff gets the "Getting the ball rolling" achievement award for being the first contributor besides myself.
6
+ John Duff gets the "Getting the ball rolling" achievement award for being the first contributor outside of Get Satisfaction.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in ruby-satisfaction.gemspec
4
+ gemspec
5
+
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby-satisfaction (0.6.0)
5
+ activesupport (~> 2.3)
6
+ json (>= 1.4.6)
7
+ memcache-client (>= 1.5.0)
8
+ nokogiri (>= 1.4.2)
9
+ oauth (>= 0.3.5)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ activesupport (2.3.10)
15
+ columnize (0.3.2)
16
+ configuration (1.2.0)
17
+ diff-lcs (1.1.2)
18
+ fakeweb (1.3.0)
19
+ json (1.4.6)
20
+ launchy (0.3.7)
21
+ configuration (>= 0.0.5)
22
+ rake (>= 0.8.1)
23
+ linecache (0.43)
24
+ memcache-client (1.8.5)
25
+ nokogiri (1.4.4)
26
+ oauth (0.4.4)
27
+ open_gem (1.4.2)
28
+ launchy (~> 0.3.5)
29
+ rake (0.8.7)
30
+ rspec (2.2.0)
31
+ rspec-core (~> 2.2)
32
+ rspec-expectations (~> 2.2)
33
+ rspec-mocks (~> 2.2)
34
+ rspec-core (2.2.1)
35
+ rspec-expectations (2.2.0)
36
+ diff-lcs (~> 1.1.2)
37
+ rspec-mocks (2.2.0)
38
+ ruby-debug (0.10.4)
39
+ columnize (>= 0.1)
40
+ ruby-debug-base (~> 0.10.4.0)
41
+ ruby-debug-base (0.10.4)
42
+ linecache (>= 0.3)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ activesupport (~> 2.3)
49
+ bundler (>= 1.0.0)
50
+ fakeweb (~> 1.3)
51
+ json (>= 1.4.6)
52
+ memcache-client (>= 1.5.0)
53
+ nokogiri (>= 1.4.2)
54
+ oauth (>= 0.3.5)
55
+ open_gem (>= 1.4)
56
+ rspec (~> 2.2)
57
+ ruby-debug (>= 0.10.4)
58
+ ruby-satisfaction!
data/License.txt CHANGED
@@ -1,20 +1,22 @@
1
- Copyright (c) 2008 Scott Fleckenstein
1
+ The MIT License
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
3
+ Copyright (c) 2008-2010 Get Satisfaction, Inc.
10
4
 
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
13
22
 
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,45 @@
1
+ Get Satisfaction Ruby library
2
+ =============================
3
+
4
+ Please check our Web site for the latest documentation:
5
+
6
+ [Web API documentation][1]
7
+
8
+ [Ruby library documentation][2]
9
+
10
+ For questions, please visit the [Get Satisfaction API community][3]
11
+
12
+ Known Issues
13
+ ============
14
+
15
+ If you use your Satisfaction object to get a person, then that object is scoped to that person.
16
+
17
+ For example:
18
+
19
+ sfn = Satisfaction.new
20
+ person = sfn.peson.get('jargon')
21
+ topics = sfn.topics.page(3, :order => 'recently_created') # Jargon's topics
22
+
23
+ In the above case, topics will be scoped to topics created by Jargon instead of scoped to the
24
+ top level. A simple workaround for now is to create a new Satisfaction object like so:
25
+
26
+ sfn = Satisfaction.new
27
+ person = sfn.peson.get('jargon')
28
+
29
+ sfn = Satisfaction.new
30
+ topics = sfn.topics.page(3, :order => 'recently_created') # Everyone's topics
31
+
32
+ Changelog
33
+ =========
34
+
35
+ 0.6.0
36
+
37
+ * The biggest change is that we're using exceptions to indicate error conditions. This will make it easier to detect errors, especially when chaining methods. We've also made it easier to tell when the site is in maintenance mode.
38
+ * Moved repository to https://github.com/satisfaction/ruby-satisfaction
39
+ * Updated gemspec to include all dependencies.
40
+ * Using Nokogiri instead of Hpricot
41
+ * Improved testing. Original tests ran against production. Our specs now use Fakeweb instead of trying to connect to a server. There still aren't very many specs, but changes in this release have coverage.
42
+
43
+ [1]: http://getsatisfaction.com/developers/
44
+ [2]: http://getsatisfaction.com/developers/api-libraries
45
+ [3]: http://getsatisfaction.com/getsatisfaction/products/satisfaction_satisfaction_api
data/Rakefile CHANGED
@@ -1,19 +1,3 @@
1
- begin
2
- require 'jeweler'
3
- Jeweler::Tasks.new do |gemspec|
4
- gemspec.name = "ruby-satisfaction"
5
- gemspec.summary = "Ruby interface to Get Satisfaction"
6
- gemspec.description = "Ruby interface to Get Satisfaction"
7
- gemspec.email = "scott@getsatisfaction.com"
8
- gemspec.homepage = "http://github.com/nullstyle/ruby-satisfaction"
9
- gemspec.authors = ["Scott Fleckenstein", "Josh Nichols", "Pius Uzamere"]
10
- gemspec.rubyforge_project = "satisfaction"
11
- gemspec.add_dependency('memcache-client', '>= 1.5.0')
12
- gemspec.add_dependency('oauth', '>= 0.3.5')
13
- gemspec.add_dependency('activesupport', '>= 2.3.2')
14
- end
15
-
16
- Jeweler::RubyforgeTasks.new
17
- rescue LoadError
18
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
- end
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
data/lib/satisfaction.rb CHANGED
@@ -2,6 +2,11 @@ require 'satisfaction/external_dependencies'
2
2
  module Sfn
3
3
  end
4
4
  class Satisfaction
5
+ # ==============
6
+ # = Exceptions =
7
+ # ==============
8
+ require 'satisfaction/exceptions'
9
+
5
10
  # ==================
6
11
  # = Core Utilities =
7
12
  # ==================
@@ -12,7 +17,6 @@ class Satisfaction
12
17
  require 'satisfaction/loader'
13
18
  require 'satisfaction/identity_map'
14
19
 
15
-
16
20
  # =============
17
21
  # = Resources =
18
22
  # =============
@@ -0,0 +1,10 @@
1
+
2
+ module Sfn
3
+ class Error < StandardError; end
4
+ class TooManyRedirects < Sfn::Error; end
5
+ class BadRequest < Sfn::Error; end
6
+ class AuthorizationError < Sfn::Error; end
7
+ class NotFound < Sfn::Error; end
8
+ class SiteMaintenance < Sfn::Error; end
9
+ class MethodNotAllowed < Sfn::Error; end
10
+ end
@@ -1,6 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'active_support'
3
- require 'hpricot'
3
+ require 'nokogiri'
4
4
  require 'json'
5
5
  require 'json/add/rails' #make json play nice with the json rails outputs
6
6
  gem('memcache-client')
@@ -38,26 +38,26 @@ class Sfn::Loader
38
38
  response = execute(http, request)
39
39
 
40
40
  case response
41
- when Net::HTTPNotModified
42
- return [:ok, cache_record.body]
43
41
  when Net::HTTPSuccess
44
42
  cache.put(uri, response)
45
43
  [:ok, response.body]
46
- when Net::HTTPMovedPermanently
44
+ when Net::HTTPMovedPermanently, Net::HTTPMovedTemporarily
47
45
  limit = options[:redirect_limit] || 3
48
- raise ArgumentError, "Too many redirects" unless limit > 0 #TODO: what is a better error here?
46
+ raise Sfn::TooManyRedirects, "Too many redirects" unless limit > 0
49
47
  get(response['location'], options.merge(:redirect_limit => limit - 1))
50
48
  when Net::HTTPBadRequest
51
- [:bad_request, response.body]
52
- when Net::HTTPForbidden
53
- [:forbidden, response.body]
54
- when Net::HTTPUnauthorized
55
- [:unauthorized, response.body]
49
+ raise Sfn::BadRequest, "Bad request. Response body:\n" + response.body
50
+ when Net::HTTPForbidden, Net::HTTPUnauthorized
51
+ raise Sfn::AuthorizationError, "Not authorized"
52
+ when Net::HTTPNotFound
53
+ raise Sfn::NotFound, "Not found"
54
+ when Net::HTTPServiceUnavailable
55
+ raise Sfn::SiteMaintenance, maintenance_message(response.body)
56
56
  else
57
- raise "Explode: #{response.to_yaml}"
57
+ raise Sfn::Error, "Encountered error. Body of response:\n" + response.body
58
58
  end
59
59
  end
60
-
60
+
61
61
  def post(url, options)
62
62
  uri = get_uri(url)
63
63
  form = options[:form] || {}
@@ -77,16 +77,24 @@ class Sfn::Loader
77
77
  response = execute(http, request)
78
78
 
79
79
  case response
80
- when Net::HTTPUnauthorized
81
- [:unauthorized, response.body]
80
+ when Net::HTTPForbidden, Net::HTTPUnauthorized
81
+ raise Sfn::AuthorizationError, "Not authorized"
82
+ when Net::HTTPNotFound
83
+ raise Sfn::NotFound, "Not found"
82
84
  when Net::HTTPBadRequest
83
- [:bad_request, response.body]
84
- when Net::HTTPForbidden
85
- [:forbidden, response.body]
85
+ raise Sfn::BadRequest, "Bad request. Response body:\n" + response.body
86
86
  when Net::HTTPSuccess
87
87
  [:ok, response.body]
88
+ when Net::HTTPMethodNotAllowed
89
+ #Post responds differently when the site is down for maintenance.
90
+ #This will raise an error if site is down otherwise we will return method_not_allowed.
91
+ get(url)
92
+
93
+ raise Sfn::MethodNotAllowed, "Method not allowed"
94
+ when Net::HTTPServiceUnavailable
95
+ raise Sfn::SiteMaintenance, maintenance_message(response.body)
88
96
  else
89
- raise "Explode: #{response.to_yaml}"
97
+ raise Sfn::Error, "Encountered error. Body of response:\n" + response.body
90
98
  end
91
99
  end
92
100
 
@@ -111,5 +119,11 @@ class Sfn::Loader
111
119
  request.oauth!(http, options[:consumer], options[:token])
112
120
  end
113
121
  end
114
- end
115
122
 
123
+ def maintenance_message(html = '')
124
+ Nokogiri::HTML(html).at('.error_message_summary').text
125
+ rescue
126
+ "The site is down for maintenance. Please try again later."
127
+ end
128
+
129
+ end
@@ -0,0 +1,10 @@
1
+ module Satisfaction
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 6
5
+ PATCH = 1
6
+ PRE = ""
7
+
8
+ STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
9
+ end
10
+ end
@@ -1,75 +1,34 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/satisfaction/version", __FILE__)
2
3
 
3
4
  Gem::Specification.new do |s|
4
- s.name = %q{ruby-satisfaction}
5
- s.version = "0.4.0"
5
+ s.name = "ruby-satisfaction"
6
+ s.version = '0.6.1'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.author = 'Get Satisfaction'
9
+ s.email = ["nerds+rubygems@getsatisfaction.com"]
10
+ s.homepage = "https://github.com/satisfaction/ruby-satisfaction"
11
+ s.summary = "Get Satisfaction ruby client"
12
+ s.description = "Get Satisfaction is a simple way to build online communities that enable productive conversations between companies and their customers. More than 46,000 companies use Get Satisfaction to provide a more social support experience, build better products, increase SEO and improve customer loyalty. Get Satisfaction communities are available at http://getsatisfaction.com."
6
13
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["Scott Fleckenstein", "Josh Nichols", "Pius Uzamere"]
9
- s.date = %q{2009-07-10}
10
- s.description = %q{Ruby interface to Get Satisfaction}
11
- s.email = %q{scott@getsatisfaction.com}
12
- s.extra_rdoc_files = [
13
- "README.txt"
14
- ]
15
- s.files = [
16
- ".gitignore",
17
- "CONTRIBUTORS.txt",
18
- "License.txt",
19
- "README.txt",
20
- "Rakefile",
21
- "VERSION.yml",
22
- "init.rb",
23
- "lib/satisfaction.rb",
24
- "lib/satisfaction/associations.rb",
25
- "lib/satisfaction/cache/hash.rb",
26
- "lib/satisfaction/cache/memcache.rb",
27
- "lib/satisfaction/company.rb",
28
- "lib/satisfaction/external_dependencies.rb",
29
- "lib/satisfaction/has_satisfaction.rb",
30
- "lib/satisfaction/identity_map.rb",
31
- "lib/satisfaction/loader.rb",
32
- "lib/satisfaction/person.rb",
33
- "lib/satisfaction/product.rb",
34
- "lib/satisfaction/reply.rb",
35
- "lib/satisfaction/resource.rb",
36
- "lib/satisfaction/resource/attributes.rb",
37
- "lib/satisfaction/tag.rb",
38
- "lib/satisfaction/topic.rb",
39
- "lib/satisfaction/util.rb",
40
- "ruby-satisfaction.gemspec",
41
- "spec/company_spec.rb",
42
- "spec/identity_map_spec.rb",
43
- "spec/spec_helper.rb"
44
- ]
45
- s.homepage = %q{http://github.com/nullstyle/ruby-satisfaction}
46
- s.rdoc_options = ["--charset=UTF-8"]
47
- s.require_paths = ["lib"]
48
- s.rubyforge_project = %q{satisfaction}
49
- s.rubygems_version = %q{1.3.4}
50
- s.summary = %q{Ruby interface to Get Satisfaction}
51
- s.test_files = [
52
- "spec/company_spec.rb",
53
- "spec/identity_map_spec.rb",
54
- "spec/spec_helper.rb"
55
- ]
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "ruby-satisfaction"
56
16
 
57
- if s.respond_to? :specification_version then
58
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
- s.specification_version = 3
17
+ s.add_dependency 'nokogiri', '>= 1.4.2'
18
+ s.add_dependency 'json', '>= 1.4.6'
19
+ s.add_dependency 'activesupport', '~> 2.3'
20
+ s.add_dependency 'memcache-client', '>= 1.5.0'
21
+ s.add_dependency 'oauth', '>= 0.3.5'
60
22
 
61
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
62
- s.add_runtime_dependency(%q<memcache-client>, [">= 1.5.0"])
63
- s.add_runtime_dependency(%q<oauth>, [">= 0.3.5"])
64
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
65
- else
66
- s.add_dependency(%q<memcache-client>, [">= 1.5.0"])
67
- s.add_dependency(%q<oauth>, [">= 0.3.5"])
68
- s.add_dependency(%q<activesupport>, [">= 2.3.2"])
69
- end
70
- else
71
- s.add_dependency(%q<memcache-client>, [">= 1.5.0"])
72
- s.add_dependency(%q<oauth>, [">= 0.3.5"])
73
- s.add_dependency(%q<activesupport>, [">= 2.3.2"])
74
- end
23
+ s.add_development_dependency "bundler", ">= 1.0.0"
24
+ s.add_development_dependency "rspec", "~> 2.2"
25
+ s.add_development_dependency "fakeweb", "~> 1.3"
26
+ s.add_development_dependency "open_gem", ">= 1.4"
27
+ s.add_development_dependency "ruby-debug", ">= 0.10.4"
28
+
29
+ s.extra_rdoc_files = [ "README.markdown" ]
30
+ s.files = `git ls-files`.split("\n") - ['.rvmrc', '.gitignore']
31
+ s.test_files = `git ls-files`.split("\n").grep(/^spec/)
32
+ s.require_path = 'lib'
75
33
  end
34
+
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Identity Map" do
4
+ before(:each) do
5
+ gsfn = {:id => 4, :domain => 'getsatisfaction'}
6
+
7
+ # Single record response w/ gsfn
8
+ FakeWeb.register_uri(
9
+ :get,
10
+ "http://#{@api_host}/companies/4.json",
11
+ :body => gsfn.to_json
12
+ )
13
+
14
+ # Collection response that includes gsfn
15
+ FakeWeb.register_uri(
16
+ :get,
17
+ "http://#{@api_host}/companies.json?q=satisfaction&page=1&limit=10",
18
+ :body => {"total" => 1, "data" => [gsfn]}.to_json
19
+ )
20
+ end
21
+
22
+ it "should work single instances" do
23
+ c1 = @sfn.companies.get(4)
24
+ c2 = @sfn.companies.get(4)
25
+
26
+ c1.object_id.should == c2.object_id
27
+ end
28
+
29
+ it "should load one if the other gets loaded" do
30
+ c1 = @sfn.companies.get(4)
31
+ c2 = @sfn.companies.get(4)
32
+ c2.should_not be_loaded
33
+
34
+ c1.load
35
+
36
+ c2.should be_loaded
37
+ c2.domain.should == 'getsatisfaction'
38
+ end
39
+
40
+ it "should work with pages too" do
41
+ c1 = @sfn.companies.get(4)
42
+ c2 = @sfn.companies.page(1, :q => 'satisfaction').first
43
+
44
+ c1.object_id.should == c2.object_id
45
+ end
46
+ end
@@ -0,0 +1,307 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sfn::Loader do
4
+
5
+ # ==== GET ==========================================================================================================
6
+
7
+ describe "#get" do
8
+ before(:each) do
9
+ @response = nil
10
+ @status_code = '200'
11
+ @get = lambda do
12
+ FakeWeb.register_uri(
13
+ :get,
14
+ 'http://test',
15
+ :body => @response_body,
16
+ :status => [@status_code]
17
+ )
18
+ loader = Sfn::Loader.new
19
+ stub(loader).add_authentication {}
20
+ @response = loader.get('http://test')
21
+ end
22
+ end
23
+
24
+ describe "when the status is successful (2xx)" do
25
+ before(:each) do
26
+ @status_code.should == '200'
27
+ @response_body = {:id => "123", :domain => "foo.bar"}.to_json
28
+ @get.call
29
+ end
30
+
31
+ it "should return a status of :ok and the response body" do
32
+ @response.should == [:ok, @response_body]
33
+ end
34
+ end
35
+
36
+ describe "when we are in a redirect loop" do
37
+ attr_reader :loader
38
+
39
+ before(:each) do
40
+ @url = 'http://loop/'
41
+ @loader = Sfn::Loader.new
42
+ stub(loader).add_authentication {}
43
+ end
44
+
45
+ describe "and the status is 301" do
46
+ before(:each) do
47
+ @get = lambda {
48
+ FakeWeb.register_uri(:get, @url, :status => 301, :location => @url)
49
+ @response = loader.get(@url)
50
+ }
51
+ end
52
+
53
+ it "should raise a TooManyRedirects exception with an appropriate message" do
54
+ @get.should raise_error(Sfn::TooManyRedirects, "Too many redirects")
55
+ end
56
+ end
57
+
58
+ describe "and the status is 302" do
59
+ before(:each) do
60
+ @get = lambda {
61
+ FakeWeb.register_uri(:get, @url, :status => 302, :location => @url)
62
+ @response = loader.get(@url)
63
+ }
64
+ end
65
+
66
+ it "should raise a TooManyRedirects exception with an appropriate message" do
67
+ @get.should raise_error(Sfn::TooManyRedirects, "Too many redirects")
68
+ end
69
+ end
70
+
71
+
72
+ end
73
+
74
+ describe "when the status is 400 (Bad Request)" do
75
+ before(:each) do
76
+ @status_code = '400'
77
+ @response_body = {:message => "You've already me-too'd this topic."}.to_json
78
+ end
79
+
80
+ it "should return a status of :bad_request and the response body" do
81
+ @get.should raise_error(Sfn::BadRequest, "Bad request. Response body:\n" + @response_body)
82
+ end
83
+ end
84
+
85
+ describe "when there is an authentication error" do
86
+ describe "when the status is 401 (Unauthorized)" do
87
+ before(:each) do
88
+ @status_code = '401'
89
+ end
90
+
91
+ it "should raise an Sfn::AuthorizationError" do
92
+ @get.should raise_error(Sfn::AuthorizationError, "Not authorized")
93
+ end
94
+ end
95
+
96
+ describe "when the status is 403 (Forbidden)" do
97
+ before(:each) do
98
+ @status_code = '403'
99
+ end
100
+
101
+ it "should raise an Sfn::AuthorizationError" do
102
+ @get.should raise_error(Sfn::AuthorizationError, "Not authorized")
103
+ end
104
+ end
105
+ end
106
+
107
+ # ---- MAINTENANCE --------------------------------------------------------------------------------------------------
108
+ describe "when the status is 404 (Not Found)" do
109
+ before(:each) do
110
+ @status_code = '404'
111
+ end
112
+
113
+ it "should raise an Sfn::NotFound error" do
114
+ @get.should raise_error(Sfn::NotFound, "Not found")
115
+ end
116
+ end
117
+
118
+ describe "when the site is in maintenance mode (503)" do
119
+ before(:each) do
120
+ @status_code = '503'
121
+ @response_body = "blah blah maintenance blah"
122
+ end
123
+
124
+ describe "and there is not an element with a class of error_message_summary in the HTML" do
125
+ it "should raise an error and include the default maintenance message" do
126
+ @get.should raise_error(Sfn::SiteMaintenance, "The site is down for maintenance. Please try again later.")
127
+ end
128
+ end
129
+
130
+ describe "and there is an element with a class of error_message_summary in the HTML" do
131
+ before(:each) do
132
+ @custom_error = "Something crazy is going down!"
133
+ @response_body = "<html><head></head><body><h2 class='error_message_summary'>#{@custom_error}</h2></body>"
134
+ end
135
+
136
+ it "should raise an error and include the contents of the element" do
137
+ @get.should raise_error(Sfn::SiteMaintenance, @custom_error)
138
+ end
139
+ end
140
+ end
141
+
142
+ describe "when the error is not one we explicitly check for" do
143
+ before(:each) do
144
+ @status_code = '505' # HTTP Version Not Supported
145
+ @response_body = "it'd be a little weird if our app responded with this error"
146
+ end
147
+
148
+ it "should raise an Sfn::Error and include the response body" do
149
+ begin
150
+ @get.call
151
+ rescue Sfn::Error => e
152
+ e.class.should == Sfn::Error
153
+ e.message.should == "Encountered error. Body of response:\n" + @response_body
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ # ==== POST ==================================================================================================
160
+ describe "#post" do
161
+ before(:each) do
162
+ @response = nil
163
+ @status_code = '200'
164
+ @post = lambda do
165
+ FakeWeb.register_uri(
166
+ :post,
167
+ 'http://test',
168
+ :body => @response_body,
169
+ :status => [@status_code]
170
+ )
171
+ loader = Sfn::Loader.new
172
+ stub(loader).add_authentication {}
173
+ @response = loader.post('http://test', "a=b")
174
+ end
175
+ end
176
+
177
+ describe "when the status is successful (2xx)" do
178
+ before(:each) do
179
+ @status_code.should == '200'
180
+ @response_body = {:id => "123", :domain => "foo.bar"}.to_json
181
+ @post.call
182
+ end
183
+
184
+ it "should return a status of :ok and the response body" do
185
+ @response.should == [:ok, @response_body]
186
+ end
187
+ end
188
+
189
+ describe "when the status is 400 (bad request)" do
190
+ before(:each) do
191
+ @status_code = '400'
192
+ @response_body = 'some error message'.to_json
193
+ end
194
+
195
+ it "should return raise an Sfn::BadRequest error and the response body" do
196
+ @post.should raise_error(Sfn::BadRequest, "Bad request. Response body:\n" + @response_body)
197
+ end
198
+ end
199
+
200
+ describe "when there is an authentication error" do
201
+ describe "when the status is 401 (Unauthorized)" do
202
+ before(:each) do
203
+ @status_code = '401'
204
+ end
205
+
206
+ it "should raise an Sfn::AuthorizationError" do
207
+ @post.should raise_error(Sfn::AuthorizationError, "Not authorized")
208
+ end
209
+ end
210
+
211
+ describe "when the status is 403 (Forbidden)" do
212
+ before(:each) do
213
+ @status_code = '403'
214
+ end
215
+
216
+ it "should raise an Sfn::AuthorizationError" do
217
+ @post.should raise_error(Sfn::AuthorizationError, "Not authorized")
218
+ end
219
+ end
220
+ end
221
+
222
+ describe "when the status is 404 (Not Found)" do
223
+ before(:each) do
224
+ @status_code = '404'
225
+ end
226
+
227
+ it "should raise an Sfn::NotFound error" do
228
+ @post.should raise_error(Sfn::NotFound, "Not found")
229
+ end
230
+ end
231
+
232
+ # ---- MAINTENANCE --------------------------------------------------------------------------------------------------
233
+
234
+ shared_examples_for "the site is in maintenance mode" do
235
+
236
+ describe "and there is not an element with a class of error_message_summary in the HTML" do
237
+ before(:each) do
238
+ FakeWeb.register_uri(:get, 'http://test', :body => "blah", :status => "503")
239
+ end
240
+
241
+ it "should raise an error and include the default maintenance message" do
242
+ @post.should raise_error(Sfn::SiteMaintenance, "The site is down for maintenance. Please try again later.")
243
+ end
244
+ end
245
+
246
+ describe "and there is an element with a class of error_message_summary in the HTML" do
247
+ before(:each) do
248
+ @custom_error = "Something crazy is going down!"
249
+ @response_body = "<html><head></head><body><h2 class='error_message_summary'>#{@custom_error}</h2></body>"
250
+ FakeWeb.register_uri(:get, 'http://test', :body => @response_body, :status => "503")
251
+ end
252
+
253
+ it "should raise an error and include the contents of the element" do
254
+ @post.should raise_error(Sfn::SiteMaintenance, @custom_error)
255
+ end
256
+ end
257
+
258
+ end
259
+
260
+ describe "when the status is 405 (Method Not Allowed)" do
261
+ before(:each) do
262
+ @status_code = '405'
263
+ @response_body = "blah blah maintenance blah"
264
+ end
265
+
266
+ it_should_behave_like "the site is in maintenance mode"
267
+
268
+ describe "when the site is not in maintenance mode" do
269
+ before(:each) do
270
+ FakeWeb.register_uri(:get, 'http://test', :body => "blah", :status => "200")
271
+ end
272
+
273
+ it "should raise an error and include the reponse body" do
274
+ @post.should raise_error(Sfn::MethodNotAllowed, "Method not allowed")
275
+ end
276
+ end
277
+ end
278
+
279
+ describe "when the status is 503 (Service Unavailable)" do
280
+ before :each do
281
+ @status_code = '503'
282
+ @response_body = "blah blah maintenance mode"
283
+ end
284
+
285
+ it_should_behave_like "the site is in maintenance mode"
286
+ end
287
+
288
+
289
+ describe "when the error is not one we explicitly check for" do
290
+ before(:each) do
291
+ @status_code = '505' # HTTP Version Not Supported
292
+ @response_body = "it'd be a little weird if our app responded with this error"
293
+ end
294
+
295
+ it "should raise an Sfn::Error and include the response body" do
296
+ begin
297
+ @post.call
298
+ rescue Sfn::Error => e
299
+ e.class.should == Sfn::Error
300
+ e.message.should == "Encountered error. Body of response:\n" + @response_body
301
+ end
302
+ end
303
+ end
304
+
305
+ end
306
+
307
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Satisfaction do
4
+
5
+ describe "#request_token" do
6
+
7
+ describe "when the http response is 200 OK" do
8
+ before :each do
9
+ @sfn.set_consumer('key', 'secret')
10
+
11
+ FakeWeb.register_uri(
12
+ :get,
13
+ "http://#{@app_host}/api/request_token",
14
+ :body => "oauth_token=foo&oauth_token_secret=bar",
15
+ :status => ['200']
16
+ )
17
+ end
18
+
19
+ it "should be successful" do
20
+ oauth = @sfn.request_token
21
+ oauth.token.first.should == "foo"
22
+ oauth.secret.first.should == "bar"
23
+ end
24
+ end
25
+
26
+ describe "when the http response is 503 Service Temporarily Unavailable" do
27
+ before(:each) do
28
+ FakeWeb.register_uri(
29
+ :get,
30
+ "http://#{@app_host}/api/request_token",
31
+ :body => "<html><head><title>maintenance</title><head><body>maintenance</body></html>",
32
+ :status => ['503']
33
+ )
34
+ end
35
+
36
+ it "should raise an exception" do
37
+ lambda {@sfn.request_token}.should raise_exception(Sfn::Error)
38
+ end
39
+ end
40
+ end
41
+
42
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,37 @@
1
1
  require 'rubygems'
2
- require 'spec'
2
+ require 'rspec'
3
+ require 'fakeweb'
4
+ require 'ruby-debug'
5
+ require 'rr'
6
+
7
+ Debugger.settings[:autolist] = 1
8
+ Debugger.settings[:autoeval] = true
9
+ Debugger.start
10
+
3
11
  $:.unshift "#{File.dirname(__FILE__)}/../lib"
4
12
 
5
13
  require 'satisfaction'
6
14
 
7
- Spec::Runner.configure do |config|
8
- config.prepend_before(:each){ @satisfaction = Satisfaction.new(:root => 'http://api.getsatisfaction.com') }
9
- end
15
+ RSpec.configure do |config|
16
+
17
+ config.mock_with(:rr)
18
+
19
+ config.before(:each) do
20
+ @app_host = 'app.gsfn:3000'
21
+ @api_host = 'api.gsfn:3001'
22
+ @sfn = Satisfaction.new(
23
+ :root => "http://#{@api_host}",
24
+ :autoload => false,
25
+ :request_token_url => "http://#{@app_host}/api/request_token",
26
+ :access_token_url => "http://#{@app_host}/api/access_token",
27
+ :authorize_url => "http://#{@app_host}/api/authorize"
28
+ )
29
+ FakeWeb.allow_net_connect = false
30
+ end
31
+
32
+ config.after(:each) do
33
+ FakeWeb.clean_registry
34
+ FakeWeb.allow_net_connect = true
35
+ end
36
+
37
+ end
metadata CHANGED
@@ -1,70 +1,202 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-satisfaction
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ hash: 5
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 1
10
+ version: 0.6.1
5
11
  platform: ruby
6
12
  authors:
7
- - Scott Fleckenstein
8
- - Josh Nichols
9
- - Pius Uzamere
13
+ - Get Satisfaction
10
14
  autorequire:
11
15
  bindir: bin
12
16
  cert_chain: []
13
17
 
14
- date: 2009-07-10 00:00:00 -07:00
18
+ date: 2010-12-10 00:00:00 -08:00
15
19
  default_executable:
16
20
  dependencies:
17
21
  - !ruby/object:Gem::Dependency
18
- name: memcache-client
22
+ name: nokogiri
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 1
32
+ - 4
33
+ - 2
34
+ version: 1.4.2
19
35
  type: :runtime
20
- version_requirement:
21
- version_requirements: !ruby/object:Gem::Requirement
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: json
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
22
42
  requirements:
23
43
  - - ">="
24
44
  - !ruby/object:Gem::Version
45
+ hash: 11
46
+ segments:
47
+ - 1
48
+ - 4
49
+ - 6
50
+ version: 1.4.6
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: activesupport
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 5
62
+ segments:
63
+ - 2
64
+ - 3
65
+ version: "2.3"
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: memcache-client
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 1
79
+ - 5
80
+ - 0
25
81
  version: 1.5.0
26
- version:
82
+ type: :runtime
83
+ version_requirements: *id004
27
84
  - !ruby/object:Gem::Dependency
28
85
  name: oauth
29
- type: :runtime
30
- version_requirement:
31
- version_requirements: !ruby/object:Gem::Requirement
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
32
89
  requirements:
33
90
  - - ">="
34
91
  - !ruby/object:Gem::Version
92
+ hash: 25
93
+ segments:
94
+ - 0
95
+ - 3
96
+ - 5
35
97
  version: 0.3.5
36
- version:
37
- - !ruby/object:Gem::Dependency
38
- name: activesupport
39
98
  type: :runtime
40
- version_requirement:
41
- version_requirements: !ruby/object:Gem::Requirement
99
+ version_requirements: *id005
100
+ - !ruby/object:Gem::Dependency
101
+ name: bundler
102
+ prerelease: false
103
+ requirement: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 23
109
+ segments:
110
+ - 1
111
+ - 0
112
+ - 0
113
+ version: 1.0.0
114
+ type: :development
115
+ version_requirements: *id006
116
+ - !ruby/object:Gem::Dependency
117
+ name: rspec
118
+ prerelease: false
119
+ requirement: &id007 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ hash: 7
125
+ segments:
126
+ - 2
127
+ - 2
128
+ version: "2.2"
129
+ type: :development
130
+ version_requirements: *id007
131
+ - !ruby/object:Gem::Dependency
132
+ name: fakeweb
133
+ prerelease: false
134
+ requirement: &id008 !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ hash: 9
140
+ segments:
141
+ - 1
142
+ - 3
143
+ version: "1.3"
144
+ type: :development
145
+ version_requirements: *id008
146
+ - !ruby/object:Gem::Dependency
147
+ name: open_gem
148
+ prerelease: false
149
+ requirement: &id009 !ruby/object:Gem::Requirement
150
+ none: false
42
151
  requirements:
43
152
  - - ">="
44
153
  - !ruby/object:Gem::Version
45
- version: 2.3.2
46
- version:
47
- description: Ruby interface to Get Satisfaction
48
- email: scott@getsatisfaction.com
154
+ hash: 7
155
+ segments:
156
+ - 1
157
+ - 4
158
+ version: "1.4"
159
+ type: :development
160
+ version_requirements: *id009
161
+ - !ruby/object:Gem::Dependency
162
+ name: ruby-debug
163
+ prerelease: false
164
+ requirement: &id010 !ruby/object:Gem::Requirement
165
+ none: false
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ hash: 63
170
+ segments:
171
+ - 0
172
+ - 10
173
+ - 4
174
+ version: 0.10.4
175
+ type: :development
176
+ version_requirements: *id010
177
+ description: Get Satisfaction is a simple way to build online communities that enable productive conversations between companies and their customers. More than 46,000 companies use Get Satisfaction to provide a more social support experience, build better products, increase SEO and improve customer loyalty. Get Satisfaction communities are available at http://getsatisfaction.com.
178
+ email:
179
+ - nerds+rubygems@getsatisfaction.com
49
180
  executables: []
50
181
 
51
182
  extensions: []
52
183
 
53
184
  extra_rdoc_files:
54
- - README.txt
185
+ - README.markdown
55
186
  files:
56
- - .gitignore
57
187
  - CONTRIBUTORS.txt
188
+ - Gemfile
189
+ - Gemfile.lock
58
190
  - License.txt
59
- - README.txt
191
+ - README.markdown
60
192
  - Rakefile
61
- - VERSION.yml
62
193
  - init.rb
63
194
  - lib/satisfaction.rb
64
195
  - lib/satisfaction/associations.rb
65
196
  - lib/satisfaction/cache/hash.rb
66
197
  - lib/satisfaction/cache/memcache.rb
67
198
  - lib/satisfaction/company.rb
199
+ - lib/satisfaction/exceptions.rb
68
200
  - lib/satisfaction/external_dependencies.rb
69
201
  - lib/satisfaction/has_satisfaction.rb
70
202
  - lib/satisfaction/identity_map.rb
@@ -77,39 +209,50 @@ files:
77
209
  - lib/satisfaction/tag.rb
78
210
  - lib/satisfaction/topic.rb
79
211
  - lib/satisfaction/util.rb
212
+ - lib/satisfaction/version.rb
80
213
  - ruby-satisfaction.gemspec
81
- - spec/company_spec.rb
82
- - spec/identity_map_spec.rb
214
+ - spec/satisfaction/identity_map_spec.rb
215
+ - spec/satisfaction/loader_spec.rb
216
+ - spec/satisfaction_spec.rb
83
217
  - spec/spec_helper.rb
84
218
  has_rdoc: true
85
- homepage: http://github.com/nullstyle/ruby-satisfaction
219
+ homepage: https://github.com/satisfaction/ruby-satisfaction
86
220
  licenses: []
87
221
 
88
222
  post_install_message:
89
- rdoc_options:
90
- - --charset=UTF-8
223
+ rdoc_options: []
224
+
91
225
  require_paths:
92
226
  - lib
93
227
  required_ruby_version: !ruby/object:Gem::Requirement
228
+ none: false
94
229
  requirements:
95
230
  - - ">="
96
231
  - !ruby/object:Gem::Version
232
+ hash: 3
233
+ segments:
234
+ - 0
97
235
  version: "0"
98
- version:
99
236
  required_rubygems_version: !ruby/object:Gem::Requirement
237
+ none: false
100
238
  requirements:
101
239
  - - ">="
102
240
  - !ruby/object:Gem::Version
103
- version: "0"
104
- version:
241
+ hash: 23
242
+ segments:
243
+ - 1
244
+ - 3
245
+ - 6
246
+ version: 1.3.6
105
247
  requirements: []
106
248
 
107
- rubyforge_project: satisfaction
108
- rubygems_version: 1.3.4
249
+ rubyforge_project: ruby-satisfaction
250
+ rubygems_version: 1.3.7
109
251
  signing_key:
110
252
  specification_version: 3
111
- summary: Ruby interface to Get Satisfaction
253
+ summary: Get Satisfaction ruby client
112
254
  test_files:
113
- - spec/company_spec.rb
114
- - spec/identity_map_spec.rb
255
+ - spec/satisfaction/identity_map_spec.rb
256
+ - spec/satisfaction/loader_spec.rb
257
+ - spec/satisfaction_spec.rb
115
258
  - spec/spec_helper.rb
data/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- tmp/*
2
- log/*
3
- pkg
data/README.txt DELETED
@@ -1 +0,0 @@
1
- README
data/VERSION.yml DELETED
@@ -1,4 +0,0 @@
1
- ---
2
- :minor: 4
3
- :patch: 0
4
- :major: 0
data/spec/company_spec.rb DELETED
@@ -1,8 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Company loader" do
4
- it "should work" do
5
- @satisfaction.set_consumer('lmwjv4kzwi27', 'fiei6iv61jnoukaq1aylwd8vcmnkafrs')
6
- p @satisfaction.request_token
7
- end
8
- end
@@ -1,28 +0,0 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
2
-
3
- describe "Identity Map" do
4
- it "should work single instances" do
5
- c1 = @satisfaction.companies.get(4)
6
- c2 = @satisfaction.companies.get(4)
7
-
8
- c1.object_id.should == c2.object_id
9
- end
10
-
11
- it "should load one if the other gets loaded" do
12
- c1 = @satisfaction.companies.get(4)
13
- c2 = @satisfaction.companies.get(4)
14
- c2.should_not be_loaded
15
-
16
- c1.load
17
-
18
- c2.should be_loaded
19
- c2.domain.should == 'satisfaction'
20
- end
21
-
22
- it "should work with pages too" do
23
- c1 = @satisfaction.companies.get(4)
24
- c2 = @satisfaction.companies.page(1, :q => 'satisfaction').first
25
-
26
- c1.object_id.should == c2.object_id
27
- end
28
- end