cloudinary 1.0.72 → 1.0.73

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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YmFlNDk5YjhhMmM0MmE0YTFhM2Y1MDVkMjAyOGYyMDc5ZDhmZWM4OA==
5
+ data.tar.gz: !binary |-
6
+ OTNlOTg2MTRkNzVkNTc5M2FiNWQwMmU0NTQyMDc4Yzc0OTQ0NjE3MQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NjdlMTRkOWNiNDQ2ZWE5NTJkZDc0ZmQwMTE0MGIyMjcxZTAzMTNjYjA5Mjhl
10
+ Mzk1NTdmNzI0ODg1OGM5YzUzNzNhOThiYTQ5ZDNjYmRlZWQwZTQwYTlkMzE0
11
+ YTRhMmI0MDFlMzc2NjI3OWQ5ZWVkMTlkZjRiZWM3ZDNhNTAwZDM=
12
+ data.tar.gz: !binary |-
13
+ ZmEwZGU0NzU3MTg2MWM4MWEwMDlmNTFmZTUxNDMzOWRhNTkxN2Q1YTE0YzNj
14
+ YTAxYzBiNDA2ZjQ4OTVkYjY1NTViNWE1YWZjYzM0N2NhMWQyZWEwZGUwMDY1
15
+ NGVkNjMyNTFhNWQ3ZDFkYjg2M2ZkNzJlNWMzNTk0MzM1Yzk0Yjg=
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ = Version 1.0.73 - 2014-06-30
2
+ * Support dpr transformation parameter.
3
+ * Support automatic dpr (for HiDPI) and automatic width (for responsive).
4
+ * Accept timestamp parameter in upload method options.
5
+ * Support pHash info in admin API.
6
+ * Support the multiple upload flag directly in cl_image_upload_tag.
7
+ * 'secure' configuration parameter from environment variable.
8
+ * Make api_key and api_secret optional in unsigned upload.
9
+ * Support the case Rails is defined but Rails.root isn't.
10
+
1
11
  = Version 1.0.72 - 2014-04-15
2
12
  * Fixing broken sign_request.
3
13
 
data/cloudinary.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency "rest-client"
24
24
  s.add_dependency "aws_cf_signer"
25
25
  s.add_development_dependency "rspec"
26
+ s.add_development_dependency "actionpack"
26
27
  end
data/lib/cloudinary.rb CHANGED
@@ -50,7 +50,8 @@ module Cloudinary
50
50
  "api_key" => ENV["CLOUDINARY_API_KEY"],
51
51
  "api_secret" => ENV["CLOUDINARY_API_SECRET"],
52
52
  "secure_distribution" => ENV["CLOUDINARY_SECURE_DISTRIBUTION"],
53
- "private_cdn" => ENV["CLOUDINARY_PRIVATE_CDN"].to_s == 'true'
53
+ "private_cdn" => ENV["CLOUDINARY_PRIVATE_CDN"].to_s == 'true',
54
+ "secure" => ENV["CLOUDINARY_SECURE"].to_s == 'true'
54
55
  )
55
56
  elsif first_time && ENV["CLOUDINARY_URL"]
56
57
  config_from_url(ENV["CLOUDINARY_URL"])
@@ -62,7 +62,7 @@ class Cloudinary::Api
62
62
  resource_type = options[:resource_type] || "image"
63
63
  type = options[:type] || "upload"
64
64
  uri = "resources/#{resource_type}/#{type}/#{public_id}"
65
- call_api(:get, uri, only(options, :colors, :exif, :faces, :image_metadata, :pages, :max_results), options)
65
+ call_api(:get, uri, only(options, :colors, :exif, :faces, :image_metadata, :pages, :phash, :max_results), options)
66
66
  end
67
67
 
68
68
  def self.update(public_id, options={})
@@ -1,8 +1,10 @@
1
1
  require 'digest/md5'
2
2
  module CloudinaryHelper
3
+ CL_BLANK = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
4
+
3
5
  # Stand-in for Rails image_tag helper that accepts various options for transformations.
4
6
  #
5
- # source:: the public ID, possibly with a file type extension. If there is no extension, the
7
+ # source:: the public ID, possibly with a file type extension. If there is no extension, the
6
8
  # :format option is expected to indicate what the extension is. This value can contain
7
9
  # the version, or not.
8
10
  # options:: Options you would normally pass to image_tag as well as Cloudinary-specific options
@@ -29,17 +31,33 @@ module CloudinaryHelper
29
31
  options[:height] = options.delete(:html_height) if options.include?(:html_height)
30
32
  options[:size] = options.delete(:html_size) if options.include?(:html_size)
31
33
  options[:border] = options.delete(:html_border) if options.include?(:html_border)
32
-
33
- image_tag_without_cloudinary(source, options)
34
+ responsive_placeholder = Cloudinary::Utils.config_option_consume(options, :responsive_placeholder)
35
+ hidpi = options.delete(:hidpi)
36
+ responsive = options.delete(:responsive)
37
+ if hidpi || responsive
38
+ options["data-src"] = source
39
+ extra_class = responsive ? "cld-responsive" : "cld-hidpi"
40
+ options[:class] = [options[:class], extra_class].compact.join(" ")
41
+ source = responsive_placeholder
42
+ end
43
+ if source
44
+ image_tag_without_cloudinary(source, options)
45
+ else
46
+ content_tag 'img', nil, options
47
+ end
34
48
  end
35
49
 
50
+ def cl_blank
51
+ CL_BLANK
52
+ end
53
+
36
54
  # Works similarly to cl_image_tag, however just generates the URL of the image
37
55
  def cl_image_path(source, options = {})
38
56
  options = options.clone
39
57
  url = cloudinary_url_internal(source, options)
40
- image_path_without_cloudinary(url)
58
+ image_path_without_cloudinary(url)
41
59
  end
42
-
60
+
43
61
  def image_tag_with_cloudinary(*args)
44
62
  source, options = args
45
63
  cl_image_tag(source, {:type=>:asset}.merge(options || {}))
@@ -50,61 +68,61 @@ module CloudinaryHelper
50
68
  cl_image_path(source, {:type=>:asset}.merge(options || {}))
51
69
  end
52
70
 
53
- def fetch_image_tag(profile, options = {})
71
+ def fetch_image_tag(profile, options = {})
54
72
  cl_image_tag(profile, {:type=>:fetch}.merge(options))
55
73
  end
56
-
57
- def facebook_profile_image_tag(profile, options = {})
74
+
75
+ def facebook_profile_image_tag(profile, options = {})
58
76
  cl_image_tag(profile, {:type=>:facebook}.merge(options))
59
77
  end
60
-
61
- def facebook_profile_image_path(profile, options = {})
78
+
79
+ def facebook_profile_image_path(profile, options = {})
62
80
  cl_image_path(profile, {:type=>:facebook}.merge(options))
63
81
  end
64
82
 
65
- def gravatar_profile_image_tag(email, options = {})
83
+ def gravatar_profile_image_tag(email, options = {})
66
84
  cl_image_tag(Digest::MD5.hexdigest(email.strip.downcase), {:type=>:gravatar, :format=>:jpg}.merge(options))
67
85
  end
68
-
69
- def gravatar_profile_image_path(email, options = {})
86
+
87
+ def gravatar_profile_image_path(email, options = {})
70
88
  cl_image_path(Digest::MD5.hexdigest(email.strip.downcase), {:type=>:gravatar, :format=>:jpg}.merge(options))
71
89
  end
72
90
 
73
- def twitter_profile_image_tag(profile, options = {})
91
+ def twitter_profile_image_tag(profile, options = {})
74
92
  cl_image_tag(profile, {:type=>:twitter}.merge(options))
75
93
  end
76
-
77
- def twitter_profile_image_path(profile, options = {})
94
+
95
+ def twitter_profile_image_path(profile, options = {})
78
96
  cl_image_path(profile, {:type=>:twitter}.merge(options))
79
97
  end
80
98
 
81
- def twitter_name_profile_image_tag(profile, options = {})
99
+ def twitter_name_profile_image_tag(profile, options = {})
82
100
  cl_image_tag(profile, {:type=>:twitter_name}.merge(options))
83
101
  end
84
-
85
- def twitter_name_profile_image_path(profile, options = {})
102
+
103
+ def twitter_name_profile_image_path(profile, options = {})
86
104
  cl_image_path(profile, {:type=>:twitter_name}.merge(options))
87
105
  end
88
-
89
- def gplus_profile_image_tag(profile, options = {})
106
+
107
+ def gplus_profile_image_tag(profile, options = {})
90
108
  cl_image_tag(profile, {:type=>:gplus}.merge(options))
91
109
  end
92
-
93
- def gplus_profile_image_path(profile, options = {})
110
+
111
+ def gplus_profile_image_path(profile, options = {})
94
112
  cl_image_path(profile, {:type=>:gplus}.merge(options))
95
113
  end
96
114
 
97
115
  def cl_sprite_url(source, options = {})
98
116
  options = options.clone
99
-
117
+
100
118
  version_store = options.delete(:version_store)
101
119
  if options[:version].blank? && (version_store == :file) && defined?(Rails) && defined?(Rails.root)
102
120
  file_name = "#{Rails.root}/tmp/cloudinary/cloudinary_sprite_#{source.sub(/\..*/, '')}.version"
103
121
  if File.exists?(file_name)
104
- options[:version] = File.read(file_name).chomp
122
+ options[:version] = File.read(file_name).chomp
105
123
  end
106
- end
107
-
124
+ end
125
+
108
126
  options[:format] = "css" unless source.ends_with?(".css")
109
127
  cloudinary_url_internal(source, options.merge(:type=>:sprite))
110
128
  end
@@ -118,23 +136,23 @@ module CloudinaryHelper
118
136
  form_options = options.delete(:form) || {}
119
137
  form_options[:method] = :post
120
138
  form_options[:multipart] = true
121
-
122
- params = Cloudinary::Uploader.build_upload_params(options.merge(:callback=>callback_url))
123
- params[:signature] = Cloudinary::Utils.api_sign_request(params, Cloudinary.config.api_secret)
139
+
140
+ params = Cloudinary::Uploader.build_upload_params(options.merge(:callback=>callback_url))
141
+ params[:signature] = Cloudinary::Utils.api_sign_request(params, Cloudinary.config.api_secret)
124
142
  params[:api_key] = Cloudinary.config.api_key
125
-
126
- api_url = Cloudinary::Utils.cloudinary_api_url("upload",
143
+
144
+ api_url = Cloudinary::Utils.cloudinary_api_url("upload",
127
145
  {:resource_type => options.delete(:resource_type), :upload_prefix => options.delete(:upload_prefix)})
128
146
 
129
147
  form_tag(api_url, form_options) do
130
148
  content = []
131
-
149
+
132
150
  params.each do |name, value|
133
151
  content << hidden_field_tag(name, value, :id => nil) if value.present?
134
152
  end
135
-
153
+
136
154
  content << capture(&block)
137
-
155
+
138
156
  content.join("\n").html_safe
139
157
  end
140
158
  end
@@ -143,29 +161,29 @@ module CloudinaryHelper
143
161
  def cloudinary_js_config
144
162
  params = {}
145
163
  CLOUDINARY_JS_CONFIG_PARAMS.each do
146
- |param|
164
+ |param|
147
165
  value = Cloudinary.config.send(param)
148
166
  params[param] = value if !value.nil?
149
- end
150
- content_tag("script", "$.cloudinary.config(#{params.to_json});".html_safe, :type=>"text/javascript")
167
+ end
168
+ content_tag("script", "$.cloudinary.config(#{params.to_json});".html_safe, :type=>"text/javascript")
151
169
  end
152
170
 
153
171
  def cloudinary_url(source, options = {})
154
172
  cloudinary_url_internal(source, options.clone)
155
173
  end
156
-
174
+
157
175
  def cl_image_upload(object_name, method, options={})
158
176
  cl_image_upload_tag("#{object_name}[#{method}]", options)
159
177
  end
160
-
178
+
161
179
  def cl_unsigned_image_upload(object_name, method, upload_preset, options={})
162
180
  cl_unsigned_image_upload_tag("#{object_name}[#{method}]", upload_preset, options)
163
181
  end
164
-
182
+
165
183
  def cl_upload_url(options={})
166
184
  Cloudinary::Utils.cloudinary_api_url("upload", {:resource_type=>:auto}.merge(options))
167
185
  end
168
-
186
+
169
187
  def cl_upload_tag_params(options={})
170
188
  cloudinary_params = Cloudinary::Uploader.build_upload_params(options)
171
189
  cloudinary_params[:callback] = build_callback_url(options)
@@ -175,23 +193,27 @@ module CloudinaryHelper
175
193
  return Cloudinary::Utils.sign_request(cloudinary_params, options).to_json
176
194
  end
177
195
  end
178
-
196
+
179
197
  def cl_image_upload_tag(field, options={})
180
- html_options = options.delete(:html) || {}
198
+ html_options = options.delete(:html) || {}
199
+ if options.delete(:multiple)
200
+ html_options[:multiple] = true
201
+ field = "#{ field }[]" unless field.to_s[-2..-1] == "[]"
202
+ end
181
203
 
182
- tag_options = html_options.merge(:type=>"file", :name=>"file",
204
+ tag_options = html_options.merge(:type=>"file", :name=>"file",
183
205
  :"data-url"=>cl_upload_url(options),
184
206
  :"data-form-data"=>cl_upload_tag_params(options),
185
207
  :"data-cloudinary-field"=>field,
186
- :"class" => [html_options[:class], "cloudinary-fileupload"].flatten.compact
208
+ :"class" => [html_options[:class], "cloudinary-fileupload"].flatten.compact
187
209
  ).reject{|k,v| v.blank?}
188
210
  content_tag("input", nil, tag_options)
189
211
  end
190
-
212
+
191
213
  def cl_unsigned_image_upload_tag(field, upload_preset, options={})
192
214
  cl_image_upload_tag(field, options.merge(:unsigned => true, :upload_preset => upload_preset))
193
215
  end
194
-
216
+
195
217
  def cl_private_download_url(public_id, format, options = {})
196
218
  Cloudinary::Utils.private_download_url(public_id, format, options)
197
219
  end
@@ -203,7 +225,7 @@ module CloudinaryHelper
203
225
  def cl_signed_download_url(public_id, options = {})
204
226
  Cloudinary::Utils.signed_download_url(public_id, options)
205
227
  end
206
-
228
+
207
229
  def self.included(base)
208
230
  ActionView::Helpers::FormBuilder.send(:include, Cloudinary::FormBuilder)
209
231
  base.class_eval do
@@ -219,22 +241,22 @@ module CloudinaryHelper
219
241
  end
220
242
  end
221
243
  end
222
-
244
+
223
245
  private
224
246
  def cloudinary_url_internal(source, options = {})
225
247
  options[:ssl_detected] = request.ssl? if defined?(request) && request && request.respond_to?(:ssl?)
226
- if defined?(CarrierWave::Uploader::Base) && source.is_a?(CarrierWave::Uploader::Base)
248
+ if defined?(CarrierWave::Uploader::Base) && source.is_a?(CarrierWave::Uploader::Base)
227
249
  if source.version_name.present?
228
- options[:transformation] = Cloudinary::Utils.build_array(source.transformation) + Cloudinary::Utils.build_array(options[:transformation])
229
- end
230
- options.reverse_merge!(
250
+ options[:transformation] = Cloudinary::Utils.build_array(source.transformation) + Cloudinary::Utils.build_array(options[:transformation])
251
+ end
252
+ options.reverse_merge!(
231
253
  :resource_type => Cloudinary::Utils.resource_type_for_format(source.filename || source.format),
232
254
  :type => source.storage_type,
233
255
  :format => source.format)
234
- source = source.full_public_id
256
+ source = source.full_public_id
235
257
  end
236
258
  Cloudinary::Utils.cloudinary_url(source, options)
237
- end
259
+ end
238
260
 
239
261
  def build_callback_url(options)
240
262
  callback_path = options.delete(:callback_cors) || Cloudinary.config.callback_cors || "/cloudinary_cors.html"
@@ -248,7 +270,7 @@ module CloudinaryHelper
248
270
  callback_url << callback_path
249
271
  end
250
272
  callback_url
251
- end
273
+ end
252
274
  end
253
275
 
254
276
  module Cloudinary::FormBuilder
@@ -263,14 +285,14 @@ end
263
285
  if defined? ActionView::Helpers::AssetUrlHelper
264
286
  module ActionView::Helpers::AssetUrlHelper
265
287
  alias :original_path_to_asset :path_to_asset
266
-
288
+
267
289
  def path_to_asset(source, options={})
268
290
  options ||= {}
269
291
  if Cloudinary.config.enhance_image_tag && options[:type] == :image
270
292
  source = Cloudinary::Utils.cloudinary_url(source, options.merge(:type=>:asset))
271
293
  end
272
294
  original_path_to_asset(source, options)
273
- end
295
+ end
274
296
  end
275
297
  end
276
298
 
@@ -289,10 +311,10 @@ begin
289
311
  original_image_path(Cloudinary::Utils.cloudinary_url(img, :type=>:asset))
290
312
  else
291
313
  original_image_path(img)
292
- end
293
- end
314
+ end
315
+ end
294
316
  end
295
- end
317
+ end
296
318
  rescue LoadError
297
319
  # no sass rails support. Ignore.
298
320
  end
@@ -305,11 +327,11 @@ begin
305
327
  options = {}
306
328
  sass_options.each{|k, v| options[k.to_sym] = v.value}
307
329
  url = Cloudinary::Utils.cloudinary_url(public_id.value, {:type=>:asset}.merge(options))
308
- Sass::Script::String.new("url(#{url})")
330
+ Sass::Script::String.new("url(#{url})")
309
331
  end
310
332
  declare :cloudinary_url, [:string], :var_kwargs => true
311
333
  end
312
334
  rescue LoadError
313
335
  # no sass support. Ignore.
314
336
  end
315
-
337
+
@@ -34,7 +34,7 @@ class Cloudinary::Static
34
34
  end
35
35
 
36
36
  def self.root
37
- defined?(Rails) ? Rails.root : Pathname.new(".")
37
+ (defined?(Rails) && Rails.root) || Pathname.new(".")
38
38
  end
39
39
 
40
40
  def self.metadata_file_path
@@ -19,10 +19,10 @@ class Cloudinary::Uploader
19
19
  options = options.clone
20
20
  options.keys.each{|key| options[key.to_sym] = options.delete(key) if key.is_a?(String)}
21
21
 
22
- params = {:timestamp=>Time.now.to_i,
22
+ params = {:timestamp=>(options[:timestamp] || Time.now.to_i),
23
23
  :transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
24
- :public_id=> options[:public_id],
25
- :callback=> options[:callback],
24
+ :public_id=>options[:public_id],
25
+ :callback=>options[:callback],
26
26
  :format=>options[:format],
27
27
  :type=>options[:type],
28
28
  :backup=>Cloudinary::Utils.as_safe_bool(options[:backup]),
@@ -108,7 +108,7 @@ class Cloudinary::Uploader
108
108
  def self.upload_large_part(file, options={})
109
109
  call_api("upload_large", options.merge(:resource_type=>:raw)) do
110
110
  params = {
111
- :timestamp=>Time.now.to_i,
111
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
112
112
  :type=>options[:type],
113
113
  :public_id=>options[:public_id],
114
114
  :backup=>options[:backup],
@@ -128,7 +128,7 @@ class Cloudinary::Uploader
128
128
  def self.destroy(public_id, options={})
129
129
  call_api("destroy", options) do
130
130
  {
131
- :timestamp=>Time.now.to_i,
131
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
132
132
  :type=>options[:type],
133
133
  :public_id=> public_id,
134
134
  :invalidate=>options[:invalidate],
@@ -139,7 +139,7 @@ class Cloudinary::Uploader
139
139
  def self.rename(from_public_id, to_public_id, options={})
140
140
  call_api("rename", options) do
141
141
  {
142
- :timestamp=>Time.now.to_i,
142
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
143
143
  :type=>options[:type],
144
144
  :overwrite=>options[:overwrite],
145
145
  :from_public_id=>from_public_id,
@@ -161,7 +161,7 @@ class Cloudinary::Uploader
161
161
  def self.explicit(public_id, options={})
162
162
  call_api("explicit", options) do
163
163
  {
164
- :timestamp=>Time.now.to_i,
164
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
165
165
  :type=>options[:type],
166
166
  :public_id=> public_id,
167
167
  :callback=> options[:callback],
@@ -187,7 +187,7 @@ class Cloudinary::Uploader
187
187
 
188
188
  result = call_api("sprite", options) do
189
189
  {
190
- :timestamp=>Time.now.to_i,
190
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
191
191
  :tag=>tag,
192
192
  :async=>options[:async],
193
193
  :notification_url=>options[:notification_url],
@@ -207,7 +207,7 @@ class Cloudinary::Uploader
207
207
  def self.multi(tag, options={})
208
208
  call_api("multi", options) do
209
209
  {
210
- :timestamp=>Time.now.to_i,
210
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
211
211
  :tag=>tag,
212
212
  :format=>options[:format],
213
213
  :async=>options[:async],
@@ -220,7 +220,7 @@ class Cloudinary::Uploader
220
220
  def self.explode(public_id, options={})
221
221
  call_api("explode", options) do
222
222
  {
223
- :timestamp=>Time.now.to_i,
223
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
224
224
  :public_id=>public_id,
225
225
  :type=>options[:type],
226
226
  :format=>options[:format],
@@ -250,7 +250,7 @@ class Cloudinary::Uploader
250
250
  def self.call_tags_api(tag, command, public_ids = [], options = {})
251
251
  return call_api("tags", options) do
252
252
  {
253
- :timestamp=>Time.now.to_i,
253
+ :timestamp=>(options[:timestamp] || Time.now.to_i),
254
254
  :tag=>tag,
255
255
  :public_ids => Cloudinary::Utils.build_array(public_ids),
256
256
  :command => command,
@@ -262,13 +262,13 @@ class Cloudinary::Uploader
262
262
  def self.call_api(action, options)
263
263
  options = options.clone
264
264
  return_error = options.delete(:return_error)
265
- api_key = options[:api_key] || Cloudinary.config.api_key || raise(CloudinaryException, "Must supply api_key")
266
- api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
267
265
 
268
266
  params, non_signable = yield
269
267
  non_signable ||= []
270
268
 
271
269
  unless options[:unsigned]
270
+ api_key = options[:api_key] || Cloudinary.config.api_key || raise(CloudinaryException, "Must supply api_key")
271
+ api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
272
272
  params[:signature] = Cloudinary::Utils.api_sign_request(params.reject{|k,v| non_signable.include?(k)}, api_secret)
273
273
  params[:api_key] = api_key
274
274
  end
@@ -7,6 +7,7 @@ require 'aws_cf_signer'
7
7
  class Cloudinary::Utils
8
8
  # @deprecated Use Cloudinary::SHARED_CDN
9
9
  SHARED_CDN = Cloudinary::SHARED_CDN
10
+ DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION = {:width => :auto, :crop => :limit}
10
11
 
11
12
  # Warning: options are being destructively updated!
12
13
  def self.generate_transformation_string(options={})
@@ -18,9 +19,11 @@ class Cloudinary::Utils
18
19
  options[key.to_sym] = options.delete(key) if key.is_a?(String)
19
20
  end
20
21
 
22
+ responsive_width = config_option_consume(options, :responsive_width)
21
23
  size = options.delete(:size)
22
24
  options[:width], options[:height] = size.split("x") if size
23
25
  width = options[:width]
26
+ width = width.to_s if width.is_a?(Symbol)
24
27
  height = options[:height]
25
28
  has_layer = !options[:overlay].blank? || !options[:underlay].blank?
26
29
 
@@ -28,10 +31,10 @@ class Cloudinary::Utils
28
31
  angle = build_array(options.delete(:angle)).join(".")
29
32
 
30
33
  no_html_sizes = has_layer || !angle.blank? || crop.to_s == "fit" || crop.to_s == "limit" || crop.to_s == "lfill"
31
- options.delete(:width) if width && (width.to_f < 1 || no_html_sizes)
32
- options.delete(:height) if height && (height.to_f < 1 || no_html_sizes)
34
+ options.delete(:width) if width && (width.to_f < 1 || no_html_sizes || width == "auto" || responsive_width)
35
+ options.delete(:height) if height && (height.to_f < 1 || no_html_sizes || responsive_width)
33
36
 
34
- width=height=nil if crop.nil? && !has_layer
37
+ width=height=nil if crop.nil? && !has_layer && width != "auto"
35
38
 
36
39
  background = options.delete(:background)
37
40
  background = background.sub(/^#/, 'rgb:') if background
@@ -61,8 +64,9 @@ class Cloudinary::Utils
61
64
  border = nil
62
65
  end
63
66
  flags = build_array(options.delete(:flags)).join(".")
67
+ dpr = config_option_consume(options, :dpr)
64
68
 
65
- params = {:w=>width, :h=>height, :t=>named_transformation, :c=>crop, :b=>background, :e=>effect, :a=>angle, :bo=>border, :fl=>flags, :co=>color}
69
+ params = {:w=>width, :h=>height, :t=>named_transformation, :c=>crop, :b=>background, :e=>effect, :a=>angle, :bo=>border, :fl=>flags, :co=>color, :dpr=>dpr}
66
70
  { :x=>:x, :y=>:y, :r=>:radius, :d=>:default_image, :g=>:gravity, :q=>:quality, :cs=>:color_space, :o=>:opacity,
67
71
  :p=>:prefix, :l=>:overlay, :u=>:underlay, :f=>:fetch_format, :dn=>:density, :pg=>:page, :dl=>:delay
68
72
  }.each do
@@ -73,7 +77,20 @@ class Cloudinary::Utils
73
77
  transformation = params.reject{|k,v| v.blank?}.map{|k,v| [k.to_s, v]}.sort_by(&:first).map{|k,v| "#{k}_#{v}"}.join(",")
74
78
  raw_transformation = options.delete(:raw_transformation)
75
79
  transformation = [transformation, raw_transformation].reject(&:blank?).join(",")
76
- (base_transformations << transformation).reject(&:blank?).join("/")
80
+ transformations = base_transformations << transformation
81
+ if responsive_width
82
+ responsive_width_transformation = Cloudinary.config.responsive_width_transformation || DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION
83
+ transformations << generate_transformation_string(responsive_width_transformation.clone)
84
+ end
85
+
86
+ if width.to_s == "auto" || responsive_width
87
+ options[:responsive] = true
88
+ end
89
+ if dpr.to_s == "auto"
90
+ options[:hidpi] = true
91
+ end
92
+
93
+ transformations.reject(&:blank?).join("/")
77
94
  end
78
95
 
79
96
  def self.api_string_to_sign(params_to_sign)
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.0.72"
3
+ VERSION = "1.0.73"
4
4
  end
data/spec/api_spec.rb CHANGED
@@ -5,11 +5,12 @@ describe Cloudinary::Api do
5
5
  break puts("Please setup environment for api test to run") if Cloudinary.config.api_secret.blank?
6
6
 
7
7
  before(:all) do
8
+ @timestamp_tag = "api_test_tag_#{Time.now.to_i}"
8
9
  @api = Cloudinary::Api
9
10
  Cloudinary::Uploader.destroy("api_test")
10
11
  Cloudinary::Uploader.destroy("api_test2")
11
- Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test", :tags=>"api_test_tag", :context => "key=value", :eager=>[:width=>100,:crop=>:scale])
12
- Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test2", :tags=>"api_test_tag", :context => "key=value", :eager=>[:width=>100,:crop=>:scale])
12
+ Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test", :tags=> ["api_test_tag", @timestamp_tag], :context => "key=value", :eager=>[:width=>100,:crop=>:scale])
13
+ Cloudinary::Uploader.upload("spec/logo.png", :public_id=>"api_test2", :tags=> ["api_test_tag", @timestamp_tag], :context => "key=value", :eager=>[:width=>100,:crop=>:scale])
13
14
  @api.delete_transformation("api_test_transformation") rescue nil
14
15
  @api.delete_transformation("api_test_transformation2") rescue nil
15
16
  @api.delete_transformation("api_test_transformation3") rescue nil
@@ -44,20 +45,20 @@ describe Cloudinary::Api do
44
45
  it "should allow listing resources by type" do
45
46
  resource = @api.resources(:type=>"upload", :tags=>true)["resources"].find{|resource| resource["public_id"] == "api_test"}
46
47
  resource.should_not be_blank
47
- resource["tags"].should == ["api_test_tag"]
48
+ resource["tags"].should == ["api_test_tag", @timestamp_tag]
48
49
  end
49
50
 
50
51
  it "should allow listing resources by prefix" do
51
52
  resources = @api.resources(:type=>"upload", :prefix=>"api_test", :tags => true, :context => true)["resources"]
52
53
  resources.map{|resource| resource["public_id"]}.should include("api_test", "api_test2")
53
- resources.map{|resource| resource["tags"]}.should include(["api_test_tag"])
54
+ resources.map{|resource| resource["tags"]}.should include(["api_test_tag", @timestamp_tag])
54
55
  resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
55
56
  end
56
57
 
57
58
  it "should allow listing resources by tag" do
58
59
  resources = @api.resources_by_tag("api_test_tag", :tags => true, :context => true)["resources"]
59
60
  resources.find{|resource| resource["public_id"] == "api_test"}.should_not be_blank
60
- resources.map{|resource| resource["tags"]}.should include(["api_test_tag"])
61
+ resources.map{|resource| resource["tags"]}.should include(["api_test_tag", @timestamp_tag])
61
62
  resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
62
63
  end
63
64
 
@@ -65,7 +66,7 @@ describe Cloudinary::Api do
65
66
  resources = @api.resources_by_ids(["api_test", "api_test2"], :tags => true, :context => true)["resources"]
66
67
  resources.length.should == 2
67
68
  resources.find{|resource| resource["public_id"] == "api_test"}.should_not be_blank
68
- resources.map{|resource| resource["tags"]}.should include(["api_test_tag"])
69
+ resources.map{|resource| resource["tags"]}.should include(["api_test_tag", @timestamp_tag])
69
70
  resources.map{|resource| resource["context"]}.should include({"custom" => {"key" => "value"}})
70
71
  end
71
72
 
@@ -79,16 +80,16 @@ describe Cloudinary::Api do
79
80
  end
80
81
 
81
82
  it "should allow listing resources in both directions" do
82
- asc_resources = @api.resources(:type=>"upload", :prefix=>"api_test", :direction => "asc")["resources"]
83
- desc_resources = @api.resources(:type=>"upload", :prefix=>"api_test", :direction => "desc")["resources"]
83
+ asc_resources = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => "asc")["resources"]
84
+ desc_resources = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => "desc")["resources"]
84
85
  # NOTE: this assumes the full list fits in a page which is the case unless resources with 'api_test' prefix were
85
86
  # uploaded to the account against which this test runs
86
87
  asc_resources.reverse.should == desc_resources
87
- asc_resources_alt = @api.resources(:type=>"upload", :prefix=>"api_test", :direction => 1)["resources"]
88
- desc_resources_alt = @api.resources(:type=>"upload", :prefix=>"api_test", :direction => -1)["resources"]
88
+ asc_resources_alt = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => 1)["resources"]
89
+ desc_resources_alt = @api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => -1)["resources"]
89
90
  asc_resources_alt.reverse.should == desc_resources_alt
90
91
  asc_resources.should == asc_resources_alt
91
- lambda{@api.resources(:type=>"upload", :prefix=>"api_test", :direction => "anythingelse")["resources"]}.should raise_error(Cloudinary::Api::BadRequest)
92
+ lambda{@api.resources_by_tag(@timestamp_tag, :type=>"upload", :direction => "anythingelse")["resources"]}.should raise_error(Cloudinary::Api::BadRequest)
92
93
  end
93
94
 
94
95
  it "should allow get resource metadata" do
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'cloudinary'
3
+ require 'action_view'
4
+ require 'cloudinary/helper'
5
+
6
+ helper_class = Class.new do
7
+ include CloudinaryHelper
8
+ end
9
+
10
+ describe CloudinaryHelper do
11
+ let(:helper) { helper_class.new }
12
+
13
+
14
+ context "#cl_image_upload_tag" do
15
+ let(:options) { {} }
16
+ subject(:input) { helper.cl_image_upload_tag(:image_id, options) }
17
+
18
+ before do
19
+ Cloudinary::Utils.stub(:cloudinary_api_url)
20
+ Cloudinary::Utils.stub(:sign_request)
21
+ helper.stub(:build_callback_url)
22
+ end
23
+
24
+ it "allow multiple upload" do
25
+ options[:multiple] = true
26
+ expect(input).to include('data-cloudinary-field="image_id[]"')
27
+ expect(input).to include('multiple="multiple"')
28
+ end
29
+ end
30
+
31
+ context "#cl_image_tag" do
32
+ subject(:input) { helper.cl_image_tag("sample.jpg", options) }
33
+
34
+ context "responsive_width" do
35
+ let(:options) { {responsive_width: true, cloud_name: "test"} }
36
+ it "should use data-src for responsive_width" do
37
+ expect(input).to eq("<img class=\"cld-responsive\" data-src=\"http://res.cloudinary.com/test/image/upload/c_limit,w_auto/sample.jpg\"></img>")
38
+ end
39
+ end
40
+
41
+ context "dpr_auto" do
42
+ let(:options) { {dpr: :auto, cloud_name: "test"} }
43
+ it "should use data-src for dpr auto" do
44
+ expect(input).to eq("<img class=\"cld-hidpi\" data-src=\"http://res.cloudinary.com/test/image/upload/dpr_auto/sample.jpg\"></img>")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -135,10 +135,23 @@ describe Cloudinary::Uploader do
135
135
  result["public_id"].should match(/^[a-z0-9]+.png$/)
136
136
  end
137
137
 
138
- it "should support unsigned uploading using presets", :upload_preset => true do
139
- preset = Cloudinary::Api.create_upload_preset(:folder => "upload_folder", :unsigned => true)
140
- result = Cloudinary::Uploader.unsigned_upload("spec/logo.png", preset["name"])
141
- result["public_id"].should match(/^upload_folder\/[a-z0-9]+$/)
142
- Cloudinary::Api.delete_upload_preset(preset["name"])
138
+ context "unsigned" do
139
+ after do
140
+ Cloudinary.class_variable_set(:@@config, nil)
141
+ end
142
+
143
+ it "should support unsigned uploading using presets", :upload_preset => true do
144
+ preset = Cloudinary::Api.create_upload_preset(:folder => "upload_folder", :unsigned => true)
145
+
146
+ Cloudinary.config.api_key = nil
147
+ Cloudinary.config.api_secret = nil
148
+
149
+ result = Cloudinary::Uploader.unsigned_upload("spec/logo.png", preset["name"])
150
+ result["public_id"].should match(/^upload_folder\/[a-z0-9]+$/)
151
+
152
+ Cloudinary.class_variable_set(:@@config, nil)
153
+
154
+ Cloudinary::Api.delete_upload_preset(preset["name"])
155
+ end
143
156
  end
144
157
  end
data/spec/utils_spec.rb CHANGED
@@ -465,4 +465,16 @@ describe Cloudinary::Utils do
465
465
  params = Cloudinary::Utils.sign_request({:public_id=>"folder/file", :version=>"1234"})
466
466
  params.should == {:public_id=>"folder/file", :version=>"1234", :signature=>"7a3349cbb373e4812118d625047ede50b90e7b67", :api_key=>"1234"}
467
467
  end
468
+
469
+ it "should support responsive width" do
470
+ options = {:width=>100, :height=>100, :crop=>:crop, :responsive_width=>true}
471
+ result = Cloudinary::Utils.cloudinary_url("test", options)
472
+ options.should == {responsive: true}
473
+ result.should == "http://res.cloudinary.com/test123/image/upload/c_crop,h_100,w_100/c_limit,w_auto/test"
474
+ Cloudinary.config.responsive_width_transformation = {width: :auto, crop: :pad}
475
+ options = {:width=>100, :height=>100, :crop=>:crop, :responsive_width=>true}
476
+ result = Cloudinary::Utils.cloudinary_url("test", options)
477
+ options.should == {responsive: true}
478
+ result.should == "http://res.cloudinary.com/test123/image/upload/c_crop,h_100,w_100/c_pad,w_auto/test"
479
+ end
468
480
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudinary
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.72
5
- prerelease:
4
+ version: 1.0.73
6
5
  platform: ruby
7
6
  authors:
8
7
  - Nadav Soferman
@@ -11,12 +10,11 @@ authors:
11
10
  autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2014-04-15 00:00:00.000000000 Z
13
+ date: 2014-06-30 00:00:00.000000000 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: rest-client
18
17
  requirement: !ruby/object:Gem::Requirement
19
- none: false
20
18
  requirements:
21
19
  - - ! '>='
22
20
  - !ruby/object:Gem::Version
@@ -24,7 +22,6 @@ dependencies:
24
22
  type: :runtime
25
23
  prerelease: false
26
24
  version_requirements: !ruby/object:Gem::Requirement
27
- none: false
28
25
  requirements:
29
26
  - - ! '>='
30
27
  - !ruby/object:Gem::Version
@@ -32,7 +29,6 @@ dependencies:
32
29
  - !ruby/object:Gem::Dependency
33
30
  name: aws_cf_signer
34
31
  requirement: !ruby/object:Gem::Requirement
35
- none: false
36
32
  requirements:
37
33
  - - ! '>='
38
34
  - !ruby/object:Gem::Version
@@ -40,7 +36,6 @@ dependencies:
40
36
  type: :runtime
41
37
  prerelease: false
42
38
  version_requirements: !ruby/object:Gem::Requirement
43
- none: false
44
39
  requirements:
45
40
  - - ! '>='
46
41
  - !ruby/object:Gem::Version
@@ -48,7 +43,6 @@ dependencies:
48
43
  - !ruby/object:Gem::Dependency
49
44
  name: rspec
50
45
  requirement: !ruby/object:Gem::Requirement
51
- none: false
52
46
  requirements:
53
47
  - - ! '>='
54
48
  - !ruby/object:Gem::Version
@@ -56,7 +50,20 @@ dependencies:
56
50
  type: :development
57
51
  prerelease: false
58
52
  version_requirements: !ruby/object:Gem::Requirement
59
- none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: actionpack
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
60
67
  requirements:
61
68
  - - ! '>='
62
69
  - !ruby/object:Gem::Version
@@ -101,12 +108,14 @@ files:
101
108
  - lib/cloudinary/version.rb
102
109
  - lib/tasks/cloudinary.rake
103
110
  - spec/api_spec.rb
111
+ - spec/cloudinary_helper_spec.rb
104
112
  - spec/docx.docx
105
113
  - spec/favicon.ico
106
114
  - spec/logo.png
107
115
  - spec/spec_helper.rb
108
116
  - spec/uploader_spec.rb
109
117
  - spec/utils_spec.rb
118
+ - vendor/assets/html/cloudinary_cors.html
110
119
  - vendor/assets/javascripts/cloudinary/canvas-to-blob.min.js
111
120
  - vendor/assets/javascripts/cloudinary/index.js
112
121
  - vendor/assets/javascripts/cloudinary/jquery.cloudinary.js
@@ -118,34 +127,33 @@ files:
118
127
  - vendor/assets/javascripts/cloudinary/jquery.ui.widget.js
119
128
  - vendor/assets/javascripts/cloudinary/load-image.min.js
120
129
  - vendor/assets/javascripts/cloudinary/processing.js
121
- - vendor/assets/html/cloudinary_cors.html
122
130
  homepage: http://cloudinary.com
123
131
  licenses:
124
132
  - MIT
133
+ metadata: {}
125
134
  post_install_message:
126
135
  rdoc_options: []
127
136
  require_paths:
128
137
  - lib
129
138
  required_ruby_version: !ruby/object:Gem::Requirement
130
- none: false
131
139
  requirements:
132
140
  - - ! '>='
133
141
  - !ruby/object:Gem::Version
134
142
  version: '0'
135
143
  required_rubygems_version: !ruby/object:Gem::Requirement
136
- none: false
137
144
  requirements:
138
145
  - - ! '>='
139
146
  - !ruby/object:Gem::Version
140
147
  version: '0'
141
148
  requirements: []
142
149
  rubyforge_project: cloudinary
143
- rubygems_version: 1.8.24
150
+ rubygems_version: 2.2.2
144
151
  signing_key:
145
- specification_version: 3
152
+ specification_version: 4
146
153
  summary: Client library for easily using the Cloudinary service
147
154
  test_files:
148
155
  - spec/api_spec.rb
156
+ - spec/cloudinary_helper_spec.rb
149
157
  - spec/docx.docx
150
158
  - spec/favicon.ico
151
159
  - spec/logo.png