imgix 3.3.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/imgix/path.rb CHANGED
@@ -1,55 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
- require 'cgi/util'
5
- require 'erb'
6
- require 'imgix/param_helpers'
3
+ require "base64"
4
+ require "cgi/util"
5
+ require "erb"
7
6
 
8
7
  module Imgix
9
8
  class Path
10
- include ParamHelpers
11
9
 
12
- ALIASES = {
13
- width: :w,
14
- height: :h,
15
- rotation: :rot,
16
- noise_reduction: :nr,
17
- sharpness: :sharp,
18
- exposure: :exp,
19
- vibrance: :vib,
20
- saturation: :sat,
21
- brightness: :bri,
22
- contrast: :con,
23
- highlight: :high,
24
- shadow: :shad,
25
- gamma: :gam,
26
- pixelate: :px,
27
- halftone: :htn,
28
- watermark: :mark,
29
- text: :txt,
30
- format: :fm,
31
- quality: :q
32
- }.freeze
33
-
34
- def initialize(prefix, secure_url_token, path = '/')
10
+ def initialize(prefix, secure_url_token, path = "/")
35
11
  @prefix = prefix
36
12
  @secure_url_token = secure_url_token
37
13
  @path = path
38
14
  @options = {}
39
-
40
- @path = CGI.escape(@path) if /^https?/ =~ @path
41
- @path = "/#{@path}" if @path[0] != '/'
42
- @target_widths = TARGET_WIDTHS.call(DEFAULT_WIDTH_TOLERANCE, MIN_WIDTH, MAX_WIDTH)
43
15
  end
44
16
 
45
17
  def to_url(opts = {})
18
+ sanitized_path = sanitize_path(@path)
46
19
  prev_options = @options.dup
47
20
  @options.merge!(opts)
48
21
 
49
- url = @prefix + path_and_params
22
+ current_path_and_params = path_and_params(sanitized_path)
23
+ url = @prefix + current_path_and_params
50
24
 
51
25
  if @secure_url_token
52
- url += (has_query? ? '&' : '?') + "s=#{signature}"
26
+ url += (has_query? ? "&" : "?") + "s=#{signature(current_path_and_params)}"
53
27
  end
54
28
 
55
29
  @options = prev_options
@@ -61,61 +35,139 @@ module Imgix
61
35
  self
62
36
  end
63
37
 
38
+ def ixlib(lib_version)
39
+ @options[:ixlib] = lib_version
40
+ end
41
+
42
+ def ixlib=(lib_version)
43
+ @options[:ixlib] = lib_version
44
+ end
45
+
46
+ def to_srcset(options: {}, **params)
47
+ prev_options = @options.dup
48
+ @options.merge!(params)
49
+
50
+ width = @options[:w]
51
+ height = @options[:h]
52
+ aspect_ratio = @options[:ar]
53
+
54
+ srcset = if width || height
55
+ build_dpr_srcset(options: options, params: @options)
56
+ else
57
+ build_srcset_pairs(options: options, params: @options)
58
+ end
59
+
60
+ @options = prev_options
61
+ srcset
62
+ end
63
+
64
+ ALIASES = {
65
+ width: :w,
66
+ height: :h,
67
+ rotation: :rot,
68
+ noise_reduction: :nr,
69
+ sharpness: :sharp,
70
+ exposure: :exp,
71
+ vibrance: :vib,
72
+ saturation: :sat,
73
+ brightness: :bri,
74
+ contrast: :con,
75
+ highlight: :high,
76
+ shadow: :shad,
77
+ gamma: :gam,
78
+ pixelate: :px,
79
+ halftone: :htn,
80
+ watermark: :mark,
81
+ text: :txt,
82
+ format: :fm,
83
+ quality: :q,
84
+ fill_color: :fillcolor
85
+ }.freeze
86
+
87
+ # Define query parameters on a Path (via method_missing).
88
+ # Normally, when overriding method_missing, it is a best practice
89
+ # to fall back to super, but this method works differently.
90
+ #
91
+ # method_missing intercepts messages sent to objects of this class
92
+ # and acts as a getter, setter, and deleter. If there are no args,
93
+ # e.g. `path.width`, then this method acts like a getter.
94
+ #
95
+ # Likewise, if the first argument is nil and the method name exists
96
+ # as a key in @options, e.g. `path.param_name = nil`, then this
97
+ # method acts like a deleter and the `param_name` is removed from
98
+ # the list of @options.
99
+ #
100
+ # Finally, in _all_ other cases, the `method` name is used as the
101
+ # `key` and the `*args` are used as the value.
64
102
  def method_missing(method, *args, &block)
65
103
  key = method.to_s.gsub('=', '')
66
- if args.length == 0
104
+
105
+ if args.length == 0 # Get, or
67
106
  return @options[key]
68
- elsif args.first.nil? && @options.has_key?(key)
107
+ elsif args.first.nil? && @options.has_key?(key) # Delete, or
69
108
  @options.delete(key) and return self
70
109
  end
71
110
 
72
- @options[key] = args.join(',')
111
+ @options[key] = args.join(',') # Set the option.
73
112
  self
74
113
  end
75
114
 
115
+ # Use ALIASES to define setters for a subset of imgix parameters.
116
+ # E.g. `path.width(100)` would result in `send(:w, [100])`.
76
117
  ALIASES.each do |from, to|
77
118
  define_method from do |*args|
78
- warn "Warning: `Path.#{from}' has been deprecated and " \
79
- "will be removed in the next major version (along " \
80
- "with all parameter `ALIASES`).\n"
81
119
  self.send(to, *args)
82
120
  end
83
121
 
122
+ # E.g. `path.width = 100` would result in `send(":w=", [100])`.
84
123
  define_method "#{from}=" do |*args|
85
- warn "Warning: `Path.#{from}=' has been deprecated and " \
86
- "will be removed in the next major version (along " \
87
- "with all parameter `ALIASES`).\n"
88
124
  self.send("#{to}=", *args)
89
125
  return self
90
126
  end
91
127
  end
92
128
 
93
- def to_srcset(options: {}, **params)
94
- prev_options = @options.dup
95
- @options.merge!(params)
96
-
97
- width = @options[:w]
98
- height = @options[:h]
99
- aspect_ratio = @options[:ar]
129
+ private
100
130
 
101
- srcset = if width || (height && aspect_ratio)
102
- build_dpr_srcset(options: options, params: @options)
103
- else
104
- build_srcset_pairs(options: options, params: @options)
105
- end
131
+ # Escape and encode any characters in path that are reserved and not utf8 encoded.
132
+ # This includes " +?:#" characters. If a path is being used as a proxy, utf8
133
+ # encode everything. If it is not being used as proxy, leave certain chars, like
134
+ # "/", alone. Method assumes path is not already encoded.
135
+ def sanitize_path(path)
136
+ # remove the leading "/", we'll add it back after encoding
137
+ path = path.slice(1, path.length) if Regexp.new('^/') =~ path
138
+ # if path is being used as a proxy, encode the entire thing
139
+ if /^https?/ =~ path
140
+ return encode_URI_Component(path)
141
+ else
142
+ # otherwise, encode only specific characters
143
+ return encode_URI(path)
144
+ end
145
+ end
106
146
 
107
- @options = prev_options
108
- srcset
147
+ # URL encode the entire path
148
+ def encode_URI_Component(path)
149
+ return "/" + ERB::Util.url_encode(path)
109
150
  end
110
151
 
111
- private
152
+ # URL encode every character in the path, including
153
+ # " +?:#" characters.
154
+ def encode_URI(path)
155
+ # For each component in the path, URL encode it and add it
156
+ # to the array path component.
157
+ path_components = []
158
+ path.split("/").each do |str|
159
+ path_components << ERB::Util.url_encode(str)
160
+ end
161
+ # Prefix and join the encoded path components.
162
+ "/#{path_components.join('/')}"
163
+ end
112
164
 
113
- def signature
114
- Digest::MD5.hexdigest(@secure_url_token + path_and_params)
165
+ def signature(rest)
166
+ Digest::MD5.hexdigest(@secure_url_token + rest)
115
167
  end
116
168
 
117
- def path_and_params
118
- has_query? ? "#{@path}?#{query}" : @path
169
+ def path_and_params(path)
170
+ has_query? ? "#{path}?#{query}" : path
119
171
  end
120
172
 
121
173
  def query
@@ -127,15 +179,15 @@ module Imgix
127
179
  else
128
180
  escaped_key << "=" << ERB::Util.url_encode(val.to_s)
129
181
  end
130
- end.join('&')
182
+ end.join("&")
131
183
  end
132
184
 
133
185
  def has_query?
134
- query.length > 0
186
+ !query.empty?
135
187
  end
136
188
 
137
189
  def build_srcset_pairs(options:, params:)
138
- srcset = ''
190
+ srcset = ""
139
191
 
140
192
  widths = options[:widths] || []
141
193
  width_tolerance = options[:width_tolerance] || DEFAULT_WIDTH_TOLERANCE
@@ -150,10 +202,10 @@ module Imgix
150
202
  validate_width_tolerance!(width_tolerance)
151
203
  srcset_widths = TARGET_WIDTHS.call(width_tolerance, min_width, max_width)
152
204
  else
153
- srcset_widths = @target_widths
205
+ srcset_widths = DEFAULT_TARGET_WIDTHS
154
206
  end
155
207
 
156
- for width in srcset_widths do
208
+ srcset_widths.each do |width|
157
209
  params[:w] = width
158
210
  srcset += "#{to_url(params)} #{width}w,\n"
159
211
  end
@@ -162,7 +214,7 @@ module Imgix
162
214
  end
163
215
 
164
216
  def build_dpr_srcset(options:, params:)
165
- srcset = ''
217
+ srcset = ""
166
218
 
167
219
  disable_variable_quality = options[:disable_variable_quality] || false
168
220
  validate_variable_qualities!(disable_variable_quality)
@@ -170,12 +222,10 @@ module Imgix
170
222
  target_ratios = [1, 2, 3, 4, 5]
171
223
  quality = params[:q]
172
224
 
173
- for ratio in target_ratios do
225
+ target_ratios.each do |ratio|
174
226
  params[:dpr] = ratio
175
227
 
176
- unless disable_variable_quality
177
- params[:q] = quality || DPR_QUALITY[ratio]
178
- end
228
+ params[:q] = quality || DPR_QUALITY[ratio] unless disable_variable_quality
179
229
 
180
230
  srcset += "#{to_url(params)} #{ratio}x,\n"
181
231
  end
@@ -184,34 +234,28 @@ module Imgix
184
234
  end
185
235
 
186
236
  def validate_width_tolerance!(width_tolerance)
187
- width_increment_error = 'error: `width_tolerance` must be a positive `Numeric` value'
237
+ width_increment_error = "error: `width_tolerance` must be a positive `Numeric` value"
188
238
 
189
- if !width_tolerance.is_a?(Numeric) || width_tolerance <= 0
190
- raise ArgumentError, width_increment_error
191
- end
239
+ raise ArgumentError, width_increment_error if !width_tolerance.is_a?(Numeric) || width_tolerance <= 0
192
240
  end
193
241
 
194
242
  def validate_widths!(widths)
195
- widths_error = 'error: `widths` must be an array of positive `Numeric` values'
243
+ widths_error = "error: `widths` must be an array of positive `Numeric` values"
196
244
  raise ArgumentError, widths_error unless widths.is_a?(Array)
197
245
 
198
246
  all_positive_integers = widths.all? { |i| i.is_a?(Integer) && i > 0 }
199
247
  raise ArgumentError, widths_error unless all_positive_integers
200
248
  end
201
249
 
202
- def validate_range!(min_srcset, max_srcset)
203
- range_numeric_error = 'error: `min_width` and `max_width` must be positive `Numeric` values'
204
- unless min_srcset.is_a?(Numeric) && max_srcset.is_a?(Numeric)
205
- raise ArgumentError, range_numeric_error
206
- end
250
+ def validate_range!(min_width, max_width)
251
+ range_numeric_error = "error: `min_width` and `max_width` must be positive `Numeric` values"
252
+ raise ArgumentError, range_numeric_error unless min_width.is_a?(Numeric) && max_width.is_a?(Numeric)
207
253
 
208
- unless min_srcset > 0 && max_srcset > 0
209
- raise ArgumentError, range_numeric_error
210
- end
254
+ raise ArgumentError, range_numeric_error unless min_width > 0 && max_width > 0
211
255
  end
212
256
 
213
257
  def validate_variable_qualities!(disable_quality)
214
- disable_quality_error = 'error: `disable_quality` must be a Boolean value'
258
+ disable_quality_error = "error: `disable_quality` must be a Boolean value"
215
259
  unless disable_quality.is_a?(TrueClass) || disable_quality.is_a?(FalseClass)
216
260
  raise ArgumentError, disable_quality_error
217
261
  end
data/lib/imgix/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Imgix
4
- VERSION = '3.3.1'
4
+ VERSION = "4.0.3"
5
5
  end
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH << 'lib'
2
+ require 'imgix'
3
+ require 'benchmark/ips'
4
+
5
+ client = Imgix::Client.new(domain: 'domain.com', secure_url_token: 'token')
6
+
7
+ Benchmark.ips do |x|
8
+ x.report('Imgix::Path#initialize') do
9
+ client.path("/img.jpg")
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH << 'lib'
2
+ require 'imgix'
3
+ require 'benchmark/ips'
4
+
5
+ client = Imgix::Client.new(domain: 'domain.com', secure_url_token: 'token')
6
+ path = client.path("/img.jpg")
7
+
8
+ Benchmark.ips do |x|
9
+ x.report('Imgix::Path#to_url') do
10
+ path.to_url({ auto: 'compress,format', fit: 'crop', crop: 'top', w: 590, h: 332 })
11
+ end
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: imgix
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.1
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kelly Sutton
@@ -10,39 +10,11 @@ authors:
10
10
  - Antony Denyer
11
11
  - Paul Straw
12
12
  - Sherwin Heydarbeygi
13
- autorequire:
13
+ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2020-07-27 00:00:00.000000000 Z
17
- dependencies:
18
- - !ruby/object:Gem::Dependency
19
- name: addressable
20
- requirement: !ruby/object:Gem::Requirement
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: '0'
25
- type: :runtime
26
- prerelease: false
27
- version_requirements: !ruby/object:Gem::Requirement
28
- requirements:
29
- - - ">="
30
- - !ruby/object:Gem::Version
31
- version: '0'
32
- - !ruby/object:Gem::Dependency
33
- name: webmock
34
- requirement: !ruby/object:Gem::Requirement
35
- requirements:
36
- - - ">="
37
- - !ruby/object:Gem::Version
38
- version: '0'
39
- type: :development
40
- prerelease: false
41
- version_requirements: !ruby/object:Gem::Requirement
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- version: '0'
16
+ date: 2021-05-05 00:00:00.000000000 Z
17
+ dependencies: []
46
18
  description: Easily create and sign imgix URLs.
47
19
  email:
48
20
  - kelly@imgix.com
@@ -55,13 +27,10 @@ executables: []
55
27
  extensions: []
56
28
  extra_rdoc_files: []
57
29
  files:
58
- - ".github/CODEOWNERS"
59
- - ".github/ISSUE_TEMPLATE/bug_report.md"
60
- - ".github/ISSUE_TEMPLATE/feature_request.md"
61
- - ".github/ISSUE_TEMPLATE/question.md"
62
- - ".github/pull_request_template.md"
63
30
  - ".gitignore"
31
+ - ".rubocop.yml"
64
32
  - ".travis.yml"
33
+ - ".vscode/tasks.json"
65
34
  - CHANGELOG.md
66
35
  - Contributing.markdown
67
36
  - Gemfile
@@ -71,25 +40,19 @@ files:
71
40
  - imgix.gemspec
72
41
  - lib/imgix.rb
73
42
  - lib/imgix/client.rb
74
- - lib/imgix/param_helpers.rb
75
43
  - lib/imgix/path.rb
76
44
  - lib/imgix/version.rb
77
- - test/test_helper.rb
78
- - test/units/domains_test.rb
79
- - test/units/param_helpers_test.rb
80
- - test/units/path_test.rb
81
- - test/units/purge_test.rb
82
- - test/units/srcset_test.rb
83
- - test/units/url_test.rb
45
+ - script/bench_path.rb
46
+ - script/bench_to_url.rb
84
47
  homepage: https://github.com/imgix/imgix-rb
85
48
  licenses:
86
49
  - MIT
87
50
  metadata:
88
51
  bug_tracker_uri: https://github.com/imgix/imgix-rb/issues
89
52
  changelog_uri: https://github.com/imgix/imgix-rb/blob/main/CHANGELOG.md
90
- documentation_uri: https://www.rubydoc.info/gems/imgix/3.3.1
91
- source_code_uri: https://github.com/imgix/imgix-rb/tree/3.3.1
92
- post_install_message:
53
+ documentation_uri: https://www.rubydoc.info/gems/imgix/4.0.3
54
+ source_code_uri: https://github.com/imgix/imgix-rb/tree/4.0.3
55
+ post_install_message:
93
56
  rdoc_options: []
94
57
  require_paths:
95
58
  - lib
@@ -104,15 +67,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
67
  - !ruby/object:Gem::Version
105
68
  version: '0'
106
69
  requirements: []
107
- rubygems_version: 3.1.2
108
- signing_key:
70
+ rubygems_version: 3.1.4
71
+ signing_key:
109
72
  specification_version: 4
110
73
  summary: Official Ruby Gem for easily creating and signing imgix URLs.
111
- test_files:
112
- - test/test_helper.rb
113
- - test/units/domains_test.rb
114
- - test/units/param_helpers_test.rb
115
- - test/units/path_test.rb
116
- - test/units/purge_test.rb
117
- - test/units/srcset_test.rb
118
- - test/units/url_test.rb
74
+ test_files: []