diff --git a/lib/instapaper/api/bookmarks.rb b/lib/instapaper/api/bookmarks.rb index 103cd4d..2eccaea 100644 --- a/lib/instapaper/api/bookmarks.rb +++ b/lib/instapaper/api/bookmarks.rb @@ -10,6 +10,7 @@ module Bookmarks # @option folder_id: Optional. Possible values are unread (default), starred, archive, or a folder_id value from /api/1.1/folders/list. # @option have: Optional. A concatenation of bookmark_id values that the client already has from the specified folder. See below. # @option highlights: Optional. A '-' delimited list of highlight IDs that the client already has from the specified bookmarks. + # @option tag: Optional. Tag name to filter the returned bookmarks. Only used when folder_id is not provided. def bookmarks(options = {}) perform_post_with_object('/api/1.1/bookmarks/list', options, Instapaper::BookmarkList) end @@ -24,6 +25,10 @@ def update_read_progress(bookmark_id, progress, progress_timestamp = Time.now) # Adds a new unread bookmark to the user's account. # @param url [String] The url of the bookmark. + # @option options [String] :title Optional. If omitted, the title will be looked up by Instapaper synchronously. + # @option options [String] :description Optional. A brief, plaintext description or summary of the article. + # @option options [Integer] :folder_id Optional. The folder to add the bookmark to. + # @option options [String] :tags Optional. JSON array of tags, e.g. [{"name":"Reading List"}]. Tags will be created if they do not already exist. def add_bookmark(url, options = {}) perform_post_with_object('/api/1.1/bookmarks/add', options.merge(url: url), Instapaper::Bookmark) end diff --git a/lib/instapaper/bookmark.rb b/lib/instapaper/bookmark.rb index 5828454..a184de6 100644 --- a/lib/instapaper/bookmark.rb +++ b/lib/instapaper/bookmark.rb @@ -1,4 +1,5 @@ require 'virtus' +require 'instapaper/tag' module Instapaper class Bookmark @@ -16,6 +17,7 @@ class Bookmark attribute :progress, String attribute :starred, String attribute :type, String + attribute :tags, Array[Instapaper::Tag] end end end diff --git a/lib/instapaper/tag.rb b/lib/instapaper/tag.rb new file mode 100644 index 0000000..419d2b8 --- /dev/null +++ b/lib/instapaper/tag.rb @@ -0,0 +1,12 @@ +require 'virtus' + +module Instapaper + class Tag + include Virtus.value_object + + values do + attribute :id, Integer + attribute :name, String + end + end +end diff --git a/spec/fixtures/bookmarks_add.json b/spec/fixtures/bookmarks_add.json index 0e38ba2..90edf53 100644 --- a/spec/fixtures/bookmarks_add.json +++ b/spec/fixtures/bookmarks_add.json @@ -1 +1 @@ -[{"type":"bookmark","bookmark_id":169529989,"url":"http:\/\/www.fastcodesign.com\/1662169\/ideos-axioms-for-starting-disruptive-new-businesses","title":"Ideo's Axioms for Starting Disruptive New Businesses | Co.Design","description":"www.fastcodesign.com","time":1307586766,"starred":"0","private_source":"","hash":"9GZzaC8U","progress":"0","progress_timestamp":1307585389}] \ No newline at end of file +[{"type":"bookmark","bookmark_id":169529989,"url":"http:\/\/www.fastcodesign.com\/1662169\/ideos-axioms-for-starting-disruptive-new-businesses","title":"Ideo's Axioms for Starting Disruptive New Businesses | Co.Design","description":"www.fastcodesign.com","time":1307586766,"starred":"0","private_source":"","hash":"9GZzaC8U","progress":"0","progress_timestamp":1307585389,"tags":[{"id":12,"name":"Design"}]}] \ No newline at end of file diff --git a/spec/fixtures/bookmarks_list.json b/spec/fixtures/bookmarks_list.json index 7bf6337..c423ec1 100644 --- a/spec/fixtures/bookmarks_list.json +++ b/spec/fixtures/bookmarks_list.json @@ -1 +1 @@ -{"user":{"type":"user","user_id":1075837,"username":"steve.agalloco@gmail.com","subscription_is_active":"1"},"bookmarks":[{"type":"bookmark","bookmark_id":170939225,"url":"http:\/\/www.igvita.com\/2010\/11\/17\/routing-with-ruby-zeromq-devices\/","title":"Routing with Ruby & ZeroMQ Devices","description":"ZeroMQ sockets provide message-oriented messaging, support for multiple transports, transparent setup and teardown, and an entire array of routing patterns via different socket types","time":1307319089,"starred":"0","private_source":"","hash":"PGU0MMPw","progress":0,"progress_timestamp":0},{"type":"bookmark","bookmark_id":169529989,"url":"http:\/\/www.fastcodesign.com\/1662169\/ideos-axioms-for-starting-disruptive-new-businesses","title":"Ideo's Axioms for Starting Disruptive New Businesses | Co.Design","description":"www.fastcodesign.com","time":1306963988,"starred":"0","private_source":"","hash":"v27qHZc2","progress":"0","progress_timestamp":1307145892}],"highlights":[],"delete_ids":[12, 123, 123]} +{"user":{"type":"user","user_id":1075837,"username":"steve.agalloco@gmail.com","subscription_is_active":"1"},"bookmarks":[{"type":"bookmark","bookmark_id":170939225,"url":"http:\/\/www.igvita.com\/2010\/11\/17\/routing-with-ruby-zeromq-devices\/","title":"Routing with Ruby & ZeroMQ Devices","description":"ZeroMQ sockets provide message-oriented messaging, support for multiple transports, transparent setup and teardown, and an entire array of routing patterns via different socket types","time":1307319089,"starred":"0","private_source":"","hash":"PGU0MMPw","progress":0,"progress_timestamp":0,"tags":[{"id":7,"name":"Ruby"}]},{"type":"bookmark","bookmark_id":169529989,"url":"http:\/\/www.fastcodesign.com\/1662169\/ideos-axioms-for-starting-disruptive-new-businesses","title":"Ideo's Axioms for Starting Disruptive New Businesses | Co.Design","description":"www.fastcodesign.com","time":1306963988,"starred":"0","private_source":"","hash":"v27qHZc2","progress":"0","progress_timestamp":1307145892}],"highlights":[],"delete_ids":[12, 123, 123]} diff --git a/spec/instapaper/api/bookmarks_spec.rb b/spec/instapaper/api/bookmarks_spec.rb index 29db509..8e306aa 100644 --- a/spec/instapaper/api/bookmarks_spec.rb +++ b/spec/instapaper/api/bookmarks_spec.rb @@ -32,6 +32,12 @@ list = client.bookmarks expect(list.bookmarks.first.instapaper_hash).to_not be_nil end + + it 'coerces tags into Instapaper::Tag objects' do + list = client.bookmarks + expect(list.bookmarks.first.tags).to all be_an Instapaper::Tag + expect(list.bookmarks.first.tags.first.name).to eq('Ruby') + end end describe '#update_read_progress' do @@ -61,8 +67,8 @@ end it 'gets the correct resource' do - client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description') - expect(a_post('/api/1.1/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', tags: [{name: 'Design'}].to_json) + expect(a_post('/api/1.1/bookmarks/add').with(body: {url: 'http://someurl.com', title: 'This is the title', description: 'This is the description', tags: [{name: 'Design'}].to_json})) .to have_been_made end @@ -70,6 +76,12 @@ bookmark = client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description') expect(bookmark).to be_an Instapaper::Bookmark end + + it 'coerces tags into Instapaper::Tag objects' do + bookmark = client.add_bookmark('http://someurl.com', title: 'This is the title', description: 'This is the description') + expect(bookmark.tags).to all be_an Instapaper::Tag + expect(bookmark.tags.first.name).to eq('Design') + end end describe '#delete_bookmark' do