timespeople 0.2.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/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2008 Jacob Harris
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ THESE LICENSE TERMS APPLY TO THE GEM SOFTWARE ONLY AND DO NOT SUPPLEMENT
23
+ OR ABROGATE THE TERMS OF SERVICE FOR THE TIMESPEOPLE API.
data/README ADDED
@@ -0,0 +1,8 @@
1
+ timespeople===========
2
+
3
+ A gem for interacting with the TimesPeople API. More documentation to come.
4
+
5
+ COPYRIGHT
6
+ =========
7
+
8
+ Copyright (c) 2008 Jacob Harris. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "timespeople"
7
+ s.summary = "A simple gem for the TimesPeople API"
8
+ s.email = "jharris@nytimes.com"
9
+ s.homepage = "http://github.com/harrisj/timespeople"
10
+ s.description = "A simple gem for the TimesPeople API"
11
+ s.authors = ["Jacob Harris"]
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
15
+ end
16
+
17
+ require 'rake/rdoctask'
18
+ Rake::RDocTask.new do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'timespeople'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README*')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |t|
28
+ t.libs << 'lib' << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+ begin
34
+ require 'rcov/rcovtask'
35
+ Rcov::RcovTask.new do |t|
36
+ t.libs << 'test'
37
+ t.test_files = FileList['test/**/*_test.rb']
38
+ t.verbose = true
39
+ end
40
+ rescue LoadError
41
+ puts "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+
44
+ # begin
45
+ # require 'cucumber/rake/task'
46
+ # Cucumber::Rake::Task.new(:features)
47
+ # rescue LoadError
48
+ # puts "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
49
+ # end
50
+
51
+ task :default => :test
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 2
3
+ :patch: 0
4
+ :major: 0
File without changes
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'timespeople'
3
+
4
+ require 'test/unit/assertions'
5
+
6
+ require 'test/unit/assertions'
7
+
8
+ World do |world|
9
+
10
+ world.extend(Test::Unit::Assertions)
11
+
12
+ world
13
+ end
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
@@ -0,0 +1,3 @@
1
+ require File.join(File.dirname(__FILE__), 'times_people', 'exceptions')
2
+ require File.join(File.dirname(__FILE__), 'times_people', 'base')
3
+ require File.join(File.dirname(__FILE__), 'times_people', 'user')
@@ -0,0 +1,98 @@
1
+ require 'open-uri'
2
+ require 'json'
3
+ require 'htmlentities'
4
+
5
+ module TimesPeople
6
+ class Base
7
+ API_SERVER = 'api.nytimes.com'
8
+ API_VERSION = 'v1'
9
+ API_NAME = 'timespeople'
10
+
11
+ @@api_key = nil
12
+ @@debug = false
13
+
14
+ ##
15
+ # Set the API key used for operations. This needs to be called before any requests against the API. To obtain an API key, go to http://developer.nytimes.com/
16
+ def self.api_key=(key)
17
+ @@api_key = key
18
+ end
19
+
20
+ def self.debug=(flag)
21
+ @@debug = flag
22
+ end
23
+
24
+ ##
25
+ # Returns the current value of the API Key
26
+ def self.api_key
27
+ @@api_key
28
+ end
29
+
30
+ ##
31
+ # Builds a request URI to call the API server
32
+ def self.build_request_url(path, params)
33
+ URI::HTTP.build :host => API_SERVER,
34
+ :path => "/svc/#{API_NAME}/api/#{API_VERSION}/#{path}.js",
35
+ :query => params.map {|k,v| "#{URI.escape(k)}=#{URI.escape(v)}"}.join('&')
36
+ end
37
+
38
+ def self.text_field(value)
39
+ return nil if value.nil?
40
+ coder = HTMLEntities.new
41
+ coder.decode(value)
42
+ end
43
+
44
+ def self.integer_field(value)
45
+ return nil if value.nil?
46
+ value.to_i
47
+ end
48
+
49
+ def self.date_field(value)
50
+ return nil unless value =~ /^\d{8}$/
51
+ Date.strptime(value, "%Y%m%d")
52
+ end
53
+
54
+ def self.invoke(path, params={})
55
+ begin
56
+ if @@api_key.nil?
57
+ raise AuthenticationError, "You must initialize the API key before you run any API queries"
58
+ end
59
+
60
+ full_params = params.merge 'api-key' => @@api_key
61
+ uri = build_request_url(path, full_params)
62
+
63
+ puts "REQUEST: #{uri}" if @@debug
64
+
65
+ reply = uri.read
66
+ parsed_reply = JSON.parse reply
67
+
68
+ if parsed_reply.nil?
69
+ raise BadResponseError, "Empty reply returned from API"
70
+ end
71
+
72
+ #case parsed_reply['status']
73
+ # FIXME
74
+ #end
75
+
76
+ parsed_reply
77
+ rescue OpenURI::HTTPError => e
78
+ # FIXME: Return message from body?
79
+ case e.message
80
+ when /^400/
81
+ raise BadRequestError
82
+ when /^403/
83
+ raise AuthenticationError
84
+ when /^404/
85
+ return nil
86
+ when /^500/
87
+ raise ServerError
88
+ else
89
+ raise ConnectionError
90
+ end
91
+
92
+ raise "Error connecting to URL #{uri} #{e}"
93
+ rescue JSON::ParserError => e
94
+ raise BadResponseError, "Invalid JSON returned from API:\n#{reply}"
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,41 @@
1
+ module TimesPeople
2
+ ##
3
+ # The generic Error class from which all other Errors are derived.
4
+ class Error < ::RuntimeError
5
+ end
6
+
7
+ ##
8
+ # This error is thrown if there are problems authenticating your API key.
9
+ class AuthenticationError < Error
10
+ end
11
+
12
+ ##
13
+ # This error is thrown if the request was not parsable by the API server.
14
+ class BadRequestError < Error
15
+ end
16
+
17
+ ##
18
+ # This error is thrown if the response from the API server is not parsable.
19
+ class BadResponseError < Error
20
+ end
21
+
22
+ ##
23
+ # This error is thrown if there is an error connecting to the API server.
24
+ class ServerError < Error
25
+ end
26
+
27
+ ##
28
+ # This error is thrown if there is a timeout connecting to the server (to be implemented).
29
+ class TimeoutError < Error
30
+ end
31
+
32
+ ##
33
+ # This error is thrown for general connection errors to the API server.
34
+ class ConnectionError < Error
35
+ end
36
+
37
+ ##
38
+ # This error is thrown if the User was not found
39
+ class UserNotFoundError < Error
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ require 'digest/md5'
2
+
3
+ module TimesPeople
4
+ class User < Base
5
+ attr_reader :user_id, :display_name, :location, :picture_url, :following_count, :followers_count
6
+
7
+ def initialize(hash)
8
+ @user_id = hash[:user_id]
9
+ @display_name = hash[:display_name]
10
+ @location = hash[:location]
11
+ @picture_url = hash[:picture_url]
12
+ @following_count = hash[:following_count]
13
+ @followers_count = hash[:followers_count]
14
+ end
15
+
16
+ # http://api.nytimes.com/svc/timespeople/api/{version}/user/{hash}/id{.response-format}?api-key={your-API-key}
17
+ def self.find(email_addr)
18
+ digest = Digest::MD5.hexdigest(email_addr.downcase)
19
+
20
+ begin
21
+ reply = invoke("user/#{digest}/id")
22
+ if reply.nil?
23
+ raise UserNotFoundError, "No user with that email address was found in TimesPeople"
24
+ end
25
+
26
+ rescue ServerError
27
+ raise UserNotFoundError, "No user with that email address was found in TimesPeople"
28
+ end
29
+
30
+ # http://api.nytimes.com/svc/timespeople/api/{version}/user/{user-id}/{data-type}{.response-format}?api-key={your-API-key}
31
+ unless reply['results'].nil? || reply['results']['user_id'].nil?
32
+ user_id = reply['results']['user_id']
33
+ reply = invoke("user/#{user_id}/profile")
34
+ init_from_api(reply['results'])
35
+ end
36
+ end
37
+
38
+ def self.init_from_api(api_hash)
39
+ new :user_id => api_hash['user_id'],
40
+ :display_name => api_hash['user_displayname'],
41
+ :location => api_hash['location'],
42
+ :picture_url => api_hash['user_pic_url'],
43
+ :following_count => api_hash['following_count'],
44
+ :followers_count => api_hash['followers_count']
45
+ end
46
+ end
47
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'times_people')
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/timespeople.rb'}"
9
+ puts "Loading timespeople gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ gem 'chrisk-fakeweb'
6
+ require 'fake_web'
7
+
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+ require 'timespeople'
10
+
11
+ class Test::Unit::TestCase
12
+ API_KEY = '13e234323232222'
13
+
14
+ def init_test_key
15
+ TimesPeople::Base.api_key = API_KEY
16
+ end
17
+ end
18
+
19
+ module TestTimesPeople
20
+ end
@@ -0,0 +1,86 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ class TestTimesPeople::TestBase < Test::Unit::TestCase
4
+ include TimesPeople
5
+
6
+ context "Base.build_request_url" do
7
+ end
8
+
9
+ context "Base.invoke" do
10
+ setup do
11
+ init_test_key
12
+ end
13
+
14
+ context "when the API key has not been set" do
15
+ setup do
16
+ Base.api_key = nil
17
+ end
18
+
19
+ should_eventually "raise an AuthenticationError" do
20
+ assert_raise(AuthenticationError) do
21
+ Base.invoke
22
+ end
23
+ end
24
+ end
25
+
26
+ context "when the Articles API returns a 403 forbidden error (API key issue)" do
27
+ setup do
28
+ FakeWeb.register_uri(api_url_for, :status => ["403", "Forbidden"])
29
+ end
30
+
31
+ should_eventually "raise an AuthenticationError" do
32
+ assert_raise(AuthenticationError) do
33
+ Base.invoke
34
+ end
35
+ end
36
+ end
37
+
38
+ context "when the Articles API returns a 400 bad request error" do
39
+ setup do
40
+ FakeWeb.register_uri(api_url_for, :status => ["400", "Bad Request"])
41
+ end
42
+
43
+ should_eventually "raise an BadRequestError" do
44
+ assert_raise(BadRequestError) do
45
+ Base.invoke
46
+ end
47
+ end
48
+ end
49
+
50
+ context "When calling the Articles API returns a 500 server error" do
51
+ setup do
52
+ FakeWeb.register_uri(api_url_for, :status => ["500", "Server Error"])
53
+ end
54
+
55
+ should_eventually "raise an ServerError" do
56
+ assert_raise(ServerError) do
57
+ Base.invoke
58
+ end
59
+ end
60
+ end
61
+
62
+ context "when the Articles API returns any other HTTP error" do
63
+ setup do
64
+ FakeWeb.register_uri(api_url_for, :status => ["502", "Random Error"])
65
+ end
66
+
67
+ should_eventually "raise an ConnectionError" do
68
+ assert_raise(ConnectionError) do
69
+ Base.invoke
70
+ end
71
+ end
72
+ end
73
+
74
+ context "When the Articles API returns JSON that can't be parsed" do
75
+ setup do
76
+ FakeWeb.register_uri(api_url_for, :text => "e2131421212121221 => 3i109sdfvinp;2 112")
77
+ end
78
+
79
+ should_eventually "raise an BadResponseError" do
80
+ assert_raise(BadResponseError) do
81
+ Base.invoke
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timespeople
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Jacob Harris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-25 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A simple gem for the TimesPeople API
17
+ email: jharris@nytimes.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - LICENSE
24
+ - README
25
+ files:
26
+ - .gitignore
27
+ - LICENSE
28
+ - README
29
+ - Rakefile
30
+ - VERSION.yml
31
+ - features/steps/timespeople_steps.rb
32
+ - features/support/env.rb
33
+ - features/timespeople.feature
34
+ - lib/times_people.rb
35
+ - lib/times_people/base.rb
36
+ - lib/times_people/exceptions.rb
37
+ - lib/times_people/user.rb
38
+ - lib/timespeople.rb
39
+ - script/console
40
+ - test/test_helper.rb
41
+ - test/times_people/test_base.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/harrisj/timespeople
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.2
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A simple gem for the TimesPeople API
70
+ test_files:
71
+ - test/test_helper.rb
72
+ - test/times_people/test_base.rb