ffmike-rshoeboxed 0.0.6
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/History.txt +4 -0
- data/Manifest.txt +30 -0
- data/README.rdoc +74 -0
- data/Rakefile +28 -0
- data/lib/rshoeboxed/category.rb +26 -0
- data/lib/rshoeboxed/connection.rb +234 -0
- data/lib/rshoeboxed/list_proxy.rb +25 -0
- data/lib/rshoeboxed/parse_error.rb +19 -0
- data/lib/rshoeboxed/receipt.rb +62 -0
- data/lib/rshoeboxed.rb +14 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/fixtures/category_request.xml +8 -0
- data/test/fixtures/category_response.xml +7 -0
- data/test/fixtures/receipt_info_request.xml +12 -0
- data/test/fixtures/receipt_info_response.xml +5 -0
- data/test/fixtures/receipt_request.xml +16 -0
- data/test/fixtures/receipt_response.xml +14 -0
- data/test/fixtures/receipt_response_bad_credentials.xml +1 -0
- data/test/fixtures/receipt_response_internal_error.xml +1 -0
- data/test/fixtures/receipt_response_restricted_ip.xml +1 -0
- data/test/fixtures/receipt_response_unknown_api_call.xml +1 -0
- data/test/fixtures/receipt_response_xml_validation.xml +1 -0
- data/test/fixtures/receipt_with_category_id_request.xml +17 -0
- data/test/test_category.rb +31 -0
- data/test/test_connection.rb +177 -0
- data/test/test_helper.rb +20 -0
- data/test/test_list_proxy.rb +19 -0
- data/test/test_receipt.rb +58 -0
- metadata +133 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.rdoc
|
4
|
+
Rakefile
|
5
|
+
lib/rshoeboxed.rb
|
6
|
+
lib/rshoeboxed/category.rb
|
7
|
+
lib/rshoeboxed/connection.rb
|
8
|
+
lib/rshoeboxed/list_proxy.rb
|
9
|
+
lib/rshoeboxed/parse_error.rb
|
10
|
+
lib/rshoeboxed/receipt.rb
|
11
|
+
script/console
|
12
|
+
script/destroy
|
13
|
+
script/generate
|
14
|
+
test/fixtures/category_request.xml
|
15
|
+
test/fixtures/category_response.xml
|
16
|
+
test/fixtures/receipt_info_request.xml
|
17
|
+
test/fixtures/receipt_info_response.xml
|
18
|
+
test/fixtures/receipt_request.xml
|
19
|
+
test/fixtures/receipt_response.xml
|
20
|
+
test/fixtures/receipt_response_bad_credentials.xml
|
21
|
+
test/fixtures/receipt_response_internal_error.xml
|
22
|
+
test/fixtures/receipt_response_restricted_ip.xml
|
23
|
+
test/fixtures/receipt_response_unknown_api_call.xml
|
24
|
+
test/fixtures/receipt_response_xml_validation.xml
|
25
|
+
test/fixtures/receipt_with_category_id_request.xml
|
26
|
+
test/test_category.rb
|
27
|
+
test/test_connection.rb
|
28
|
+
test/test_helper.rb
|
29
|
+
test/test_list_proxy.rb
|
30
|
+
test/test_receipt.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= rshoeboxed
|
2
|
+
|
3
|
+
Master repo:
|
4
|
+
|
5
|
+
* http://github.com/bcurren/rshoeboxed
|
6
|
+
|
7
|
+
== DESCRIPTION:
|
8
|
+
|
9
|
+
Ruby wrapper for the Shoeboxed API.
|
10
|
+
|
11
|
+
== SYNOPSIS:
|
12
|
+
|
13
|
+
=== Generate authentication url
|
14
|
+
|
15
|
+
Use the following code to generate a url to send a user to to authenticate. The first parameter is the
|
16
|
+
AppName provided by Shoeboxed. Shoeboxed will redirect back to the return url once a user successfully
|
17
|
+
authenticates. When the user is redirected back to the return_url, a token will be provided in the url
|
18
|
+
for you to store for future API calls.
|
19
|
+
|
20
|
+
RShoeboxed::Connection.authentication_url("Outright", "http://example.com")
|
21
|
+
|
22
|
+
=== Get a list of all receipts
|
23
|
+
|
24
|
+
The api_token is provided by Shoeboxed when you setup your API account. The user_token is retrieved by
|
25
|
+
sending a user to authentication_url so they can log in to Shoeboxed. On success, they will be redirected
|
26
|
+
to the return_url with the user_token.
|
27
|
+
|
28
|
+
connection = RShoeboxed::Connection.new("api_token", "user_token")
|
29
|
+
receipts = connection.get_receipt_call(Date.new(2008, 1, 1), Date.new(2008, 12, 29))
|
30
|
+
|
31
|
+
=== Get a particular receipt
|
32
|
+
|
33
|
+
connection = RShoeboxed::Connection.new("api_token", "user_token")
|
34
|
+
receipt = connection.get_receipt_info_call("2342442424")
|
35
|
+
|
36
|
+
=== Get a list of all categories
|
37
|
+
|
38
|
+
connection = RShoeboxed::Connection.new("api_token", "user_token")
|
39
|
+
categories = connection.get_category_call
|
40
|
+
|
41
|
+
=== Get a list of all business cards
|
42
|
+
|
43
|
+
connection = RShoeboxed::Connection.new("api_token", "user_token")
|
44
|
+
cards = connection.get_business_card_call(200,1)
|
45
|
+
|
46
|
+
|
47
|
+
== INSTALL:
|
48
|
+
|
49
|
+
* sudo gem install bcurren_rshoeboxed
|
50
|
+
|
51
|
+
== LICENSE:
|
52
|
+
|
53
|
+
(The MIT License)
|
54
|
+
|
55
|
+
Copyright (c) 2009 Ben Curren
|
56
|
+
|
57
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
58
|
+
a copy of this software and associated documentation files (the
|
59
|
+
'Software'), to deal in the Software without restriction, including
|
60
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
61
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
62
|
+
permit persons to whom the Software is furnished to do so, subject to
|
63
|
+
the following conditions:
|
64
|
+
|
65
|
+
The above copyright notice and this permission notice shall be
|
66
|
+
included in all copies or substantial portions of the Software.
|
67
|
+
|
68
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
69
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
70
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
71
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
72
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
73
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
74
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/rshoeboxed'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('rshoeboxed', RShoeboxed::VERSION) do |p|
|
7
|
+
p.developer('Ben Curren', 'ben@gobootstrap.com')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.rubyforge_name = p.name # TODO this is default value
|
10
|
+
p.extra_deps = [
|
11
|
+
['builder','>= 2.1.2'],
|
12
|
+
]
|
13
|
+
p.extra_dev_deps = [
|
14
|
+
['newgem', ">= #{::Newgem::VERSION}"],
|
15
|
+
['mocha', ">= 0.9.4"]
|
16
|
+
]
|
17
|
+
|
18
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
19
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
20
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
21
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
25
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
26
|
+
|
27
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
28
|
+
# task :default => [:spec, :features]
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module RShoeboxed
|
4
|
+
class Category
|
5
|
+
attr_accessor :id, :name
|
6
|
+
|
7
|
+
def self.parse(xml)
|
8
|
+
document = REXML::Document.new(xml)
|
9
|
+
document.elements.collect("//Category") do |category_element|
|
10
|
+
category = Category.new
|
11
|
+
begin
|
12
|
+
category.id = category_element.attributes["id"]
|
13
|
+
category.name = category_element.attributes["name"]
|
14
|
+
rescue => e
|
15
|
+
raise RShoeboxed::ParseError.new(e, category_element.to_s, "Error parsing category.")
|
16
|
+
end
|
17
|
+
category
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(category)
|
22
|
+
self.id == category.id && self.name == category.name
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
gem "builder"
|
2
|
+
require "builder"
|
3
|
+
require "cgi"
|
4
|
+
require "net/https"
|
5
|
+
require 'rexml/document'
|
6
|
+
require 'logger'
|
7
|
+
require 'iconv'
|
8
|
+
|
9
|
+
module RShoeboxed
|
10
|
+
class Error < StandardError; end;
|
11
|
+
class UnknownAPICallError < Error; end;
|
12
|
+
class InternalError < Error; end;
|
13
|
+
class AuthenticationError < Error; end;
|
14
|
+
class RestrictedIPError < Error; end;
|
15
|
+
class XMLValidationError < Error; end;
|
16
|
+
|
17
|
+
class Connection
|
18
|
+
attr_accessor :api_key, :user_token
|
19
|
+
|
20
|
+
API_SERVER = "app.shoeboxed.com"
|
21
|
+
API_PATH = "/ws/api.htm"
|
22
|
+
API_URL = "https://" + API_SERVER + API_PATH
|
23
|
+
|
24
|
+
@@logger = Logger.new(STDOUT)
|
25
|
+
def logger
|
26
|
+
@@logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.log_level=(level)
|
30
|
+
@@logger.level = level
|
31
|
+
end
|
32
|
+
self.log_level = Logger::WARN
|
33
|
+
|
34
|
+
# Generates a url for you to obtain the user token. This url with take the user to the Shoeboxed authentication
|
35
|
+
# page. After the user successfully authenticates, they will be redirected to the app_url with the token and uname
|
36
|
+
# as parameters.
|
37
|
+
#
|
38
|
+
# app_name - string that contains the name of the app that is calling the API
|
39
|
+
# app_url - url that Shoeboxed will redirect to after a successful authentication
|
40
|
+
# app_params - option hash or array of strings containing params that will be passed back to app_url
|
41
|
+
def self.authentication_url(app_name, app_url, app_params={})
|
42
|
+
API_URL + "?" + encode_params(
|
43
|
+
[[:appname, app_name],
|
44
|
+
[:appurl, app_url],
|
45
|
+
[:apparams, encode_params(app_params)],
|
46
|
+
[:SignIn, 1]]
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# The initialization method takes in two params:
|
52
|
+
# api_key -
|
53
|
+
# user_token (generated after validating from the authentication url)
|
54
|
+
def initialize(api_key, user_token)
|
55
|
+
@api_key = api_key
|
56
|
+
@user_token = user_token
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_receipt_info_call(id)
|
60
|
+
request = build_receipt_info_request(id)
|
61
|
+
response = post_xml(request)
|
62
|
+
|
63
|
+
receipts = Receipt.parse(response)
|
64
|
+
receipts ? receipts.first : nil
|
65
|
+
end
|
66
|
+
|
67
|
+
# Note: the result_count can only be 50, 100, or 200
|
68
|
+
def get_receipt_call(start_date, end_date, options = {})
|
69
|
+
options = {
|
70
|
+
:use_sell_date => false,
|
71
|
+
:per_page => 50,
|
72
|
+
:current_page => 1
|
73
|
+
}.merge(options)
|
74
|
+
|
75
|
+
request = build_receipt_request(start_date, end_date, options)
|
76
|
+
response = post_xml(request)
|
77
|
+
|
78
|
+
receipts = Receipt.parse(response)
|
79
|
+
wrap_array_with_pagination(receipts, response, options[:current_page], options[:per_page])
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_category_call
|
83
|
+
request = build_category_request
|
84
|
+
response = post_xml(request)
|
85
|
+
|
86
|
+
Category.parse(response)
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_business_card_call(options = {})
|
90
|
+
request = build_business_card_request(options)
|
91
|
+
response = post_xml(request)
|
92
|
+
|
93
|
+
BusinessCard.parse(response)
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def wrap_array_with_pagination(receipts, response, current_page, per_page)
|
99
|
+
document = REXML::Document.new(response)
|
100
|
+
counts = document.elements.collect("//Receipts") { |element| element.attributes["count"] || 0 }
|
101
|
+
|
102
|
+
ListProxy.new(receipts, counts.first, current_page, per_page)
|
103
|
+
end
|
104
|
+
|
105
|
+
def date_to_s(date)
|
106
|
+
my_date = date
|
107
|
+
if !date.kind_of?(String)
|
108
|
+
my_date = date.strftime("%Y-%m-%dT%H:%M:%S")
|
109
|
+
end
|
110
|
+
my_date
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.encode_params(params)
|
114
|
+
# If hash, turn to array and give it alpha ordering
|
115
|
+
if params.kind_of? Hash
|
116
|
+
params = params.to_a
|
117
|
+
end
|
118
|
+
|
119
|
+
encoded_params = params.collect do |name, value|
|
120
|
+
"#{CGI.escape(name.to_s)}=#{CGI.escape(value.to_s)}"
|
121
|
+
end
|
122
|
+
encoded_params.join("&")
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def post_xml(body)
|
127
|
+
connection = Net::HTTP.new(API_SERVER, 443)
|
128
|
+
connection.use_ssl = true
|
129
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
130
|
+
|
131
|
+
request = Net::HTTP::Post.new(API_PATH)
|
132
|
+
request.set_form_data({'xml'=>body})
|
133
|
+
|
134
|
+
result = connection.start { |http| http.request(request) }
|
135
|
+
|
136
|
+
# Convert to UTF-8, shoeboxed encodes with ISO-8859-1
|
137
|
+
result_body = Iconv.conv('UTF-8', 'ISO-8859-1', result.body)
|
138
|
+
|
139
|
+
if logger.debug?
|
140
|
+
logger.debug "Request:"
|
141
|
+
logger.debug body
|
142
|
+
logger.debug "Response:"
|
143
|
+
logger.debug result_body
|
144
|
+
end
|
145
|
+
|
146
|
+
check_for_api_error(result_body)
|
147
|
+
end
|
148
|
+
|
149
|
+
def check_for_api_error(body)
|
150
|
+
document = REXML::Document.new(body)
|
151
|
+
root = document.root
|
152
|
+
puts root.inspect
|
153
|
+
if root && root.name == "Error"
|
154
|
+
description = root.attributes["description"]
|
155
|
+
|
156
|
+
case root.attributes["code"]
|
157
|
+
when "1"
|
158
|
+
raise AuthenticationError.new(description)
|
159
|
+
when "2"
|
160
|
+
raise UnknownAPICallError.new(description)
|
161
|
+
when "3"
|
162
|
+
raise RestrictedIPError.new(description)
|
163
|
+
when "4"
|
164
|
+
raise XMLValidationError.new(description)
|
165
|
+
when "5"
|
166
|
+
raise InternalError.new(description)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
body
|
171
|
+
end
|
172
|
+
|
173
|
+
def build_receipt_request(start_date, end_date, options)
|
174
|
+
xml = Builder::XmlMarkup.new
|
175
|
+
xml.instruct!
|
176
|
+
xml.Request(:xmlns => "urn:sbx:apis:SbxBaseComponents") do |xml|
|
177
|
+
append_credentials(xml)
|
178
|
+
xml.GetReceiptCall do |xml|
|
179
|
+
xml.ReceiptFilter do |xml|
|
180
|
+
xml.Results(options[:per_page])
|
181
|
+
xml.PageNo(options[:current_page])
|
182
|
+
xml.DateStart(date_to_s(start_date))
|
183
|
+
xml.DateEnd(date_to_s(end_date))
|
184
|
+
xml.UseSellDate(options[:use_sell_date])
|
185
|
+
xml.Category(options[:category_id]) if options[:category_id]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def build_category_request
|
192
|
+
xml = Builder::XmlMarkup.new
|
193
|
+
xml.instruct!
|
194
|
+
xml.Request(:xmlns => "urn:sbx:apis:SbxBaseComponents") do |xml|
|
195
|
+
append_credentials(xml)
|
196
|
+
xml.GetCategoryCall
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def build_business_card_request(options)
|
201
|
+
xml = Builder::XmlMarkup.new
|
202
|
+
xml.instruct!
|
203
|
+
xml.Request(:xmlns => "urn:sbx:apis:SbxBaseComponents") do |xml|
|
204
|
+
append_credentials(xml)
|
205
|
+
xml.GetBusinessCardCall do |xml|
|
206
|
+
xml.BusinessCardFilter do |xml|
|
207
|
+
xml.Results(options[:per_page])
|
208
|
+
xml.PageNo(options[:current_page])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def build_receipt_info_request(id)
|
215
|
+
xml = Builder::XmlMarkup.new
|
216
|
+
xml.instruct!
|
217
|
+
xml.Request(:xmlns => "urn:sbx:apis:SbxBaseComponents") do |xml|
|
218
|
+
append_credentials(xml)
|
219
|
+
xml.GetReceiptInfoCall do |xml|
|
220
|
+
xml.ReceiptFilter do |xml|
|
221
|
+
xml.ReceiptId(id)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def append_credentials(xml)
|
228
|
+
xml.RequesterCredentials do |xml|
|
229
|
+
xml.ApiUserToken(@api_key)
|
230
|
+
xml.SbxUserToken(@user_token)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RShoeboxed
|
2
|
+
class ListProxy
|
3
|
+
attr_reader :current_page, :per_page, :total
|
4
|
+
|
5
|
+
def initialize(array, total, current_page, per_page)
|
6
|
+
@array = array
|
7
|
+
|
8
|
+
@total = total.to_i
|
9
|
+
@current_page = current_page.to_i
|
10
|
+
@per_page = per_page.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def pages
|
14
|
+
pages = total / per_page
|
15
|
+
if total % per_page != 0
|
16
|
+
pages += 1
|
17
|
+
end
|
18
|
+
pages
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_missing(method, *args, &block)
|
22
|
+
@array.send(method, *args, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RShoeboxed
|
2
|
+
class ParseError < StandardError
|
3
|
+
attr_accessor :original_error, :xml
|
4
|
+
|
5
|
+
def initialize(original_error, xml, msg = nil)
|
6
|
+
@original_error = original_error
|
7
|
+
@xml = xml
|
8
|
+
super(msg)
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
message = super
|
13
|
+
|
14
|
+
"Original Error: #{original_error.to_s}\n" +
|
15
|
+
"XML: #{xml.to_s}\n" +
|
16
|
+
"Message: #{message}\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'date'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
module RShoeboxed
|
6
|
+
class Receipt
|
7
|
+
attr_accessor :id, :store, :image_url, :categories
|
8
|
+
attr_reader :sell_date, :created_date, :modified_date, :total
|
9
|
+
|
10
|
+
def self.parse(xml)
|
11
|
+
document = REXML::Document.new(xml)
|
12
|
+
document.elements.collect("//Receipt") do |receipt_element|
|
13
|
+
receipt = Receipt.new
|
14
|
+
begin
|
15
|
+
receipt.id = receipt_element.attributes["id"]
|
16
|
+
receipt.store = receipt_element.attributes["store"]
|
17
|
+
receipt.sell_date = receipt_element.attributes["selldate"]
|
18
|
+
receipt.created_date = receipt_element.attributes["createdDate"]
|
19
|
+
receipt.modified_date = receipt_element.attributes["modifiedDate"]
|
20
|
+
receipt.total = receipt_element.attributes["total"]
|
21
|
+
receipt.image_url = receipt_element.attributes["imgurl"]
|
22
|
+
|
23
|
+
# Get the categories elements and have Category parse them
|
24
|
+
category_element = receipt_element.elements["Categories"]
|
25
|
+
receipt.categories = category_element ? Category.parse(category_element.to_s) : []
|
26
|
+
rescue => e
|
27
|
+
raise RShoeboxed::ParseError.new(e, receipt_element.to_s, "Error parsing receipt.")
|
28
|
+
end
|
29
|
+
receipt
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def total=(total)
|
34
|
+
total.gsub!(/[^\d|.]/, "") if total.is_a?(String)
|
35
|
+
total = BigDecimal.new(total) unless total.is_a?(BigDecimal)
|
36
|
+
|
37
|
+
@total = total
|
38
|
+
end
|
39
|
+
|
40
|
+
def sell_date=(date)
|
41
|
+
date = Date.parse(date) if date.is_a?(String)
|
42
|
+
@sell_date = date
|
43
|
+
end
|
44
|
+
|
45
|
+
def created_date=(date)
|
46
|
+
date = Date.parse(date) if date.is_a?(String)
|
47
|
+
@created_date = date
|
48
|
+
end
|
49
|
+
|
50
|
+
def modified_date=(date)
|
51
|
+
date = Date.parse(date) if date.is_a?(String)
|
52
|
+
@modified_date = date
|
53
|
+
end
|
54
|
+
|
55
|
+
def ==(receipt)
|
56
|
+
self.id == receipt.id && self.store == receipt.store && self.image_url == receipt.image_url &&
|
57
|
+
self.categories == receipt.categories && self.sell_date == receipt.sell_date &&
|
58
|
+
self.modified_date == receipt.modified_date && self.created_date == receipt.created_date &&
|
59
|
+
self.total == receipt.total
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/rshoeboxed.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rshoeboxed/receipt'
|
6
|
+
require 'rshoeboxed/category'
|
7
|
+
require 'rshoeboxed/business_card'
|
8
|
+
require 'rshoeboxed/connection'
|
9
|
+
require 'rshoeboxed/list_proxy'
|
10
|
+
require 'rshoeboxed/parse_error'
|
11
|
+
|
12
|
+
module RShoeboxed
|
13
|
+
VERSION = '0.0.6'
|
14
|
+
end
|
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/rshoeboxed.rb'}"
|
9
|
+
puts "Loading rshoeboxed gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Request xmlns="urn:sbx:apis:SbxBaseComponents">
|
3
|
+
<RequesterCredentials>
|
4
|
+
<ApiUserToken>api_key</ApiUserToken>
|
5
|
+
<SbxUserToken>user_token</SbxUserToken>
|
6
|
+
</RequesterCredentials>
|
7
|
+
<GetReceiptInfoCall>
|
8
|
+
<ReceiptFilter>
|
9
|
+
<ReceiptId>1</ReceiptId>
|
10
|
+
</ReceiptFilter>
|
11
|
+
</GetReceiptInfoCall>
|
12
|
+
</Request>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Request xmlns="urn:sbx:apis:SbxBaseComponents">
|
3
|
+
<RequesterCredentials>
|
4
|
+
<ApiUserToken>api_key</ApiUserToken>
|
5
|
+
<SbxUserToken>user_token</SbxUserToken>
|
6
|
+
</RequesterCredentials>
|
7
|
+
<GetReceiptCall>
|
8
|
+
<ReceiptFilter>
|
9
|
+
<Results>50</Results>
|
10
|
+
<PageNo>1</PageNo>
|
11
|
+
<DateStart>2008-01-01T00:00:00</DateStart>
|
12
|
+
<DateEnd>2009-01-01T00:00:00</DateEnd>
|
13
|
+
<UseSellDate>false</UseSellDate>
|
14
|
+
</ReceiptFilter>
|
15
|
+
</GetReceiptCall>
|
16
|
+
</Request>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<GetReceiptCallResponse>
|
2
|
+
<Receipts count="2">
|
3
|
+
<Receipt store="Great Plains Trust Company" id="23984923842" total="$3,378.30" selldate="5/12/2008" createdDate="4/12/2008" modifiedDate="4/20/2008" imgurl="http://www.shoeboxed.com/receipt1.jpeg">
|
4
|
+
<Categories>
|
5
|
+
<Category name="Category 1" id="1"/>
|
6
|
+
</Categories>
|
7
|
+
</Receipt>
|
8
|
+
<Receipt store="RadioShack" id="39239293" total="$3.51" selldate="5/12/2008" createdDate="4/12/2008" modifiedDate="4/20/2008" imgurl="http://www.shoeboxed.com/receipt2.jpeg">
|
9
|
+
<Categories>
|
10
|
+
<Category name="Category 2" id="2"/>
|
11
|
+
</Categories>
|
12
|
+
</Receipt>
|
13
|
+
</Receipts>
|
14
|
+
</GetReceiptCallResponse>
|
@@ -0,0 +1 @@
|
|
1
|
+
<Error code="1" description="Bad credentials" />
|
@@ -0,0 +1 @@
|
|
1
|
+
<Error code="5" description="Internal Error" />
|
@@ -0,0 +1 @@
|
|
1
|
+
<Error code="3" description="Restricted IP" />
|
@@ -0,0 +1 @@
|
|
1
|
+
<Error code="2" description="Unknown API Call" />
|
@@ -0,0 +1 @@
|
|
1
|
+
<Error code="4" description="XML Validation" />
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Request xmlns="urn:sbx:apis:SbxBaseComponents">
|
3
|
+
<RequesterCredentials>
|
4
|
+
<ApiUserToken>api_key</ApiUserToken>
|
5
|
+
<SbxUserToken>user_token</SbxUserToken>
|
6
|
+
</RequesterCredentials>
|
7
|
+
<GetReceiptCall>
|
8
|
+
<ReceiptFilter>
|
9
|
+
<Results>50</Results>
|
10
|
+
<PageNo>1</PageNo>
|
11
|
+
<DateStart>2008-01-01T00:00:00</DateStart>
|
12
|
+
<DateEnd>2009-01-01T00:00:00</DateEnd>
|
13
|
+
<UseSellDate>true</UseSellDate>
|
14
|
+
<Category>10</Category>
|
15
|
+
</ReceiptFilter>
|
16
|
+
</GetReceiptCall>
|
17
|
+
</Request>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestCategory < Test::Unit::TestCase
|
4
|
+
include RShoeboxed
|
5
|
+
|
6
|
+
def setup
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_initialize_parse_xml
|
10
|
+
response = fixture_xml_content("category_response")
|
11
|
+
categories = Category.parse(response)
|
12
|
+
assert_equal 3, categories.size
|
13
|
+
|
14
|
+
categories.each_with_index do |category, i|
|
15
|
+
category_id = (i+1).to_s
|
16
|
+
assert_equal category_id, category.id
|
17
|
+
assert_equal "Category #{category_id}", category.name
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_category__accessors
|
22
|
+
category = Category.new
|
23
|
+
assert category
|
24
|
+
|
25
|
+
category.name = "Category 1"
|
26
|
+
assert_equal "Category 1", category.name
|
27
|
+
|
28
|
+
category.id = "1"
|
29
|
+
assert_equal "1", category.id
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestConnection < Test::Unit::TestCase
|
4
|
+
include RShoeboxed
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@conn = Connection.new("api_key", "user_token")
|
8
|
+
|
9
|
+
@category1 = Category.new
|
10
|
+
@category1.id = "1"
|
11
|
+
@category1.name = "Category 1"
|
12
|
+
|
13
|
+
@category2 = Category.new
|
14
|
+
@category2.id = "2"
|
15
|
+
@category2.name = "Category 2"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_authenticate__connection_failures
|
19
|
+
assert true
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_authentication_url__success_with_options
|
23
|
+
assert_equal "https://app.shoeboxed.com/ws/api.htm?appname=Bootstrap&appurl=http%3A%2F%2Fexample.com&apparams=test%3D1%26test2%3D1&SignIn=1",
|
24
|
+
Connection.authentication_url("Bootstrap", "http://example.com", [[:test, 1], [:test2, 1]])
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def test_authentication_url__success_no_options
|
29
|
+
assert_equal "https://app.shoeboxed.com/ws/api.htm?appname=Bootstrap&appurl=http%3A%2F%2Fexample.com&apparams=&SignIn=1",
|
30
|
+
Connection.authentication_url("Bootstrap", "http://example.com")
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_connection__instantiate_object
|
34
|
+
assert_equal "api_key", @conn.api_key
|
35
|
+
assert_equal "user_token", @conn.user_token
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def test_get_receipt_info_call__success_getting_one_receipt
|
40
|
+
request = fixture_xml_content("receipt_info_request")
|
41
|
+
response = fixture_xml_content("receipt_info_response")
|
42
|
+
|
43
|
+
conn = Connection.new("api_key", "user_token")
|
44
|
+
conn.expects(:post_xml).with(request).returns(response)
|
45
|
+
|
46
|
+
receipt = conn.get_receipt_info_call('1')
|
47
|
+
assert_not_nil receipt
|
48
|
+
assert_equal "1", receipt.id
|
49
|
+
assert_equal "Morgan Imports", receipt.store
|
50
|
+
assert_equal Date.new(2008, 5, 12), receipt.sell_date
|
51
|
+
assert_equal Date.new(2008, 4, 12), receipt.created_date
|
52
|
+
assert_equal Date.new(2008, 4, 20), receipt.modified_date
|
53
|
+
assert_equal BigDecimal.new("1929.00"), receipt.total
|
54
|
+
assert_equal "http://www.shoeboxed.com/receipt.jpeg", receipt.image_url
|
55
|
+
assert_equal [@category1], receipt.categories
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_build_receipt_info_call_request
|
59
|
+
assert_equal fixture_xml_content("receipt_info_request"), @conn.send(:build_receipt_info_request, "1")
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_get_receipt_call__success_getting_two_receipt
|
63
|
+
request = fixture_xml_content("receipt_request")
|
64
|
+
response = fixture_xml_content("receipt_response")
|
65
|
+
|
66
|
+
conn = Connection.new("api_key", "user_token")
|
67
|
+
conn.expects(:post_xml).with(request).returns(response)
|
68
|
+
|
69
|
+
receipts = conn.get_receipt_call(Date.new(2008, 1, 1), Date.new(2009, 1, 1))
|
70
|
+
assert_equal 2, receipts.total
|
71
|
+
assert_equal 1, receipts.current_page
|
72
|
+
assert_equal 50, receipts.per_page
|
73
|
+
assert_equal 1, receipts.pages
|
74
|
+
assert_equal 2, receipts.size
|
75
|
+
|
76
|
+
receipt = receipts[0]
|
77
|
+
assert_equal "23984923842", receipt.id
|
78
|
+
assert_equal "Great Plains Trust Company", receipt.store
|
79
|
+
assert_equal Date.new(2008, 5, 12), receipt.sell_date
|
80
|
+
assert_equal Date.new(2008, 4, 12), receipt.created_date
|
81
|
+
assert_equal Date.new(2008, 4, 20), receipt.modified_date
|
82
|
+
assert_equal BigDecimal.new("3378.30"), receipt.total
|
83
|
+
assert_equal "http://www.shoeboxed.com/receipt1.jpeg", receipt.image_url
|
84
|
+
assert_equal [@category1], receipt.categories
|
85
|
+
|
86
|
+
receipt = receipts[1]
|
87
|
+
assert_equal "39239293", receipt.id
|
88
|
+
assert_equal "RadioShack", receipt.store
|
89
|
+
assert_equal Date.new(2008, 5, 12), receipt.sell_date
|
90
|
+
assert_equal Date.new(2008, 4, 12), receipt.created_date
|
91
|
+
assert_equal Date.new(2008, 4, 20), receipt.modified_date
|
92
|
+
assert_equal BigDecimal.new("3.51"), receipt.total
|
93
|
+
assert_equal "http://www.shoeboxed.com/receipt2.jpeg", receipt.image_url
|
94
|
+
assert_equal [@category2], receipt.categories
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_build_receipt_request
|
98
|
+
options = {
|
99
|
+
:per_page => 50,
|
100
|
+
:current_page => 1,
|
101
|
+
:use_sell_date => false
|
102
|
+
}
|
103
|
+
assert_equal fixture_xml_content("receipt_request"),
|
104
|
+
@conn.send(:build_receipt_request, Date.new(2008, 1, 1), Date.new(2009, 1, 1), options)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_build_receipt_request__category_filter
|
108
|
+
options = {
|
109
|
+
:per_page => 50,
|
110
|
+
:current_page => 1,
|
111
|
+
:use_sell_date => true,
|
112
|
+
:category_id => 10
|
113
|
+
}
|
114
|
+
assert_equal fixture_xml_content("receipt_with_category_id_request"),
|
115
|
+
@conn.send(:build_receipt_request, Date.new(2008, 1, 1), Date.new(2009, 1, 1), options)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_check_for_api_error__all_error_codes
|
119
|
+
assert_api_error_raised("receipt_response_bad_credentials", AuthenticationError, "Bad credentials")
|
120
|
+
assert_api_error_raised("receipt_response_unknown_api_call", UnknownAPICallError, "Unknown API Call")
|
121
|
+
assert_api_error_raised("receipt_response_restricted_ip", RestrictedIPError, "Restricted IP")
|
122
|
+
assert_api_error_raised("receipt_response_xml_validation", XMLValidationError, "XML Validation")
|
123
|
+
assert_api_error_raised("receipt_response_unknown_api_call", UnknownAPICallError, "Unknown API Call")
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_check_for_api_error__no_error
|
127
|
+
assert_nothing_raised do
|
128
|
+
assert_equal "", @conn.send(:check_for_api_error, "")
|
129
|
+
end
|
130
|
+
|
131
|
+
response = fixture_xml_content("receipt_info_response")
|
132
|
+
assert_nothing_raised do
|
133
|
+
assert_equal response, @conn.send(:check_for_api_error, response)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_date_to_s
|
138
|
+
assert_equal "2009-01-15T00:00:00", @conn.send(:date_to_s, Date.new(2009, 1, 15))
|
139
|
+
assert_equal "2010-02-13T05:10:23", @conn.send(:date_to_s, DateTime.new(2010, 2, 13, 5, 10, 23))
|
140
|
+
assert_equal "2008-03-14T12:13:14", @conn.send(:date_to_s, Time.utc(2008, 3, 14, 12, 13, 14))
|
141
|
+
assert_equal "2008-03-14T12:13:14", @conn.send(:date_to_s, "2008-03-14T12:13:14")
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_build_category_request
|
145
|
+
assert_equal fixture_xml_content("category_request"), @conn.send(:build_category_request)
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def test_get_category_call
|
150
|
+
request = fixture_xml_content("category_request")
|
151
|
+
response = fixture_xml_content("category_response")
|
152
|
+
|
153
|
+
conn = Connection.new("api_key", "user_token")
|
154
|
+
conn.expects(:post_xml).with(request).returns(response)
|
155
|
+
|
156
|
+
categories = conn.get_category_call
|
157
|
+
assert_equal 3, categories.size
|
158
|
+
|
159
|
+
categories.each_with_index do |category, i|
|
160
|
+
category_id = (i + 1).to_s
|
161
|
+
assert_equal category_id, category.id
|
162
|
+
assert_equal "Category #{category_id}", category.name
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def assert_api_error_raised(response_fixture, error_type, error_message)
|
169
|
+
response = fixture_xml_content(response_fixture)
|
170
|
+
begin
|
171
|
+
@conn.send(:check_for_api_error, response)
|
172
|
+
fail "#{error_type.to_s} was not thrown"
|
173
|
+
rescue error_type => e
|
174
|
+
assert_equal error_message, e.message
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/rshoeboxed'
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
gem 'mocha'
|
7
|
+
require 'mocha'
|
8
|
+
|
9
|
+
class Test::Unit::TestCase
|
10
|
+
def fixture_xml_content(file_name)
|
11
|
+
# Quick way to remove white space and newlines from xml. Makes it easier to compare in tests
|
12
|
+
open(File.join(fixture_dir, "#{file_name}.xml"), "r").readlines.inject("") do |contents, line|
|
13
|
+
contents + line.strip
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def fixture_dir
|
18
|
+
File.join(File.dirname(__FILE__), "fixtures")
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestConnection < Test::Unit::TestCase
|
4
|
+
include RShoeboxed
|
5
|
+
|
6
|
+
def test_pages
|
7
|
+
proxy = ListProxy.new([], 39, 2, 20)
|
8
|
+
assert_equal 39, proxy.total
|
9
|
+
assert_equal 2, proxy.current_page
|
10
|
+
assert_equal 20, proxy.per_page
|
11
|
+
assert_equal 2, proxy.pages
|
12
|
+
|
13
|
+
proxy = ListProxy.new([], 40, 2, 20)
|
14
|
+
assert_equal 2, proxy.pages
|
15
|
+
|
16
|
+
proxy = ListProxy.new([], 0, 1, 20)
|
17
|
+
assert_equal 0, proxy.pages
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestReceipt < Test::Unit::TestCase
|
4
|
+
include RShoeboxed
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@category1 = Category.new
|
8
|
+
@category1.id = "1"
|
9
|
+
@category1.name = "Category 1"
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_initialize_parse_xml
|
13
|
+
response = fixture_xml_content("receipt_info_response")
|
14
|
+
receipts = Receipt.parse(response)
|
15
|
+
assert_equal 1, receipts.size
|
16
|
+
|
17
|
+
receipt = receipts.first
|
18
|
+
assert_equal "1", receipt.id
|
19
|
+
assert_equal "Morgan Imports", receipt.store
|
20
|
+
assert_equal Date.new(2008, 5, 12), receipt.sell_date
|
21
|
+
assert_equal Date.new(2008, 4, 12), receipt.created_date
|
22
|
+
assert_equal Date.new(2008, 4, 20), receipt.modified_date
|
23
|
+
assert_equal BigDecimal.new("1929.00"), receipt.total
|
24
|
+
assert_equal "http://www.shoeboxed.com/receipt.jpeg", receipt.image_url
|
25
|
+
assert_equal [@category1], receipt.categories
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_receipt__accessors
|
29
|
+
receipt = Receipt.new
|
30
|
+
assert receipt
|
31
|
+
|
32
|
+
receipt.store = "Macy's"
|
33
|
+
assert_equal "Macy's", receipt.store
|
34
|
+
|
35
|
+
receipt.id = "1"
|
36
|
+
assert_equal "1", receipt.id
|
37
|
+
|
38
|
+
receipt.total = '$1,000.19'
|
39
|
+
assert_equal BigDecimal.new('1000.19'), receipt.total
|
40
|
+
|
41
|
+
receipt.created_date = '1/2/2001'
|
42
|
+
assert_equal Date.parse('1/2/2001'), receipt.created_date
|
43
|
+
|
44
|
+
receipt.modified_date = '1/3/2001'
|
45
|
+
assert_equal Date.parse('1/3/2001'), receipt.modified_date
|
46
|
+
|
47
|
+
receipt.image_url = "http://www.example.com/one.image"
|
48
|
+
assert_equal "http://www.example.com/one.image", receipt.image_url
|
49
|
+
|
50
|
+
receipt.categories = [@category1]
|
51
|
+
assert_equal [@category1], receipt.categories
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_equal
|
55
|
+
# lame test but at least execute the code
|
56
|
+
assert_equal Receipt.new, Receipt.new
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ffmike-rshoeboxed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Curren
|
8
|
+
- William Chow
|
9
|
+
- Mike Gunderloy
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2009-02-13 00:00:00 -08:00
|
15
|
+
default_executable:
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: builder
|
19
|
+
type: :runtime
|
20
|
+
version_requirement:
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 2.1.2
|
26
|
+
version:
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: newgem
|
29
|
+
type: :development
|
30
|
+
version_requirement:
|
31
|
+
version_requirements: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.1.0
|
36
|
+
version:
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mocha
|
39
|
+
type: :development
|
40
|
+
version_requirement:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.9.4
|
46
|
+
version:
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: hoe
|
49
|
+
type: :development
|
50
|
+
version_requirement:
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.8.0
|
56
|
+
version:
|
57
|
+
description: Ruby wrapper for the Shoeboxed API.
|
58
|
+
email:
|
59
|
+
- ben@outright.com
|
60
|
+
- will@outright.com
|
61
|
+
- MikeG1@larkfarm.com
|
62
|
+
executables: []
|
63
|
+
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files:
|
67
|
+
- History.txt
|
68
|
+
- Manifest.txt
|
69
|
+
- README.rdoc
|
70
|
+
files:
|
71
|
+
- History.txt
|
72
|
+
- Manifest.txt
|
73
|
+
- README.rdoc
|
74
|
+
- Rakefile
|
75
|
+
- lib/rshoeboxed.rb
|
76
|
+
- lib/rshoeboxed/category.rb
|
77
|
+
- lib/rshoeboxed/connection.rb
|
78
|
+
- lib/rshoeboxed/list_proxy.rb
|
79
|
+
- lib/rshoeboxed/parse_error.rb
|
80
|
+
- lib/rshoeboxed/receipt.rb
|
81
|
+
- script/console
|
82
|
+
- script/destroy
|
83
|
+
- script/generate
|
84
|
+
- test/fixtures/category_request.xml
|
85
|
+
- test/fixtures/category_response.xml
|
86
|
+
- test/fixtures/receipt_info_request.xml
|
87
|
+
- test/fixtures/receipt_info_response.xml
|
88
|
+
- test/fixtures/receipt_request.xml
|
89
|
+
- test/fixtures/receipt_response.xml
|
90
|
+
- test/fixtures/receipt_response_bad_credentials.xml
|
91
|
+
- test/fixtures/receipt_response_internal_error.xml
|
92
|
+
- test/fixtures/receipt_response_restricted_ip.xml
|
93
|
+
- test/fixtures/receipt_response_unknown_api_call.xml
|
94
|
+
- test/fixtures/receipt_response_xml_validation.xml
|
95
|
+
- test/fixtures/receipt_with_category_id_request.xml
|
96
|
+
- test/test_category.rb
|
97
|
+
- test/test_connection.rb
|
98
|
+
- test/test_helper.rb
|
99
|
+
- test/test_list_proxy.rb
|
100
|
+
- test/test_receipt.rb
|
101
|
+
has_rdoc: true
|
102
|
+
homepage: http://github.com/bcurren/rshoeboxed
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options:
|
105
|
+
- --main
|
106
|
+
- README.rdoc
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
version:
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: "0"
|
120
|
+
version:
|
121
|
+
requirements: []
|
122
|
+
|
123
|
+
rubyforge_project: rshoeboxed
|
124
|
+
rubygems_version: 1.2.0
|
125
|
+
signing_key:
|
126
|
+
specification_version: 2
|
127
|
+
summary: Ruby wrapper for the Shoeboxed API.
|
128
|
+
test_files:
|
129
|
+
- test/test_category.rb
|
130
|
+
- test/test_connection.rb
|
131
|
+
- test/test_helper.rb
|
132
|
+
- test/test_list_proxy.rb
|
133
|
+
- test/test_receipt.rb
|