paperclip-googledrive-new 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0fe5f090fad771e4faddaf9fe0115b56f9d81c91
4
+ data.tar.gz: 0a6f678018c2705defde95f0f4147f39a188d875
5
+ SHA512:
6
+ metadata.gz: e9ed10cf2bafe7502c1b6e59a9a375fffebf50a5400de3c4e80f1b74c2b9f27d8280679d8c525bc00b818d236221aeff742dda584a27d1b57e9f2aaa5985a2e6
7
+ data.tar.gz: 2dde2fa5c5e546b694e1d9af75f891a1b277c2678f17bad77af6a50b384d67ead11b5c674beb1bdb150e7ea709602619aa5bb28b22ea132f0c33b154ae8e2750
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ivan
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,103 @@
1
+ # PaperclipGoogledrive
2
+ [![Gem Version](https://badge.fury.io/rb/paperclip-googledrive.png)](http://badge.fury.io/rb/paperclip-googledrive)
3
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/evinsou/paperclip-googledrive)
4
+
5
+ PaperclipGoogledrive is a gem that extends paperclip storage for Google Drive. Works with Rails 3.x && RAILS 4x.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'paperclip-googledrive-new'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install paperclip-googledrive-new
20
+
21
+ ## Google Drive Setup
22
+
23
+ Google Drive is a free service for file storage files. In order to use this storage you have to create oauth 2.0 client in [Google APIs console](https://code.google.com/apis/console/) and authorize access to Google Drive account.
24
+
25
+ After creating your app, it will have an Client ID, Client Secret, Redirect URL. Get auth scope for drive [Google Drive scopes](https://developers.google.com/drive/scopes). You need these for the authorization Rake task:
26
+ ```
27
+ $ rake google_drive:authorize
28
+ ```
29
+ When you call this Rake task, it will ask you to provide the client id, client secret, redirect url and auth scope. Afterwards it will present you with an authorize url on Google Drive. Simply go to that url, authorize the app, then enter code from url in the console. The rake task will output valid ruby code which you can use to create a client.
30
+
31
+ ## Configuration
32
+
33
+ Example:
34
+ ```ruby
35
+ class Product < ActiveRecord::Base
36
+ has_attached_file :photo,
37
+ :storage => :google_drive,
38
+ :google_drive_credentials => "#{Rails.root}/config/google_drive.yml"
39
+ end
40
+ ```
41
+ The `:google_drive_credentials` option
42
+
43
+ This can be a hash or path to a YAML file containing the keys listed in the example below. These are obtained from your Google Drive app settings and the authorization Rake task.
44
+
45
+ Example `config/google_drive.yml`:
46
+ ```erb
47
+ client_id: <%= ENV["CLIENT_ID"] %>
48
+ client_secret: <%= ENV["CLIENT_SECRET"] %>
49
+ access_token: <%= ENV["ACCESS_TOKEN"] %>
50
+ refresh_token: <%= ENV["REFRESH_TOKEN"] %>
51
+ ```
52
+ It is good practice to not include the credentials directly in the YAML file. Instead you can set them in environment variables and embed them with ERB.
53
+
54
+ ## Options
55
+
56
+ The `:google_drive_options` option
57
+
58
+ This is a hash containing any of the following options:
59
+ - `:path` – block, works similarly to Paperclip's `:path` option
60
+ - `:public_folder_id`- id of folder that must be created in google drive and set public permessions on it
61
+ - `:default_image` - an image in Public folder that used for attachemnts if attachement is not present
62
+
63
+ The :path option should be a block that returns a path that the uploaded file should be saved to. The block yields the attachment style and is executed in the scope of the model instance. For example:
64
+ ```ruby
65
+ class Product < ActiveRecord::Base
66
+ has_attached_file :photo,
67
+ :storage => :google_drive,
68
+ :google_drive_credentials => "#{Rails.root}/config/google_drive.yml",
69
+ :styles => { :medium => "300x300" },
70
+ :google_drive_options => {
71
+ :path => proc { |style| "#{style}_#{id}_#{photo.original_filename}" }
72
+ }
73
+ end
74
+ ```
75
+ For example, a new product is created with the ID of 14, and a some_photo.jpg as its photo. The following files would be saved to the Google Drive:
76
+
77
+ Public/14_some_photo.jpg
78
+ Public/14_some_photo_medium.jpg
79
+
80
+ The another file is called some_photo_medium.jpg because style names (other than original) will always be appended to the filenames, for better management.
81
+
82
+ ## Misc
83
+
84
+ Useful links
85
+ [Google APIs console](https://code.google.com/apis/console/)
86
+
87
+ [Google Drive scopes](https://developers.google.com/drive/scopes)
88
+
89
+ [Enable the Drive API and SDK](https://developers.google.com/drive/enable-sdk)
90
+
91
+ [Quickstart](https://developers.google.com/drive/quickstart-ruby#step_1_enable_the_drive_api)
92
+
93
+ ## License
94
+
95
+ [MIT License](https://github.com/shoaibmalik786/paperclip-googledrive-new/blob/master/LICENSE)
96
+
97
+ ## Contributing
98
+
99
+ 1. Fork it
100
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
101
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
102
+ 4. Push to the branch (`git push origin my-new-feature`)
103
+ 5. Create new Pull Request
@@ -0,0 +1,3 @@
1
+
2
+ require 'paperclip'
3
+ require 'paperclip/google_drive'
@@ -0,0 +1,2 @@
1
+ require "paperclip/storage/google_drive"
2
+ require "paperclip/google_drive/railtie" if defined?(Rails)
@@ -0,0 +1,10 @@
1
+
2
+ module Paperclip
3
+ module GoogleDrive
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load "paperclip/google_drive/tasks.rake"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,51 @@
1
+
2
+ require 'google/api_client'
3
+
4
+ module Paperclip
5
+ module GoogleDrive
6
+ module Rake
7
+ extend self
8
+
9
+ def authorize
10
+ puts 'Enter client ID:'
11
+ client_id = $stdin.gets.chomp
12
+ puts 'Enter client SECRET:'
13
+ client_secret = $stdin.gets.chomp.strip
14
+ # puts 'Enter SCOPE:'
15
+ # oauth_scope = $stdin.gets.chomp.strip
16
+ oauth_scope = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/userinfo.profile']
17
+ puts 'Enter redirect URI:'
18
+ redirect_uri = $stdin.gets.chomp.strip
19
+
20
+ # Create a new API client & load the Google Drive API
21
+ client = Google::APIClient.new(:application_name => 'ppc-gd', :application_version => PaperclipGoogleDrive::VERSION)
22
+ drive = client.discovered_api('drive', 'v2')
23
+
24
+ client.authorization.client_id = client_id
25
+ client.authorization.client_secret = client_secret
26
+ client.authorization.scope = oauth_scope
27
+ client.authorization.redirect_uri = redirect_uri
28
+
29
+ # Request authorization
30
+ uri = client.authorization.authorization_uri.to_s
31
+ puts "\nGo to this url:"
32
+ puts client.authorization.authorization_uri.to_s
33
+ puts "\n Accept the authorization request from Google in your browser"
34
+
35
+ puts "\n\n\n Google will redirect you to localhost, but just copy the code parameter out of the URL they redirect you to, paste it here and hit enter:\n"
36
+
37
+ code = $stdin.gets.chomp.strip
38
+ client.authorization.code = code
39
+ client.authorization.fetch_access_token!
40
+
41
+ puts "\nAuthorization completed.\n\n"
42
+ puts "client = Google::APIClient.new"
43
+ puts "client.authorization.client_id = '#{client_id}'"
44
+ puts "client.authorization.client_secret = '#{client_secret}'"
45
+ puts "client.authorization.access_token = '#{client.authorization.access_token}'"
46
+ puts "client.authorization.refresh_token = '#{client.authorization.refresh_token}'"
47
+ puts "\n"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+
2
+ require "paperclip/google_drive/rake"
3
+
4
+ namespace :google_drive do
5
+ desc "Authorize Google Drive account: "
6
+ task :authorize do
7
+ Paperclip::GoogleDrive::Rake.authorize
8
+ end
9
+ end
10
+
@@ -0,0 +1,256 @@
1
+
2
+ require 'active_support/core_ext/hash/keys'
3
+ require 'active_support/inflector/methods'
4
+ require 'active_support/core_ext/object/blank'
5
+ require 'yaml'
6
+ require 'erb'
7
+ require 'google/api_client'
8
+
9
+ module Paperclip
10
+
11
+ module Storage
12
+ # * self.extended(base) add instance variable to attachment on call
13
+ # * url return url to show on site with style options
14
+ # * path(style) return title that used to insert file to store or find it in store
15
+ # * public_url_for title return url to file if find by title or url to default image if set
16
+ # * search_for_title(title) take title, search in given folder and if it finds a file, return id of a file or nil
17
+ # * metadata_by_id(file_i get file metadata from store, used to back url or find out value of trashed
18
+ # * exists?(style) check either exists file with title or not
19
+ # * default_image return url to default url if set in option
20
+ # * find_public_folder return id of Public folder, must be in options
21
+ # return id of Public folder, must be in options
22
+ # * file_tit return base pattern of title or custom one set by user
23
+ # * parse_credentials(credenti get credentials from file, hash or path
24
+ # * assert_required_keys check either all ccredentials keys is set
25
+ # * original_extension return extension of file
26
+
27
+ module GoogleDrive
28
+
29
+ def self.extended(base)
30
+ begin
31
+ require 'google-api-client'
32
+ rescue LoadError => e
33
+ e.message << " (You may need to install the google-api-client gem)"
34
+ raise e
35
+ end unless defined?(Google)
36
+
37
+ base.instance_eval do
38
+ @google_drive_credentials = parse_credentials(@options[:google_drive_credentials] || {})
39
+ @google_drive_options = @options[:google_drive_options] || {}
40
+ google_api_client # Force validations of credentials
41
+ end
42
+ end
43
+ #
44
+ def flush_writes
45
+ @queued_for_write.each do |style, file|
46
+ if exists?(path(style))
47
+ raise FileExists, "file \"#{path(style)}\" already exists in your Google Drive"
48
+ else
49
+ #upload(style, file) #style file
50
+ client = google_api_client
51
+ drive = client.discovered_api('drive', 'v2')
52
+ result = client.execute(
53
+ :api_method => drive.files.get,
54
+ :parameters => { 'fileId' => @google_drive_options[:public_folder_id],
55
+ 'fields' => ' id, title' })
56
+ client.authorization.access_token = result.request.authorization.access_token
57
+ client.authorization.refresh_token = result.request.authorization.refresh_token
58
+ title, mime_type = title_for_file(style), "#{content_type}"
59
+ parent_id = @google_drive_options[:public_folder_id] # folder_id for Public folder
60
+ metadata = drive.files.insert.request_schema.new({
61
+ 'title' => title, #if it is no extension, that is a folder and another folder
62
+ 'description' => 'paperclip file on google drive',
63
+ 'mimeType' => mime_type })
64
+ if parent_id
65
+ metadata.parents = [{'id' => parent_id}]
66
+ end
67
+ media = Google::APIClient::UploadIO.new( file, mime_type)
68
+ result = client.execute(
69
+ :api_method => drive.files.insert,
70
+ :body_object => metadata,
71
+ :media => media,
72
+ :parameters => {
73
+ 'uploadType' => 'multipart',
74
+ 'alt' => 'json' })
75
+ end
76
+ end
77
+ after_flush_writes
78
+ @queued_for_write = {}
79
+ end
80
+ #
81
+ def flush_deletes
82
+ @queued_for_delete.each do |path|
83
+ Paperclip.log("delete #{path}")
84
+ client = google_api_client
85
+ drive = client.discovered_api('drive', 'v2')
86
+ file_id = search_for_title(path)
87
+ unless file_id.nil?
88
+ folder_id = find_public_folder
89
+ parameters = {'fileId' => file_id,
90
+ 'folder_id' => folder_id }
91
+ result = client.execute(
92
+ :api_method => drive.files.delete,
93
+ :parameters => parameters)
94
+ if result.status != 200
95
+ puts "An error occurred: #{result.data['error']['message']}"
96
+ end
97
+ end
98
+ end
99
+ @queued_for_delete = []
100
+ end
101
+ #
102
+ def google_api_client
103
+ @google_api_client ||= begin
104
+ assert_required_keys
105
+ # Initialize the client & Google+ API
106
+ client = Google::APIClient.new(:application_name => 'ppc-gd', :application_version => PaperclipGoogleDrive::VERSION)
107
+ # client = Google::APIClient.new(:application_name => @google_drive_credentials[:application_name], :application_version => @google_drive_credentials[:application_version])
108
+ client.authorization.client_id = @google_drive_credentials[:client_id]
109
+ client.authorization.client_secret = @google_drive_credentials[:client_secret]
110
+ client.authorization.access_token = @google_drive_credentials[:access_token]
111
+ client.authorization.refresh_token = @google_drive_credentials[:refresh_token]
112
+ client
113
+ end
114
+ end
115
+ #
116
+ def google_drive
117
+ client = google_api_client
118
+ drive = client.discovered_api('drive', 'v2')
119
+ drive
120
+ end
121
+
122
+ def url(*args)
123
+ if present?
124
+ style = args.first.is_a?(Symbol) ? args.first : default_style
125
+ options = args.last.is_a?(Hash) ? args.last : {}
126
+ public_url_for(path(style))
127
+ else
128
+ default_image
129
+ end
130
+ end
131
+
132
+ def path(style)
133
+ title_for_file(style)
134
+ end
135
+
136
+ def title_for_file(style)
137
+ file_name = instance.instance_exec(style, &file_title)
138
+ style_suffix = (style != default_style ? "_#{style}" : "")
139
+ if original_extension.present? && file_name =~ /#{original_extension}$/
140
+ file_name.sub(original_extension, "#{style_suffix}#{original_extension}")
141
+ else
142
+ file_name + style_suffix + original_extension.to_s
143
+ end
144
+ end # full title
145
+
146
+ def public_url_for title
147
+ searched_id = search_for_title(title) #return id if any or style
148
+ if searched_id.nil? # it finds some file
149
+ default_image
150
+ else
151
+ metadata = metadata_by_id(searched_id)
152
+ metadata['webContentLink']
153
+ end
154
+ end # url
155
+ # take title, search in given folder and if it finds a file, return id of a file or nil
156
+ def search_for_title(title)
157
+ parameters = {
158
+ 'folderId' => find_public_folder,
159
+ 'q' => "title contains '#{title}'", # full_title
160
+ 'fields' => 'items/id'}
161
+ client = google_api_client
162
+ drive = client.discovered_api('drive', 'v2')
163
+ result = client.execute(:api_method => drive.children.list,
164
+ :parameters => parameters)
165
+ if result.status == 200
166
+ if result.data.items.length > 0
167
+ result.data.items[0]['id']
168
+ elsif result.data.items.length == 0
169
+ nil
170
+ else
171
+ nil
172
+ end
173
+ end
174
+ end # id or nil
175
+
176
+ def metadata_by_id(file_id)
177
+ if file_id.is_a? String
178
+ client = google_api_client
179
+ drive = client.discovered_api('drive', 'v2')
180
+ result = client.execute(
181
+ :api_method => drive.files.get,
182
+ :parameters => {'fileId' => file_id,
183
+ 'fields' => 'title, id, webContentLink, labels/trashed' })
184
+ if result.status == 200
185
+ result.data # data.class # => Hash
186
+ end
187
+ end
188
+ end
189
+
190
+ def exists?(style = default_style)
191
+ return false if not present?
192
+ result_id = search_for_title(path(style))
193
+ if result_id.nil?
194
+ false
195
+ else
196
+ data_hash = metadata_by_id(result_id)
197
+ !data_hash['labels']['trashed'] # if trashed -> not exists
198
+ end
199
+ end
200
+
201
+ def default_image
202
+ if @google_drive_options[:default_url] #if default image is set
203
+ title = @google_drive_options[:default_url]
204
+ searched_id = search_for_title(title) # id
205
+ metadata = metadata_by_id(searched_id) unless searched_id.nil?
206
+ metadata['webContentLink']
207
+ else
208
+ 'No picture' # ---- ?
209
+ end
210
+ end
211
+
212
+ def find_public_folder
213
+ unless @google_drive_options[:public_folder_id]
214
+ raise KeyError, "you must set a Public folder if into options"
215
+ end
216
+ @google_drive_options[:public_folder_id]
217
+ end
218
+ class FileExists < ArgumentError
219
+ end
220
+ private
221
+
222
+ def file_title
223
+ return @google_drive_options[:path] if @google_drive_options[:path] #path: proc
224
+ eval %(proc { |style| "\#{id}_\#{#{name}.original_filename}"})
225
+ end
226
+
227
+ def parse_credentials(credentials)
228
+ result =
229
+ case credentials
230
+ when File
231
+ YAML.load(ERB.new(File.read(credentials.path)).result)
232
+ when String, Pathname
233
+ YAML.load(ERB.new(File.read(credentials)).result)
234
+ when Hash
235
+ credentials
236
+ else
237
+ raise ArgumentError, ":google_drive_credentials are not a path, file, nor a hash"
238
+ end
239
+ result.symbolize_keys #or string keys
240
+ end
241
+ # check either all ccredentials keys is set
242
+ def assert_required_keys
243
+ keys_list = [:client_id, :client_secret, :access_token, :refresh_token]
244
+ keys_list.each do |key|
245
+ @google_drive_credentials.fetch(key)
246
+ end
247
+ end
248
+ # return extension of file
249
+ def original_extension
250
+ File.extname(original_filename)
251
+ end
252
+ end
253
+
254
+ end
255
+
256
+ end
@@ -0,0 +1,3 @@
1
+ module PaperclipGoogleDrive
2
+ VERSION = "1.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #require File.expand_path('../lib/paperclip_googledrive/version', __FILE__)
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require "paperclip/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "paperclip-googledrive-new"
8
+ spec.version = PaperclipGoogleDrive::VERSION
9
+ spec.authors = ['Shoaib Malik']
10
+ spec.email = ["shoaib2109@gmail.com"]
11
+
12
+ if spec.respond_to?(:metadata)
13
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
14
+ end
15
+
16
+ spec.summary = %q{Extends Paperclip with Google Drive storage with latest version of paperclip}
17
+ spec.description = %q{paperclip-googledrive-new extends paperclip support of storage for google drive storage}
18
+ spec.homepage = "https://github.com/shoaibmalik786/paperclip-googledrive-new"
19
+
20
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ spec.files = Dir["lib/**/*"] + ["README.md", "LICENSE", "paperclip-googledrive-new.gemspec"]
22
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+
24
+ spec.require_paths = ["lib"]
25
+ spec.required_ruby_version = ">= 2.0.0"
26
+ spec.license = "MIT"
27
+
28
+ spec.add_dependency "paperclip"
29
+ spec.add_dependency 'google-api-client', "~> 0.5"
30
+
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paperclip-googledrive-new
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Shoaib Malik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: paperclip
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-api-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: paperclip-googledrive-new extends paperclip support of storage for google
56
+ drive storage
57
+ email:
58
+ - shoaib2109@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE
64
+ - README.md
65
+ - lib/paperclip-googledrive-new.rb
66
+ - lib/paperclip/google_drive.rb
67
+ - lib/paperclip/google_drive/railtie.rb
68
+ - lib/paperclip/google_drive/rake.rb
69
+ - lib/paperclip/google_drive/tasks.rake
70
+ - lib/paperclip/storage/google_drive.rb
71
+ - lib/paperclip/version.rb
72
+ - paperclip-googledrive-new.gemspec
73
+ homepage: https://github.com/shoaibmalik786/paperclip-googledrive-new
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ allowed_push_host: https://rubygems.org
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 2.0.0
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.2.2
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Extends Paperclip with Google Drive storage with latest version of paperclip
98
+ test_files: []
99
+ has_rdoc: