ardekantur-wondercroc 0.0.4 → 0.0.5

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.
@@ -1,3 +1,33 @@
1
1
  = wondercroc
2
2
 
3
- A gem that provides...
3
+ A gem that provides functionality for interfacing with the NewsGator online feed reading service.
4
+
5
+ = simple to use
6
+
7
+ c = WonderCroc::Client.new :user => 'newsgator_user', :password => 'newsgator_pass', :location => 'newsgator_location'
8
+
9
+ Or, if you have a YAML file like this:
10
+
11
+ user: newsgator_user
12
+ password: newsgator_password
13
+ location: newsgator_location
14
+
15
+ You can pass it in like this:
16
+
17
+ c = WonderCroc::Client.new :file => '/path/to/config.yml'
18
+
19
+ If you don't specify a location anywhere, it will default to the name of the library, a hyphen, and the name of your machine (in all caps), like thus:
20
+
21
+ wondercroc-MY_IMAC
22
+
23
+ = folders
24
+
25
+ Folders are a tree of the folders you have at the location you specified previously.
26
+
27
+ c.get_folders
28
+
29
+ = subscriptions
30
+
31
+ c.get_subscriptions_from_location
32
+
33
+ That's kind of where I am right now, poke around in irb to get a better feel for what you can do from there.
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ require 'spec/rake/verify_rcov'
8
8
 
9
9
 
10
10
  GEM = "wondercroc"
11
- GEM_VERSION = "0.0.4"
11
+ GEM_VERSION = "0.0.5"
12
12
  AUTHOR = "Ardekantur"
13
13
  EMAIL = "greystone@ardekantur.com"
14
14
  HOMEPAGE = "http://github.com/ardekantur/wondercroc"
@@ -59,10 +59,15 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
59
59
  rdoc.rdoc_dir = 'doc' # rdoc output folder
60
60
  end
61
61
 
62
- desc "Run RSpec and Rcov"
62
+ desc "run specs"
63
+ Spec::Rake::SpecTask.new("spec") do |t|
64
+ t.spec_files = FileList['spec/**/*_spec.rb']
65
+ end
66
+
67
+ desc "run rspec + rcov"
63
68
  Spec::Rake::SpecTask.new("spec:rcov") do |t|
64
69
  t.spec_files = FileList['spec/**/*_spec.rb']
65
- t.rcov_opts = ['--exclude', "spec/,rcov.rb,rspec.rb,spec*"]
70
+ t.rcov_opts = ['--exclude', "spec/,rcov.rb,rspec.rb,spec*,gems*"]
66
71
  t.rcov = true
67
72
  t.rcov_dir = 'doc/coverage'
68
73
  end
@@ -1 +1,6 @@
1
- %w{ client folder location subscription }.each { |x| require "wondercroc/#{x}" }
1
+
2
+ # WonderCroc is a library for retrieving subscriptions from a NewsGator online RSS feed reading account.
3
+ # Please see the README for more information.
4
+ module WonderCroc; end;
5
+
6
+ %w{ config client folder location subscription }.each { |x| require "wondercroc/#{x}" }
@@ -2,20 +2,18 @@ require 'rubygems'
2
2
  require 'rest_client'
3
3
  require 'rexml/document'
4
4
  require 'rss/2.0'
5
-
6
- # NewsGator is a Ruby layer for interacting with the
7
- # NewsGator API.
8
5
 
9
6
  module WonderCroc
10
7
 
8
+ VERSION = [ 0, 0, 5 ].join '.'
9
+
11
10
  class Client
12
11
 
13
- VERSION = [ 0, 0, 4 ].join '.'
14
12
  SERVICE = "http://services.newsgator.com/ngws/svc"
15
13
 
16
14
  BULLETIN_TOKEN = {
17
15
  "X-NGAPITOKEN" => "A8BBE03745F2439287D9425AB4BFFC30",
18
- "User-Agent" => "wondercroc/#{VERSION}",
16
+ "User-Agent" => "wondercroc/#{WonderCroc::VERSION}",
19
17
  "Accept-Encoding" => "compress,gzip"
20
18
  }
21
19
 
@@ -23,13 +21,22 @@ module WonderCroc
23
21
  attr_accessor :folders
24
22
 
25
23
  # Initializes an instance of a NewsGator Client.
26
- # +config_obj+ is a hash consisting of the keys
27
- # +:name+, +:password+, and +:location+, if you do
28
- # not want WonderCroc auto-generating a location name.
29
- def initialize config_obj
30
- @config = config_obj
24
+ # +config_options+ is a hash consisting of either all the informatio
25
+ # required to start a NewsGator connection (:user, :password, and :location),
26
+ # or the name of a file that has all those values in a YAML file (:file).
27
+ #
28
+ # We then set the location from the configuration hash passed through
29
+ # at the instantsiation of the Client object. If a +:location+
30
+ # key was not passed with that has, the location name is generated
31
+ # like so: 'newsgator_account_name-MACHINE_HOSTNAME'.
32
+ def initialize config_options
33
+ @config = WonderCroc::Configuration.new config_options
31
34
  @folder_unread_counts = {}
32
- self.clear_locations
35
+
36
+ get_locations
37
+ @location = @locations.find { |l| l[:title] == @config.location }
38
+ raise "no location found for name #{@config.location}" unless @location
39
+
33
40
  end
34
41
 
35
42
  def get_feed id, unread = true
@@ -37,19 +44,13 @@ module WonderCroc
37
44
  send_request :get
38
45
  end
39
46
 
40
- def get_random_feed
41
- raise "no feeds" unless @subscriptions
42
- get_feed @subscriptions[(rand * @subscriptions.length).floor].id, false
43
- end
44
-
45
47
  def parse_stories
46
48
  p = RSS::Parser.new @response
47
49
  p.do_validate = false
48
50
  p.parse
49
51
  end
50
52
 
51
- def get_unread_counts ui = nil
52
- ui.update_status 'Getting subscription counts...' if ui
53
+ def get_unread_counts
53
54
  new_connection_to "/Subscription.aspx/#{@location[:id]}/subscriptionCounts"
54
55
  send_request :get
55
56
  doc = REXML::Document.new @response
@@ -57,26 +58,46 @@ module WonderCroc
57
58
  @folder_unread_counts[e.attributes['ng:folderId']] = @folder_unread_counts.fetch(e.attributes['ng:folderId'], 0) + e.attributes['ng:unreadCount'].to_i
58
59
  end
59
60
  @folders.flatten.each { |f| f.unread_count = @folder_unread_counts.fetch(f.id, 0) }
60
- ui.update_status ''
61
61
  end
62
62
 
63
63
  private
64
64
 
65
65
  def new_connection_to url
66
- @request = RestClient::Resource.new(SERVICE + url, @config[:user], @config[:password])
66
+ @request = RestClient::Resource.new(SERVICE + url, @config.user, @config.password)
67
67
  end
68
68
 
69
69
  def send_request type, headers = {}
70
70
  raise ArgumentError, "invalid send request type #{type}" unless [ :get, :delete ].include? type
71
- @response = @request.send type, BULLETIN_TOKEN.merge(headers)
71
+
72
+ begin
73
+ @response = @request.send type, BULLETIN_TOKEN.merge(headers)
74
+ rescue RestClient::Unauthorized
75
+ raise IncorrectLoginError, "#{@config.user} was not able to login"
76
+ end
77
+
78
+ log_request_and_response
72
79
  end
73
80
 
74
81
  def send_data type, payload, headers = {}
75
82
  raise ArgumentError, "invalid send data request type #{type}" unless [ :put, :post ].include? type
76
83
  @response = @request.send type, payload, BULLETIN_TOKEN.merge(headers)
84
+
85
+ log_request_and_response
86
+ end
87
+
88
+ def log_request_and_response
89
+ File.open(File.join(ENV['HOME'], 'wondercroc_logs'), 'a') do |f|
90
+ f.write "REQUEST TO: #{@request.inspect}\n"
91
+ f.write "RESPONSE: #{@response}"
92
+ f.write "\n\n\n"
93
+ end
77
94
  end
78
95
 
79
96
  end
97
+
98
+ class IncorrectLoginError < RuntimeError
99
+ end
100
+
80
101
  end
81
102
 
82
103
  class RSS::Rss::Channel::Item
@@ -86,8 +107,7 @@ class RSS::Rss::Channel::Item
86
107
  ["postId", :integer ],
87
108
  ["avgRating", :float ],
88
109
  ["clipped", :boolean ],
89
- ["token", :text ],
90
- ["folderId", :text ]
110
+ ["token", :text ]
91
111
  ].each do |elem, type|
92
112
  install_text_element "ng:#{elem}", "http://newsgator.com/schema/extensions", '?', "#{elem}", type, "ng:#{elem}"
93
113
  RSS::BaseListener.install_get_text_element "http://newsgator.com/schema/extensions", "#{elem}", "#{elem}="
@@ -1,15 +1,28 @@
1
- # A folder is a folder that resides in a NewsGator location.
2
- # It can contain subscriptions and other folders.
3
1
 
4
2
  module WonderCroc
3
+
4
+ class Client
5
+
6
+ def find_folder_by_id folder_id
7
+ @subfolders.each { |subfolder| return subfolder if subfolder and subfolder.find_by_id folder_id}
8
+ return nil
9
+ end
10
+
11
+ end
12
+
13
+ # A folder is a folder that resides in a NewsGator location.
14
+ # It can contain subscriptions and other folders.
5
15
  class Folder
6
16
 
7
- attr_accessor :id, :name, :unread_count
17
+ attr_accessor :folder_id, :name
18
+ attr_reader :unread_count
8
19
 
9
20
  def initialize name, id
21
+ raise ArgumentException unless name
10
22
  @name = name
11
- @id = id
23
+ @folder_id = id
12
24
  @unread_count = 0
25
+ @subfolders = []
13
26
  end
14
27
 
15
28
  def to_str
@@ -17,6 +30,23 @@ class Folder
17
30
  return "#{@name} (#{@unread_count})"
18
31
  end
19
32
 
33
+ def subfolders
34
+ return @subfolders
35
+ end
36
+
37
+ def << subfolder
38
+ @subfolders << subfolder
39
+ end
40
+
41
+ def merge array
42
+ @subfolders += array if array
43
+ end
44
+
45
+ def find_by_id id
46
+ return self if @folder_id == id
47
+ @subfolders.each { |subfolder| return subfolder if subfolder.find_by_id id}
48
+ end
49
+
20
50
  end
21
51
 
22
52
  class Client
@@ -25,28 +55,29 @@ class Client
25
55
  def get_folders
26
56
  new_connection_to "/Folder.aspx"
27
57
  send_request :get
28
- @folders = folders_from_xml(@response)
58
+ @folders = folders_from_xml(@response).subfolders
29
59
  end
30
60
 
31
61
  private
32
62
 
33
63
  def folders_from_xml xml
34
- folders = []
64
+ root_folder = Folder.new 'Root', -1
35
65
  doc = REXML::Document.new xml
36
66
  doc.elements.each('opml/body/outline') do |e|
37
- dir = [ Folder.new(e.attributes['title'], e.attributes['ng:id']) ]
38
- dir << subfolders(e)
39
- folders << dir.compact
67
+ dir = Folder.new e.attributes['title'], e.attributes['ng:id']
68
+ dir.merge subfolders(e)
69
+ root_folder << dir
40
70
  end
41
- return folders.compact
71
+ return root_folder
42
72
  end
43
73
 
44
74
  def subfolders element
45
75
  return nil if element.elements.size == 0
46
76
  folders = []
47
77
  element.each do |e|
48
- folders << Folder.new(e.attributes['title'], e.attributes['ng:id'])
49
- folders << subfolders(e)
78
+ folder = Folder.new(e.attributes['title'], e.attributes['ng:id'])
79
+ folder.merge subfolders(e)
80
+ folders << folder
50
81
  end
51
82
 
52
83
  return folders.compact
@@ -7,17 +7,6 @@ class Client
7
7
  @locations = []
8
8
  end
9
9
 
10
- # Sets the location from the configuration hash passed through
11
- # at the instantsiation of the Client object. If a +:location+
12
- # key was not passed with that has, the location name is generated
13
- # like so: 'newsgator_account_name-MACHINE_HOSTNAME'.
14
- def set_location_from_config
15
- get_locations
16
- @config[:location] ||= "#{@config[:user]}-#{`hostname`.strip.upcase}"
17
- @location = @locations.find { |l| l[:title] == @config[:location] }
18
- raise "no location found for name #{@config.location}" unless @location
19
- end
20
-
21
10
  # Retrieves a list of all the locations that the logged in user
22
11
  # has available.
23
12
  def get_locations
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ardekantur-wondercroc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ardekantur
@@ -9,7 +9,7 @@ autorequire: wondercroc
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-07-01 00:00:00 -07:00
12
+ date: 2008-07-06 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -30,6 +30,7 @@ files:
30
30
  - TODO
31
31
  - lib/wondercroc
32
32
  - lib/wondercroc/client.rb
33
+ - lib/wondercroc/config.rb
33
34
  - lib/wondercroc/folder.rb
34
35
  - lib/wondercroc/location.rb
35
36
  - lib/wondercroc/subscription.rb