jekyll-auto-thumbnails 2.0.1 → 2.1.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
  SHA256:
3
- metadata.gz: d593b4ae0f39bd0020f6656a021327666afa8ee4776a2147d36ce3f8283a1840
4
- data.tar.gz: af035e37d27382e9a8d1d15b20ea14e3a0994f2fe1d1ff312c09b4dac924829f
3
+ metadata.gz: 3f0fec7cfa3ac45d704dcce4f97edc9e71311df06174f99dd24c3231d1675589
4
+ data.tar.gz: edc7920b2ff080b42728ead47fee4fcec02d9892979156127c85fba3661844d2
5
5
  SHA512:
6
- metadata.gz: 89945f98a6e83a64ec2d4f20b96e827d4e408ffdda0f3340da9e99086ef156ef146a6617db1f3cb1ba7de8f34d4790f47783924fc3e02afb5e1f9a9c90506d33
7
- data.tar.gz: 0b0a29fc0985c1a1930f2b1a644ed574fb4abae81fe52f0722b0a329c2731020e7cc915b7fdf8155b63e1767f2227ac409a5e2697152648d61cdca6816f59582
6
+ metadata.gz: 06b2ed4d1aa33f8f4a978e7679688daf25ffdc31fd4d0f8ca3f09eb79aa121920ee76a017750b5e2eda9d5ed5d5970e3106fd7dc1620e8e818960c012227d2f9
7
+ data.tar.gz: 837a87b1c64202fe40cd163081e9c03ee36c9289796b6c3bd90a9694e42d19c8408ce666401860c729cf5b942512ad5b2695f595b15f57c2530a2002c70906e2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.1.0](https://github.com/Texarkanine/jekyll-auto-thumbnails/compare/v2.0.1...v2.1.0) (2026-07-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * **test:** add Mutant mutation testing with RSpec ([#50](https://github.com/Texarkanine/jekyll-auto-thumbnails/issues/50)) ([42f4de6](https://github.com/Texarkanine/jekyll-auto-thumbnails/commit/42f4de6cd4740a05d7acfa4b57c01350e7054d95))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **deps:** bump nokogiri from 1.19.3 to 1.19.4 in the production-deps group ([#42](https://github.com/Texarkanine/jekyll-auto-thumbnails/issues/42)) ([0e41fd2](https://github.com/Texarkanine/jekyll-auto-thumbnails/commit/0e41fd2f3c6c475d77ca53e73be90ff4bf536ec7))
14
+ * **deps:** bump nokogiri in the production-deps group ([0e41fd2](https://github.com/Texarkanine/jekyll-auto-thumbnails/commit/0e41fd2f3c6c475d77ca53e73be90ff4bf536ec7))
15
+
3
16
  ## [2.0.1](https://github.com/Texarkanine/jekyll-auto-thumbnails/compare/v2.0.0...v2.0.1) (2026-05-14)
4
17
 
5
18
 
@@ -35,11 +35,13 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency "nokogiri", "~> 1.15"
36
36
 
37
37
  # Development dependencies
38
+ spec.add_development_dependency "mutant", "~> 0.16"
39
+ spec.add_development_dependency "mutant-rspec", "~> 0.16"
38
40
  spec.add_development_dependency "rake", "~> 13.3"
39
41
  spec.add_development_dependency "rspec", "~> 3.13"
40
42
  spec.add_development_dependency "rubocop", "~> 1.81"
41
43
  spec.add_development_dependency "rubocop-rake", "~> 0.7"
42
44
  spec.add_development_dependency "rubocop-rspec", "~> 3.8"
43
- spec.add_development_dependency "simplecov", "~> 0.22"
44
- spec.add_development_dependency "simplecov-cobertura", "~> 3.1"
45
+ spec.add_development_dependency "simplecov", "~> 1.0"
46
+ spec.add_development_dependency "simplecov-cobertura", "~> 4.0"
45
47
  end
@@ -19,7 +19,11 @@ module JekyllAutoThumbnails
19
19
  @enabled = config_hash.fetch("enabled", true)
20
20
  @max_width = parse_dimension(config_hash["max_width"])
21
21
  @max_height = parse_dimension(config_hash["max_height"])
22
- @quality = parse_quality(config_hash.fetch("quality", 85))
22
+ @quality = if config_hash.key?("quality")
23
+ parse_quality(config_hash.fetch("quality"))
24
+ else
25
+ 85
26
+ end
23
27
  @parser = parse_parser(config_hash.fetch("parser", "html5"))
24
28
  @cache_dir = File.join(site.source, ".jekyll-cache", "jekyll-auto-thumbnails")
25
29
  end
@@ -39,7 +43,7 @@ module JekyllAutoThumbnails
39
43
  # @return [Integer, nil] positive integer or nil
40
44
  def parse_dimension(value)
41
45
  val = value.to_i
42
- val.positive? ? val : nil
46
+ val if val.positive?
43
47
  end
44
48
 
45
49
  # Parse quality value (0-100)
@@ -63,7 +67,7 @@ module JekyllAutoThumbnails
63
67
  # @return [Symbol] :html4 or :html5
64
68
  # @raise [ArgumentError] for invalid values or JRuby + :html5
65
69
  def parse_parser(value)
66
- unless value.is_a?(String)
70
+ unless value.instance_of?(String)
67
71
  raise ArgumentError,
68
72
  "auto_thumbnails: parser must be a string (\"html4\" or \"html5\"); got #{value.inspect}"
69
73
  end
@@ -13,7 +13,7 @@ module JekyllAutoThumbnails
13
13
  # @return [String] first 6 characters of MD5 hex digest
14
14
  # @raise [Errno::ENOENT] if file doesn't exist
15
15
  def self.short_digest(file_path)
16
- Digest::MD5.file(file_path).hexdigest[0...6]
16
+ Digest::MD5.file(file_path).hexdigest.byteslice(0, 6)
17
17
  end
18
18
  end
19
19
  end
@@ -72,9 +72,7 @@ module JekyllAutoThumbnails
72
72
  # @param ext [String] file extension
73
73
  # @return [String] thumbnail filename
74
74
  def build_thumbnail_filename(basename, digest, width, height, ext)
75
- width_str = width || ""
76
- height_str = height || ""
77
- "#{basename}_thumb-#{digest}-#{width_str}x#{height_str}#{ext}"
75
+ "#{basename}_thumb-#{digest}-#{width}x#{height}#{ext}"
78
76
  end
79
77
 
80
78
  private
@@ -111,9 +109,7 @@ module JekyllAutoThumbnails
111
109
  # @param height [Integer, nil] target height
112
110
  # @return [String] geometry string (e.g., "400x300>")
113
111
  def build_geometry(width, height)
114
- width_str = width || ""
115
- height_str = height || ""
116
- "#{width_str}x#{height_str}>"
112
+ "#{width}x#{height}>"
117
113
  end
118
114
 
119
115
  # Check if quality parameter needed for image format
@@ -97,7 +97,7 @@ module JekyllAutoThumbnails
97
97
  cached_path = File.join(config.cache_dir, thumb_filename)
98
98
 
99
99
  # Build destination path in _site preserving directory structure
100
- dest_path = File.join(site.dest, thumb_url.sub(%r{^/}, ""))
100
+ dest_path = File.join(site.dest, thumb_url)
101
101
  dest_dir = File.dirname(dest_path)
102
102
 
103
103
  FileUtils.mkdir_p(dest_dir)
@@ -128,8 +128,6 @@ module JekyllAutoThumbnails
128
128
  modified = false
129
129
  doc.css("article img").each do |img|
130
130
  src = img["src"]
131
- next unless src
132
-
133
131
  thumb_url = url_map[src]
134
132
  next unless thumb_url
135
133
 
@@ -148,8 +146,6 @@ module JekyllAutoThumbnails
148
146
  ext = File.extname(doc.path || doc.url || "").downcase
149
147
  [".html", ".htm", ".md", ".markdown"].include?(ext)
150
148
  end
151
-
152
- private_class_method :replace_urls, :html_document?
153
149
  end
154
150
  end
155
151
 
@@ -14,8 +14,6 @@ module JekyllAutoThumbnails
14
14
  # users who depended on libxml2's serialization quirks (notably the
15
15
  # injected `<meta http-equiv="Content-Type">`).
16
16
  module HtmlParser
17
- module_function
18
-
19
17
  # Parse an HTML string with the selected parser.
20
18
  #
21
19
  # @param html [String] HTML source
@@ -25,7 +23,7 @@ module JekyllAutoThumbnails
25
23
  # @raise [NameError] if :html5 is requested under JRuby (should be
26
24
  # prevented by Configuration validation; this is a belt-and-suspenders
27
25
  # guard)
28
- def parse(html, parser)
26
+ def self.parse(html, parser)
29
27
  case parser
30
28
  when :html5
31
29
  Nokogiri::HTML5.parse(html)
@@ -25,10 +25,8 @@ module JekyllAutoThumbnails
25
25
  case detect_version
26
26
  when :v7
27
27
  %w[magick convert]
28
- when :v6
29
- ["convert"]
30
28
  else
31
- ["convert"] # Default fallback (will fail if not available)
29
+ ["convert"] # v6 and unavailable fallback (will fail if not available)
32
30
  end
33
31
  end
34
32
 
@@ -39,10 +37,8 @@ module JekyllAutoThumbnails
39
37
  case detect_version
40
38
  when :v7
41
39
  %w[magick identify]
42
- when :v6
43
- ["identify"]
44
40
  else
45
- ["identify"] # Default fallback (will fail if not available)
41
+ ["identify"] # v6 and unavailable fallback (will fail if not available)
46
42
  end
47
43
  end
48
44
 
@@ -68,9 +64,7 @@ module JekyllAutoThumbnails
68
64
  #
69
65
  # @return [Symbol] :v6, :v7, or :none
70
66
  def self.detect_version
71
- return @detected_version if defined?(@detected_version) && @detected_version
72
-
73
- @detected_version = if command_exists?("magick")
67
+ @detect_version ||= if command_exists?("magick")
74
68
  :v7
75
69
  elsif command_exists?("convert")
76
70
  :v6
@@ -79,6 +73,16 @@ module JekyllAutoThumbnails
79
73
  end
80
74
  end
81
75
 
76
+ # Clear the memoized result of {.detect_version}.
77
+ #
78
+ # Intended for tests that mutate PATH between examples so detection can
79
+ # be re-probed through the public API rather than via reflection.
80
+ #
81
+ # @return [void]
82
+ def self.reset_detection_cache!
83
+ @detect_version = nil
84
+ end
85
+
82
86
  # Check if a command exists in PATH
83
87
  #
84
88
  # @param cmd [String] command name
@@ -17,17 +17,11 @@ module JekyllAutoThumbnails
17
17
  # @param width [Integer, nil] required width
18
18
  # @param height [Integer, nil] required height
19
19
  def register(url, width, height)
20
- existing = @entries[url]
21
-
22
- @entries[url] = if existing
23
- # Update to max dimensions
24
- {
25
- width: [existing[:width], width].compact.max,
26
- height: [existing[:height], height].compact.max
27
- }
28
- else
29
- { width: width, height: height }
30
- end
20
+ previous = @entries[url]
21
+ @entries[url] = {
22
+ width: [previous&.dig(:width), width].compact.max,
23
+ height: [previous&.dig(:height), height].compact.max
24
+ }
31
25
  end
32
26
 
33
27
  # Check if image is registered
@@ -43,7 +37,7 @@ module JekyllAutoThumbnails
43
37
  # @param url [String] image URL
44
38
  # @return [Hash, nil] {width:, height:} or nil if not registered
45
39
  def requirements_for(url)
46
- @entries[url]&.dup
40
+ @entries[url].dup
47
41
  end
48
42
 
49
43
  # Get all registered entries
@@ -28,20 +28,12 @@ module JekyllAutoThumbnails
28
28
  height = parse_dimension(img["height"])
29
29
 
30
30
  if width || height
31
- # Explicitly sized - calculate missing dimension if needed
32
- if site_source && (width.nil? || height.nil?)
33
- Jekyll.logger.debug "AutoThumbnails:", "Calculating dimensions for #{src} (#{width}x#{height})"
34
- width, height = calculate_dimensions(src, width, height, site_source)
35
- Jekyll.logger.debug "AutoThumbnails:", "Calculated: #{width}x#{height}"
36
- end
31
+ # Only identify for aspect-ratio fill when a dimension is missing
32
+ width, height = calculate_dimensions(src, width, height, site_source) if site_source && (!width || !height)
37
33
 
38
34
  # Skip if dimensions match original (no thumbnail needed)
39
- if site_source && dimensions_match_original?(src, width, height, site_source)
40
- Jekyll.logger.debug "AutoThumbnails:", "Skipping #{src} - dimensions match original"
41
- next
42
- end
35
+ next if site_source && dimensions_match_original?(src, width, height, site_source)
43
36
 
44
- Jekyll.logger.debug "AutoThumbnails:", "Registering #{src} at #{width}x#{height}"
45
37
  registry.register(src, width, height)
46
38
  elsif site_source && (config.max_width || config.max_height)
47
39
  # Unsized but max config exists - check actual dimensions
@@ -61,7 +53,7 @@ module JekyllAutoThumbnails
61
53
  return unless file_path && File.exist?(file_path)
62
54
 
63
55
  actual_width, actual_height = image_dimensions(file_path)
64
- return unless actual_width && actual_height
56
+ return unless actual_height
65
57
 
66
58
  # Check if exceeds max dimensions
67
59
  exceeds_width = config.max_width && actual_width > config.max_width
@@ -82,10 +74,10 @@ module JekyllAutoThumbnails
82
74
  # Use [0] to get only first frame (important for animated GIFs)
83
75
  # Wrapper handles both ImageMagick v6 and v7
84
76
  output, status = ImageMagickWrapper.execute_identify("-format", "%wx%h", "#{file_path}[0]")
85
- return nil unless status.success? && !output.strip.empty?
77
+ return nil unless status.success?
86
78
 
87
- width, height = output.strip.split("x").map(&:to_i)
88
- [width, height]
79
+ match = output.match(/\A\s*(\d+)x(\d+)\s*\z/)
80
+ [Integer(match[1]), Integer(match[2])]
89
81
  rescue StandardError
90
82
  nil
91
83
  end
@@ -102,7 +94,7 @@ module JekyllAutoThumbnails
102
94
  return [width, height] unless file_path && File.exist?(file_path)
103
95
 
104
96
  actual_width, actual_height = image_dimensions(file_path)
105
- return [width, height] unless actual_width && actual_height
97
+ return [width, height] unless actual_height
106
98
 
107
99
  # Calculate missing dimension preserving aspect ratio
108
100
  if width && !height
@@ -123,13 +115,11 @@ module JekyllAutoThumbnails
123
115
  # @param value [String, nil] attribute value
124
116
  # @return [Integer, nil] parsed integer or nil
125
117
  def self.parse_dimension(value)
126
- return nil if value.nil? || value.empty?
127
-
128
118
  # Strip non-numeric characters (e.g., "300px" -> 300)
129
119
  numeric = value.to_s.gsub(/[^\d]/, "")
130
120
  return nil if numeric.empty?
131
121
 
132
- numeric.to_i
122
+ Integer(numeric)
133
123
  end
134
124
 
135
125
  # Check if requested dimensions match original dimensions
@@ -144,12 +134,8 @@ module JekyllAutoThumbnails
144
134
  return false unless file_path && File.exist?(file_path)
145
135
 
146
136
  actual_width, actual_height = image_dimensions(file_path)
147
- return false unless actual_width && actual_height
148
137
 
149
138
  width == actual_width && height == actual_height
150
139
  end
151
-
152
- private_class_method :check_and_register_oversized, :calculate_dimensions, :parse_dimension,
153
- :dimensions_match_original?
154
140
  end
155
141
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pathname"
4
+
3
5
  module JekyllAutoThumbnails
4
6
  # URL resolution and path handling
5
7
  #
@@ -23,13 +25,8 @@ module JekyllAutoThumbnails
23
25
  return nil if external?(url)
24
26
  return url if url.start_with?("/")
25
27
 
26
- # Relative path - resolve against base_dir
27
- # Remove ./ prefix if present
28
- cleaned_url = url.sub(%r{^\./}, "")
29
-
30
28
  # Join with base_dir and normalize
31
- require "pathname"
32
- Pathname.new(File.join(base_dir, cleaned_url)).cleanpath.to_s
29
+ Pathname.new(File.join(base_dir, url)).cleanpath.to_s
33
30
  end
34
31
 
35
32
  # Convert site-relative URL to filesystem path
@@ -40,9 +37,7 @@ module JekyllAutoThumbnails
40
37
  def self.to_filesystem_path(url, site_source)
41
38
  return nil if external?(url)
42
39
 
43
- # Strip leading slash and join with site source
44
- cleaned_url = url.sub(%r{^/}, "")
45
- File.join(site_source, cleaned_url)
40
+ File.join(site_source, url)
46
41
  end
47
42
  end
48
43
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JekyllAutoThumbnails
4
- VERSION = "2.0.1"
4
+ VERSION = "2.1.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-auto-thumbnails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Texarkanine
@@ -43,6 +43,34 @@ dependencies:
43
43
  - - "~>"
44
44
  - !ruby/object:Gem::Version
45
45
  version: '1.15'
46
+ - !ruby/object:Gem::Dependency
47
+ name: mutant
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '0.16'
53
+ type: :development
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.16'
60
+ - !ruby/object:Gem::Dependency
61
+ name: mutant-rspec
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.16'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '0.16'
46
74
  - !ruby/object:Gem::Dependency
47
75
  name: rake
48
76
  requirement: !ruby/object:Gem::Requirement
@@ -119,28 +147,28 @@ dependencies:
119
147
  requirements:
120
148
  - - "~>"
121
149
  - !ruby/object:Gem::Version
122
- version: '0.22'
150
+ version: '1.0'
123
151
  type: :development
124
152
  prerelease: false
125
153
  version_requirements: !ruby/object:Gem::Requirement
126
154
  requirements:
127
155
  - - "~>"
128
156
  - !ruby/object:Gem::Version
129
- version: '0.22'
157
+ version: '1.0'
130
158
  - !ruby/object:Gem::Dependency
131
159
  name: simplecov-cobertura
132
160
  requirement: !ruby/object:Gem::Requirement
133
161
  requirements:
134
162
  - - "~>"
135
163
  - !ruby/object:Gem::Version
136
- version: '3.1'
164
+ version: '4.0'
137
165
  type: :development
138
166
  prerelease: false
139
167
  version_requirements: !ruby/object:Gem::Requirement
140
168
  requirements:
141
169
  - - "~>"
142
170
  - !ruby/object:Gem::Version
143
- version: '3.1'
171
+ version: '4.0'
144
172
  description: Jekyll plugin that automatically generates and serves optimized image
145
173
  thumbnails for faster page loads.
146
174
  email: