read_it_later 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ config/test.yml
data/README.textile ADDED
@@ -0,0 +1,7 @@
1
+ h1. ReadItLater API Library for Ruby
2
+
3
+ p. Please see sample_usage.rb for examples of use.
4
+
5
+ p. For details on the ReadItLater API see http://readitlaterlist.com/api/docs/
6
+
7
+ p. For details on what is ReadItLater see http://readitlaterlist.com/
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "read_it_later"
5
+ gemspec.summary = "ReadItLaterList.com API Library for Ruby"
6
+ gemspec.description = "A very simple one-to-one api library for Read It Later API"
7
+ gemspec.email = "rha7.com@gmail.com"
8
+ gemspec.homepage = "http://github.com/rha7dotcom/read_it_later"
9
+ gemspec.authors = ["Gabriel Medina"]
10
+ end
11
+ rescue LoadError
12
+ puts "Jeweler not available. Install it with: gem install jeweler"
13
+ end
14
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1 @@
1
+ default: --format pretty --color features
@@ -0,0 +1,3 @@
1
+ :api_key: <Your Read It Later API Key Here>
2
+ :username: <Your user name>
3
+ :password: <Your password>
@@ -0,0 +1,69 @@
1
+ Feature: Read It Later Management
2
+ In order to manage a list of bookmarks from read it later lists,
3
+ I should be able to add, get and mark as read bookmarks.
4
+
5
+ Scenario: Add a new bookmark
6
+ Given I have a valid API Key and User
7
+ When I create a ReadItLater API Object
8
+ And I add a new bookmark
9
+ Then I should get back a success response from RIL server
10
+ And I should receive usual user and key limits
11
+
12
+ Scenario: Send several updates at once
13
+ Given I have a valid API Key and User
14
+ When I create a ReadItLater API Object
15
+ And I send several updates
16
+ Then I should get back a success response from RIL server
17
+ And I should receive usual user and key limits
18
+
19
+ Scenario: Request statistics of Read It Later bookmarks
20
+ Given I have a valid API Key and User
21
+ When I create a ReadItLater API Object
22
+ And I send a statistics request
23
+ Then I should get back a success response from RIL server
24
+ And I should receive usual user and key limits
25
+ And I should receive statistics of usage
26
+
27
+ Scenario Outline: Get a list of bookmarks from Read It Later
28
+ Given I have a valid API Key and User
29
+ When I create a ReadItLater API Object
30
+ And I send a request for a list of "<count>" "<state>" Read It Later bookmarks for page "<page>", which are "<mine_only>", since "<since>", with tags "<tags>"
31
+ Then I should get back a success response from RIL server
32
+ And I should receive data about the list of bookmarks
33
+ And I should receive a list of bookmarks, although it can be empty
34
+
35
+ Examples:
36
+ | state | mine_only | since | count | page | tags |
37
+ | read | | | | | |
38
+ | unread | | | | | |
39
+ | | true | | | | |
40
+ | | false | | | | |
41
+ | | | 2000-01-01 | | | |
42
+ | | | | 10 | | |
43
+ | | | | 10 | 2 | |
44
+ | | | | | | true |
45
+ | | | | | | false |
46
+
47
+ Scenario: Authenticate an existing user
48
+ Given I have a valid API Key and User
49
+ When I create a ReadItLater API Object
50
+ And I authenticate an existing user
51
+ Then I should get back a success response from RIL server
52
+ And I should receive usual user and key limits
53
+
54
+ Scenario:Sign up a new user
55
+ Given I have a valid API Key and User
56
+ When I create a ReadItLater API Object
57
+ And I sign up a new user
58
+ Then I should get back a success response from RIL server
59
+ And I should receive usual user and key limits
60
+
61
+ Scenario: Get bookmark list statistics
62
+ Given I have a valid API Key and User
63
+ When I create a ReadItLater API Object
64
+ And I send an API bookmarks list statistics request
65
+ Then I should get back a success response from RIL server
66
+ And I should receive usual user and key limits
67
+
68
+
69
+
@@ -0,0 +1,24 @@
1
+ Feature: ReadItLater User Management
2
+ In order to make requests to ReadItLaterList.com API
3
+ Library user should be able to create User objects.
4
+
5
+ Scenario: User object created with both a user name and a password
6
+ When I create a User object with a user name "sample" and password "mypassword"
7
+ Then I should get a User object with no errors
8
+ And The User object should have a "user name" of "sample"
9
+ And The User object should have a "password" of "mypassword"
10
+
11
+ Scenario: User object created with a user name only
12
+ When I create a User object with a user name "sample" and password "unspecified"
13
+ Then I should get a User object with no errors
14
+ And The User object should have a "user name" of "sample"
15
+ And The User object should have a "password" of "unspecified"
16
+
17
+ Scenario: User object created without a user name or password
18
+ When I create a User object with a user name "unspecified" and password "unspecified"
19
+ Then I should get a User object with no errors
20
+ And The User object should have a "user name" of "unspecified"
21
+ And The User object should have a "password" of "unspecified"
22
+
23
+
24
+
@@ -0,0 +1,101 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'read_it_later')
4
+
5
+ CONFIG=YAML.load(ERB.new(File.open(File.join(File.dirname(__FILE__), '..', '..', 'config', 'test.yml')).read).result)
6
+
7
+ Given /^I have a valid API Key and User$/ do
8
+ @api_key = CONFIG[:api_key]
9
+ @username = CONFIG[:username]
10
+ @password = CONFIG[:password]
11
+ end
12
+
13
+ When /^I create a ReadItLater API Object$/ do
14
+ @ril = ReadItLater.new(@api_key)
15
+ @usr = ReadItLater::User.new(@username, @password)
16
+ end
17
+
18
+ When /^I add a new bookmark$/ do
19
+ @response = @ril.add(@usr, "http://www.google.com/search?q=#{rand(999999)}")
20
+ end
21
+
22
+ When /^I send several updates$/ do
23
+ @response = @ril.send(@usr,
24
+ :new => [
25
+ { :url => "http://www.url1.com/", :title => "URL New 1" },
26
+ { :url => "http://www.url2.com/", :title => "URL New 2" },
27
+ { :url => "http://www.url3.com/", :title => "URL New 3" }
28
+ ],
29
+ :read => [
30
+ { :url => "http://www.url1.com/" },
31
+ { :url => "http://www.url2.com/" },
32
+ { :url => "http://www.url3.com/" }
33
+ ],
34
+ :update_title => [
35
+ { :url => "http://www.url1.com/", :title => "Updated URL New 1" },
36
+ { :url => "http://www.url2.com/", :title => "Updated URL New 2" },
37
+ { :url => "http://www.url3.com/", :title => "Updated URL New 3" }
38
+ ],
39
+ :update_tags => [
40
+ { :url => "http://www.url1.com/", :tags => "url1tag1, url1tag2, url1tag3" },
41
+ { :url => "http://www.url2.com/", :tags => "url2tag1, url2tag2, url2tag3" },
42
+ { :url => "http://www.url3.com/", :tags => "url3tag1, url3tag2, url3tag3" }
43
+ ]
44
+ )
45
+ end
46
+
47
+ When /^I send a statistics request$/ do
48
+ @response = @ril.stats(@usr)
49
+ end
50
+
51
+ When /^I send a request for a list of "([^\"]*)" "([^\"]*)" Read It Later bookmarks for page "([^\"]*)", which are "([^\"]*)", since "([^\"]*)", with tags "([^\"]*)"$/ do |count, state, page, mine_only, since, tags|
52
+ params = {}
53
+ params[:state] = state.to_sym unless state.empty? if state
54
+ params[:count] = count.to_i unless count.empty? if count
55
+ params[:page] = page.to_i unless page.empty? if page
56
+ params[:mine_only] = eval(mine_only) unless mine_only.empty? if mine_only
57
+ params[:tags] = eval(tags) unless tags.empty? if tags
58
+ params[:since] = Time.parse(since) unless since.empty? if since
59
+ @response = @ril.get(@usr, params)
60
+ end
61
+
62
+ When /^I authenticate an existing user$/ do
63
+ @response = @ril.auth(@usr)
64
+ end
65
+
66
+ When /^I send an API bookmarks list statistics request$/ do
67
+ @response = @ril.api
68
+ end
69
+
70
+ When /^I sign up a new user$/ do
71
+ @response = @ril.api
72
+ end
73
+
74
+ Then /^I should get back a success response from RIL server$/ do
75
+ @response[:status].should == ReadItLater::STATUS_SUCCESS
76
+ end
77
+
78
+ Then /^I should receive usual user and key limits$/ do
79
+ @response.has_key?(:key).should be_true
80
+ @response.has_key?(:user).should be_true
81
+ @response.has_key?(:text).should be_true
82
+ @response.has_key?(:status).should be_true
83
+ end
84
+
85
+ Then /^I should receive statistics of usage$/ do
86
+ @response.has_key?(:data).should be_true
87
+ @response[:data].has_key?(:user_since).should be_true
88
+ @response[:data].has_key?(:count_unread).should be_true
89
+ @response[:data].has_key?(:count_read).should be_true
90
+ @response[:data].has_key?(:count_list).should be_true
91
+ end
92
+
93
+ Then /^I should receive data about the list of bookmarks$/ do
94
+ @response.should have_key(:data)
95
+ end
96
+
97
+ Then /^I should receive a list of bookmarks, although it can be empty$/ do
98
+ @response[:data].should have_key(:list)
99
+ end
100
+
101
+
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'read_it_later')
2
+
3
+ When /^I create a User object with a user name "([^\"]*)" and password "([^\"]*)"$/ do |username, password|
4
+ @username = (username == "unspecified" ? nil : username)
5
+ @password = (password == "unspecified" ? nil : password)
6
+ end
7
+
8
+ Then /^I should get a User object with no errors$/ do
9
+ lambda {
10
+ if @username and @password
11
+ @user = ReadItLater::User.new(@username, @password)
12
+ elsif @username
13
+ @user = ReadItLater::User.new(@username)
14
+ else
15
+ @user = ReadItLater::User.new
16
+ end
17
+ }.should_not raise_error
18
+ end
19
+
20
+ Then /^The User object should have a "([^\"]*)" of "([^\"]*)"$/ do |field_name, value|
21
+ if field_name == "user name"
22
+ if value == "unspecified"
23
+ @user.username.should be_nil
24
+ else
25
+ @user.username.should == value
26
+ end
27
+ else
28
+ if value == "unspecified"
29
+ @user.password.should be_nil
30
+ else
31
+ @user.password.should == value
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,2 @@
1
+ require 'spec/expectations'
2
+
@@ -0,0 +1,132 @@
1
+ require 'open-uri'
2
+ require 'json'
3
+
4
+ class ReadItLater
5
+
6
+ STATUS_SUCCESS = 200
7
+ STATUS_INVALID = 400
8
+ STATUS_DENIED = 401
9
+ STATUS_EXCEEDED = 403
10
+ STATUS_MAINTENANCE = 503
11
+
12
+ URL_BASE = 'https://readitlaterlist.com/v2'
13
+ URLS = {
14
+ :add => ReadItLater::URL_BASE+'/add' ,
15
+ :send => ReadItLater::URL_BASE+'/send' ,
16
+ :stats => ReadItLater::URL_BASE+'/stats' ,
17
+ :get => ReadItLater::URL_BASE+'/get' ,
18
+ :auth => ReadItLater::URL_BASE+'/auth' ,
19
+ :signup => ReadItLater::URL_BASE+'/signup',
20
+ :api => ReadItLater::URL_BASE+'/api'
21
+ }
22
+
23
+ attr_reader :last_response
24
+
25
+ class User
26
+ attr_accessor :username, :password
27
+ def initialize(username=nil, password=nil)
28
+ @username, @password, @last_response = username, password, ""
29
+ end
30
+ end
31
+
32
+ attr_accessor :api_key
33
+
34
+ def initialize(api_key)
35
+ @api_key = api_key
36
+ end
37
+
38
+ def add(user, url)
39
+ @last_response = query(:add, user, :url => url)
40
+ end
41
+
42
+ def send(user, params)
43
+ %w(new read update_title update_tags).map(&:to_sym).each do |param|
44
+ params[param] = URI.escape((0..params[param].size-1).to_a.map{|n|{n.to_s=>params[param][n]}}.inject(){|a,b|a.merge(b)}.to_json) if params[param]
45
+ end
46
+ @last_response = query(:send, user, params)
47
+ end
48
+
49
+ def stats(user)
50
+ response = query(:stats, user, :format => "json")
51
+ response[:data] = stringify_keys(JSON.parse(response[:text]))
52
+ response[:data][:user_since] = Time.at(response[:data][:user_since].to_i)
53
+ @last_response = response
54
+ end
55
+
56
+ def get(user, call_params)
57
+ params = { :format => "json" }
58
+ params[:state] = call_params[:state].to_s.strip if call_params[:state]
59
+ params[:myAppOnly] = (call_params[:mine_only] ? "1" : "0") if call_params[:mine_only]
60
+ params[:since] = call_params[:since].to_i if call_params[:since]
61
+ params[:count] = call_params[:count] if call_params[:count]
62
+ params[:page] = call_params[:page] if call_params[:page]
63
+ params[:tags] = (call_params[:tags] ? "1" : "0") if call_params[:tags]
64
+ response = query(:get, user, params)
65
+ response[:data] = stringify_keys(JSON.parse(response[:text]))
66
+ response[:data][:since] = Time.at(response[:data][:since])
67
+ response[:data][:status] = response[:data][:status] == 1 ? :normal : :no_changes
68
+ response[:data][:list] = response[:data][:list].map{|k,v|v.merge(:time_added => Time.at(v[:time_added].to_i), :time_updated => Time.at(v[:time_updated].to_i), :item_id => v[:item_id].to_i, :read => (v[:state].strip == "0")).delete_if{|k,v|k==:state}}
69
+ @last_response = response
70
+ end
71
+
72
+ def auth(user)
73
+ @last_reponse = query(:auth, user)
74
+ end
75
+
76
+ def signup(user)
77
+ @last_reponse = query(:signup, user)
78
+ end
79
+
80
+ def api
81
+ @last_response = query(:api, User.new('',''))
82
+ end
83
+
84
+ private
85
+
86
+ def ril_api_url(method, user, params={})
87
+ params = { :apikey => @api_key, :username => user.username, :password => user.password }.merge(params)
88
+ query_str = URLS[method] + "?" + params.map{|k,v| "#{k.to_s}=#{URI.escape(v.to_s)}" }.join("&")
89
+ return query_str
90
+ end
91
+
92
+ def unique_id
93
+ return (1..24).to_a.map{|i|(('a'..'z').to_a+('0'..'9').to_a)[rand(36)]}.join
94
+ end
95
+
96
+ def query(method, user, params={})
97
+ response = nil
98
+ begin
99
+ open(ril_api_url(method, user, params)) do |f|
100
+ response = build_response(f)
101
+ end
102
+ rescue OpenURI::HTTPError => e
103
+ response = build_response(e.io)
104
+ end
105
+ return response
106
+ end
107
+
108
+ def build_response(io_object)
109
+ return {
110
+ :text => io_object.read.strip,
111
+ :status => io_object.meta["status"].split[0].strip.to_i,
112
+ :user => {
113
+ :limit => (io_object.meta["x-limit-user-limit" ] || "-1").to_i,
114
+ :remaining => (io_object.meta["x-limit-user-remaining"] || "-1").to_i,
115
+ :reset => (io_object.meta["x-limit-user-reset" ] || "-1").to_i
116
+ },
117
+ :key => {
118
+ :limit => (io_object.meta["x-limit-key-limit" ] || "-1").to_i,
119
+ :remaining => (io_object.meta["x-limit-key-remaining" ] || "-1").to_i,
120
+ :reset => (io_object.meta["x-limit-key-reset" ] || "-1").to_i
121
+ },
122
+ :error => io_object.meta["x-error"]
123
+ }
124
+ end
125
+
126
+ def stringify_keys(hsh)
127
+ hsh.map{|k,v|{k.to_sym => (v.class == Hash ? stringify_keys(v) : v)}}.inject(){|a,b|a.merge(b)}
128
+ end
129
+
130
+ end
131
+
132
+
@@ -0,0 +1,50 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{read_it_later}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Gabriel Medina"]
12
+ s.date = %q{2010-02-15}
13
+ s.description = %q{A very simple one-to-one api library for Read It Later API}
14
+ s.email = %q{rha7.com@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.textile"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.textile",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "config/cucumber.yml",
24
+ "config/test.yml.dist",
25
+ "features/read_it_later.feature",
26
+ "features/read_it_later_users.feature",
27
+ "features/step_definitions/read_it_later_steps.rb",
28
+ "features/step_definitions/read_it_later_user_steps.rb",
29
+ "features/support/env.rb",
30
+ "lib/read_it_later.rb",
31
+ "read_it_later.gemspec",
32
+ "sample_usage.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/rha7dotcom/read_it_later}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.5}
38
+ s.summary = %q{ReadItLaterList.com API Library for Ruby}
39
+
40
+ if s.respond_to? :specification_version then
41
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
+ s.specification_version = 3
43
+
44
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
45
+ else
46
+ end
47
+ else
48
+ end
49
+ end
50
+
data/sample_usage.rb ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require "lib/read_it_later"
4
+
5
+ ril = ReadItLater.new("<Your ReadItLater API Key Here>")
6
+ usr = ReadItLater::User.new('SomeUserName', 'SomeUserPass')
7
+
8
+ # Add method
9
+ # ===================================================================================
10
+ # pp ril.add(usr, "http://www.google.com/search?q=add+to+ril")
11
+
12
+ # Send method
13
+ # ===================================================================================
14
+ # pp ril.send(usr,
15
+ # :new => [
16
+ # { :url => "http://www.url1.com/", :title => "URL New 1" },
17
+ # { :url => "http://www.url2.com/", :title => "URL New 2" },
18
+ # { :url => "http://www.url3.com/", :title => "URL New 3" }
19
+ # ],
20
+ # :read => [
21
+ # { :url => "http://www.url1.com/" },
22
+ # { :url => "http://www.url2.com/" },
23
+ # { :url => "http://www.url3.com/" }
24
+ # ],
25
+ # :update_title => [
26
+ # { :url => "http://www.url1.com/", :title => "Updated URL New 1" },
27
+ # { :url => "http://www.url2.com/", :title => "Updated URL New 2" },
28
+ # { :url => "http://www.url3.com/", :title => "Updated URL New 3" }
29
+ # ],
30
+ # :update_tags => [
31
+ # { :url => "http://www.url1.com/", :tags => "url1tag1, url1tag2, url1tag3" },
32
+ # { :url => "http://www.url2.com/", :tags => "url2tag1, url2tag2, url2tag3" },
33
+ # { :url => "http://www.url3.com/", :tags => "url3tag1, url3tag2, url3tag3" }
34
+ # ]
35
+ # )
36
+
37
+ # Stats method
38
+ # ===================================================================================
39
+ # pp ril.stats(usr)
40
+
41
+ # Get method
42
+ # ===================================================================================
43
+ # pp ril.get(usr,
44
+ # :state => :unread,
45
+ # :mine_only => false,
46
+ # :since => (Time.now-30*24*60*60),
47
+ # :count => 10,
48
+ # :page => 2,
49
+ # :tags => false)
50
+
51
+ # Auth method
52
+ # ===================================================================================
53
+ # pp ril.auth(usr)
54
+
55
+ # Sign Up method
56
+ # ===================================================================================
57
+ # pp ril.auth(usr)
58
+
59
+ # API method
60
+ # ===================================================================================
61
+ # pp ril.api
62
+
63
+
64
+
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: read_it_later
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel Medina
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A very simple one-to-one api library for Read It Later API
17
+ email: rha7.com@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.textile
24
+ files:
25
+ - .gitignore
26
+ - README.textile
27
+ - Rakefile
28
+ - VERSION
29
+ - config/cucumber.yml
30
+ - config/test.yml.dist
31
+ - features/read_it_later.feature
32
+ - features/read_it_later_users.feature
33
+ - features/step_definitions/read_it_later_steps.rb
34
+ - features/step_definitions/read_it_later_user_steps.rb
35
+ - features/support/env.rb
36
+ - lib/read_it_later.rb
37
+ - read_it_later.gemspec
38
+ - sample_usage.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/rha7dotcom/read_it_later
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.3.5
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: ReadItLaterList.com API Library for Ruby
67
+ test_files: []
68
+