cloudinary 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 36330c17f742e019c7770d39fe11a5e394d69acc
4
- data.tar.gz: 511246947d366e91a8d34095f256437bde533f9e
3
+ metadata.gz: 154b7abbf7ae3c462f1277f49dfed3cfdd4ef60c
4
+ data.tar.gz: 56a961c58cc636da0830ba4e1db3f486fe1dffd4
5
5
  SHA512:
6
- metadata.gz: 4fcbb47f1760342d5e1b36e0438a605524eb20b9f0fac98521846f71102447ce6dda1ebb3f435e43d6227320bb48a65c85f5ae44da20b0c4fcb1539f7d78232a
7
- data.tar.gz: 190f0970236cb76615d6537276fdd3633297e4c749815a6c54ae985188bee5e493d778a55c60798ac3ebaf9cb14930eb2b3589f45914c69cc489d378d5b19970
6
+ metadata.gz: 7fc132e944b87f3bd829f3e45a16609c7e4743a8fa331fad6d62a490a6f1625c533ea26b9eb50d1da71123abc5948166d5b606694b4765562877d255f54f93e9
7
+ data.tar.gz: 5a1ca4908473ea368ed4a2c1753852879fc75bf3dba22819f44637728de83c6a69f0a48482b5729e46d9f582a3c70748deeaad5dc683a8a2fa831ec784c3b302
@@ -1,4 +1,43 @@
1
1
 
2
+ 1.7.0 / 2017-04-09
3
+ ==================
4
+
5
+ New functionality and features
6
+ ------------------------------
7
+
8
+ * Added resource publishing API
9
+ * `Api.publish_by_prefix`
10
+ * `Api.publish_by_tag`
11
+ * `Api.publish_by_ids`
12
+ * Support remote URLs in `Uploader.upload_large` API
13
+ * Add missing parameters to generate-archive
14
+ * `skip_transformation_name`
15
+ * `allow_missing`
16
+ * Added context API methods
17
+ * `Api.add_context`
18
+ * `Api.remove_all_context`
19
+ * Added `Uploader.remove_all_tags` method
20
+ * Support URL SEO suffix for authenticated images
21
+ * Add support of "format" parameter to responsive-breakpoints hash
22
+ * Add notification_url to update API
23
+
24
+
25
+ Other Changes
26
+ -------------
27
+
28
+ * Remove tag from test
29
+ * Change test criteria from changing versions to bytes
30
+ * Use `TRAVIS_JOB_ID` if available or random. Move auth test constants to spec_helper.
31
+ * Add test for deleting public IDs which contain commas
32
+ * Move expression and replacement to constants
33
+ * Don't normalize negative numbers
34
+ * Added generic aliasing to methods named with image
35
+ * Added Private annotation to certain utility methods
36
+ * Add `encode_context` method to `Utils`
37
+ * Escape = and | characters in context values + test
38
+ * Add more complex eager test cases
39
+ * Switch alias_method_chain to alias_method to support Rails version >5.1
40
+
2
41
  1.6.0 / 2017-03-08
3
42
  ==================
4
43
 
@@ -88,7 +88,7 @@ class Cloudinary::Api
88
88
  uri = "resources/#{resource_type}/#{type}/#{public_id}"
89
89
  update_options = {
90
90
  :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
91
- :context => Cloudinary::Utils.encode_hash(options[:context]),
91
+ :context => Cloudinary::Utils.encode_context(options[:context]),
92
92
  :face_coordinates => Cloudinary::Utils.encode_double_array(options[:face_coordinates]),
93
93
  :custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
94
94
  :moderation_status => options[:moderation_status],
@@ -98,7 +98,8 @@ class Cloudinary::Api
98
98
  :detection => options[:detection],
99
99
  :similarity_search => options[:similarity_search],
100
100
  :background_removal => options[:background_removal],
101
- :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f
101
+ :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
102
+ :notification_url => options[:notification_url]
102
103
  }
103
104
  call_api(:post, uri, update_options, options)
104
105
  end
@@ -357,6 +358,24 @@ class Cloudinary::Api
357
358
  transformation.is_a?(String) ? transformation : Cloudinary::Utils.generate_transformation_string(transformation.clone)
358
359
  end
359
360
 
361
+ def self.publish_resources(options = {})
362
+ resource_type = options[:resource_type] || "image"
363
+ params = only(options, :public_ids, :prefix, :tag, :type, :overwrite, :invalidate)
364
+ call_api("post", "resources/#{resource_type}/publish_resources", params, options)
365
+ end
366
+
367
+ def self.publish_by_prefix(prefix, options = {})
368
+ return self.publish_resources(options.merge(:prefix => prefix))
369
+ end
370
+
371
+ def self.publish_by_tag(tag, options = {})
372
+ return self.publish_resources(options.merge(:tag => tag))
373
+ end
374
+
375
+ def self.publish_by_ids(publicIds, options = {})
376
+ return self.publish_resources(options.merge(:public_ids => publicIds))
377
+ end
378
+
360
379
  def self.update_resources_access_mode(access_mode, by_key, value, options = {})
361
380
  resource_type = options[:resource_type] || "image"
362
381
  type = options[:type] || "upload"
@@ -75,6 +75,7 @@ module CloudinaryHelper
75
75
  url = cloudinary_url_internal(source, options)
76
76
  image_path_without_cloudinary(url)
77
77
  end
78
+ alias_method :cl_path, :cl_image_path
78
79
 
79
80
  def image_tag_with_cloudinary(*args)
80
81
  source, options = args
@@ -200,6 +201,7 @@ module CloudinaryHelper
200
201
  def cl_unsigned_image_upload(object_name, method, upload_preset, options={})
201
202
  cl_unsigned_image_upload_tag("#{object_name}[#{method}]", upload_preset, options)
202
203
  end
204
+ alias_method :cl_unsigned_upload, :cl_unsigned_image_upload
203
205
 
204
206
  def cl_upload_url(options={})
205
207
  Cloudinary::Utils.cloudinary_api_url("upload", {:resource_type=>:auto}.merge(options))
@@ -236,6 +238,7 @@ module CloudinaryHelper
236
238
  def cl_unsigned_image_upload_tag(field, upload_preset, options={})
237
239
  cl_image_upload_tag(field, options.merge(:unsigned => true, :upload_preset => upload_preset))
238
240
  end
241
+ alias_method :cl_unsigned_upload_tag, :cl_unsigned_image_upload_tag
239
242
 
240
243
  def cl_private_download_url(public_id, format, options = {})
241
244
  Cloudinary::Utils.private_download_url(public_id, format, options)
@@ -268,13 +271,12 @@ module CloudinaryHelper
268
271
  if !method_defined?(:image_tag)
269
272
  include ActionView::Helpers::AssetTagHelper
270
273
  end
271
- if defined?(::Rails::VERSION::MAJOR) && ::Rails::VERSION::MAJOR > 2 && Cloudinary.config.enhance_image_tag
272
- alias_method_chain :image_tag, :cloudinary unless public_method_defined? :image_tag_without_cloudinary
273
- alias_method_chain :image_path, :cloudinary unless public_method_defined? :image_path_without_cloudinary
274
- else
275
- alias_method :image_tag_without_cloudinary, :image_tag unless public_method_defined? :image_tag_without_cloudinary
276
- alias_method :image_path_without_cloudinary, :image_path unless public_method_defined? :image_path_without_cloudinary
277
- end
274
+ alias_method :image_tag_without_cloudinary, :image_tag unless public_method_defined? :image_tag_without_cloudinary
275
+ alias_method :image_path_without_cloudinary, :image_path unless public_method_defined? :image_path_without_cloudinary
276
+ if Cloudinary.config.enhance_image_tag
277
+ alias_method :image_tag, :image_tag_with_cloudinary
278
+ alias_method :image_path, :image_path_with_cloudinary
279
+ end
278
280
  end
279
281
  end
280
282
 
@@ -318,6 +320,7 @@ module Cloudinary::FormBuilder
318
320
  def cl_unsigned_image_upload(method, upload_preset, options={})
319
321
  @template.cl_unsigned_image_upload(@object_name, method, upload_preset, objectify_options(options))
320
322
  end
323
+ alias_method :cl_unsigned_upload, :cl_unsigned_image_upload
321
324
  end
322
325
 
323
326
  if defined? ActionView::Helpers::AssetUrlHelper
@@ -4,6 +4,8 @@ require 'json'
4
4
 
5
5
  class Cloudinary::Uploader
6
6
 
7
+ REMOTE_URL_REGEX = %r(^ftp:|^https?:|^s3:|^data:[^;]*;base64,([a-zA-Z0-9\/+\n=]+)$)
8
+
7
9
  # @deprecated use {Cloudinary::Utils.build_eager} instead
8
10
  def self.build_eager(eager)
9
11
  Cloudinary::Utils.build_eager(eager)
@@ -25,7 +27,7 @@ class Cloudinary::Uploader
25
27
  :callback => options[:callback],
26
28
  :categorization => options[:categorization],
27
29
  :colors => Cloudinary::Utils.as_safe_bool(options[:colors]),
28
- :context => Cloudinary::Utils.encode_hash(options[:context]),
30
+ :context => Cloudinary::Utils.encode_context(options[:context]),
29
31
  :custom_coordinates => Cloudinary::Utils.encode_double_array(options[:custom_coordinates]),
30
32
  :detection => options[:detection],
31
33
  :discard_original_filename => Cloudinary::Utils.as_safe_bool(options[:discard_original_filename]),
@@ -71,7 +73,7 @@ class Cloudinary::Uploader
71
73
  params = build_upload_params(options)
72
74
  if file.is_a?(Pathname)
73
75
  params[:file] = File.open(file, "rb")
74
- elsif file.respond_to?(:read) || file =~ /^ftp:|^https?:|^s3:|^data:[^;]*;base64,([a-zA-Z0-9\/+\n=]+)$/
76
+ elsif file.respond_to?(:read) || file.match(REMOTE_URL_REGEX)
75
77
  params[:file] = file
76
78
  else
77
79
  params[:file] = File.open(file, "rb")
@@ -89,7 +91,9 @@ class Cloudinary::Uploader
89
91
  public_id = public_id_or_options
90
92
  options = old_options
91
93
  end
92
- if file.is_a?(Pathname) || !file.respond_to?(:read)
94
+ if file.match(REMOTE_URL_REGEX)
95
+ return upload(file, options.merge(:public_id => public_id))
96
+ elsif file.is_a?(Pathname) || !file.respond_to?(:read)
93
97
  filename = file
94
98
  file = File.open(file, "rb")
95
99
  else
@@ -255,6 +259,10 @@ class Cloudinary::Uploader
255
259
  return self.call_tags_api(tag, "replace", public_ids, options)
256
260
  end
257
261
 
262
+ def self.remove_all_tags(public_ids = [], options = {})
263
+ return self.call_tags_api(nil, "remove_all", public_ids, options)
264
+ end
265
+
258
266
  private
259
267
 
260
268
  def self.call_tags_api(tag, command, public_ids = [], options = {})
@@ -269,6 +277,28 @@ class Cloudinary::Uploader
269
277
  end
270
278
  end
271
279
 
280
+ def self.add_context(context, public_ids = [], options = {})
281
+ return self.call_context_api(context, "add", public_ids, options)
282
+ end
283
+
284
+ def self.remove_all_context(public_ids = [], options = {})
285
+ return self.call_context_api(nil, "remove_all", public_ids, options)
286
+ end
287
+
288
+ private
289
+
290
+ def self.call_context_api(context, command, public_ids = [], options = {})
291
+ return call_api("context", options) do
292
+ {
293
+ :timestamp => (options[:timestamp] || Time.now.to_i),
294
+ :context => Cloudinary::Utils.encode_hash(context),
295
+ :public_ids => Cloudinary::Utils.build_array(public_ids),
296
+ :command => command,
297
+ :type => options[:type]
298
+ }
299
+ end
300
+ end
301
+
272
302
  def self.call_api(action, options)
273
303
  options = options.clone
274
304
  return_error = options.delete(:return_error)
@@ -205,14 +205,14 @@ class Cloudinary::Utils
205
205
  end
206
206
  end
207
207
 
208
+ EXP_REGEXP = Regexp.new(PREDEFINED_VARS.keys.join("|")+'|('+CONDITIONAL_OPERATORS.keys.reverse.map { |k| Regexp.escape(k) }.join('|')+')(?=[ _])')
209
+ EXP_REPLACEMENT = PREDEFINED_VARS.merge(CONDITIONAL_OPERATORS)
210
+
208
211
  def self.normalize_expression(expression)
209
212
  if expression =~ /^!.+!$/ # quoted string
210
213
  expression
211
214
  else
212
- expression.to_s.gsub(
213
- Regexp.union(*PREDEFINED_VARS.keys, *CONDITIONAL_OPERATORS.keys.reverse),
214
- PREDEFINED_VARS.merge(CONDITIONAL_OPERATORS)
215
- ).gsub(/[ _]+/, "_")
215
+ expression.to_s.gsub(EXP_REGEXP,EXP_REPLACEMENT).gsub(/[ _]+/, "_")
216
216
  end
217
217
  end
218
218
 
@@ -321,12 +321,13 @@ class Cloudinary::Utils
321
321
  unless breakpoint_settings.nil?
322
322
  breakpoint_settings = breakpoint_settings.clone
323
323
  transformation = breakpoint_settings.delete(:transformation) || breakpoint_settings.delete("transformation")
324
+ format = breakpoint_settings.delete(:format) || breakpoint_settings.delete("format")
324
325
  if transformation
325
- breakpoint_settings[:transformation] = Cloudinary::Utils.generate_transformation_string(transformation.clone, true)
326
+ transformation = Cloudinary::Utils.generate_transformation_string(transformation.clone, true)
326
327
  end
328
+ breakpoint_settings[:transformation] = [transformation, format].compact.join("/")
327
329
  end
328
330
  breakpoint_settings
329
-
330
331
  end.to_json
331
332
  end
332
333
 
@@ -450,6 +451,9 @@ class Cloudinary::Utils
450
451
  when resource_type.to_s == "image" && type.to_s == "private"
451
452
  resource_type = "private_images"
452
453
  type = nil
454
+ when resource_type.to_s == "image" && type.to_s == "authenticated"
455
+ resource_type = "authenticated_images"
456
+ type = nil
453
457
  when resource_type.to_s == "raw" && type.to_s == "upload"
454
458
  resource_type = "files"
455
459
  type = nil
@@ -457,7 +461,7 @@ class Cloudinary::Utils
457
461
  resource_type = "videos"
458
462
  type = nil
459
463
  else
460
- raise(CloudinaryException, "URL Suffix only supported for image/upload, image/private and raw/upload")
464
+ raise(CloudinaryException, "URL Suffix only supported for image/upload, image/private, image/authenticated, video/upload and raw/upload")
461
465
  end
462
466
  end
463
467
  if use_root_path
@@ -668,6 +672,10 @@ class Cloudinary::Utils
668
672
  end
669
673
  end
670
674
 
675
+ # encodes a hash into pipe-delimited key-value pairs string
676
+ # @hash [Hash] key-value hash to be encoded
677
+ # @return [String] a joined string of all keys and values separated by a pipe character
678
+ # @private
671
679
  def self.encode_hash(hash)
672
680
  case hash
673
681
  when Hash then hash.map{|k,v| "#{k}=#{v}"}.join("|")
@@ -676,6 +684,18 @@ class Cloudinary::Utils
676
684
  end
677
685
  end
678
686
 
687
+ # Same like encode_hash, with additional escaping of | and = characters
688
+ # @hash [Hash] key-value hash to be encoded
689
+ # @return [String] a joined string of all keys and values properly escaped and separated by a pipe character
690
+ # @private
691
+ def self.encode_context(hash)
692
+ case hash
693
+ when Hash then hash.map{|k,v| "#{k}=#{v.gsub(/([=|])/, '\\\\\1')}"}.join("|")
694
+ when nil then ""
695
+ else hash
696
+ end
697
+ end
698
+
679
699
  def self.encode_double_array(array)
680
700
  array = build_array(array)
681
701
  if array.length > 0 && array[0].is_a?(Array)
@@ -804,7 +824,9 @@ class Cloudinary::Utils
804
824
  :public_ids=>options[:public_ids] && Cloudinary::Utils.build_array(options[:public_ids]),
805
825
  :prefixes=>options[:prefixes] && Cloudinary::Utils.build_array(options[:prefixes]),
806
826
  :expires_at=>options[:expires_at],
807
- :transformations => build_eager(options[:transformations])
827
+ :transformations => build_eager(options[:transformations]),
828
+ :skip_transformation_name=>Cloudinary::Utils.as_safe_bool(options[:skip_transformation_name]),
829
+ :allow_missing=>Cloudinary::Utils.as_safe_bool(options[:allow_missing])
808
830
  }
809
831
  end
810
832
 
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.6.0"
3
+ VERSION = "1.7.0"
4
4
  end
@@ -6,7 +6,7 @@ describe Cloudinary::Api do
6
6
  include_context "cleanup", TIMESTAMP_TAG
7
7
  TEST_WIDTH = rand(1000)
8
8
  TEST_TRANSFOMATION = "c_scale,w_#{TEST_WIDTH}"
9
- prefix = "api_test_#{Time.now.to_i}"
9
+ prefix = "api_test_#{SUFFIX}"
10
10
  test_id_1 = "#{prefix}_1"
11
11
  test_id_2 = "#{prefix}_2"
12
12
  test_id_3 = "#{prefix}_3"
@@ -157,9 +157,11 @@ describe Cloudinary::Api do
157
157
 
158
158
  end
159
159
 
160
- it "should allow deleting resources" do
160
+ it "should allow deleting multiple resources and comma inclusive public IDs", :focus => true do
161
161
  expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :public_ids] => ["apit_test", "test_id_2", "api_test3"]}))
162
162
  @api.delete_resources(["apit_test", "test_id_2", "api_test3"])
163
+ expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :public_ids] => "apit_test,test_id_2,api_test3"}))
164
+ @api.delete_resources("apit_test,test_id_2,api_test3")
163
165
  end
164
166
 
165
167
  it "should allow deleting resource transformations" do
@@ -352,9 +354,13 @@ describe Cloudinary::Api do
352
354
  expect{Cloudinary::Api.update(result["public_id"], {:categorization => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
353
355
  end
354
356
 
355
- it "should support requesting detection" do
356
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :detection] => "adv_face"))
357
- Cloudinary::Api.update("public_id", {:detection => "adv_face"})
357
+ it "should support requesting detection with server notification", :focus => true do
358
+ expected = {
359
+ [:payload, :detection] => "adv_face",
360
+ [:payload, :notification_url] => "http://example.com"
361
+ }
362
+ expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
363
+ Cloudinary::Api.update("public_id", {:detection => "adv_face", :notification_url => "http://example.com"})
358
364
  end
359
365
 
360
366
  it "should support requesting auto_tagging" do
@@ -437,4 +443,60 @@ describe Cloudinary::Api do
437
443
  expect(resource["access_mode"]).to eq('public')
438
444
  end
439
445
  end
446
+
447
+ context "resource of type authenticated" do
448
+ i = 0
449
+ bytes = nil
450
+ publicId = ""
451
+ publish_resource_tag = "publish_resource_tag"
452
+ before(:each) do
453
+ i += 1
454
+ result = Cloudinary::Uploader.upload TEST_IMG, type: "authenticated", tags: [TEST_TAG, TIMESTAMP_TAG, publish_resource_tag], transformation: {width: 100*i, crop: "scale"}
455
+ publicId = result["public_id"]
456
+ expect(result["type"]).to eq("authenticated")
457
+ end
458
+
459
+ it "should publish resources by ids" do
460
+ result = Cloudinary::Api.publish_by_ids( [publicId])
461
+
462
+ expect(result["published"]).to be_an_instance_of(Array)
463
+ expect(result["published"].length).to eq(1)
464
+
465
+ resource = result["published"][0]
466
+
467
+ expect(resource["public_id"]).to eq(publicId)
468
+ expect(resource["type"]).to eq('upload')
469
+
470
+ bytes = resource["bytes"]
471
+ end
472
+ it "should publish resources by prefix and overwrite" do
473
+ result = Cloudinary::Api.publish_by_prefix(publicId[0..-3], overwrite: true)
474
+
475
+ expect(result["published"]).to be_an_instance_of(Array)
476
+ expect(result["published"].length).to eq(1)
477
+
478
+ resource = result["published"][0]
479
+
480
+ expect(resource["public_id"]).to eq(publicId)
481
+ expect(resource["bytes"]).not_to eq(bytes)
482
+ expect(resource["type"]).to eq('upload')
483
+
484
+ bytes = resource["bytes"]
485
+ end
486
+ it "should publish resources by tag and overwrite" do
487
+ result = Cloudinary::Api.publish_by_tag(publish_resource_tag, overwrite: true)
488
+
489
+ expect(result["published"]).to be_an_instance_of(Array)
490
+ expect(result["published"].length).to eq(1)
491
+
492
+ resource = result["published"][0]
493
+
494
+ expect(resource["public_id"]).to eq(publicId)
495
+ expect(resource["bytes"]).not_to eq(bytes)
496
+ expect(resource["type"]).to eq('upload')
497
+
498
+ bytes = resource["bytes"]
499
+ end
500
+
501
+ end
440
502
  end
@@ -22,6 +22,12 @@ RSpec.shared_context 'archive' do
22
22
  :effect => :blackwhite
23
23
  }
24
24
  )
25
+ Cloudinary::Uploader.upload(
26
+ "http://res.cloudinary.com/demo/image/upload/sample.jpg",
27
+ :public_id => 'tag_sample_raw.jpg',
28
+ :resource_type => 'raw',
29
+ :tags => [TEST_TAG, TIMESTAMP_TAG],
30
+ )
25
31
  end
26
32
  include_context "cleanup", TIMESTAMP_TAG
27
33
  end
@@ -62,20 +68,8 @@ describe Cloudinary::Uploader do
62
68
 
63
69
  describe '.create_archive' do
64
70
  let!(:target_public_id) {
65
- "gem_test#{ rand(1000000)}"
66
- }
67
- let!(:archive_result) {
68
- Cloudinary::Uploader.create_archive(
69
- {
70
- :target_public_id => target_public_id,
71
- :public_ids => %w(tag_sample tag_samplebw),
72
- :tags => [TEST_TAG, TIMESTAMP_TAG]
73
- }.merge(options))
71
+ "gem_test#{ SUFFIX}"
74
72
  }
75
- let(:options) { { :mode => :create } }
76
- it 'should return a Hash' do
77
- expect(archive_result).to be_a(Hash)
78
- end
79
73
  expected_keys = %w(
80
74
  resource_type
81
75
  type
@@ -91,10 +85,41 @@ describe Cloudinary::Uploader do
91
85
  resource_count
92
86
  file_count
93
87
  )
94
- it "should include keys: #{expected_keys.join(', ')}" do
88
+ let!(:archive_result) {
89
+ Cloudinary::Uploader.create_archive(
90
+ {
91
+ :target_public_id => target_public_id,
92
+ :public_ids => %w(tag_sample tag_samplebw),
93
+ :tags => [TEST_TAG, TIMESTAMP_TAG],
94
+ :transformations => [{width: 100, height: 100, crop: "fill"},{effect: "grayscale"}],
95
+ :skip_transformation_name => true
96
+ }.merge(options))
97
+ }
98
+ let(:options) { { :mode => :create } }
99
+ it 'should return a Hash with suitable set of keys' do
100
+ expect(archive_result).to be_a(Hash)
95
101
  expect(archive_result.keys).to include(*expected_keys)
96
102
  end
97
103
  end
104
+ describe 'create archive based on raw resources and missing public IDs' do
105
+ let!(:target_public_id) {
106
+ "gem_test#{ SUFFIX}"
107
+ }
108
+ let!(:archive_result) {
109
+ Cloudinary::Uploader.create_archive(
110
+ {
111
+ :target_public_id => target_public_id,
112
+ :public_ids => %w(tag_sample_raw.jpg non-wxisting-resource),
113
+ :resource_type => 'raw',
114
+ :allow_missing => true
115
+ }.merge(options))
116
+ }
117
+ let(:options) { { :mode => :create } }
118
+ it 'should skip missing public IDs and successfully generate the archive containing raw resources' do
119
+ expect(archive_result).to be_a(Hash)
120
+ expect(archive_result["resource_count"]).to equal(1)
121
+ end
122
+ end
98
123
  describe '.create_zip' do
99
124
  it 'should call create_archive with "zip" format' do
100
125
  expect(Cloudinary::Uploader).to receive(:create_archive).with({ :tags => TEST_TAG }, "zip")