dewey 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|