imgix 3.3.1 → 4.0.3

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.
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: []