gazette 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .bundle
2
+ .yardoc
3
+ doc
4
+ pkg/*.gem
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rake"
4
+ gem "jeweler"
5
+ gem "yard"
6
+ gem "bluecloth"
7
+
8
+ group :test do
9
+ gem "fakeweb"
10
+ gem "rspec"
11
+ gem "rcov"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ bluecloth (2.0.9)
5
+ fakeweb (1.2.8)
6
+ gemcutter (0.6.1)
7
+ git (1.2.5)
8
+ jeweler (1.4.0)
9
+ gemcutter (>= 0.1.0)
10
+ git (>= 1.2.5)
11
+ rubyforge (>= 2.0.0)
12
+ json_pure (1.4.6)
13
+ rake (0.8.7)
14
+ rcov (0.9.9)
15
+ rspec (1.3.0)
16
+ rubyforge (2.0.4)
17
+ json_pure (>= 1.1.7)
18
+ yard (0.6.1)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bluecloth
25
+ fakeweb
26
+ jeweler
27
+ rake
28
+ rcov
29
+ rspec
30
+ yard
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jeff Pollard
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:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
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.md ADDED
@@ -0,0 +1,67 @@
1
+ # Gazette
2
+
3
+ Gazette is a Ruby gem to interact with the [Instapaper API](http://www.instapaper.com/api). It offers complete functionality with all API features, including authentication and adding URLs to read later. Gazette operates over HTTP and HTTPS, and uses (Instapaper-preferred) HTTP basic authentication.
4
+
5
+ **NOTE: This gem is still in beta. Production use not suggested, but encouraged.**
6
+
7
+ ## Installation
8
+
9
+ At your favorite shell:
10
+
11
+ gem install gazette
12
+
13
+ ## Usage
14
+
15
+ All interaction with the Instapaper API is done with an instance of `Gazette::Client` object. The constructor requires one argument, the user's Instapaper email or username. The 2nd argument is an optional hash, which can contain a `:password => "user_pass"` and/or `:https => true` if you would like to use HTTPS
16
+
17
+ @client = Gazette::Client.new("user@eample.com", :password => "seeecrets")
18
+ => #<Gazette::Client:0x101f41cb0 @password=nil, @https=false, @username="user@eample.com", @options={}>
19
+
20
+ By default Gazette communicates with the Instapaper API over good 'ol HTTP. You are strongly encouraged to use HTTPS if at all possible.
21
+
22
+
23
+ ### Authentication
24
+
25
+ With a client in hand, you can call `@client.authenticate` to authenticate the user's credentials. Per the API documentation, authentication is totally optional. It may be useful if you want to verify the credentials provided by a user, but is not a required step before adding URLs.
26
+
27
+ >> @client.authenticate
28
+ => #<Gazette::Response::Success:0x101f37260 @instapaper_title=nil, @content_location=nil>
29
+
30
+ ### Responses
31
+
32
+ All valid responses to the Instapaper API return a `Gazette::Response::Success` object. All invalid response *raise* one of the following exceptions:
33
+
34
+ * `Gazette::Response::InvalidCredentials` - Invalid user credentials.
35
+ * `Gazette::Response::ServerError` - API encountered an error. Please try again later.
36
+ * `Gazette::Response::UnknownError` - Some other unknown error. File a bug...maybe.
37
+
38
+ Thus, for proper error checking, please `rescue` any/all of the above exceptions.
39
+
40
+ ### Adding URLs
41
+
42
+ To add URLs to the client's Instapaper account, call `@client.add(url)`:
43
+
44
+ >> @client.add("http://patmaddox.com/blog/2010/5/9/a-response-to-unit-and-functional-tests-are-as-useful-as-100.html", :title => "How do you write 100% correct code?", :selection => "How do you guarantee an application's correctness?")
45
+ => #<Gazette::Response::Success:0x101f17a00 @instapaper_title="\"How do you write 100% correct code?\"", @content_location="http://patmaddox.com/blog/2010/5/9/a-response-to-unit-and-functional-tests-are-as-useful-as-100.html">
46
+
47
+ The `#add` method takes only one required parameter, a string of the URL you want to add. The 2nd parameter is an optional hash, which can contain any of the following. See the [Instapaper API documentation](http://www.instapaper.com/api) for details:
48
+
49
+ * `:title => "string"`
50
+ * `:selection => "string"`
51
+ * `:redirect => :close` which attempts to close the window after a short delay.
52
+ * `:jsonp => "string"`
53
+
54
+
55
+ ## Note on Patches/Pull Requests
56
+
57
+ * Fork the project.
58
+ * Make your feature addition or bug fix.
59
+ * Add tests for it. This is important so I don't break it in a
60
+ future version unintentionally.
61
+ * Commit, do not mess with rakefile, version, or history.
62
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
63
+ * Send me a pull request. Bonus points for topic branches.
64
+
65
+ ## Copyright
66
+
67
+ Copyright (c) 2010 Jeff Pollard. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts "!! Bundler not found. Please run `gem install bundler` to install and preface commands with `bundle exec`"
5
+ end
6
+
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "gazette"
10
+ gem.summary = %Q{Ruby library to interact with the Instapaper API.}
11
+ gem.description = %Q{Simple Ruby wrapper gem to interact with the Instapaper API. Supports authenticate and add API methods, as well as https, jsonp and redirect featres of the API.}
12
+ gem.email = "jeff.pollard@gmail.com"
13
+ gem.homepage = "http://github.com/Fluxx/gazette"
14
+ gem.authors = ["Jeff Pollard"]
15
+ gem.add_development_dependency "rspec", ">= 1.2.9"
16
+ gem.add_development_dependency "yard", ">= 0"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+ task :default => :spec
35
+
36
+ require 'yard'
37
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/gazette.gemspec ADDED
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gazette}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jeff Pollard"]
12
+ s.date = %q{2010-10-22}
13
+ s.description = %q{Simple Ruby wrapper gem to interact with the Instapaper API. Supports authenticate and add API methods, as well as https, jsonp and redirect featres of the API.}
14
+ s.email = %q{jeff.pollard@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "gazette.gemspec",
28
+ "lib/gazette.rb",
29
+ "lib/gazette/api.rb",
30
+ "lib/gazette/client.rb",
31
+ "lib/gazette/response.rb",
32
+ "spec/client/add_spec.rb",
33
+ "spec/client/authenticate_spec.rb",
34
+ "spec/client/client_spec.rb",
35
+ "spec/response/success_spec.rb",
36
+ "spec/spec.opts",
37
+ "spec/spec_helper.rb",
38
+ "todo.txt"
39
+ ]
40
+ s.homepage = %q{http://github.com/Fluxx/gazette}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.6}
44
+ s.summary = %q{Ruby library to interact with the Instapaper API.}
45
+ s.test_files = [
46
+ "spec/client/add_spec.rb",
47
+ "spec/client/authenticate_spec.rb",
48
+ "spec/client/client_spec.rb",
49
+ "spec/response/success_spec.rb",
50
+ "spec/spec_helper.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
59
+ s.add_development_dependency(%q<yard>, [">= 0"])
60
+ else
61
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
62
+ s.add_dependency(%q<yard>, [">= 0"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ s.add_dependency(%q<yard>, [">= 0"])
67
+ end
68
+ end
69
+
@@ -0,0 +1,10 @@
1
+ module Gazette
2
+ module Api
3
+
4
+ # Web address of the Instapaper API
5
+ ADDRESS = 'www.instapaper.com'.freeze
6
+
7
+ # Endpoint of the Intsapper API
8
+ ENDPOINT = '/api/'.freeze
9
+ end
10
+ end
@@ -0,0 +1,94 @@
1
+ require "net/http"
2
+ require "net/https"
3
+ require "openssl"
4
+ require "pp"
5
+
6
+ module Gazette
7
+ # The Client class interacts with the Instapaper API. Client hold user authentication
8
+ # information, as well as provide methods to authenticate user credentials and add URLs
9
+ # to their user's Instapaper account.
10
+ #
11
+ # @author Jeff Pollard
12
+ # @see http://www.instapaper.com/api Instapaper-provided API documenation.
13
+ class Client
14
+
15
+ attr_reader :username
16
+ attr_reader :password
17
+
18
+ # Create a new client. Instapaper requires a user username. Most Instapaper users
19
+ # <b>don't</b> have a password, as such it is optional.
20
+ #
21
+ # @param [String] username Instapaper username
22
+ # @param [Hash] options Additional client options
23
+ # @option options [String] :password Instapaper username
24
+ # @option options [Boolean] :https (false) Interact with the Instapaper API over
25
+ # HTTPS.
26
+ def initialize(username, options = {})
27
+ raise ArgumentError.new("2nd parameter must be a Hash") unless options.is_a?(Hash)
28
+ @username = username
29
+ @password = options.delete(:password)
30
+ @options = options
31
+ @https = !!(options.delete(:https))
32
+ end
33
+
34
+ # Attempts to authenticate the client's user credentials with Instapaper.
35
+ #
36
+ # @param [Hash] options Additional authentication options
37
+ # @option options [String] :jsonp (nil) Returns results as JSON to the specified
38
+ # Javascript callback.
39
+ # @return [Response::Success] Successful response from the Instapaper API.
40
+ # @raise [Response::InvalidCredentials]
41
+ # @raise [Response::ServerError]
42
+ # @raise [Response::UnknownError]
43
+ def authenticate(options = {})
44
+ parse_response_for request(:authenticate, options)
45
+ end
46
+
47
+ # Adds a URL to a user's instapaper account.
48
+ #
49
+ # @param [String] url URL of the content to add.
50
+ # @param [Hash] options Additional add options
51
+ # @option options [String] :title Title of the content. If omitted, Instapaper will
52
+ # generate a title.
53
+ # @option options [String] :select Sample/selection of content.
54
+ # @option options [:close] :redirect Response returns "Saved!" string and attempts to
55
+ # close its own window after a short delay.
56
+ # @option options [String] :jsonp (nil) Returns results as JSON to the specified
57
+ # Javascript callback.
58
+ # @return [Response::Success] Successful response from the Instapaper API.
59
+ # @raise [Response::InvalidCredentials]
60
+ # @raise [Response::ServerError]
61
+ # @raise [Response::UnknownError]
62
+ def add(url, options = {})
63
+ parse_response_for request(:add, options.merge(:url => url))
64
+ end
65
+
66
+ private
67
+
68
+ # Handles the response from Instapaper.
69
+ #
70
+ # @todo Put the raising logic in the Api class/module, then leave the response return
71
+ # to this method
72
+ def parse_response_for(response)
73
+ case response
74
+ when Net::HTTPOK, Net::HTTPCreated then return Response::Success.new(response)
75
+ when Net::HTTPForbidden then raise Response::InvalidCredentials
76
+ when Net::HTTPInternalServerError then raise Response::ServerError
77
+ else raise Response::UnknownError
78
+ end
79
+ end
80
+
81
+ # Actually heads out to the internet and performs the request
82
+ # @todo Perhaps put me in the Api class/module?
83
+ def request(method, params = {})
84
+ http = Net::HTTP.new(Api::ADDRESS, (@https ? 443 : 80))
85
+ http.use_ssl = @https
86
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
87
+ request = Net::HTTP::Post.new(Api::ENDPOINT+method.to_s)
88
+ request.basic_auth @username, @password
89
+ request.set_form_data(params)
90
+ http.start { http.request(request) }
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,39 @@
1
+ module Gazette
2
+ # Container class for response from the Instapaper API.
3
+ # @author Jeff Pollard
4
+ class Response
5
+ # Successful response from the Instapaper API
6
+ # @author Jeff Pollard
7
+ class Success < Response
8
+
9
+ # Final saved URL of the content returned from the Instapaper API.
10
+ attr_reader :content_location
11
+
12
+ # Saved title of the content returned from the Instapaper API.
13
+ attr_reader :instapaper_title
14
+
15
+ # Create a new Success object out of a net/http response.
16
+ def initialize(response)
17
+ unless response.is_a?(Net::HTTPResponse)
18
+ # Require a net/http response object
19
+ raise ArgumentError.new("Argument must be a Net::HTTPResponse object")
20
+ end
21
+
22
+ # Build our ivars from the headers
23
+ @content_location = response.header['Content-Location']
24
+ @instapaper_title = response.header['X-Instapaper-Title']
25
+ end
26
+ end
27
+
28
+ # Response raised of the Instapaper returned a response indicating invalid user
29
+ # credentials.
30
+ class InvalidCredentials < Exception; end
31
+
32
+ # Retponse raised if the Instapaper returned a server error (500).
33
+ class ServerError < Exception; end
34
+
35
+ # Response returned if there was some other type of unknown error.
36
+ class UnknownError < Exception; end
37
+
38
+ end
39
+ end
data/lib/gazette.rb ADDED
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require "gazette/api"
4
+ require "gazette/client"
5
+ require "gazette/response"
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ INTERESTING_ARTICLE = "http://blog.instapaper.com/post/1256471940"
4
+
5
+ describe Gazette::Client, "#add" do
6
+ before(:each) do
7
+ # @todo Abstract me out
8
+ @my_post = stub_http_client('/api/add')
9
+ @client = Gazette::Client.new("foo")
10
+ end
11
+
12
+ it "should raise an ArgumentError if no first argument is provided" do
13
+ lambda do
14
+ @client.add
15
+ end.should raise_error(ArgumentError)
16
+ end
17
+
18
+ describe "with a 201 OK response" do
19
+ before(:each) do
20
+ stub_instapaper_api(:add => {:status => 201})
21
+ end
22
+
23
+ it "returns a Gazette::Response::Success object" do
24
+ @client.add(INTERESTING_ARTICLE).should be_a Gazette::Response::Success
25
+ end
26
+
27
+ it "calls the add instapaper API call" do
28
+ Net::HTTP::Post.should_receive(:new).with(/add/).and_return(@my_post)
29
+ @client.add(INTERESTING_ARTICLE)
30
+ end
31
+
32
+ describe "parameters" do
33
+
34
+ it "passes the URL as a parameter" do
35
+ @my_post.should_receive(:set_form_data).with(hash_including(:url => INTERESTING_ARTICLE))
36
+ @client.add(INTERESTING_ARTICLE)
37
+ end
38
+
39
+ it "passes the title as a parameter if specified" do
40
+ @my_post.should_receive(:set_form_data).with(hash_including(:title => "my title"))
41
+ @client.add(INTERESTING_ARTICLE, :title => "my title")
42
+ end
43
+
44
+ it "passes the selection as a parameter if specified" do
45
+ @my_post.should_receive(:set_form_data).with(hash_including(:selection => "read me!"))
46
+ @client.add(INTERESTING_ARTICLE, :selection => "read me!")
47
+ end
48
+
49
+ it "passes redirect as a parameter if specified" do
50
+ @my_post.should_receive(:set_form_data).with(hash_including(:redirect => :close))
51
+ @client.add(INTERESTING_ARTICLE, :redirect => :close)
52
+ end
53
+
54
+ it "passes the jsonp as a parameter if specified" do
55
+ @my_post.should_receive(:set_form_data).with(hash_including(:jsonp => "myfunc"))
56
+ @client.add(INTERESTING_ARTICLE, :jsonp => "myfunc")
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+ describe "with a 403 response" do
63
+ before(:each) do
64
+ stub_instapaper_api(:add => {:status => 403})
65
+ end
66
+
67
+ it "rasises a Gazette::Response::InvalidCredentials" do
68
+ lambda {
69
+ @client.add(INTERESTING_ARTICLE)
70
+ }.should raise_error(Gazette::Response::InvalidCredentials)
71
+ end
72
+ end
73
+
74
+ describe "with a 500 response" do
75
+ before(:each) do
76
+ stub_instapaper_api(:add => {:status => 500})
77
+ end
78
+
79
+ it "rasises a Gazette::Response::ServerError" do
80
+ lambda {
81
+ @client.add(INTERESTING_ARTICLE)
82
+ }.should raise_error(Gazette::Response::ServerError)
83
+ end
84
+ end
85
+
86
+ describe "with a XXX response" do
87
+ before(:each) do
88
+ stub_instapaper_api(:add => {:status => 999})
89
+ end
90
+
91
+ it "rasises a Gazette::Response::UnknownError" do
92
+ lambda {
93
+ @client.add(INTERESTING_ARTICLE)
94
+ }.should raise_error(Gazette::Response::UnknownError)
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Gazette::Client, "#authenticate" do
4
+ before(:each) do
5
+ @client = Gazette::Client.new("foo")
6
+ @my_post = stub_http_client('/api/authenticate')
7
+ end
8
+
9
+ describe "with a 200 OK response" do
10
+ before(:each) do
11
+ stub_instapaper_api(:authenticate => {:status => 200})
12
+ end
13
+
14
+ it "returns a Gazette::Response::Success object" do
15
+ @client.authenticate.should be_a Gazette::Response::Success
16
+ end
17
+
18
+ it "calls the 'authenticate' instapaper API call" do
19
+ Net::HTTP::Post.should_receive(:new).with(/authenticate/).and_return(@my_post)
20
+ @client.authenticate
21
+ end
22
+ end
23
+
24
+ describe "with a 403 response" do
25
+ before(:each) do
26
+ stub_instapaper_api(:authenticate => {:status => 403})
27
+ end
28
+
29
+ it "rasises a Gazette::Response::InvalidCredentials" do
30
+ lambda {
31
+ @client.authenticate
32
+ }.should raise_error(Gazette::Response::InvalidCredentials)
33
+ end
34
+ end
35
+
36
+ describe "with a 500 response" do
37
+ before(:each) do
38
+ stub_instapaper_api(:authenticate => {:status => 500})
39
+ end
40
+
41
+ it "rasises a Gazette::Response::ServerError" do
42
+ lambda {
43
+ @client.authenticate
44
+ }.should raise_error(Gazette::Response::ServerError)
45
+ end
46
+ end
47
+
48
+ describe "with a XXX response" do
49
+ before(:each) do
50
+ stub_instapaper_api(:authenticate => {:status => 999})
51
+ end
52
+
53
+ it "rasises a Gazette::Response::UnknownError" do
54
+ lambda {
55
+ @client.authenticate
56
+ }.should raise_error(Gazette::Response::UnknownError)
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Gazette::Client, ".new" do
4
+
5
+ it "raises an error if no fist argument it passed" do
6
+ lambda { Gazette::Client.new }.should raise_error(ArgumentError)
7
+ end
8
+
9
+ it "raises an argument error if the 2nd parameter is not a hash" do
10
+ lambda { Gazette::Client.new("foo", 56) }.should raise_error(ArgumentError)
11
+ end
12
+
13
+ shared_examples_for "a properlty constructed client" do
14
+ it "sets the username as the first argument" do
15
+ @client.username.should eql("foo")
16
+ end
17
+ end
18
+
19
+ describe "with a single string argument" do
20
+ before(:each) do
21
+ @client = Gazette::Client.new("foo")
22
+ end
23
+
24
+ it_should_behave_like "a properlty constructed client"
25
+
26
+ it "has no password set" do
27
+ @client.password.should be_nil
28
+ end
29
+
30
+ end
31
+
32
+ describe "with a string and hash containing a :password" do
33
+ before(:each) do
34
+ @client = Gazette::Client.new("foo", :password => "bar")
35
+ end
36
+
37
+ it_should_behave_like "a properlty constructed client"
38
+
39
+ it "has a password set" do
40
+ @client.password.should eql("bar")
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ describe Gazette::Client, "HTTP basic auth" do
48
+ before(:each) do
49
+ stub_instapaper_api(:authenticate => {:status => 200})
50
+ @client = Gazette::Client.new("foo")
51
+ @my_post = Net::HTTP::Post.new('/api/authenticate')
52
+ Net::HTTP::Post.stub!(:new).and_return(@my_post)
53
+ end
54
+
55
+ it "passes along the username" do
56
+ @my_post.should_receive(:basic_auth).with("foo", nil)
57
+ @client.authenticate
58
+ end
59
+
60
+ it "passes along the password if specified" do
61
+ @client = Gazette::Client.new("foo", :password => "bar")
62
+ @my_post.should_receive(:basic_auth).with("foo", "bar")
63
+ @client.authenticate
64
+ end
65
+
66
+ it "passes the jsonp as a parameter if specified" do
67
+ @my_post.should_receive(:set_form_data).with(hash_including(:jsonp => "myfunc"))
68
+ @client.authenticate(:jsonp => "myfunc")
69
+ end
70
+ end
71
+
72
+ describe Gazette::Client, "over HTTPS" do
73
+ before(:each) do
74
+ @client = Gazette::Client.new("foo", :https => true)
75
+ stub_instapaper_api(:authenticate => {:status => 200})
76
+ @my_http = Net::HTTP.new(Gazette::Api::ADDRESS, 443)
77
+ end
78
+
79
+ it "tells the HTTP client to use ssl" do
80
+ Net::HTTP.should_receive(:new).with(anything, 443).and_return(@my_http)
81
+ @client.authenticate
82
+ end
83
+
84
+ end
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Gazette::Response::Success do
4
+ before(:each) do
5
+ @response = mock("response", :is_a? => true, :header => {})
6
+ end
7
+
8
+ it "raises an argument error unless the first argument is a Net::HTTPResponse object" do
9
+ lambda do
10
+ Gazette::Response::Success.new(:nonse)
11
+ end.should raise_error(ArgumentError)
12
+
13
+ end
14
+
15
+ it "has a content_location attribute" do
16
+ Gazette::Response::Success.new(@response).content_location.should be_nil
17
+ end
18
+
19
+ it "has an instapaper_title attribute" do
20
+ Gazette::Response::Success.new(@response).instapaper_title.should be_nil
21
+ end
22
+
23
+ it "sets content_location if the 'Content-Location' header is present" do
24
+ @response.stub!(:header).and_return({'Content-Location' => 'http://www.example.com/'})
25
+ Gazette::Response::Success.new(@response).content_location.should == 'http://www.example.com/'
26
+ end
27
+
28
+ it "sets instapaper_title if the 'X-Instapaper-Title' header is present" do
29
+ @response.stub!(:header).and_return({'X-Instapaper-Title' => 'nonse'})
30
+ Gazette::Response::Success.new(@response).instapaper_title.should == 'nonse'
31
+ end
32
+
33
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,32 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'gazette'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+ require 'fakeweb'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
12
+
13
+ # Stubs out the instapaper API using a simple configuration syntax:
14
+ #
15
+ # :method => {:hash_of => :fakeweb_options}
16
+ def stub_instapaper_api(configuration)
17
+ configuration.each do |method, opts|
18
+ ["", "foo@", "foo:bar@"].each do |hba|
19
+ base = "#{hba}#{Gazette::Api::ADDRESS}#{Gazette::Api::ENDPOINT}"
20
+ FakeWeb.register_uri(:any, "http://"+base+method.to_s, opts.merge(:body => "lol"))
21
+ FakeWeb.register_uri(:any, "https://"+base+method.to_s, opts)
22
+ end
23
+ end
24
+ end
25
+
26
+ # Stubs out the HTTP client and builds a @my_post variable, which is our own mock we can
27
+ # use to verify HTTP actions
28
+ def stub_http_client(path)
29
+ @my_post = Net::HTTP::Post.new(path)
30
+ Net::HTTP::Post.stub!(:new).and_return(@my_post)
31
+ @my_post
32
+ end
data/todo.txt ADDED
@@ -0,0 +1 @@
1
+ - Add `gazette` bin
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gazette
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
+ platform: ruby
11
+ authors:
12
+ - Jeff Pollard
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-22 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ prerelease: false
22
+ type: :development
23
+ name: rspec
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 2
31
+ - 9
32
+ version: 1.2.9
33
+ requirement: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ prerelease: false
36
+ type: :development
37
+ name: yard
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ requirement: *id002
46
+ description: Simple Ruby wrapper gem to interact with the Instapaper API. Supports authenticate and add API methods, as well as https, jsonp and redirect featres of the API.
47
+ email: jeff.pollard@gmail.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - LICENSE
54
+ - README.md
55
+ files:
56
+ - .gitignore
57
+ - Gemfile
58
+ - Gemfile.lock
59
+ - LICENSE
60
+ - README.md
61
+ - Rakefile
62
+ - VERSION
63
+ - gazette.gemspec
64
+ - lib/gazette.rb
65
+ - lib/gazette/api.rb
66
+ - lib/gazette/client.rb
67
+ - lib/gazette/response.rb
68
+ - spec/client/add_spec.rb
69
+ - spec/client/authenticate_spec.rb
70
+ - spec/client/client_spec.rb
71
+ - spec/response/success_spec.rb
72
+ - spec/spec.opts
73
+ - spec/spec_helper.rb
74
+ - todo.txt
75
+ has_rdoc: true
76
+ homepage: http://github.com/Fluxx/gazette
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.3.6
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Ruby library to interact with the Instapaper API.
105
+ test_files:
106
+ - spec/client/add_spec.rb
107
+ - spec/client/authenticate_spec.rb
108
+ - spec/client/client_spec.rb
109
+ - spec/response/success_spec.rb
110
+ - spec/spec_helper.rb