diff --git a/lib/faraday/response/parse_json.rb b/lib/faraday/response/parse_json.rb new file mode 100644 index 0000000..56be647 --- /dev/null +++ b/lib/faraday/response/parse_json.rb @@ -0,0 +1,31 @@ +require 'faraday' +require 'json' + +module Instapaper + module API + module Response + class ParseJson < Faraday::Response::Middleware + WHITESPACE_REGEX = /\A^\s*$\z/ + + def parse(body) + case body + when WHITESPACE_REGEX, nil + nil + else + JSON.parse(body, :symbolize_names => true) + end + end + + def on_complete(response) + response.body = parse(response.body) if respond_to?(:parse) && !unparsable_status_codes.include?(response.status) + end + + def unparsable_status_codes + [204, 301, 302, 304] + end + end + end + end +end + +Faraday::Response.register_middleware :instapaper_parse_json => Instapaper::API::Response::ParseJson diff --git a/lib/instapaper/api.rb b/lib/instapaper/api.rb index 21fb752..4d6eea0 100644 --- a/lib/instapaper/api.rb +++ b/lib/instapaper/api.rb @@ -3,6 +3,7 @@ require 'instapaper/api/bookmark' require 'instapaper/api/folder' require 'instapaper/api/highlight' require 'instapaper/api/oauth' +require 'instapaper/api/utils' module Instapaper module API @@ -11,5 +12,6 @@ module Instapaper include Instapaper::API::Folder include Instapaper::API::Highlight include Instapaper::API::OAuth + include Instapaper::API::Utils end end diff --git a/lib/instapaper/api/highlight.rb b/lib/instapaper/api/highlight.rb index e84b11f..96163b7 100644 --- a/lib/instapaper/api/highlight.rb +++ b/lib/instapaper/api/highlight.rb @@ -1,7 +1,33 @@ +require 'instapaper/highlight' + module Instapaper module API # Defines methods related to highlights module Highlight + + # List highlights for a bookmark + def highlights(bookmark_id) + perform_post_with_objects("/api/1.1/bookmarks/#{bookmark_id}/highlights", {}, Instapaper::Highlight) + end + + # Create a new highlight + # @note Non-subscribers are limited to 5 highlights per month. + # @param bookmark_id [String, Integer] + # @param options [Hash] + # @option options [String] :text The text for the highlight (HTML tags in text parameter should be unescaped.) + # @option options [String, Integer] :posiiton The 0-indexed position of text in the content. Defaults to 0. + # @return [Instapaper::Highlight] + def highlight(bookmark_id, options = {}) + perform_post_with_object("/api/1.1/bookmarks/#{bookmark_id}/highlight", options, Instapaper::Highlight) + end + + # Delete a highlight + # @param highlight_id [String, Integer] + # @return [Boolean] + def delete_highlight(highlight_id, options = {}) + perform_post_with_empty_response("/api/1.1/highlights/#{highlight_id}/delete", options) + true + end end end end diff --git a/lib/instapaper/api/utils.rb b/lib/instapaper/api/utils.rb new file mode 100644 index 0000000..e8211c8 --- /dev/null +++ b/lib/instapaper/api/utils.rb @@ -0,0 +1,46 @@ +module Instapaper + module API + module Utils + private + + # @param path [String] + # @param options [Hash] + # @param klass [Class] + def perform_post_with_objects(path, options, klass) + perform_request_with_objects(:post, path, options, klass) + end + + # @param request_method [Symbol] + # @param path [String] + # @param options [Hash] + # @param klass [Class] + def perform_request_with_objects(request_method, path, options, klass) + perform_request(request_method, path, options).collect do |element| + klass.with(element) + end + end + + # @param path [String] + # @param options [Hash] + # @param klass [Class] + def perform_post_with_object(path, options, klass) + perform_request_with_object(:post, path, options, klass) + end + + # @param request_method [Symbol] + # @param path [String] + # @param options [Hash] + # @param klass [Class] + def perform_request_with_object(request_method, path, options, klass) + response = perform_request(request_method, path, options) + klass.with(response) + end + + # @param path [String] + # @param options [Hash] + def perform_post_with_empty_response(path, options) + perform_request(:post, path, options, true) + end + end + end +end diff --git a/lib/instapaper/client.rb b/lib/instapaper/client.rb index 7f7bf0f..55f644b 100644 --- a/lib/instapaper/client.rb +++ b/lib/instapaper/client.rb @@ -2,6 +2,7 @@ require 'instapaper/api' require 'instapaper/error' require 'instapaper/version' require 'faraday_middleware' +require 'faraday/response/parse_json' require 'faraday/response/raise_http_1xxx' module Instapaper @@ -81,8 +82,8 @@ module Instapaper 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::Rashify unless raw + builder.use Instapaper::API::Response::ParseJson unless raw builder.use Faraday::Response::RaiseHttp1xxx builder.adapter(adapter) end @@ -112,6 +113,7 @@ module Instapaper end raw ? response : response.body end + alias_method :perform_request, :request # Authentication hash # diff --git a/lib/instapaper/highlight.rb b/lib/instapaper/highlight.rb new file mode 100644 index 0000000..3290c86 --- /dev/null +++ b/lib/instapaper/highlight.rb @@ -0,0 +1,6 @@ +require 'values' + +module Instapaper + class Highlight < Value.new(:type, :highlight_id, :bookmark_id, :text, :position, :time) + end +end diff --git a/spec/fixtures/highlight.json b/spec/fixtures/highlight.json new file mode 100644 index 0000000..6ae84be --- /dev/null +++ b/spec/fixtures/highlight.json @@ -0,0 +1,8 @@ +{ + "type":"highlight", + "highlight_id":42, + "bookmark_id":123, + "text":"example page", + "position":0, + "time":1394470555 +} diff --git a/spec/fixtures/highlights_list.json b/spec/fixtures/highlights_list.json new file mode 100644 index 0000000..459f6d4 --- /dev/null +++ b/spec/fixtures/highlights_list.json @@ -0,0 +1,18 @@ +[ + { + "type":"highlight", + "highlight_id":42, + "bookmark_id":123, + "text":"example page", + "position":0, + "time":1394470555 + }, + { + "type":"highlight", + "highlight_id":43, + "bookmark_id":123, + "text":"example page 2", + "position":1, + "time":1394470555 + } +] diff --git a/spec/instapaper/api/highlight_spec.rb b/spec/instapaper/api/highlight_spec.rb new file mode 100644 index 0000000..66ca6c5 --- /dev/null +++ b/spec/instapaper/api/highlight_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe Instapaper::Client::Highlight do + let(:client) { Instapaper::Client.new(consumer_key: 'CK', consumer_secret: 'CS', oauth_token: 'OT', oauth_token_secret: 'OS') } + + describe '#highlights' do + before do + stub_post('/api/1.1/bookmarks/123/highlights') + .to_return(status: 200, body: fixture('highlights_list.json'), headers: {content_type: 'application/json; charset=utf-8'}) + end + + it 'should get the correct resource' do + client.highlights(123) + expect(a_post('/api/1.1/bookmarks/123/highlights')).to have_been_made + end + + it 'should return an array containing folders on success' do + highlights = client.highlights(123) + expect(highlights).to be_an Array + expect(highlights.size).to eq(2) + expect(highlights.first).to be_an Instapaper::Highlight + end + end + + describe '#highlight' do + before do + stub_post('/api/1.1/bookmarks/123/highlight') + .to_return(status: 200, body: fixture('highlight.json'), headers: {content_type: 'application/json; charset=utf-8'}) + end + + it 'should get the correct resource' do + client.highlight(123, text: 'This is the highlighted text.', position: 22) + expect(a_post('/api/1.1/bookmarks/123/highlight')).to have_been_made + end + + it 'should return an array containing folders on success' do + highlight = client.highlight(123, text: 'This is the highlighted text.', position: 22) + expect(highlight).to be_an Instapaper::Highlight + end + end + + describe '#delete_highlight' do + before do + stub_post('/api/1.1/highlights/123/delete') + .to_return(status: 200, body: '', headers: {content_type: 'application/json; charset=utf-8'}) + end + + it 'should post to the correct resource' do + client.delete_highlight(123) + expect(a_post('/api/1.1/highlights/123/delete')).to have_been_made + end + + it 'should return true when successful' do + response = client.delete_highlight(123) + expect(response).to be true + end + end +end