dewey 0.1.4 → 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/CHANGELOG.md +30 -1
- data/README.md +36 -19
- data/lib/dewey.rb +10 -199
- data/lib/dewey/client_auth.rb +48 -0
- data/lib/dewey/core.rb +158 -0
- data/lib/dewey/version.rb +3 -0
- metadata +7 -5
- data/TODO.md +0 -5
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,37 @@
|
|
1
|
+
## 0.2.0 (October 20, 2010)
|
2
|
+
|
3
|
+
Additions:
|
4
|
+
|
5
|
+
- Class-wide authentication. You only have to set up authentication once and
|
6
|
+
then utilize that in all successive calls.
|
7
|
+
- All file operations are stateless (Dewey.put, Dewey.get, etc)
|
8
|
+
- Store multiple authorizations simultaneously.
|
9
|
+
|
10
|
+
Changes:
|
11
|
+
|
12
|
+
- Convert API change. Format is required, not an option.
|
13
|
+
- No longer supports upload or download, instead use put or get.
|
14
|
+
|
15
|
+
## 0.1.4 (October 19, 2010)
|
16
|
+
|
17
|
+
Additions:
|
18
|
+
|
19
|
+
- Handle bad mimetypes.
|
20
|
+
- Modular validation
|
21
|
+
- Removed service option, needless.
|
22
|
+
- Automatic implicit authorization, removes need to call authorize! manually.
|
23
|
+
|
24
|
+
Bugfixes:
|
25
|
+
|
26
|
+
- Prevent peer certificate warnings in 1.9
|
27
|
+
- Fixed id extraction regex that prevented resources with dashes or underscores
|
28
|
+
from being pulled.
|
29
|
+
|
1
30
|
## 0.1.3 (June 29, 2010)
|
2
31
|
|
3
32
|
Bugfixes:
|
4
33
|
|
5
|
-
- Handle mime type changes for files with no extension
|
34
|
+
- Handle mime type changes for files with no extension.
|
6
35
|
|
7
36
|
## 0.1.2 (June 28, 2010)
|
8
37
|
|
data/README.md
CHANGED
@@ -15,32 +15,49 @@ Let Google do all of the hard work of converting your documents!
|
|
15
15
|
|
16
16
|
Dewey is in alpha. It is not recommended you use this in production code.
|
17
17
|
|
18
|
-
##
|
18
|
+
## Authorization
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
You can configure Dewey to connect with either ClientLogin or OAuth. If you choose
|
21
|
+
OAuth you'll only have to authenticate the first time you connect and subsequent
|
22
|
+
connections will use the saved token.
|
22
23
|
|
23
|
-
|
24
|
+
ClientLogin
|
24
25
|
|
25
|
-
|
26
|
+
Dewey.authorization :client, :email => 'example@gmail.com', :password => 'password'
|
27
|
+
|
28
|
+
OAuth
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
Dewey.authorization :oauth, :idontknowwhatgoeshereyet
|
31
|
+
|
32
|
+
## File Operations
|
33
|
+
|
34
|
+
You can put, get, delete and convert documents, spreadsheets or presentations in
|
35
|
+
any of the formats that Docs accepts. There is a full listing in dewey/validations.rb
|
36
|
+
or available here: http://code.google.com/apis/documents/faq.html#WhatKindOfFilesCanIUpload
|
29
37
|
|
30
|
-
|
31
|
-
|
38
|
+
Be sure to set up authorization before attempting any file operations! You don't
|
39
|
+
need to explictely call authorize though, as it will attempt to do that on the
|
40
|
+
first operation.
|
32
41
|
|
33
|
-
|
34
|
-
|
42
|
+
Putting a document:
|
43
|
+
|
44
|
+
document = File.new('my_document.doc')
|
45
|
+
resource = Dewey.put(document, 'My First Upload') # Returns the id when successful
|
35
46
|
|
36
|
-
|
47
|
+
Getting a document:
|
37
48
|
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
# Upload your file
|
50
|
+
id = Dewey.put(File.new('my_document.doc'), 'My Second Upload')
|
51
|
+
|
52
|
+
# Get it in various formats
|
53
|
+
original = Dewey.get(id) # -> Tempfile
|
54
|
+
pdf = Dewey.get(id, :pdf) # -> Tempfile
|
55
|
+
html = Dewey.get(id, :html) # -> Tempfile
|
56
|
+
|
57
|
+
# A tempfile is returned, so you'll have to move it
|
58
|
+
FileUtils.mv html.path, 'path/to/destination'
|
41
59
|
|
42
|
-
|
43
|
-
folder. The file should contain two lines:
|
60
|
+
Deleting a document:
|
44
61
|
|
45
|
-
|
46
|
-
|
62
|
+
id = Dewey.put(File.new('my_spreadsheet.xls'))
|
63
|
+
result = Dewey.delete(id) # -> true
|
data/lib/dewey.rb
CHANGED
@@ -1,13 +1,3 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'net/https'
|
3
|
-
require 'open-uri'
|
4
|
-
require 'rexml/document'
|
5
|
-
require 'tempfile'
|
6
|
-
require 'dewey/https'
|
7
|
-
require 'dewey/mime'
|
8
|
-
require 'dewey/utils'
|
9
|
-
require 'dewey/validation'
|
10
|
-
|
11
1
|
module Dewey
|
12
2
|
GOOGLE_DOCS_URL = "https://docs.google.com"
|
13
3
|
GOOGLE_SPRD_URL = "https://spreadsheets.google.com"
|
@@ -17,193 +7,14 @@ module Dewey
|
|
17
7
|
GOOGLE_DOCUMENT_URL = GOOGLE_DOCS_URL + "/feeds/download/documents/Export"
|
18
8
|
GOOGLE_SPREADSHEET_URL = GOOGLE_SPRD_URL + "/feeds/download/spreadsheets/Export"
|
19
9
|
|
20
|
-
class DeweyException < Exception
|
21
|
-
end
|
22
|
-
|
23
|
-
# Doc
|
24
|
-
# This base class handles authentication and requests
|
25
|
-
#
|
26
|
-
class Document
|
27
|
-
attr_accessor :account, :password, :token
|
28
|
-
|
29
|
-
# Create a new Doc object
|
30
|
-
# Options specified in +opts+ consist of:
|
31
|
-
#
|
32
|
-
# * :account - The Google Doc's account that will be used for authentication.
|
33
|
-
# This will most typically be a gmail account, i.e. +example@gmail.com+
|
34
|
-
# * :password - The password for the Google Doc's account.
|
35
|
-
def initialize(options = {})
|
36
|
-
@account = options[:account]
|
37
|
-
@password = options[:password]
|
38
|
-
end
|
39
|
-
|
40
|
-
# Returns true if this instance has been authorized
|
41
|
-
def authorized?
|
42
|
-
!! @token
|
43
|
-
end
|
44
|
-
|
45
|
-
# Gets an authorization token for this instance. Raises an error if no
|
46
|
-
# credentials have been provided, +false+ if authorization fails, and +true+ if
|
47
|
-
# authorization is successful.
|
48
|
-
def authorize!
|
49
|
-
if @account.nil? || @password.nil?
|
50
|
-
raise DeweyException, "Account or password missing."
|
51
|
-
end
|
52
|
-
|
53
|
-
url = URI.parse(GOOGLE_LOGIN_URL)
|
54
|
-
params = { 'accountType' => 'HOSTED_OR_GOOGLE', 'Email' => @account,
|
55
|
-
'Passwd' => @password, 'service'=> 'writely' }
|
56
|
-
|
57
|
-
response = Net::HTTPS.post_form(url, params)
|
58
|
-
|
59
|
-
case response
|
60
|
-
when Net::HTTPSuccess
|
61
|
-
@token = response.body.split(/=/).last
|
62
|
-
true
|
63
|
-
when Net::HTTPForbidden
|
64
|
-
false
|
65
|
-
else
|
66
|
-
raise DeweyException, "Unexpected response: #{response}"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Upload a file to the account. A successful upload will return the resource
|
71
|
-
# id, which is useful for downloading the file without doing a title search.
|
72
|
-
# * file - A File reference
|
73
|
-
# * title - An alternative title, to be used instead of the filename
|
74
|
-
def put(file, title = nil)
|
75
|
-
authorize! unless authorized?
|
76
|
-
|
77
|
-
extension = File.extname(file.path).sub('.', '')
|
78
|
-
basename = File.basename(file.path, ".#{extension}")
|
79
|
-
mimetype = Dewey::Mime.mime_type(file)
|
80
|
-
service = Dewey::Mime.guess_service(mimetype)
|
81
|
-
|
82
|
-
title ||= basename
|
83
|
-
|
84
|
-
raise DeweyException, "Invalid file type: #{extension}" unless Dewey::Validation.valid_upload_format?(extension, service)
|
85
|
-
|
86
|
-
headers = base_headers
|
87
|
-
headers['Content-Length'] = File.size?(file).to_s
|
88
|
-
headers['Slug'] = Dewey::Utils.escape(title)
|
89
|
-
headers['Content-Type'] = mimetype unless mimetype =~ /Can't expand summary_info/
|
90
|
-
|
91
|
-
# Rewind the file in the case of multiple uploads, or conversions
|
92
|
-
file.rewind
|
93
|
-
|
94
|
-
response = post_request(GOOGLE_FEED_URL, file.read.to_s, headers)
|
95
|
-
|
96
|
-
case response
|
97
|
-
when Net::HTTPCreated
|
98
|
-
extract_rid(response.body)
|
99
|
-
else
|
100
|
-
nil
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
alias :upload :put
|
105
|
-
|
106
|
-
# Download, or export more accurately, a file to a specified format
|
107
|
-
# * rid - A resource id, for example +document:12345+
|
108
|
-
# * format - The output format, see *_EXPORT_FORMATS for possiblibilites
|
109
|
-
def get(rid, format = nil)
|
110
|
-
authorize! unless authorized?
|
111
|
-
|
112
|
-
spreadsheet = !! rid.match(/^spreadsheet/)
|
113
|
-
id = rid.sub(/[a-z]+:/, '')
|
114
|
-
|
115
|
-
url = ''
|
116
|
-
url << (spreadsheet ? GOOGLE_SPREADSHEET_URL : GOOGLE_DOCUMENT_URL)
|
117
|
-
url << (spreadsheet ? "?key=#{id}" : "?docID=#{id}")
|
118
|
-
url << "&exportFormat=#{format.to_s}" unless format.nil?
|
119
|
-
|
120
|
-
headers = base_headers
|
121
|
-
|
122
|
-
file = Tempfile.new([rid, format].join('.'))
|
123
|
-
file.binmode
|
124
|
-
|
125
|
-
open(url, headers) { |data| file.write data.read }
|
126
|
-
|
127
|
-
file
|
128
|
-
end
|
129
|
-
|
130
|
-
alias :download :get
|
131
|
-
|
132
|
-
# Deletes a document referenced either by resource id or by name.
|
133
|
-
# * id - A resource id or exact file name matching a document in the account
|
134
|
-
def delete(id)
|
135
|
-
authorize! unless authorized?
|
136
|
-
|
137
|
-
headers = base_headers
|
138
|
-
headers['If-Match'] = '*' # We don't care if others have modified
|
139
|
-
|
140
|
-
url = GOOGLE_FEED_URL + "/#{Dewey::Utils.escape(id)}?delete=true"
|
141
|
-
response = delete_request(url, headers)
|
142
|
-
|
143
|
-
case response
|
144
|
-
when Net::HTTPOK
|
145
|
-
true
|
146
|
-
else
|
147
|
-
false
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# Convenience method for +upload+, +download+, +delete+. Returns a Tempfile
|
152
|
-
# with in the provided type.
|
153
|
-
# * file - The file that will be converted
|
154
|
-
# * options - Takes :title and :format. See +upload+ for title, and +download+
|
155
|
-
# for format.
|
156
|
-
def convert(file, options = {})
|
157
|
-
rid = upload(file, options[:title])
|
158
|
-
con = download(rid, options[:format])
|
159
|
-
|
160
|
-
delete(rid)
|
161
|
-
|
162
|
-
con
|
163
|
-
end
|
164
|
-
|
165
|
-
private
|
166
|
-
|
167
|
-
def post_request(url, data, headers) #:nodoc:
|
168
|
-
http_request(:post, url, headers, data)
|
169
|
-
end
|
170
|
-
|
171
|
-
def delete_request(url, headers) #:nodoc:
|
172
|
-
http_request(:delete, url, headers)
|
173
|
-
end
|
174
|
-
|
175
|
-
def http_request(method, url, headers, data = nil) #:nodoc:
|
176
|
-
url = URI.parse(url) if url.kind_of? String
|
10
|
+
class DeweyException < Exception; end
|
11
|
+
class DeweyAuthorizationException < Exception; end
|
12
|
+
end
|
177
13
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
else
|
186
|
-
raise DeweyException, "Invalid request type. Valid options are :post and :delete"
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def base_headers #:nodoc:
|
191
|
-
base = {}
|
192
|
-
base['GData-Version'] = '3.0'
|
193
|
-
base['Content-Type'] = 'application/x-www-form-urlencoded'
|
194
|
-
base['Authorization'] = "GoogleLogin auth=#{@token}" if authorized?
|
195
|
-
|
196
|
-
base
|
197
|
-
end
|
198
|
-
|
199
|
-
def extract_rid(response) #:nodoc:
|
200
|
-
xml = REXML::Document.new(response)
|
201
|
-
|
202
|
-
begin
|
203
|
-
"#{$1}:#{$2}" if xml.elements['//id'].text =~ /.+(document|spreadsheet|presentation)%3A([0-9a-zA-Z_-]+)$/
|
204
|
-
rescue
|
205
|
-
raise DeweyException, "id could not be extracted from: #{response}"
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
14
|
+
require 'dewey/core'
|
15
|
+
require 'dewey/client_auth'
|
16
|
+
require 'dewey/https'
|
17
|
+
require 'dewey/mime'
|
18
|
+
require 'dewey/utils'
|
19
|
+
require 'dewey/validation'
|
20
|
+
require 'dewey/version'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Dewey
|
2
|
+
class ClientAuth
|
3
|
+
attr_reader :authentications
|
4
|
+
|
5
|
+
def initialize(email, password)
|
6
|
+
@email = email
|
7
|
+
@password = password
|
8
|
+
@authentications = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def authenticated?(service = nil)
|
12
|
+
if service
|
13
|
+
@authentications.has_key?(service)
|
14
|
+
else
|
15
|
+
@authentications.any?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def authenticate!(service = nil)
|
20
|
+
service ||= :writely
|
21
|
+
|
22
|
+
|
23
|
+
params = { 'accountType' => 'HOSTED_OR_GOOGLE',
|
24
|
+
'Email' => @email,
|
25
|
+
'Passwd' => @password,
|
26
|
+
'service' => service.to_s
|
27
|
+
}
|
28
|
+
|
29
|
+
url = URI.parse(Dewey::GOOGLE_LOGIN_URL)
|
30
|
+
response = Net::HTTPS.post_form(url, params)
|
31
|
+
|
32
|
+
case response
|
33
|
+
when Net::HTTPSuccess
|
34
|
+
@authentications[service] = response.body.split('=').last
|
35
|
+
true
|
36
|
+
when Net::HTTPForbidden
|
37
|
+
false
|
38
|
+
else
|
39
|
+
raise DeweyAuthorizationException, "Unexpected response: #{response}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def token(service = nil)
|
44
|
+
@authentications[service || :writely]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
data/lib/dewey/core.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/https'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
module Dewey
|
8
|
+
class << self
|
9
|
+
def authentication(strategy, options)
|
10
|
+
case strategy
|
11
|
+
when :client
|
12
|
+
@@authenticator = Dewey::ClientAuth.new(options[:email], options[:password])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def authenticated?
|
17
|
+
!@@authenticator.nil? && @@authenticator.authenticated?
|
18
|
+
end
|
19
|
+
|
20
|
+
def authenticate!
|
21
|
+
@@authenticator.authenticate!
|
22
|
+
end
|
23
|
+
|
24
|
+
# Upload a file to the account. A successful upload will return the resource
|
25
|
+
# id, which is useful for downloading the file without doing a title search.
|
26
|
+
# * file - A File reference
|
27
|
+
# * title - An alternative title, to be used instead of the filename
|
28
|
+
def put(file, title = nil)
|
29
|
+
authenticate! unless authenticated?
|
30
|
+
|
31
|
+
extension = File.extname(file.path).sub('.', '')
|
32
|
+
basename = File.basename(file.path, ".#{extension}")
|
33
|
+
mimetype = Dewey::Mime.mime_type(file)
|
34
|
+
service = Dewey::Mime.guess_service(mimetype)
|
35
|
+
|
36
|
+
title ||= basename
|
37
|
+
|
38
|
+
raise DeweyException, "Invalid file type: #{extension}" unless Dewey::Validation.valid_upload_format?(extension, service)
|
39
|
+
|
40
|
+
headers = base_headers
|
41
|
+
headers['Content-Length'] = File.size?(file).to_s
|
42
|
+
headers['Slug'] = Dewey::Utils.escape(title)
|
43
|
+
headers['Content-Type'] = mimetype unless mimetype =~ /Can't expand summary_info/
|
44
|
+
|
45
|
+
# Rewind the file in the case of multiple uploads, or conversions
|
46
|
+
file.rewind
|
47
|
+
|
48
|
+
response = post_request(GOOGLE_FEED_URL, file.read.to_s, headers)
|
49
|
+
|
50
|
+
case response
|
51
|
+
when Net::HTTPCreated
|
52
|
+
extract_rid(response.body)
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Download, or export more accurately, a file to a specified format
|
59
|
+
# * rid - A resource id, for example +document:12345+
|
60
|
+
# * format - The output format, see *_EXPORT_FORMATS for possiblibilites
|
61
|
+
def get(rid, format = nil)
|
62
|
+
authenticate! unless authenticated?
|
63
|
+
|
64
|
+
spreadsheet = !! rid.match(/^spreadsheet/)
|
65
|
+
id = rid.sub(/[a-z]+:/, '')
|
66
|
+
|
67
|
+
url = ''
|
68
|
+
url << (spreadsheet ? GOOGLE_SPREADSHEET_URL : GOOGLE_DOCUMENT_URL)
|
69
|
+
url << (spreadsheet ? "?key=#{id}" : "?docID=#{id}")
|
70
|
+
url << "&exportFormat=#{format.to_s}" unless format.nil?
|
71
|
+
|
72
|
+
headers = base_headers
|
73
|
+
|
74
|
+
file = Tempfile.new([rid, format].join('.'))
|
75
|
+
file.binmode
|
76
|
+
|
77
|
+
open(url, headers) { |data| file.write data.read }
|
78
|
+
|
79
|
+
file
|
80
|
+
end
|
81
|
+
|
82
|
+
# Deletes a document referenced either by resource id or by name.
|
83
|
+
# * id - A resource id or exact file name matching a document in the account
|
84
|
+
def delete(id)
|
85
|
+
authenticate! unless authenticated?
|
86
|
+
|
87
|
+
headers = base_headers
|
88
|
+
headers['If-Match'] = '*' # We don't care if others have modified
|
89
|
+
|
90
|
+
url = GOOGLE_FEED_URL + "/#{Dewey::Utils.escape(id)}?delete=true"
|
91
|
+
response = delete_request(url, headers)
|
92
|
+
|
93
|
+
case response
|
94
|
+
when Net::HTTPOK
|
95
|
+
true
|
96
|
+
else
|
97
|
+
false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Convenience method for +put+, +get+, +delete+. Returns a Tempfile
|
102
|
+
# with in the provided type. Note that if you omit the format option it will
|
103
|
+
# simply upload the file and return it.
|
104
|
+
# * file - The file that will be converted
|
105
|
+
# * options - Takes :title and :format. See +upload+ for title, and +download+
|
106
|
+
# for format.
|
107
|
+
def convert(file, options = {})
|
108
|
+
rid = put(file, options[:title])
|
109
|
+
con = get(rid, options[:format])
|
110
|
+
|
111
|
+
delete(rid)
|
112
|
+
|
113
|
+
con
|
114
|
+
end
|
115
|
+
|
116
|
+
def post_request(url, data, headers) #:nodoc:
|
117
|
+
http_request(:post, url, headers, data)
|
118
|
+
end
|
119
|
+
|
120
|
+
def delete_request(url, headers) #:nodoc:
|
121
|
+
http_request(:delete, url, headers)
|
122
|
+
end
|
123
|
+
|
124
|
+
def http_request(method, url, headers, data = nil) #:nodoc:
|
125
|
+
url = URI.parse(url) if url.kind_of? String
|
126
|
+
|
127
|
+
connection = (url.scheme == 'https') ? Net::HTTPS.new(url.host, url.port) : Net::HTTP.new(url.host, url.port)
|
128
|
+
|
129
|
+
case method
|
130
|
+
when :post
|
131
|
+
connection.post(url.path, data, headers)
|
132
|
+
when :delete
|
133
|
+
connection.delete(url.path, headers)
|
134
|
+
else
|
135
|
+
raise DeweyException, "Invalid request type. Valid options are :post and :delete"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def base_headers #:nodoc:
|
140
|
+
base = {}
|
141
|
+
base['GData-Version'] = '3.0'
|
142
|
+
base['Content-Type'] = 'application/x-www-form-urlencoded'
|
143
|
+
base['Authorization'] = "GoogleLogin auth=#{@@authenticator.token}" if authenticated?
|
144
|
+
|
145
|
+
base
|
146
|
+
end
|
147
|
+
|
148
|
+
def extract_rid(response) #:nodoc:
|
149
|
+
xml = REXML::Document.new(response)
|
150
|
+
|
151
|
+
begin
|
152
|
+
"#{$1}:#{$2}" if xml.elements['//id'].text =~ /.*(document|spreadsheet|presentation)%3A([0-9a-zA-Z_-]+)$/
|
153
|
+
rescue
|
154
|
+
raise DeweyException, "id could not be extracted from: #{response}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Parker Selbert
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-23 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -40,14 +40,16 @@ extensions: []
|
|
40
40
|
extra_rdoc_files: []
|
41
41
|
|
42
42
|
files:
|
43
|
+
- lib/dewey/client_auth.rb
|
44
|
+
- lib/dewey/core.rb
|
43
45
|
- lib/dewey/https.rb
|
44
46
|
- lib/dewey/mime.rb
|
45
47
|
- lib/dewey/utils.rb
|
46
48
|
- lib/dewey/validation.rb
|
49
|
+
- lib/dewey/version.rb
|
47
50
|
- lib/dewey.rb
|
48
51
|
- README.md
|
49
52
|
- CHANGELOG.md
|
50
|
-
- TODO.md
|
51
53
|
has_rdoc: true
|
52
54
|
homepage: http://github.com/sorentwo/dewey
|
53
55
|
licenses: []
|