cloudinary 1.0.72 → 1.0.73

Sign up to get free protection for your applications and to get access to all the features.
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