love 0.0.1 → 0.0.2
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 +1 -0
- data/Gemfile.lock +11 -1
- data/README.rdoc +8 -4
- data/lib/love.rb +106 -78
- data/love.gemspec +4 -4
- data/spec/love_spec.rb +72 -0
- data/spec/spec_helper.rb +8 -0
- metadata +32 -12
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
love (0.0.
|
4
|
+
love (0.0.2)
|
5
5
|
activesupport
|
6
6
|
yajl-ruby
|
7
7
|
|
@@ -9,7 +9,16 @@ GEM
|
|
9
9
|
remote: http://rubygems.org/
|
10
10
|
specs:
|
11
11
|
activesupport (3.0.3)
|
12
|
+
diff-lcs (1.1.2)
|
12
13
|
rake (0.8.7)
|
14
|
+
rspec (2.2.0)
|
15
|
+
rspec-core (~> 2.2)
|
16
|
+
rspec-expectations (~> 2.2)
|
17
|
+
rspec-mocks (~> 2.2)
|
18
|
+
rspec-core (2.2.1)
|
19
|
+
rspec-expectations (2.2.0)
|
20
|
+
diff-lcs (~> 1.1.2)
|
21
|
+
rspec-mocks (2.2.0)
|
13
22
|
yajl-ruby (0.7.8)
|
14
23
|
|
15
24
|
PLATFORMS
|
@@ -19,4 +28,5 @@ DEPENDENCIES
|
|
19
28
|
activesupport
|
20
29
|
love!
|
21
30
|
rake
|
31
|
+
rspec (~> 2)
|
22
32
|
yajl-ruby
|
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= Love
|
2
2
|
|
3
|
-
This library accesses the Tender REST API. It is my ode and thanks
|
4
|
-
|
3
|
+
This library accesses the Tender REST API. It is my ode to and thanks for the tender
|
4
|
+
lovemaking Aaron Patterson is doing on ActiveRecord.
|
5
5
|
|
6
6
|
It is currently read-only, and made especially for scripts that import data from
|
7
7
|
Tender to use in your own application. Feel free to fork and add missing API calls.
|
@@ -16,10 +16,14 @@ I previously used HTTParty to connect to the Tender API, but I ran into two issu
|
|
16
16
|
receive, invalid UTF-8 characters can get into the system, which will break Ruby
|
17
17
|
1.9. Love handles character encoding manually, and will replace all the invalid
|
18
18
|
UTF-8 characters by the UTF "unknown character" character.
|
19
|
-
* I
|
19
|
+
* I had to handle paging manually to get all data. Love will automatically
|
20
20
|
send multiple requests to get all the pages to iterate over all the available
|
21
21
|
objects.
|
22
22
|
|
23
|
+
== Installation
|
24
|
+
|
25
|
+
Run <tt>gem install love</tt> or add <tt>gem 'love'</tt> to your Gemfile.
|
26
|
+
|
23
27
|
== Usage
|
24
28
|
|
25
29
|
require 'love'
|
@@ -31,7 +35,7 @@ I previously used HTTParty to connect to the Tender API, but I ran into two issu
|
|
31
35
|
end
|
32
36
|
|
33
37
|
# Also available:
|
34
|
-
tender.
|
38
|
+
tender.each_user { |c| ... }
|
35
39
|
tender.each_queue { |q| ... }
|
36
40
|
tender.each_category { |c| ... }
|
37
41
|
|
data/lib/love.rb
CHANGED
@@ -1,113 +1,141 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'net/https'
|
3
|
-
require 'active_support'
|
3
|
+
require 'active_support/core_ext/module/attribute_accessors.rb'
|
4
4
|
require 'yajl'
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
module Love
|
7
|
+
|
8
8
|
# Create a custom exception class.
|
9
9
|
class Exception < StandardError; end
|
10
10
|
|
11
11
|
# Class for unauthorized exceptions
|
12
12
|
class Unauthorized < Love::Exception; end
|
13
13
|
|
14
|
-
attr_accessor :logger
|
15
|
-
|
16
|
-
attr_reader :account
|
17
|
-
attr_reader :api_key
|
18
|
-
|
19
|
-
attr_accessor :sleep_between_requests
|
20
|
-
|
21
|
-
def initialize(account, api_key, options = {})
|
22
|
-
@account, @api_key = account, api_key
|
23
|
-
|
24
|
-
# Handle options
|
25
|
-
@sleep_between_requests = options[:sleep_between_requests] || 0.5
|
26
|
-
end
|
27
14
|
|
28
15
|
def self.connect(account, api_key, options = {})
|
29
|
-
new(account, api_key, options)
|
16
|
+
Love::Client.new(account, api_key, options)
|
30
17
|
end
|
18
|
+
|
19
|
+
mattr_accessor :logger
|
31
20
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
21
|
+
module ResourceURI
|
22
|
+
def collection_uri(input)
|
23
|
+
case input.to_s
|
24
|
+
when /^[\w-]+$/
|
25
|
+
::URI.parse("https://api.tenderapp.com/#{account}/#{input}")
|
26
|
+
when %r[^https?://api\.tenderapp\.com/#{account}/[\w-]+]
|
27
|
+
::URI.parse(input.to_s)
|
28
|
+
else
|
29
|
+
raise Love::Exception, "This does not appear to be a valid Tender category URI!"
|
30
|
+
end
|
38
31
|
end
|
39
|
-
end
|
40
32
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
33
|
+
def singleton_uri(input, kind)
|
34
|
+
case input.to_s
|
35
|
+
when /^\d+/
|
36
|
+
::URI.parse("https://api.tenderapp.com/#{account}/#{kind}/#{input}")
|
37
|
+
when %r[^https?://api\.tenderapp\.com/#{account}/#{kind}/\d+]
|
38
|
+
::URI.parse(input.to_s)
|
39
|
+
else
|
40
|
+
raise Love::Exception, "This does not appear to be a Tender #{kind} URI or ID!"
|
41
|
+
end
|
47
42
|
end
|
48
43
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
|
45
|
+
class Client
|
46
|
+
|
47
|
+
include Love::ResourceURI
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
attr_reader :account
|
50
|
+
attr_reader :api_key
|
51
|
+
|
52
|
+
attr_accessor :sleep_between_requests
|
53
|
+
|
54
|
+
def initialize(account, api_key, options = {})
|
55
|
+
@account, @api_key = account, api_key
|
56
|
+
|
57
|
+
# Handle options
|
58
|
+
@sleep_between_requests = options[:sleep_between_requests] || 0.5
|
59
|
+
end
|
57
60
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
+
def get_user(id_or_href, options = {})
|
62
|
+
get(singleton_uri(id_or_href, 'users'))
|
63
|
+
end
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
+
def get_discussion(id_or_href, options = {})
|
66
|
+
get(singleton_uri(id_or_href, 'discussions'))
|
67
|
+
end
|
65
68
|
|
66
|
-
|
69
|
+
def get_category(id_or_href, options = {})
|
70
|
+
get(singleton_uri(id_or_href, 'categories'))
|
71
|
+
end
|
67
72
|
|
68
|
-
|
69
|
-
|
73
|
+
def get_queue(id_or_href, options = {})
|
74
|
+
get(singleton_uri(id_or_href, 'queues'), options)
|
75
|
+
end
|
76
|
+
|
77
|
+
def each_category(options = {}, &block)
|
78
|
+
buffered_each(collection_uri('categories'), 'categories', options, &block)
|
79
|
+
end
|
70
80
|
|
71
|
-
|
81
|
+
def each_queue(options = {}, &block)
|
82
|
+
buffered_each(collection_uri('queues'), 'named_queues', options, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def each_user(options = {}, &block)
|
86
|
+
buffered_each(collection_uri('users'), 'users', options, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def each_discussion(options = {}, &block)
|
90
|
+
buffered_each(collection_uri('discussions'), 'discussions', options, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def get(uri)
|
96
|
+
Love.logger.debug "GET #{url}" if Love.logger
|
72
97
|
|
73
|
-
|
74
|
-
|
75
|
-
|
98
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
99
|
+
if uri.scheme = 'https'
|
100
|
+
http.use_ssl = true
|
101
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
102
|
+
end
|
76
103
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
104
|
+
req = Net::HTTP::Get.new(uri.request_uri, {
|
105
|
+
"Accept" => "application/vnd.tender-v1+json",
|
106
|
+
"X-Tender-Auth" => api_key
|
107
|
+
})
|
81
108
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
109
|
+
response = http.request(req)
|
110
|
+
case response.code
|
111
|
+
when /^2\d\d/
|
112
|
+
converter = Encoding::Converter.new('binary', 'utf-8', :invalid => :replace, :undef => :replace)
|
113
|
+
Yajl::Parser.new.parse(converter.convert(response.body))
|
114
|
+
when '401'
|
115
|
+
raise Love::Unauthorized, "Invalid credentials used!"
|
116
|
+
else
|
117
|
+
raise Love::Exception, "#{response.code}: #{response.body}"
|
118
|
+
end
|
91
119
|
end
|
92
|
-
end
|
93
120
|
|
94
|
-
|
95
|
-
|
96
|
-
|
121
|
+
def buffered_each(uri, list_key, options = {}, &block)
|
122
|
+
query_options = {}
|
123
|
+
query_options[:since] = options[:since].to_date.to_s(:db) if options[:since]
|
97
124
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# Print out some initial debugging information
|
125
|
+
initial_result = get(path, :query => query_options)
|
126
|
+
start_page = [options[:start_page].to_i, 1].max rescue 1
|
127
|
+
max_page = (initial_result['total'].to_f / initial_result['per_page'].to_f).ceil
|
128
|
+
end_page = options[:end_page].nil? ? max_page : [options[:end_page].to_i, max_page].min
|
104
129
|
|
105
|
-
|
130
|
+
# Print out some initial debugging information
|
131
|
+
Love.logger.debug "Paged requests to #{path}: #{max_page} total pages, importing #{start_page} upto #{end_page}." if Love.logger
|
106
132
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
133
|
+
start_page.upto(end_page) do |page|
|
134
|
+
uri.query = query_options.map { |k, v| "#{k}=#{v}" }.join('&')
|
135
|
+
result = get(uri)
|
136
|
+
result[list_key].each { |record| yield(record) }
|
137
|
+
sleep(sleep_between_requests) if sleep_between_requests
|
138
|
+
end
|
111
139
|
end
|
112
140
|
end
|
113
141
|
end
|
data/love.gemspec
CHANGED
@@ -3,7 +3,7 @@ Gem::Specification.new do |s|
|
|
3
3
|
|
4
4
|
# Do not change the version and date fields by hand. This will be done
|
5
5
|
# automatically by the gem release script.
|
6
|
-
s.version = "0.0.
|
6
|
+
s.version = "0.0.2"
|
7
7
|
s.date = "2010-11-29"
|
8
8
|
|
9
9
|
s.summary = "Ruby library to access the Tender REST API."
|
@@ -21,13 +21,13 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_runtime_dependency('yajl-ruby')
|
22
22
|
|
23
23
|
s.add_development_dependency('rake')
|
24
|
-
|
24
|
+
s.add_development_dependency('rspec', '~> 2')
|
25
25
|
|
26
26
|
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
27
27
|
s.extra_rdoc_files = ['README.rdoc']
|
28
28
|
|
29
29
|
# Do not change the files and test_files fields by hand. This will be done
|
30
30
|
# automatically by the gem release script.
|
31
|
-
s.files = %w(.gitignore Gemfile Gemfile.lock LICENSE README.rdoc Rakefile lib/love.rb love.gemspec tasks/github-gem.rb)
|
32
|
-
s.test_files = %w()
|
31
|
+
s.files = %w(.gitignore Gemfile Gemfile.lock LICENSE README.rdoc Rakefile lib/love.rb love.gemspec spec/love_spec.rb spec/spec_helper.rb tasks/github-gem.rb)
|
32
|
+
s.test_files = %w(spec/love_spec.rb)
|
33
33
|
end
|
data/spec/love_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Love::ResourceURI do
|
4
|
+
|
5
|
+
include Love::ResourceURI
|
6
|
+
def account; "mysupport"; end
|
7
|
+
|
8
|
+
describe '#collection_uri' do
|
9
|
+
|
10
|
+
it "should build a valid URI based on the resource name" do
|
11
|
+
collection_uri('foos').should be_kind_of(::URI)
|
12
|
+
collection_uri('bars').to_s.should == 'https://api.tenderapp.com/mysupport/bars'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should accept a valid URI string" do
|
16
|
+
collection_uri('https://api.tenderapp.com/mysupport/bars').should be_kind_of(::URI)
|
17
|
+
collection_uri('https://api.tenderapp.com/mysupport/bars').to_s.should == 'https://api.tenderapp.com/mysupport/bars'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should accept a valid URI object" do
|
21
|
+
uri = URI.parse('https://api.tenderapp.com/mysupport/bars')
|
22
|
+
collection_uri(uri).should be_kind_of(::URI)
|
23
|
+
collection_uri(uri).should == uri
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not accept a URI for another account" do
|
27
|
+
lambda { collection_uri('https://api.tenderapp.com/other/bars') }.should raise_error(Love::Exception)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not accept an unrelated URI" do
|
31
|
+
lambda { collection_uri('http://www.vanbergen.org/mysupport/foos') }.should raise_error(Love::Exception)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not weird resource names" do
|
35
|
+
lambda { collection_uri('%!&') }.should raise_error(Love::Exception)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#singleton_uri' do
|
40
|
+
|
41
|
+
it "should build a valid URI based on the resource ID" do
|
42
|
+
singleton_uri(123, 'foos').should be_kind_of(::URI)
|
43
|
+
singleton_uri('456', 'bars').to_s.should == 'https://api.tenderapp.com/mysupport/bars/456'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should accept a valid URI string" do
|
47
|
+
singleton_uri('https://api.tenderapp.com/mysupport/foos/123', 'foos').should be_kind_of(::URI)
|
48
|
+
singleton_uri('https://api.tenderapp.com/mysupport/bars/456', 'bars').to_s.should == 'https://api.tenderapp.com/mysupport/bars/456'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should accept a valid URI object" do
|
52
|
+
uri = URI.parse('https://api.tenderapp.com/mysupport/bars/789')
|
53
|
+
singleton_uri(uri, 'bars').should be_kind_of(::URI)
|
54
|
+
singleton_uri(uri, 'bars').should == uri
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not accept a URI for another account" do
|
58
|
+
lambda { singleton_uri('https://api.tenderapp.com/other/bars/123', 'bars') }.should raise_error(Love::Exception)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should not accept an unrelated URI" do
|
62
|
+
lambda { singleton_uri('http://www.vanbergen.org/mysupport/foos', 'foos') }.should raise_error(Love::Exception)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not weird resource IDs" do
|
66
|
+
lambda { singleton_uri('%!&', 'bars') }.should raise_error(Love::Exception)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Love::Client do
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: love
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Willem van Bergen
|
@@ -18,44 +19,61 @@ date: 2010-11-29 00:00:00 -05:00
|
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name: activesupport
|
22
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
23
23
|
none: false
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
27
28
|
segments:
|
28
29
|
- 0
|
29
30
|
version: "0"
|
30
|
-
|
31
|
+
name: activesupport
|
31
32
|
prerelease: false
|
33
|
+
type: :runtime
|
32
34
|
version_requirements: *id001
|
33
35
|
- !ruby/object:Gem::Dependency
|
34
|
-
name: yajl-ruby
|
35
36
|
requirement: &id002 !ruby/object:Gem::Requirement
|
36
37
|
none: false
|
37
38
|
requirements:
|
38
39
|
- - ">="
|
39
40
|
- !ruby/object:Gem::Version
|
41
|
+
hash: 3
|
40
42
|
segments:
|
41
43
|
- 0
|
42
44
|
version: "0"
|
43
|
-
|
45
|
+
name: yajl-ruby
|
44
46
|
prerelease: false
|
47
|
+
type: :runtime
|
45
48
|
version_requirements: *id002
|
46
49
|
- !ruby/object:Gem::Dependency
|
47
|
-
name: rake
|
48
50
|
requirement: &id003 !ruby/object:Gem::Requirement
|
49
51
|
none: false
|
50
52
|
requirements:
|
51
53
|
- - ">="
|
52
54
|
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
53
56
|
segments:
|
54
57
|
- 0
|
55
58
|
version: "0"
|
56
|
-
|
59
|
+
name: rake
|
57
60
|
prerelease: false
|
61
|
+
type: :development
|
58
62
|
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
hash: 7
|
70
|
+
segments:
|
71
|
+
- 2
|
72
|
+
version: "2"
|
73
|
+
name: rspec
|
74
|
+
prerelease: false
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
59
77
|
description: " A simple API wrapper for Tender, that handles paged results, uses yajl-ruby for\n JSON parsing, and manually handles UTF-8 encoding to circumvent the invalid UTF-8\n character problem in Ruby 1.9.\n"
|
60
78
|
email:
|
61
79
|
- willem@railsdoctors.com
|
@@ -74,6 +92,8 @@ files:
|
|
74
92
|
- Rakefile
|
75
93
|
- lib/love.rb
|
76
94
|
- love.gemspec
|
95
|
+
- spec/love_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
77
97
|
- tasks/github-gem.rb
|
78
98
|
has_rdoc: true
|
79
99
|
homepage: http://github.com/wvanbergen/love
|
@@ -94,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
114
|
requirements:
|
95
115
|
- - ">="
|
96
116
|
- !ruby/object:Gem::Version
|
97
|
-
hash:
|
117
|
+
hash: 3
|
98
118
|
segments:
|
99
119
|
- 0
|
100
120
|
version: "0"
|
@@ -103,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
123
|
requirements:
|
104
124
|
- - ">="
|
105
125
|
- !ruby/object:Gem::Version
|
106
|
-
hash:
|
126
|
+
hash: 3
|
107
127
|
segments:
|
108
128
|
- 0
|
109
129
|
version: "0"
|
@@ -114,5 +134,5 @@ rubygems_version: 1.3.7
|
|
114
134
|
signing_key:
|
115
135
|
specification_version: 3
|
116
136
|
summary: Ruby library to access the Tender REST API.
|
117
|
-
test_files:
|
118
|
-
|
137
|
+
test_files:
|
138
|
+
- spec/love_spec.rb
|