cloudinary 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- M2E1MWI3ZmRiNDA2YWE2ZTA0OTYzZDUyZmIxMmNjYWJhMjFhNzVmNA==
5
- data.tar.gz: !binary |-
6
- NjUzMWYwOGVkNTU0ZmE3ZDIyZjJjNzM1MGE5YWM4ZWRhYWY2OGQyYg==
2
+ SHA1:
3
+ metadata.gz: 36330c17f742e019c7770d39fe11a5e394d69acc
4
+ data.tar.gz: 511246947d366e91a8d34095f256437bde533f9e
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NDFjMjgyNTE1MTkxODkxZjcyN2VmOGU3ODZiMWU2NjAyMWNiODc2YjJiMGMz
10
- YzkxOTYyZjRkOTU4MmM2MGMxNThmMDQ3NThiMWUxOTFmZGE0OTBkNjJkYTlk
11
- ZWI1MDdhOGVjMzUyZmE2NzMzMWQ3M2U0MTFmZWY5NmYxNDJjNWY=
12
- data.tar.gz: !binary |-
13
- ZDEzODU4YWJhOGExNmQxZjY2NGI5OTZkMjk1NmFiMGY1YWFiZTdkODcwZWIw
14
- MmM5NGQ5OWIzZGJmNjBhZmE1OGViZmFhZGMzOGJmNTU4M2M2ZTAzM2FkNTlk
15
- ZDMxNDA1MDNmOGE4ODk5M2Y5MDkyZDRhOTI4NTNlOGVhYmRjZWI=
6
+ metadata.gz: 4fcbb47f1760342d5e1b36e0438a605524eb20b9f0fac98521846f71102447ce6dda1ebb3f435e43d6227320bb48a65c85f5ae44da20b0c4fcb1539f7d78232a
7
+ data.tar.gz: 190f0970236cb76615d6537276fdd3633297e4c749815a6c54ae985188bee5e493d778a55c60798ac3ebaf9cb14930eb2b3589f45914c69cc489d378d5b19970
@@ -1,4 +1,20 @@
1
1
 
2
+ 1.6.0 / 2017-03-08
3
+ ==================
4
+
5
+ New functionality and features
6
+ ------------------------------
7
+
8
+ * Support user defined variables
9
+ * Add `to_type` parameter to the rename method (#236)
10
+ * Add `async` parameter to the upload method (#235)
11
+
12
+ Other Changes
13
+ -------------
14
+
15
+ * Switch ow & oh to iw & ih on respective test case
16
+ * test auto gravity transformation in URL build
17
+
2
18
  1.5.2 / 2017-02-22
3
19
  ==================
4
20
 
@@ -18,6 +18,7 @@ class Cloudinary::Uploader
18
18
  params = {
19
19
  :access_mode => options[:access_mode],
20
20
  :allowed_formats => Cloudinary::Utils.build_array(options[:allowed_formats]).join(","),
21
+ :async => Cloudinary::Utils.as_safe_bool(options[:async]),
21
22
  :auto_tagging => options[:auto_tagging] && options[:auto_tagging].to_f,
22
23
  :background_removal => options[:background_removal],
23
24
  :backup => Cloudinary::Utils.as_safe_bool(options[:backup]),
@@ -142,6 +143,7 @@ class Cloudinary::Uploader
142
143
  :overwrite => Cloudinary::Utils.as_safe_bool(options[:overwrite]),
143
144
  :from_public_id => from_public_id,
144
145
  :to_public_id => to_public_id,
146
+ :to_type => options[:to_type],
145
147
  :invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate])
146
148
  }
147
149
  end
@@ -19,15 +19,26 @@ class Cloudinary::Utils
19
19
  "<=" => 'lte',
20
20
  ">=" => 'gte',
21
21
  "&&" => 'and',
22
- "||" => 'or'
22
+ "||" => 'or',
23
+ "*" => 'mul',
24
+ "/" => 'div',
25
+ "+" => 'add',
26
+ "-" => 'sub'
23
27
  }
24
28
 
25
- CONDITIONAL_PARAMETERS = {
26
- "width" => "w",
27
- "height" => "h",
28
- "aspect_ratio" => "ar",
29
- "page_count" => "pc",
30
- "face_count" => "fc"
29
+ PREDEFINED_VARS = {
30
+ "aspect_ratio" => "ar",
31
+ "current_page" => "cp",
32
+ "face_count" => "fc",
33
+ "height" => "h",
34
+ "initial_aspect_ratio" => "iar",
35
+ "initial_height" => "ih",
36
+ "initial_width" => "iw",
37
+ "page_count" => "pc",
38
+ "page_x" => "px",
39
+ "page_y" => "py",
40
+ "tags" => "tags",
41
+ "width" => "w"
31
42
  }
32
43
  # Warning: options are being destructively updated!
33
44
  def self.generate_transformation_string(options={}, allow_implicit_crop_mode = false)
@@ -96,24 +107,30 @@ class Cloudinary::Utils
96
107
  ifValue = process_if(options.delete(:if))
97
108
 
98
109
  params = {
99
- :a => angle,
110
+ :a => normalize_expression(angle),
111
+ :ar => normalize_expression(options.delete(:aspect_ratio)),
100
112
  :b => background,
101
113
  :bo => border,
102
114
  :c => crop,
103
115
  :co => color,
104
- :dpr => dpr,
105
- :e => effect,
116
+ :dpr => normalize_expression(dpr),
117
+ :e => normalize_expression(effect),
106
118
  :fl => flags,
107
- :h => height,
119
+ :h => normalize_expression(height),
108
120
  :l => overlay,
121
+ :o => normalize_expression(options.delete(:opacity)),
122
+ :q => normalize_expression(options.delete(:quality)),
123
+ :r => normalize_expression(options.delete(:radius)),
109
124
  :t => named_transformation,
110
125
  :u => underlay,
111
- :w => width
126
+ :w => normalize_expression(width),
127
+ :x => normalize_expression(options.delete(:x)),
128
+ :y => normalize_expression(options.delete(:y)),
129
+ :z => normalize_expression(options.delete(:zoom))
112
130
  }
113
131
  {
114
132
  :ac => :audio_codec,
115
133
  :af => :audio_frequency,
116
- :ar => :aspect_ratio,
117
134
  :br => :bit_rate,
118
135
  :cs => :color_space,
119
136
  :d => :default_image,
@@ -124,18 +141,12 @@ class Cloudinary::Utils
124
141
  :f => :fetch_format,
125
142
  :g => :gravity,
126
143
  :ki => :keyframe_interval,
127
- :o => :opacity,
128
144
  :p => :prefix,
129
145
  :pg => :page,
130
- :q => :quality,
131
- :r => :radius,
132
146
  :so => :start_offset,
133
147
  :sp => :streaming_profile,
134
148
  :vc => :video_codec,
135
- :vs => :video_sampling,
136
- :x => :x,
137
- :y => :y,
138
- :z => :zoom
149
+ :vs => :video_sampling
139
150
  }.each do
140
151
  |param, option|
141
152
  params[param] = options.delete(option)
@@ -146,10 +157,25 @@ class Cloudinary::Utils
146
157
  params[range_value] = norm_range_value params[range_value] if params[range_value].present?
147
158
  end
148
159
 
160
+ variables = options.delete(:variables)
161
+ var_params = []
162
+ options.each_pair do |key, value|
163
+ if key =~ /^\$/
164
+ var_params.push "#{key}_#{normalize_expression(value.to_s)}"
165
+ end
166
+ end
167
+ var_params.sort!
168
+ unless variables.nil? || variables.empty?
169
+ for name, value in variables
170
+ var_params.push "#{name}_#{normalize_expression(value.to_s)}"
171
+ end
172
+ end
173
+ variables = var_params.join(',')
174
+
149
175
  raw_transformation = options.delete(:raw_transformation)
150
176
  transformation = params.reject{|_k,v| v.blank?}.map{|k,v| "#{k}_#{v}"}.sort
151
177
  transformation = transformation.join(",")
152
- transformation = [ifValue, transformation, raw_transformation].reject(&:blank?).join(",")
178
+ transformation = [ifValue, variables, transformation, raw_transformation].reject(&:blank?).join(",")
153
179
 
154
180
  transformations = base_transformations << transformation
155
181
  if responsive_width
@@ -173,15 +199,23 @@ class Cloudinary::Utils
173
199
  # @private
174
200
  def self.process_if(ifValue)
175
201
  if ifValue
176
- ifValue = ifValue.gsub(
177
- /(#{CONDITIONAL_PARAMETERS.keys.join("|")}|[=<>&|!]+)/,
178
- CONDITIONAL_PARAMETERS.merge(CONDITIONAL_OPERATORS))
179
- .gsub(/[ _]+/, "_")
202
+ ifValue = normalize_expression(ifValue)
180
203
 
181
204
  ifValue = "if_" + ifValue
182
205
  end
183
206
  end
184
207
 
208
+ def self.normalize_expression(expression)
209
+ if expression =~ /^!.+!$/ # quoted string
210
+ expression
211
+ else
212
+ expression.to_s.gsub(
213
+ Regexp.union(*PREDEFINED_VARS.keys, *CONDITIONAL_OPERATORS.keys.reverse),
214
+ PREDEFINED_VARS.merge(CONDITIONAL_OPERATORS)
215
+ ).gsub(/[ _]+/, "_")
216
+ end
217
+ end
218
+
185
219
  # Parse layer options
186
220
  # @return [string] layer transformation string
187
221
  # @private
@@ -218,8 +252,16 @@ class Cloudinary::Utils
218
252
  unless public_id.blank? ^ text_style.blank?
219
253
  raise(CloudinaryException, "Must supply either style parameters or a public_id when providing text parameter in a text overlay/underlay")
220
254
  end
221
- text = smart_escape smart_escape(text, %r"([,/])")
222
255
 
256
+ result = ""
257
+ # Don't encode interpolation expressions e.g. $(variable)
258
+ while(/\$\([a-zA-Z]\w+\)/.match text) do
259
+ match = Regexp.last_match
260
+ result += smart_escape smart_escape(match.pre_match, %r"([,/])") # append encoded pre-match
261
+ result += match.to_s # append match
262
+ text = match.post_match
263
+ end
264
+ text = result + smart_escape( smart_escape(text, %r"([,/])"))
223
265
  end
224
266
  end
225
267
  components.push(resource_type) if resource_type != "image"
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.5.2"
3
+ VERSION = "1.6.0"
4
4
  end
@@ -30,10 +30,16 @@ describe Cloudinary::Uploader do
30
30
  expect(result["signature"]).to eq(expected_signature)
31
31
  end
32
32
 
33
+ it "should successfully upload file asynchronously" do
34
+ result = Cloudinary::Uploader.upload(Pathname.new(TEST_IMG), :async => true)
35
+ expect(result["status"]).to eq("pending")
36
+ end
37
+
33
38
  describe '.rename' do
34
39
  before(:all) do
35
40
  @result = Cloudinary::Uploader.upload(TEST_IMG, :tags => [TEST_TAG, TIMESTAMP_TAG])
36
41
  @resource_1_id = @result["public_id"]
42
+ @resource_1_type = @result["type"]
37
43
  result = Cloudinary::Uploader.upload("spec/favicon.ico", :tags => [TEST_TAG, TIMESTAMP_TAG])
38
44
  @resource_2_id = result["public_id"]
39
45
  end
@@ -49,6 +55,14 @@ describe Cloudinary::Uploader do
49
55
  expect { Cloudinary::Uploader.rename(id, @resource_1_id+"2") }.to raise_error(CloudinaryException)
50
56
  @resource_2_id = id
51
57
  end
58
+ it 'should allow changing type of an uploaded resource' do
59
+ id = @resource_2_id
60
+ from_type = @resource_1_type
61
+ to_type = "private"
62
+ Cloudinary::Uploader.rename(id, id, :type => from_type, :to_type => to_type)
63
+ expect(Cloudinary::Api.resource(id, type: to_type)).to_not be_empty
64
+ Cloudinary::Uploader.rename(id, id, :type => to_type, :to_type => from_type)
65
+ end
52
66
  context ':overwrite => true' do
53
67
  it 'should rename to an existing ID' do
54
68
  new_id = Cloudinary::Uploader.upload(TEST_IMG, :tags => [TEST_TAG, TIMESTAMP_TAG])["public_id"]
@@ -230,9 +230,9 @@ describe Cloudinary::Utils do
230
230
  expect(["test", { :width => "auto:breakpoints:json", :crop => :fill }])
231
231
  .to produce_url("#{upload_path}/c_fill,w_auto:breakpoints:json/test")
232
232
  end
233
- it 'should support oh,ow' do
234
- expect(["test", {:width => "ow", :height => "oh", :crop => :crop}])
235
- .to produce_url("#{upload_path}/c_crop,h_oh,w_ow/test")
233
+ it 'should support ih,iw' do
234
+ expect(["test", {:width => "iw", :height => "ih", :crop => :crop}])
235
+ .to produce_url("#{upload_path}/c_crop,h_ih,w_iw/test")
236
236
  end
237
237
  end
238
238
 
@@ -240,8 +240,12 @@ describe Cloudinary::Utils do
240
240
  expect(["test", { :x => 1, :y => 2, :radius => 3, :gravity => :center, :quality => 0.4, :prefix => "a" }])
241
241
  .to produce_url("#{upload_path}/g_center,p_a,q_0.4,r_3,x_1,y_2/test")
242
242
  .and empty_options
243
+
244
+ expect(["test", { :width => 0.5, :crop => :crop, :gravity => :auto }])
245
+ .to produce_url("#{upload_path}/c_crop,g_auto,w_0.5/test")
246
+ .and empty_options
243
247
  end
244
- context ":quality" do
248
+ describe ":quality" do
245
249
  it "support a percent value" do
246
250
  expect(["test", { :x => 1, :y => 2, :radius => 3, :gravity => :center, :quality => 80, :prefix => "a" }])
247
251
  .to produce_url("#{upload_path}/g_center,p_a,q_80,r_3,x_1,y_2/test")
@@ -771,21 +775,51 @@ describe Cloudinary::Utils do
771
775
  end
772
776
  it "should support and translate operators: '=', '!=', '<', '>', '<=', '>=', '&&', '||'" do
773
777
 
774
- allOperators =
775
- 'if_' +
776
- 'w_eq_0_and' +
777
- '_w_ne_0_or' +
778
- '_h_lt_0_and' +
779
- '_ar_gt_0_and' +
780
- '_pc_lte_0_and' +
781
- '_fc_gte_0' +
778
+ all_operators =
779
+ 'if_' +
780
+ 'w_eq_0_and' +
781
+ '_w_ne_0_or' +
782
+ '_h_lt_0_and' +
783
+ '_ar_gt_0_and' +
784
+ '_pc_lte_0_and' +
785
+ '_fc_gte_0' +
782
786
  ',e_grayscale'
783
787
 
784
788
  expect( ["sample",
785
789
  :if =>"width = 0 && w != 0 || height < 0 and aspect_ratio > 0 and page_count <= 0 and face_count >= 0",
786
790
  :effect =>"grayscale"])
787
- .to produce_url("#{upload_path}/#{allOperators}/sample")
791
+ .to produce_url("#{upload_path}/#{all_operators}/sample")
792
+ end
793
+
794
+ end
795
+ end
796
+
797
+ describe "variables" do
798
+ it "array should define a set of variables" do
799
+ options = {
800
+ :if => "face_count > 2",
801
+ :variables => [ ["$z", 5], ["$foo", "$z * 2"] ],
802
+ :crop => "scale", :width => "$foo * 200"
803
+ }
804
+ t = Cloudinary::Utils.generate_transformation_string options
805
+ expect(t).to eq("if_fc_gt_2,$z_5,$foo_$z_mul_2,c_scale,w_$foo_mul_200")
806
+ end
807
+ it "'$key' should define a variable" do
808
+ options = { :transformation => [
809
+ {"$foo" => 10 },
810
+ {:if => "face_count > 2"},
811
+ {:crop => "scale", :width => "$foo * 200 / face_count"},
812
+ {:if => "end"}
813
+ ] }
814
+ t = Cloudinary::Utils.generate_transformation_string options
815
+ expect(t).to eq("$foo_10/if_fc_gt_2/c_scale,w_$foo_mul_200_div_fc/if_end")
816
+ end
817
+ it "should support text values" do
818
+ expect( ["sample", :effect => "$efname:100", "$efname" => "!blur!"]).to produce_url "#{upload_path}/$efname_!blur!,e_$efname:100/sample"
819
+
788
820
  end
821
+ it "should support string interpolation" do
822
+ expect( ["sample", :crop => "scale", :overlay => {:text => "$(start)Hello $(name)$(ext), $(no ) $( no)$(end)", :font_family => "Arial", :font_size => "18"} ]).to produce_url "#{upload_path}/c_scale,l_text:Arial_18:$(start)Hello%20$(name)$(ext)%252C%20%24%28no%20%29%20%24%28%20no%29$(end)/sample"
789
823
 
790
824
  end
791
825
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudinary
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nadav Soferman
@@ -10,134 +10,106 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-02-22 00:00:00.000000000 Z
13
+ date: 2017-03-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: aws_cf_signer
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - ! '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - ! '>='
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: '0'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rspec
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - ! '>='
33
+ - - ">="
34
34
  - !ruby/object:Gem::Version
35
35
  version: '3.5'
36
36
  type: :development
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - ! '>='
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
42
  version: '3.5'
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: rspec-rails
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ! '>='
47
+ - - ">="
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - ! '>='
54
+ - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: rest-client
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - <
61
+ - - ">="
62
62
  - !ruby/object:Gem::Version
63
- version: '2.0'
64
- type: :runtime
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - <
69
- - !ruby/object:Gem::Version
70
- version: '2.0'
71
- - !ruby/object:Gem::Dependency
72
- name: json
73
- requirement: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - ~>
76
- - !ruby/object:Gem::Version
77
- version: '1.8'
63
+ version: '0'
78
64
  type: :runtime
79
65
  prerelease: false
80
66
  version_requirements: !ruby/object:Gem::Requirement
81
67
  requirements:
82
- - - ~>
68
+ - - ">="
83
69
  - !ruby/object:Gem::Version
84
- version: '1.8'
70
+ version: '0'
85
71
  - !ruby/object:Gem::Dependency
86
72
  name: actionpack
87
73
  requirement: !ruby/object:Gem::Requirement
88
74
  requirements:
89
- - - <
75
+ - - ">="
90
76
  - !ruby/object:Gem::Version
91
- version: '5.0'
77
+ version: '0'
92
78
  type: :development
93
79
  prerelease: false
94
80
  version_requirements: !ruby/object:Gem::Requirement
95
81
  requirements:
96
- - - <
82
+ - - ">="
97
83
  - !ruby/object:Gem::Version
98
- version: '5.0'
84
+ version: '0'
99
85
  - !ruby/object:Gem::Dependency
100
86
  name: simplecov
101
87
  requirement: !ruby/object:Gem::Requirement
102
88
  requirements:
103
- - - ! '>='
89
+ - - ">="
104
90
  - !ruby/object:Gem::Version
105
91
  version: '0'
106
92
  type: :development
107
93
  prerelease: false
108
94
  version_requirements: !ruby/object:Gem::Requirement
109
95
  requirements:
110
- - - ! '>='
96
+ - - ">="
111
97
  - !ruby/object:Gem::Version
112
98
  version: '0'
113
- - !ruby/object:Gem::Dependency
114
- name: nokogiri
115
- requirement: !ruby/object:Gem::Requirement
116
- requirements:
117
- - - <
118
- - !ruby/object:Gem::Version
119
- version: 1.7.0
120
- type: :development
121
- prerelease: false
122
- version_requirements: !ruby/object:Gem::Requirement
123
- requirements:
124
- - - <
125
- - !ruby/object:Gem::Version
126
- version: 1.7.0
127
99
  - !ruby/object:Gem::Dependency
128
100
  name: rubyzip
129
101
  requirement: !ruby/object:Gem::Requirement
130
102
  requirements:
131
- - - <
103
+ - - ">="
132
104
  - !ruby/object:Gem::Version
133
- version: 1.2.1
105
+ version: '0'
134
106
  type: :development
135
107
  prerelease: false
136
108
  version_requirements: !ruby/object:Gem::Requirement
137
109
  requirements:
138
- - - <
110
+ - - ">="
139
111
  - !ruby/object:Gem::Version
140
- version: 1.2.1
112
+ version: '0'
141
113
  description: Client library for easily using the Cloudinary service
142
114
  email:
143
115
  - nadav.soferman@cloudinary.com
@@ -147,9 +119,9 @@ executables: []
147
119
  extensions: []
148
120
  extra_rdoc_files: []
149
121
  files:
150
- - .gitignore
151
- - .rspec
152
- - .travis.yml
122
+ - ".gitignore"
123
+ - ".rspec"
124
+ - ".travis.yml"
153
125
  - CHANGELOG.md
154
126
  - CONTRIBUTING.md
155
127
  - Gemfile
@@ -219,17 +191,17 @@ require_paths:
219
191
  - lib
220
192
  required_ruby_version: !ruby/object:Gem::Requirement
221
193
  requirements:
222
- - - ! '>='
194
+ - - ">="
223
195
  - !ruby/object:Gem::Version
224
196
  version: '0'
225
197
  required_rubygems_version: !ruby/object:Gem::Requirement
226
198
  requirements:
227
- - - ! '>='
199
+ - - ">="
228
200
  - !ruby/object:Gem::Version
229
201
  version: '0'
230
202
  requirements: []
231
203
  rubyforge_project: cloudinary
232
- rubygems_version: 2.4.8
204
+ rubygems_version: 2.4.5.1
233
205
  signing_key:
234
206
  specification_version: 4
235
207
  summary: Client library for easily using the Cloudinary service