From 62713568473306a7fdc7b0597b98b554d6d441cb Mon Sep 17 00:00:00 2001 From: stve Date: Mon, 9 Feb 2015 16:21:30 -0500 Subject: [PATCH] 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 --- lib/instapaper.rb | 25 --- lib/instapaper/api.rb | 15 ++ lib/instapaper/{client => api}/account.rb | 4 +- lib/instapaper/{client => api}/bookmark.rb | 22 +-- lib/instapaper/{client => api}/folder.rb | 10 +- lib/instapaper/api/highlight.rb | 7 + lib/instapaper/{client => api}/user.rb | 4 +- lib/instapaper/authentication.rb | 32 ---- lib/instapaper/client.rb | 153 +++++++++++++++--- lib/instapaper/configuration.rb | 97 ----------- lib/instapaper/connection.rb | 38 ----- lib/instapaper/request.rb | 20 --- spec/faraday/response_spec.rb | 2 +- .../{client => api}/account_spec.rb | 12 +- .../{client => api}/bookmark_spec.rb | 98 ++++++----- .../instapaper/{client => api}/folder_spec.rb | 36 ++--- spec/instapaper/{client => api}/user_spec.rb | 16 +- spec/instapaper/client_spec.rb | 61 +------ spec/instapaper_spec.rb | 82 ---------- spec/spec_helper.rb | 16 +- 20 files changed, 257 insertions(+), 493 deletions(-) create mode 100644 lib/instapaper/api.rb rename lib/instapaper/{client => api}/account.rb (74%) rename lib/instapaper/{client => api}/bookmark.rb (78%) rename lib/instapaper/{client => api}/folder.rb (80%) create mode 100644 lib/instapaper/api/highlight.rb rename lib/instapaper/{client => api}/user.rb (70%) delete mode 100644 lib/instapaper/authentication.rb delete mode 100644 lib/instapaper/configuration.rb delete mode 100644 lib/instapaper/connection.rb delete mode 100644 lib/instapaper/request.rb rename spec/instapaper/{client => api}/account_spec.rb (66%) rename spec/instapaper/{client => api}/bookmark_spec.rb (63%) rename spec/instapaper/{client => api}/folder_spec.rb (68%) rename spec/instapaper/{client => api}/user_spec.rb (60%) delete mode 100644 spec/instapaper_spec.rb diff --git a/lib/instapaper.rb b/lib/instapaper.rb index 7b8ed04..06e2c66 100644 --- a/lib/instapaper.rb +++ b/lib/instapaper.rb @@ -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 diff --git a/lib/instapaper/api.rb b/lib/instapaper/api.rb new file mode 100644 index 0000000..377be7d --- /dev/null +++ b/lib/instapaper/api.rb @@ -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 diff --git a/lib/instapaper/client/account.rb b/lib/instapaper/api/account.rb similarity index 74% rename from lib/instapaper/client/account.rb rename to lib/instapaper/api/account.rb index a92b71e..597f9a0 100644 --- a/lib/instapaper/client/account.rb +++ b/lib/instapaper/api/account.rb @@ -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 diff --git a/lib/instapaper/client/bookmark.rb b/lib/instapaper/api/bookmark.rb similarity index 78% rename from lib/instapaper/client/bookmark.rb rename to lib/instapaper/api/bookmark.rb index 7005c09..3a27f2c 100644 --- a/lib/instapaper/client/bookmark.rb +++ b/lib/instapaper/api/bookmark.rb @@ -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 diff --git a/lib/instapaper/client/folder.rb b/lib/instapaper/api/folder.rb similarity index 80% rename from lib/instapaper/client/folder.rb rename to lib/instapaper/api/folder.rb index 04bf45d..eedb645 100644 --- a/lib/instapaper/client/folder.rb +++ b/lib/instapaper/api/folder.rb @@ -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 diff --git a/lib/instapaper/api/highlight.rb b/lib/instapaper/api/highlight.rb new file mode 100644 index 0000000..e84b11f --- /dev/null +++ b/lib/instapaper/api/highlight.rb @@ -0,0 +1,7 @@ +module Instapaper + module API + # Defines methods related to highlights + module Highlight + end + end +end diff --git a/lib/instapaper/client/user.rb b/lib/instapaper/api/user.rb similarity index 70% rename from lib/instapaper/client/user.rb rename to lib/instapaper/api/user.rb index 7bfb202..64dde2f 100644 --- a/lib/instapaper/client/user.rb +++ b/lib/instapaper/api/user.rb @@ -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 diff --git a/lib/instapaper/authentication.rb b/lib/instapaper/authentication.rb deleted file mode 100644 index d9e93c9..0000000 --- a/lib/instapaper/authentication.rb +++ /dev/null @@ -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 diff --git a/lib/instapaper/client.rb b/lib/instapaper/client.rb index e23572e..5b8703f 100644 --- a/lib/instapaper/client.rb +++ b/lib/instapaper/client.rb @@ -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 diff --git a/lib/instapaper/configuration.rb b/lib/instapaper/configuration.rb deleted file mode 100644 index 8b5e6ca..0000000 --- a/lib/instapaper/configuration.rb +++ /dev/null @@ -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 diff --git a/lib/instapaper/connection.rb b/lib/instapaper/connection.rb deleted file mode 100644 index 783fd92..0000000 --- a/lib/instapaper/connection.rb +++ /dev/null @@ -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 diff --git a/lib/instapaper/request.rb b/lib/instapaper/request.rb deleted file mode 100644 index c55675b..0000000 --- a/lib/instapaper/request.rb +++ /dev/null @@ -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 diff --git a/spec/faraday/response_spec.rb b/spec/faraday/response_spec.rb index 79c2921..39d91f5 100644 --- a/spec/faraday/response_spec.rb +++ b/spec/faraday/response_spec.rb @@ -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 diff --git a/spec/instapaper/client/account_spec.rb b/spec/instapaper/api/account_spec.rb similarity index 66% rename from spec/instapaper/client/account_spec.rb rename to spec/instapaper/api/account_spec.rb index 4286d58..620c3b4 100644 --- a/spec/instapaper/client/account_spec.rb +++ b/spec/instapaper/api/account_spec.rb @@ -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 diff --git a/spec/instapaper/client/bookmark_spec.rb b/spec/instapaper/api/bookmark_spec.rb similarity index 63% rename from spec/instapaper/client/bookmark_spec.rb rename to spec/instapaper/api/bookmark_spec.rb index 7999a15..d1083b4 100644 --- a/spec/instapaper/client/bookmark_spec.rb +++ b/spec/instapaper/api/bookmark_spec.rb @@ -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 diff --git a/spec/instapaper/client/folder_spec.rb b/spec/instapaper/api/folder_spec.rb similarity index 68% rename from spec/instapaper/client/folder_spec.rb rename to spec/instapaper/api/folder_spec.rb index f09253e..90af538 100644 --- a/spec/instapaper/client/folder_spec.rb +++ b/spec/instapaper/api/folder_spec.rb @@ -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) diff --git a/spec/instapaper/client/user_spec.rb b/spec/instapaper/api/user_spec.rb similarity index 60% rename from spec/instapaper/client/user_spec.rb rename to spec/instapaper/api/user_spec.rb index 2b81ecb..14c2212 100644 --- a/spec/instapaper/client/user_spec.rb +++ b/spec/instapaper/api/user_spec.rb @@ -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 diff --git a/spec/instapaper/client_spec.rb b/spec/instapaper/client_spec.rb index eb456a9..de4be8e 100644 --- a/spec/instapaper/client_spec.rb +++ b/spec/instapaper/client_spec.rb @@ -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 diff --git a/spec/instapaper_spec.rb b/spec/instapaper_spec.rb deleted file mode 100644 index dab6792..0000000 --- a/spec/instapaper_spec.rb +++ /dev/null @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 178ee64..1774f0b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -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