grapi 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.textile CHANGED
@@ -1,13 +1,14 @@
1
1
  h2. Grapi : Ruby client to access the unofficial Google Reader API
2
2
 
3
- h3. Client Dependencies
3
+ h3. Install
4
4
 
5
- * "Curb":http://github.com/taf2/curb (gem install curb)
5
+ <pre>
6
+ gem install grapi
7
+ </pre>
6
8
 
7
- h3. ReadingList Parser
9
+ h3. Client Dependencies
8
10
 
9
- * "Nokogiri":http://github.com/tenderlove/nokogiri (gem install nokogiri)
10
- * "Loofah":http://github.com/flavorjones/loofah (gem install loofah)
11
+ * "Curb":http://github.com/taf2/curb (gem install curb)
11
12
 
12
13
  h3. Synopsis
13
14
 
@@ -18,20 +19,27 @@ require "grapi"
18
19
  reader = Grapi::Reader.new
19
20
  reader.login USERNAME, PASSWORD
20
21
 
21
- require "grapi/parser"
22
- list= Grapi::Parser::ReadingList.parse reader.reading_list
22
+ puts reader.reading_list
23
23
 
24
24
  </pre>
25
25
 
26
26
  h3. API methods
27
27
 
28
+ Public API:
29
+
28
30
  * initialize(verbose= false)
29
31
  * login(USERNAME, PASSWORD)
30
- * reading_list(continuation=nil, dump_data= false)
32
+ * reading_list(:continuation => nil, :dump_data => false, :output => "atom/json")
31
33
  * subscribe(feed_url, label=test)
32
34
  * unsubscribe(feed_url)
33
35
  * mark_as_read(entry_google_id)
34
36
 
37
+ Protected API:
38
+
39
+ * get(url)
40
+ * post(url, params={})
41
+ * post_with_token(url, params={})
42
+
35
43
  h3. License: see "MIT-LICENSE":http://github.com/aurelian/grapi/blob/master/MIT-LICENSE
36
44
 
37
45
  h3. For: contact - ideas - patches please use github infrastructure
data/Rakefile CHANGED
@@ -11,9 +11,6 @@ begin
11
11
  gem.homepage = "http://github.com/aurelian/grapi"
12
12
  gem.authors = ["Aurelian Oancea"]
13
13
  gem.add_dependency("curb", ">=0.6.1.0")
14
- gem.add_dependency("nokogiri", ">=1.4.1")
15
- gem.add_dependency("loofah", ">=0.4.1")
16
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
14
  end
18
15
  Jeweler::GemcutterTasks.new
19
16
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/grapi.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{grapi}
8
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Aurelian Oancea"]
@@ -21,11 +21,9 @@ Gem::Specification.new do |s|
21
21
  "README.textile",
22
22
  "Rakefile",
23
23
  "VERSION",
24
- "example.rb",
25
24
  "grapi.gemspec",
26
25
  "lib/core_ext/string.rb",
27
26
  "lib/grapi.rb",
28
- "lib/grapi/parser.rb",
29
27
  "lib/grapi/reader.rb",
30
28
  "test/helper.rb",
31
29
  "test/test_grapi.rb"
@@ -46,17 +44,11 @@ Gem::Specification.new do |s|
46
44
 
47
45
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
48
46
  s.add_runtime_dependency(%q<curb>, [">= 0.6.1.0"])
49
- s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.1"])
50
- s.add_runtime_dependency(%q<loofah>, [">= 0.4.1"])
51
47
  else
52
48
  s.add_dependency(%q<curb>, [">= 0.6.1.0"])
53
- s.add_dependency(%q<nokogiri>, [">= 1.4.1"])
54
- s.add_dependency(%q<loofah>, [">= 0.4.1"])
55
49
  end
56
50
  else
57
51
  s.add_dependency(%q<curb>, [">= 0.6.1.0"])
58
- s.add_dependency(%q<nokogiri>, [">= 1.4.1"])
59
- s.add_dependency(%q<loofah>, [">= 0.4.1"])
60
52
  end
61
53
  end
62
54
 
data/lib/grapi/reader.rb CHANGED
@@ -4,32 +4,19 @@ module Grapi
4
4
 
5
5
  class Reader
6
6
 
7
+ VERSION = File.read(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "VERSION"))).strip
8
+
7
9
  def initialize(verbose= false)
8
10
  @client = ::Curl::Easy.new do | easy |
9
11
  easy.headers= {
10
- "User-Agent" => "Grapi::Reader /0.2 +gzip",
12
+ "User-Agent" => "Grapi::Reader /#{Grapi::Reader::VERSION} +gzip",
11
13
  "Accept-Encoding" => "gzip, deflate",
12
14
  "GData-Version" => 2
13
15
  }
14
16
  easy.follow_location= true
15
17
  easy.verbose= true if verbose
16
18
  end
17
- @token = nil
18
- end
19
-
20
- def get(url)
21
- make_request(url){|c| c.http_get }
22
- end
23
-
24
- def post(url, params)
25
- curl_post_params= params.inject([]){|p, e| p << ::Curl::PostField.content(e[0],e[1])}
26
- make_request(url){|c| c.http_post(*curl_post_params)}
27
- end
28
-
29
- def post_with_token(url, params)
30
- request_token if @token.nil?
31
- params["T"]= @token
32
- post url, params
19
+ @token= nil
33
20
  end
34
21
 
35
22
  def login(username, password)
@@ -57,18 +44,42 @@ module Grapi
57
44
  post_with_token "http://www.google.com/reader/api/0/edit-tag", {"i" => entry_id, "a" => "user/-/state/com.google/read"}
58
45
  end
59
46
 
60
- def reading_list(continuation= nil, dump_data= false)
61
- get "http://www.google.com/reader/atom/user/-/state/com.google/reading-list?xt=user/-/state/com.google/read&ck=#{Time.now.to_i*1000}&n=1000&c=#{continuation}"
47
+ # options:
48
+ # :continuation (default: nil) -> continuation string
49
+ # :dump_data (default: false) -> whether to write the response to a file in /tmp or not
50
+ # :output (default: atom) -> desired output (atom|json)
51
+ def reading_list(options={})
52
+ options= {:continuation => nil, :output => "atom", :dump_data => false}.update(options)
53
+ if options[:output] == "atom"
54
+ get "http://www.google.com/reader/atom/user/-/state/com.google/reading-list?xt=user/-/state/com.google/read&ck=#{Time.now.to_i*1000}&n=1000&c=#{options[:continuation]}"
55
+ else
56
+ get "http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list?output=#{options[:output]}&xt=user/-/state/com.google/read&ck=#{Time.now.to_i*1000}&n=1000&c=#{options[:continuation]}"
57
+ end
62
58
  response= @client.body_str.uncompress
63
- File.open("/tmp/#{Time.now.to_i}-reading_list.atom", "w"){|f|f<<response} if dump_data
59
+ File.open("/tmp/#{Time.now.to_i}-reading_list.#{options[:output]}", "w"){|f|f<<response} if options[:dump_data]
64
60
  response
65
61
  end
66
62
 
67
- private
63
+ protected
64
+ def get(url)
65
+ make_request(url){|c| c.http_get }
66
+ end
67
+
68
+ def post(url, params)
69
+ curl_post_params= params.inject([]){|p, e| p << ::Curl::PostField.content(e[0],e[1])}
70
+ make_request(url){|c| c.http_post(*curl_post_params)}
71
+ end
68
72
 
73
+ def post_with_token(url, params)
74
+ request_token if @token.nil?
75
+ params["T"]= @token
76
+ post url, params
77
+ end
78
+
79
+ private
69
80
  def edit_subscription(feed_url, action, params={})
70
81
  post_with_token "http://www.google.com/reader/api/0/subscription/edit", { "s" => "feed/#{feed_url}", "ac" => action }.update(params)
71
- response = @client.body_str.uncompress
82
+ response= @client.body_str.uncompress
72
83
  unless response == "OK"
73
84
  $stderr<< "WARN: [#{__FILE__}:#{__LINE__}] ~> response is not OK. probably token has expired!\n#{response}\n\n"
74
85
  end
@@ -76,7 +87,7 @@ module Grapi
76
87
 
77
88
  def request_token
78
89
  get "http://www.google.com/reader/api/0/token"
79
- @token = @client.body_str.uncompress
90
+ @token= @client.body_str.uncompress
80
91
  end
81
92
 
82
93
  def make_request(url)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aurelian Oancea
@@ -22,26 +22,6 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: 0.6.1.0
24
24
  version:
25
- - !ruby/object:Gem::Dependency
26
- name: nokogiri
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.4.1
34
- version:
35
- - !ruby/object:Gem::Dependency
36
- name: loofah
37
- type: :runtime
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 0.4.1
44
- version:
45
25
  description: Ruby client for unofficial Google Reader API
46
26
  email: oancea@gmail.com
47
27
  executables: []
@@ -56,11 +36,9 @@ files:
56
36
  - README.textile
57
37
  - Rakefile
58
38
  - VERSION
59
- - example.rb
60
39
  - grapi.gemspec
61
40
  - lib/core_ext/string.rb
62
41
  - lib/grapi.rb
63
- - lib/grapi/parser.rb
64
42
  - lib/grapi/reader.rb
65
43
  - test/helper.rb
66
44
  - test/test_grapi.rb
data/example.rb DELETED
@@ -1,34 +0,0 @@
1
- $LOAD_PATH<< "lib"
2
-
3
- require "rubygems"
4
- require "grapi"
5
- require "grapi/parser"
6
- require "yaml"
7
-
8
- def print_list(list)
9
- puts "~> Got: #{list.gid} updated at: #{list.updated_at}\n\t contains: #{list.entries.size} items. continuation: #{list.continuation}"
10
- list.entries.each do | entry |
11
- puts "~> #{entry.title}"
12
- puts "\tpublished at: #{entry.published_at}"
13
- puts "\tcategories: \n\t\t#{entry.categories.map{|k| "label= #{k[:label]} | term= #{k[:term]}"}.join("\n\t\t")}"
14
- puts "\tsource: #{entry.source[:title]}"
15
- puts "\tauthor: #{entry.author}"
16
- puts "\turl: #{entry.link}"
17
- puts "\tsummary: #{entry.summary}"
18
- puts "======================================================================="
19
- end
20
- end
21
-
22
- config= YAML.load_file File.expand_path("~/.gdata.yml")
23
-
24
- reader= Grapi::Reader.new(true)
25
- reader.login config["username"], config["password"]
26
-
27
- continuation= nil
28
- loop do
29
- list= Grapi::Parser::ReadingList.parse(reader.reading_list(continuation))
30
- print_list list
31
- continuation= list.continuation
32
- break if continuation.nil?
33
- end
34
-
data/lib/grapi/parser.rb DELETED
@@ -1,55 +0,0 @@
1
- require "nokogiri"
2
- require "loofah"
3
- require "time"
4
-
5
- module Grapi
6
-
7
- module Parser
8
-
9
- class Entry
10
- attr_accessor :crawled_at, :summary, :gid, :categories, :published_at, :updated_at, :author, :source, :title, :link
11
-
12
- def initialize
13
- @categories= []
14
- yield self
15
- end
16
- end
17
-
18
- class ReadingList
19
- attr_accessor :entries, :gid, :updated_at, :continuation
20
-
21
- def initialize
22
- @entries= []
23
- yield self
24
- end
25
-
26
- def self.parse(xml)
27
- doc= Nokogiri::XML xml
28
- Grapi::Parser::ReadingList.new do | list |
29
- list.gid = doc.search("id").first.inner_text
30
- list.updated_at = Time.parse(doc.search("updated").first.inner_text)
31
- list.continuation = doc.at_xpath("//gr:continuation").inner_text rescue nil
32
- doc.search("entry").each do | entry |
33
- list.entries << Grapi::Parser::Entry.new do | e |
34
- e.gid = entry.search("id").first.inner_text
35
- e.title = entry.search("title").first.inner_text
36
- e.published_at = Time.parse(entry.search("published").first.inner_text)
37
- e.updated_at = Time.parse(entry.search("updated").first.inner_text)
38
- e.link = entry.search("link").attr("href").value
39
- e.crawled_at = Time.at(entry["crawl-timestamp-msec"].to_i/1000.0).utc
40
- e.summary = Loofah.fragment(entry.search("summary").inner_text).scrub!(:strip).text
41
- e.author = entry.search("author/name").inner_text
42
- e.source = {
43
- :id => entry.search("source/id").inner_text,
44
- :title => entry.search("source/title").inner_text,
45
- :link => entry.search("source/link").attr("href").value
46
- }
47
- entry.search("category").each { | category | e.categories << {:term=>category.attr("term"), :label=>category.attr("label")} }
48
- end
49
- end
50
- end
51
- end
52
- end
53
- end
54
- end
55
-