slight refactor in preparation for adding version 1.1 support

a couple breaking changes as part of this:

* the api version can no longer be set via configuration (since the API
itself now supports more than one version 1 and 1.1 this no longer makes
sense)
* removed module based support, all requests will require an Instapaper::Client from now on
* removed path_prefix configuration for same reasons that the api version was removed
This commit is contained in:
stve 2015-02-09 16:21:30 -05:00
parent 813cfc7426
commit 6271356847
20 changed files with 257 additions and 493 deletions

View file

@ -1,26 +1 @@
require 'instapaper/configuration'
require 'instapaper/client'
module Instapaper
extend Configuration
# Alias for Instapaper::Client.new
#
# @return [Instapaper::Client]
def self.client(options = {})
Instapaper::Client.new(options)
end
# Delegate to Instapaper::Client
def self.method_missing(method, *args, &block)
return super unless client.respond_to?(method)
client.send(method, *args, &block)
end
def self.respond_to?(method, include_private = false)
client.respond_to?(method, include_private) || super(method, include_private)
end
# Custom error class for rescuing from all Instapaper errors
class Error < StandardError; end
end

15
lib/instapaper/api.rb Normal file
View file

@ -0,0 +1,15 @@
require 'instapaper/api/account'
require 'instapaper/api/bookmark'
require 'instapaper/api/folder'
require 'instapaper/api/highlight'
require 'instapaper/api/user'
module Instapaper
module API
include Instapaper::API::Account
include Instapaper::API::Bookmark
include Instapaper::API::Folder
include Instapaper::API::Highlight
include Instapaper::API::User
end
end

View file

@ -1,10 +1,10 @@
module Instapaper
class Client
module API
# Defines methods related to accounts
module Account
# Returns the currently logged in user.
def verify_credentials
post('account/verify_credentials')
post('/api/1/account/verify_credentials')
end
end
end

View file

@ -1,5 +1,5 @@
module Instapaper
class Client
module API
# Defines methods related to bookmarks
module Bookmark
# Lists the user's unread bookmarks, and can also synchronize reading positions.
@ -7,7 +7,7 @@ module Instapaper
# @option folder_id: Optional. Possible values are unread (default), starred, archive, or a folder_id value from /api/1/folders/list.
# @option have: Optional. A concatenation of bookmark_id values that the client already has from the specified folder. See below.
def bookmarks(options = {})
post('bookmarks/list', options)[2..-1]
post('/api/1/bookmarks/list', options)[2..-1]
end
# Updates the user's reading progress on a single article.
@ -15,47 +15,47 @@ module Instapaper
# @param progress [Float] The user's progress, as a floating-point number between 0.0 and 1.0, defined as the top edge of the user's current viewport, expressed as a percentage of the article's total length.
# @param progress_timestamp [Integer] The Unix timestamp value of the time that the progress was recorded.
def update_read_progress(bookmark_id, progress, progress_timestamp = Time.now)
post('bookmarks/update_read_progress', bookmark_id: bookmark_id, progress: progress, progress_timestamp: progress_timestamp.to_i).first
post('/api/1/bookmarks/update_read_progress', bookmark_id: bookmark_id, progress: progress, progress_timestamp: progress_timestamp.to_i).first
end
# Adds a new unread bookmark to the user's account.
# @param url [String] The url of the bookmark.
def add_bookmark(url, options = {})
post('bookmarks/add', options.merge(url: url)).first
post('/api/1/bookmarks/add', options.merge(url: url)).first
end
# Permanently deletes the specified bookmark.
# This is NOT the same as Archive. Please be clear to users if you're going to do this.
# @param bookmark_id [String] The id of the bookmark.
def delete_bookmark(bookmark_id)
post('bookmarks/delete', bookmark_id: bookmark_id)
post('/api/1/bookmarks/delete', bookmark_id: bookmark_id)
end
# Stars the specified bookmark.
# @param bookmark_id [String] The id of the bookmark.
def star(bookmark_id)
post('bookmarks/star', bookmark_id: bookmark_id).first
post('/api/1/bookmarks/star', bookmark_id: bookmark_id).first
end
alias_method :star_bookmark, :star
# Un-stars the specified bookmark.
# @param bookmark_id [String] The id of the bookmark.
def unstar(bookmark_id)
post('bookmarks/unstar', bookmark_id: bookmark_id).first
post('/api/1/bookmarks/unstar', bookmark_id: bookmark_id).first
end
alias_method :unstar_bookmark, :unstar
# Moves the specified bookmark to the Archive.
# @param bookmark_id [String] The id of the bookmark.
def archive(bookmark_id)
post('bookmarks/archive', bookmark_id: bookmark_id).first
post('/api/1/bookmarks/archive', bookmark_id: bookmark_id).first
end
alias_method :archive_bookmark, :archive
# Moves the specified bookmark to the top of the Unread folder.
# @param bookmark_id [String] The id of the bookmark.
def unarchive(bookmark_id)
post('bookmarks/unarchive', bookmark_id: bookmark_id).first
post('/api/1/bookmarks/unarchive', bookmark_id: bookmark_id).first
end
alias_method :unarchive_bookmark, :unarchive
@ -63,7 +63,7 @@ module Instapaper
# @param bookmark_id [String] The id of the bookmark.
# @param folder_id [String] The id of the folder to move the bookmark to.
def move(bookmark_id, folder_id)
post('bookmarks/move', bookmark_id: bookmark_id, folder_id: folder_id).first
post('/api/1/bookmarks/move', bookmark_id: bookmark_id, folder_id: folder_id).first
end
alias_method :move_bookmark, :move
@ -71,7 +71,7 @@ module Instapaper
# always text/html encoded as UTF-8.
# @param bookmark_id [String] The id of the bookmark.
def text(bookmark_id)
post('bookmarks/get_text', {bookmark_id: bookmark_id}, true).body
post('/api/1/bookmarks/get_text', {bookmark_id: bookmark_id}, true).body
end
alias_method :get_text, :text
end

View file

@ -1,23 +1,23 @@
module Instapaper
class Client
module API
# Defines methods related to folders
module Folder
# List the account's user-created folders.
# @note This only includes organizational folders and does not include RSS-feed folders or starred-subscription folders
def folders
post('folders/list')
post('/api/1/folders/list')
end
# Creates an organizational folder.
# @param title [String] The title of the folder to create
def add_folder(title)
post('folders/add', title: title)
post('/api/1/folders/add', title: title)
end
# Deletes the folder and moves any articles in it to the Archive.
# @param folder_id [String] The id of the folder.
def delete_folder(folder_id)
post('folders/delete', folder_id: folder_id)
post('/api/1/folders/delete', folder_id: folder_id)
end
# Re-orders a user's folders.
@ -25,7 +25,7 @@ module Instapaper
# @example Ordering folder_ids 100, 200, and 300
# Instapaper.set_order(['100:1','200:2','300:3'])
def set_order(order = []) # rubocop:disable Style/AccessorMethodName
post('folders/set_order', order: order.join(','))
post('/api/1/folders/set_order', order: order.join(','))
end
end
end

View file

@ -0,0 +1,7 @@
module Instapaper
module API
# Defines methods related to highlights
module Highlight
end
end
end

View file

@ -1,10 +1,10 @@
module Instapaper
class Client
module API
# Defines methods related to users
module User
# Gets an OAuth access token for a user.
def access_token(username, password)
response = post('oauth/access_token', {x_auth_username: username, x_auth_password: password, x_auth_mode: 'client_auth'}, true)
response = post('/api/1/oauth/access_token', {x_auth_username: username, x_auth_password: password, x_auth_mode: 'client_auth'}, true)
params = response.body.split('&')
values = params.map { |part| part.split('=') }.flatten
values.unshift('error') if values.length == 1

View file

@ -1,32 +0,0 @@
module Instapaper
# @private
module Authentication
private
# Authentication hash
#
# @return [Hash]
def authentication
{
consumer_key: consumer_key,
consumer_secret: consumer_secret,
token: oauth_token,
token_secret: oauth_token_secret,
}
end
def consumer_tokens
{
consumer_key: consumer_key,
consumer_secret: consumer_secret,
}
end
# Check whether user is authenticated
#
# @return [Boolean]
def authenticated?
authentication.values.all?
end
end
end

View file

@ -1,10 +1,54 @@
require 'instapaper/connection'
require 'instapaper/request'
require 'instapaper/authentication'
require 'instapaper/api'
require 'instapaper/error'
require 'instapaper/version'
require 'faraday_middleware'
require 'faraday/response/raise_http_1xxx'
module Instapaper
# Wrapper for the Instapaper REST API
class Client
include Instapaper::API
# An array of valid keys in the options hash when configuring a {Instapaper::API}
VALID_OPTIONS_KEYS = [
:adapter,
:consumer_key,
:consumer_secret,
:endpoint,
:oauth_token,
:oauth_token_secret,
:proxy,
:user_agent,
:connection_options].freeze
# The adapter that will be used to connect if none is set
#
# @note The default faraday adapter is Net::HTTP.
DEFAULT_ADAPTER = :net_http
# By default, don't set an application key
DEFAULT_CONSUMER_KEY = nil
# By default, don't set an application secret
DEFAULT_CONSUMER_SECRET = nil
# The endpoint that will be used to connect if none is set
DEFAULT_ENDPOINT = 'https://www.instapaper.com'.freeze
# By default, don't set a user oauth token
DEFAULT_OAUTH_TOKEN = nil
# By default, don't set a user oauth secret
DEFAULT_OAUTH_TOKEN_SECRET = nil
# By default, don't use a proxy server
DEFAULT_PROXY = nil
# The user agent that will be sent to the API endpoint if none is set
DEFAULT_USER_AGENT = "Instapaper Ruby Gem #{Instapaper::VERSION}".freeze
DEFAULT_CONNECTION_OPTIONS = {}
# @private
attr_accessor :adapter
attr_accessor :consumer_key
@ -13,41 +57,100 @@ module Instapaper
attr_accessor :oauth_token
attr_accessor :oauth_token_secret
attr_accessor :proxy
attr_accessor :version
attr_accessor :path_prefix
attr_accessor :user_agent
attr_accessor :connection_options
alias_method :api_endpoint, :endpoint
alias_method :api_version, :version
# Creates a new API
def initialize(options = {})
options = Instapaper.options.merge(options)
Configuration::VALID_OPTIONS_KEYS.each do |key|
reset
options.keys.each do |key|
send("#{key}=", options[key])
end
end
def endpoint_with_prefix
api_endpoint + path_prefix
private
def connection(raw = false) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
merged_options = connection_defaults.merge(@connection_options)
Faraday.new(merged_options) do |builder|
if authenticated?
builder.use Faraday::Request::OAuth, authentication
else
builder.use Faraday::Request::OAuth, consumer_tokens
end
builder.use Faraday::Request::Multipart
builder.use Faraday::Request::UrlEncoded
builder.use Faraday::Response::Rashify unless raw
builder.use Faraday::Response::ParseJson unless raw
builder.use Faraday::Response::RaiseHttp1xxx
builder.adapter(adapter)
end
end
include Connection
include Request
include Authentication
def connection_defaults
{
headers: {
'Accept' => 'application/json',
'User-Agent' => @user_agent,
},
proxy: @proxy,
url: @endpoint,
}
end
# Require client method modules after initializing the Client class in
# order to avoid a superclass mismatch error, allowing those modules to be
# Client-namespaced.
require 'instapaper/client/account'
require 'instapaper/client/user'
require 'instapaper/client/bookmark'
require 'instapaper/client/folder'
# Perform an HTTP POST request
def post(path, options = {}, raw = false)
request(:post, path, options, raw)
end
include Instapaper::Client::Account
include Instapaper::Client::User
include Instapaper::Client::Bookmark
include Instapaper::Client::Folder
# Perform an HTTP request
def request(method, path, options, raw = false)
response = connection(raw).send(method) do |request|
request.path = path
request.body = options unless options.empty?
end
raw ? response : response.body
end
# Authentication hash
#
# @return [Hash]
def authentication
{
consumer_key: @consumer_key,
consumer_secret: @consumer_secret,
token: @oauth_token,
token_secret: @oauth_token_secret,
}
end
def consumer_tokens
{
consumer_key: @consumer_key,
consumer_secret: @consumer_secret,
}
end
# Check whether user is authenticated
#
# @return [Boolean]
def authenticated?
authentication.values.all?
end
# Reset all configuration options to defaults
def reset # rubocop:disable MethodLength
@adapter = DEFAULT_ADAPTER
@consumer_key = DEFAULT_CONSUMER_KEY
@consumer_secret = DEFAULT_CONSUMER_SECRET
@endpoint = DEFAULT_ENDPOINT
@oauth_token = DEFAULT_OAUTH_TOKEN
@oauth_token_secret = DEFAULT_OAUTH_TOKEN_SECRET
@proxy = DEFAULT_PROXY
@user_agent = DEFAULT_USER_AGENT
@connection_options = DEFAULT_CONNECTION_OPTIONS
end
end
end

View file

@ -1,97 +0,0 @@
require 'instapaper/version'
module Instapaper
module Configuration
# An array of valid keys in the options hash when configuring a {Instapaper::API}
VALID_OPTIONS_KEYS = [
:adapter,
:consumer_key,
:consumer_secret,
:endpoint,
:oauth_token,
:oauth_token_secret,
:proxy,
:version,
:path_prefix,
:user_agent,
:connection_options].freeze
# The adapter that will be used to connect if none is set
#
# @note The default faraday adapter is Net::HTTP.
DEFAULT_ADAPTER = :net_http
# By default, don't set an application key
DEFAULT_CONSUMER_KEY = nil
# By default, don't set an application secret
DEFAULT_CONSUMER_SECRET = nil
# The endpoint that will be used to connect if none is set
DEFAULT_ENDPOINT = 'https://www.instapaper.com/'.freeze
# The version of the API.
DEFAULT_VERSION = '1'
DEFAULT_PATH_PREFIX = 'api/' + DEFAULT_VERSION + '/'
# By default, don't set a user oauth token
DEFAULT_OAUTH_TOKEN = nil
# By default, don't set a user oauth secret
DEFAULT_OAUTH_TOKEN_SECRET = nil
# By default, don't use a proxy server
DEFAULT_PROXY = nil
# The user agent that will be sent to the API endpoint if none is set
DEFAULT_USER_AGENT = "Instapaper Ruby Gem #{Instapaper::VERSION}".freeze
DEFAULT_CONNECTION_OPTIONS = {}
attr_accessor :adapter
attr_accessor :consumer_key
attr_accessor :consumer_secret
attr_accessor :endpoint
attr_accessor :oauth_token
attr_accessor :oauth_token_secret
attr_accessor :proxy
attr_accessor :version
attr_accessor :path_prefix
attr_accessor :user_agent
attr_accessor :connection_options
# When this module is extended, set all configuration options to their default values
def self.extended(base)
base.reset
end
# Convenience method to allow configuration options to be set in a block
def configure
yield self
end
# Create a hash of options and their values
def options
options = {}
VALID_OPTIONS_KEYS.each { |k| options[k] = send(k) }
options
end
# Reset all configuration options to defaults
def reset # rubocop:disable MethodLength
self.adapter = DEFAULT_ADAPTER
self.consumer_key = DEFAULT_CONSUMER_KEY
self.consumer_secret = DEFAULT_CONSUMER_SECRET
self.endpoint = DEFAULT_ENDPOINT
self.oauth_token = DEFAULT_OAUTH_TOKEN
self.oauth_token_secret = DEFAULT_OAUTH_TOKEN_SECRET
self.proxy = DEFAULT_PROXY
self.user_agent = DEFAULT_USER_AGENT
self.version = DEFAULT_VERSION
self.path_prefix = DEFAULT_PATH_PREFIX
self.connection_options = DEFAULT_CONNECTION_OPTIONS
self
end
end
end

View file

@ -1,38 +0,0 @@
require 'faraday_middleware'
require 'faraday/response/raise_http_1xxx'
module Instapaper
# @private
module Connection
private
def connection(raw = false) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
merged_options = connection_defaults.merge(connection_options)
Faraday.new(merged_options) do |builder|
if authenticated?
builder.use Faraday::Request::OAuth, authentication
else
builder.use Faraday::Request::OAuth, consumer_tokens
end
builder.use Faraday::Request::Multipart
builder.use Faraday::Request::UrlEncoded
builder.use Faraday::Response::Rashify unless raw
builder.use Faraday::Response::ParseJson unless raw
builder.use Faraday::Response::RaiseHttp1xxx
builder.adapter(adapter)
end
end
def connection_defaults
{
headers: {
'Accept' => 'application/json',
'User-Agent' => user_agent,
},
proxy: proxy,
url: api_endpoint,
}
end
end
end

View file

@ -1,20 +0,0 @@
module Instapaper
# Defines HTTP request methods
module Request
# Perform an HTTP POST request
def post(path, options = {}, raw = false)
request(:post, path, options, raw)
end
private
# Perform an HTTP request
def request(method, path, options, raw = false)
response = connection(raw).send(method) do |request|
request.path = path_prefix + path
request.body = options unless options.empty?
end
raw ? response : response.body
end
end
end

View file

@ -9,7 +9,7 @@ describe Faraday::Response do
1251, 1252, 1500, 1550].each do |status|
context "when HTTP status is #{status}" do
before do
stub_post('folders/list').to_return(status: status)
stub_post('/api/1/folders/list').to_return(status: status)
end
it 'should raise Instapaper::Error error' do

View file

@ -1,24 +1,22 @@
require 'spec_helper'
describe Instapaper::Client::Account do
before(:each) do
@client = Instapaper::Client.new
end
let(:client) { Instapaper::Client.new }
describe '.verify_credentials' do
before do
stub_post('account/verify_credentials')
stub_post('/api/1/account/verify_credentials')
.to_return(body: fixture('verify_credentials.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.verify_credentials
expect(a_post('account/verify_credentials'))
client.verify_credentials
expect(a_post('/api/1/account/verify_credentials'))
.to have_been_made
end
it 'should return the user' do
user = @client.verify_credentials.first
user = client.verify_credentials.first
expect(user).to be_a Hashie::Rash
expect(user.username).to eq('TestUserOMGLOL')
end

View file

@ -1,30 +1,28 @@
require 'spec_helper'
describe Instapaper::Client::Bookmark do
before(:each) do
@client = Instapaper::Client.new(consumer_key: 'CK', consumer_secret: 'CS', oauth_token: 'OT', oauth_token_secret: 'OS')
end
let(:client) { Instapaper::Client.new(consumer_key: 'CK', consumer_secret: 'CS', oauth_token: 'OT', oauth_token_secret: 'OS') }
describe '.bookmarks' do
before do
stub_post('bookmarks/list')
stub_post('/api/1/bookmarks/list')
.to_return(body: fixture('bookmarks_list.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.bookmarks
expect(a_post('bookmarks/list'))
client.bookmarks
expect(a_post('/api/1/bookmarks/list'))
.to have_been_made
end
it 'should return an array containing bookmarks on success' do
bookmarks = @client.bookmarks
bookmarks = client.bookmarks
expect(bookmarks).to be_an Array
expect(bookmarks.size).to eq(2)
end
it 'should remove the meta and current user objects from the array' do
bookmarks = @client.bookmarks
bookmarks = client.bookmarks
bookmarks.each do |bookmark|
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
@ -35,18 +33,18 @@ describe Instapaper::Client::Bookmark do
describe '.update_read_progress' do
before do
@time = Time.now
stub_post('bookmarks/update_read_progress')
stub_post('/api/1/bookmarks/update_read_progress')
.to_return(body: fixture('bookmarks_update_read_progress.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.update_read_progress(123, 0.5, @time)
expect(a_post('bookmarks/update_read_progress').with(body: {bookmark_id: '123', progress: '0.5', progress_timestamp: @time.to_i.to_s}))
client.update_read_progress(123, 0.5, @time)
expect(a_post('/api/1/bookmarks/update_read_progress').with(body: {bookmark_id: '123', progress: '0.5', progress_timestamp: @time.to_i.to_s}))
.to have_been_made
end
it 'should return an array containing bookmarks on success' do
bookmark = @client.update_read_progress(123, 0.5, @time)
bookmark = client.update_read_progress(123, 0.5, @time)
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
expect(bookmark.progress).to eq('0.5')
@ -55,18 +53,18 @@ describe Instapaper::Client::Bookmark do
describe '.add_bookmark' do
before do
stub_post('bookmarks/add')
stub_post('/api/1/bookmarks/add')
.to_return(body: fixture('bookmarks_add.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description')
expect(a_post('bookmarks/add').with(body: {url: 'http://someurl.com', title: 'This is the title', description: 'This is the description'}))
client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description')
expect(a_post('/api/1/bookmarks/add').with(body: {url: 'http://someurl.com', title: 'This is the title', description: 'This is the description'}))
.to have_been_made
end
it 'should return the bookmark on success' do
bookmark = @client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description')
bookmark = client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description')
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
end
@ -74,18 +72,18 @@ describe Instapaper::Client::Bookmark do
describe '.delete_bookmark' do
before do
stub_post('bookmarks/delete')
stub_post('/api/1/bookmarks/delete')
.to_return(body: '[]', headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.delete_bookmark(123)
expect(a_post('bookmarks/delete').with(body: {bookmark_id: '123'}))
client.delete_bookmark(123)
expect(a_post('/api/1/bookmarks/delete').with(body: {bookmark_id: '123'}))
.to have_been_made
end
it 'should return an array containing bookmarks on success' do
confirm = @client.delete_bookmark(123)
confirm = client.delete_bookmark(123)
expect(confirm).to be_an Array
expect(confirm).to be_empty
end
@ -93,141 +91,141 @@ describe Instapaper::Client::Bookmark do
describe '.star' do
before do
stub_post('bookmarks/star')
stub_post('/api/1/bookmarks/star')
.to_return(body: fixture('bookmarks_star.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.star(123)
expect(a_post('bookmarks/star').with(body: {bookmark_id: '123'}))
client.star(123)
expect(a_post('/api/1/bookmarks/star').with(body: {bookmark_id: '123'}))
.to have_been_made
end
it 'should return a starred bookmark on success' do
bookmark = @client.star(123)
bookmark = client.star(123)
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
expect(bookmark.starred).to eq('1')
end
it 'should be aliased as .star_bookmark' do
expect(@client.star(123)).to eq(@client.star_bookmark(123))
expect(client.star(123)).to eq(client.star_bookmark(123))
end
end
describe '.unstar' do
before do
stub_post('bookmarks/unstar')
stub_post('/api/1/bookmarks/unstar')
.to_return(body: fixture('bookmarks_unstar.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.unstar(123)
expect(a_post('bookmarks/unstar').with(body: {bookmark_id: '123'}))
client.unstar(123)
expect(a_post('/api/1/bookmarks/unstar').with(body: {bookmark_id: '123'}))
.to have_been_made
end
it 'should return an unstarred bookmark on success' do
bookmark = @client.unstar(123)
bookmark = client.unstar(123)
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
expect(bookmark.starred).to eq('0')
end
it 'should be aliased as .unstar_bookmark' do
expect(@client.unstar(123)).to eq(@client.unstar_bookmark(123))
expect(client.unstar(123)).to eq(client.unstar_bookmark(123))
end
end
describe '.archive' do
before do
stub_post('bookmarks/archive')
stub_post('/api/1/bookmarks/archive')
.to_return(body: fixture('bookmarks_archive.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.archive(123)
expect(a_post('bookmarks/archive').with(body: {bookmark_id: '123'}))
client.archive(123)
expect(a_post('/api/1/bookmarks/archive').with(body: {bookmark_id: '123'}))
.to have_been_made
end
it 'should return the bookmark on success' do
bookmark = @client.archive(123)
bookmark = client.archive(123)
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
end
it 'should be aliased as .archive_bookmark' do
expect(@client.archive(123)).to eq(@client.archive_bookmark(123))
expect(client.archive(123)).to eq(client.archive_bookmark(123))
end
end
describe '.unarchive' do
before do
stub_post('bookmarks/unarchive')
stub_post('/api/1/bookmarks/unarchive')
.to_return(body: fixture('bookmarks_unarchive.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.unarchive(123)
expect(a_post('bookmarks/unarchive').with(body: {bookmark_id: '123'}))
client.unarchive(123)
expect(a_post('/api/1/bookmarks/unarchive').with(body: {bookmark_id: '123'}))
.to have_been_made
end
it 'should return the bookmark on success' do
bookmark = @client.unarchive(123)
bookmark = client.unarchive(123)
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
end
it 'should be aliased as .unarchive_bookmark' do
expect(@client.unarchive(123)).to eq(@client.unarchive_bookmark(123))
expect(client.unarchive(123)).to eq(client.unarchive_bookmark(123))
end
end
describe '.move' do
before do
stub_post('bookmarks/move')
stub_post('/api/1/bookmarks/move')
.to_return(body: fixture('bookmarks_move.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.move(123, 12_345)
expect(a_post('bookmarks/move').with(body: {bookmark_id: '123', folder_id: '12345'}))
client.move(123, 12_345)
expect(a_post('/api/1/bookmarks/move').with(body: {bookmark_id: '123', folder_id: '12345'}))
.to have_been_made
end
it 'should return the bookmark on success' do
bookmark = @client.move(123, 12_345)
bookmark = client.move(123, 12_345)
expect(bookmark).to be_a Hashie::Rash
expect(bookmark.type).to eq('bookmark')
end
it 'should be aliased as .move_bookmark' do
expect(@client.move(123, 12_345)).to eq(@client.move_bookmark(123, 12_345))
expect(client.move(123, 12_345)).to eq(client.move_bookmark(123, 12_345))
end
end
describe '.text' do
before do
stub_post('bookmarks/get_text')
stub_post('/api/1/bookmarks/get_text')
.to_return(body: fixture('bookmarks_get_text.txt'), headers: {content_type: 'text/html; charset=utf-8'})
end
it 'should get the correct resource' do
@client.text(123)
expect(a_post('bookmarks/get_text').with(body: {bookmark_id: '123'}))
client.text(123)
expect(a_post('/api/1/bookmarks/get_text').with(body: {bookmark_id: '123'}))
.to have_been_made
end
it "should return the bookmark's html on success" do
bookmark = @client.text(123)
bookmark = client.text(123)
expect(bookmark.length).to be > 0
expect(bookmark).to include("Ideo's Axioms for Starting Disruptive New Businesses")
end
it 'should be aliased as .get_text' do
expect(@client.text(123)).to eq(@client.get_text(123))
expect(client.text(123)).to eq(client.get_text(123))
end
end
end

View file

@ -1,24 +1,22 @@
require 'spec_helper'
describe Instapaper::Client::Folder do
before(:each) do
@client = Instapaper::Client.new
end
let(:client) { Instapaper::Client.new(consumer_key: 'CK', consumer_secret: 'CS', oauth_token: 'OT', oauth_token_secret: 'OS') }
describe '.folders' do
before do
stub_post('folders/list')
stub_post('/api/1/folders/list')
.to_return(body: fixture('folders_list.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.folders
expect(a_post('folders/list'))
client.folders
expect(a_post('/api/1/folders/list'))
.to have_been_made
end
it 'should return an array containing folders on success' do
folders = @client.folders
folders = client.folders
expect(folders).to be_an Array
expect(folders.size).to eq(2)
expect(folders.first).to be_a Hashie::Rash
@ -28,18 +26,18 @@ describe Instapaper::Client::Folder do
describe '.add_folder' do
before do
stub_post('folders/add').with(body: {title: 'Ruby'})
stub_post('/api/1/folders/add').with(body: {title: 'Ruby'})
.to_return(body: fixture('folders_add.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.add_folder('Ruby')
expect(a_post('folders/add'))
client.add_folder('Ruby')
expect(a_post('/api/1/folders/add'))
.to have_been_made
end
it 'should return an array containing the new folder on success' do
folders = @client.add_folder('Ruby')
folders = client.add_folder('Ruby')
expect(folders).to be_an Array
expect(folders).not_to be_empty
expect(folders.first).to be_a Hashie::Rash
@ -49,18 +47,18 @@ describe Instapaper::Client::Folder do
describe '.delete_folder' do
before do
stub_post('folders/delete'). with(body: {folder_id: '1'})
stub_post('/api/1/folders/delete'). with(body: {folder_id: '1'})
.to_return(body: fixture('folders_delete.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.delete_folder('1')
expect(a_post('folders/delete'))
client.delete_folder('1')
expect(a_post('/api/1/folders/delete'))
.to have_been_made
end
it 'should return an empty array on success' do
confirm = @client.delete_folder('1')
confirm = client.delete_folder('1')
expect(confirm).to be_an Array
expect(confirm).to be_empty
end
@ -68,18 +66,18 @@ describe Instapaper::Client::Folder do
describe '.set_order' do
before do
stub_post('folders/set_order'). with(body: {order: '1121173:2,1121174:1'})
stub_post('/api/1/folders/set_order'). with(body: {order: '1121173:2,1121174:1'})
.to_return(body: fixture('folders_set_order.json'), headers: {content_type: 'application/json; charset=utf-8'})
end
it 'should get the correct resource' do
@client.set_order(['1121173:2', '1121174:1'])
expect(a_post('folders/set_order'))
client.set_order(['1121173:2', '1121174:1'])
expect(a_post('/api/1/folders/set_order'))
.to have_been_made
end
it 'should return an array reflecting the new order on success' do
folders = @client.set_order(['1121173:2', '1121174:1'])
folders = client.set_order(['1121173:2', '1121174:1'])
expect(folders).to be_an Array
expect(folders.first).to be_a Hashie::Rash
expect(folders.first['position']).to eq(1)

View file

@ -1,33 +1,31 @@
require 'spec_helper'
describe Instapaper::Client::User do
before(:each) do
@client = Instapaper::Client.new
end
let(:client) { Instapaper::Client.new }
describe '.access_token' do
before do
stub_post('oauth/access_token').with(body: {x_auth_username: 'ohai', x_auth_password: 'p455w0rd', x_auth_mode: 'client_auth'})
stub_post('/api/1/oauth/access_token').with(body: {x_auth_username: 'ohai', x_auth_password: 'p455w0rd', x_auth_mode: 'client_auth'})
.to_return(body: fixture('access_token.qline'), headers: {content_type: 'text/plain; charset=utf-8'})
stub_post('oauth/access_token').with(body: {x_auth_username: 'inval1d', x_auth_password: 'cr3dentials', x_auth_mode: 'client_auth'})
stub_post('/api/1/oauth/access_token').with(body: {x_auth_username: 'inval1d', x_auth_password: 'cr3dentials', x_auth_mode: 'client_auth'})
.to_return(body: fixture('invalid_credentials.qline'), headers: {content_type: 'text/plain; charset=utf-8'})
end
it 'should get the correct resource' do
@client.access_token('ohai', 'p455w0rd')
expect(a_post('oauth/access_token'))
client.access_token('ohai', 'p455w0rd')
expect(a_post('/api/1/oauth/access_token'))
.to have_been_made
end
it 'should return the a hash containing an oauth token and secret' do
tokens = @client.access_token('ohai', 'p455w0rd')
tokens = client.access_token('ohai', 'p455w0rd')
expect(tokens).to be_a Hash
expect(tokens.key?('oauth_token')).to be true
expect(tokens.key?('oauth_token_secret')).to be true
end
it 'should return a hash containing the error on invalid credentials' do
tokens = @client.access_token('inval1d', 'cr3dentials')
tokens = client.access_token('inval1d', 'cr3dentials')
expect(tokens).to be_a Hash
expect(tokens.key?('error')).to be true
end

View file

@ -1,64 +1,5 @@
require 'spec_helper'
describe Instapaper::Client do
before do
@options = {adapter: :em_synchrony, user_agent: 'Instapaper::Client spec'}
@keys = Instapaper::Configuration::VALID_OPTIONS_KEYS
end
describe '.new' do
before(:each) do
@keys.each do |key|
Instapaper.send("#{key}=", key)
end
end
after do
Instapaper.reset
end
context 'with module configuration' do
it 'should inherit module configuration' do
api = Instapaper::Client.new
@keys.each do |key|
expect(api.send(key)).to eq(key)
end
end
end
context 'with class configuration' do
context 'during initialization' do
it 'should override module configuration' do
api = Instapaper::Client.new(@options)
@keys.each do |key|
h = @options.key?(key) ? @options : Instapaper.options
expect(api.send(key)).to eq(h[key])
end
end
end
context 'after initialization' do
it 'should override module configuration after initialization' do
api = Instapaper::Client.new
@options.each do |key, value|
api.send("#{key}=", value)
end
@keys.each do |key|
h = @options.key?(key) ? @options : Instapaper.options
expect(api.send(key)).to eq(h[key])
end
end
end
end
end
describe '.endpoint_with_prefix' do
before(:each) do
@client = Instapaper::Client.new
end
it 'should return the ' do
expect(@client.endpoint_with_prefix).to eq(Instapaper.endpoint + Instapaper.path_prefix)
end
end
let(:client) { Instapaper::Client.new }
end

View file

@ -1,82 +0,0 @@
require 'spec_helper'
describe Instapaper do
after do
Instapaper.reset
end
describe '.respond_to?' do
it 'takes an optional include private argument' do
expect(Instapaper.respond_to?(:client, true)).to be true
end
end
describe '.client' do
it 'should be a Instapaper::Client' do
expect(Instapaper.client).to be_a Instapaper::Client
end
end
describe '.adapter' do
it 'should return the default adapter' do
expect(Instapaper.adapter).to eq(Instapaper::Configuration::DEFAULT_ADAPTER)
end
end
describe '.adapter=' do
it 'should set the adapter' do
Instapaper.adapter = :typhoeus
expect(Instapaper.adapter).to eq(:typhoeus)
end
end
describe '.endpoint' do
it 'should return the default endpoint' do
expect(Instapaper.endpoint).to eq(Instapaper::Configuration::DEFAULT_ENDPOINT)
end
end
describe '.endpoint=' do
it 'should set the endpoint' do
Instapaper.endpoint = 'http://tumblr.com/'
expect(Instapaper.endpoint).to eq('http://tumblr.com/')
end
end
describe '.user_agent' do
it 'should return the default user agent' do
expect(Instapaper.user_agent).to eq(Instapaper::Configuration::DEFAULT_USER_AGENT)
end
end
describe '.user_agent=' do
it 'should set the user_agent' do
Instapaper.user_agent = 'Custom User Agent'
expect(Instapaper.user_agent).to eq('Custom User Agent')
end
end
describe '.version' do
it 'should return the default version' do
expect(Instapaper.version).to eq(Instapaper::Configuration::DEFAULT_VERSION)
end
end
describe '.version=' do
it 'should set the user_agent' do
Instapaper.version = '2'
expect(Instapaper.version).to eq('2')
end
end
describe '.configure' do
Instapaper::Configuration::VALID_OPTIONS_KEYS.each do |key|
it "should set the #{key}" do
Instapaper.configure do |config|
config.send("#{key}=", key)
expect(Instapaper.send(key)).to eq(key)
end
end
end
end
end

View file

@ -12,35 +12,35 @@ require 'rspec'
require 'webmock/rspec'
def a_delete(path)
a_request(:delete, Instapaper.endpoint_with_prefix + path)
a_request(:delete, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def a_get(path)
a_request(:get, Instapaper.endpoint_with_prefix + path)
a_request(:get, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def a_post(path)
a_request(:post, Instapaper.endpoint_with_prefix + path)
a_request(:post, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def a_put(path)
a_request(:put, Instapaper.endpoint_with_prefix + path)
a_request(:put, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def stub_delete(path)
stub_request(:delete, Instapaper.endpoint_with_prefix + path)
stub_request(:delete, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def stub_get(path)
stub_request(:get, Instapaper.endpoint_with_prefix + path)
stub_request(:get, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def stub_post(path)
stub_request(:post, Instapaper.endpoint_with_prefix + path)
stub_request(:post, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def stub_put(path)
stub_request(:put, Instapaper.endpoint_with_prefix + path)
stub_request(:put, Instapaper::Client::DEFAULT_ENDPOINT + path)
end
def fixture_path