gem_sorter 0.5.3 → 0.5.7

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: e7eb0be5f76f0fe5bf85c828b98e7bc0aa2fedbab8131a0db6aefbd8664bfbf8
4
- data.tar.gz: 893bb62c2c6e21857660a911c649c88c244f3eb3d8dcb2fdc9b8274e535bc26b
3
+ metadata.gz: 981a2ef59205d15bdb574b03a7f7d162e3d2a2319b2d81f19380deb8bc1b03ab
4
+ data.tar.gz: 0bd57414513bcb5d5d9ebb5578bc13d9cc1239d4816b3d5e0bdcb5d80baaff68
5
5
  SHA512:
6
- metadata.gz: b412dd7b89dd9a53115ec289b4010e7da6756b792e7cd16940fb0e06c53fbf44e96456d24cd84d0a9fa204babd2775252864a688382dfcb69baee4a3b44cbe92
7
- data.tar.gz: e3b8fb028356f3c2de88c4c4bebde010325f8dc3b8d38bc1887c2c4ddf8c4f0f1162e3c86f9ea81992ccd7f88d9255e0f86b49089e6102f00e8151e6402360b3
6
+ metadata.gz: 94f6b10e1b084a7521cc35ef3a7c0ed7516c4e7a298ea9f3077c40fab480b7e5454e656d5fc50f7d349bf682e17fb26dc85c60490aa72e4224e227d01ca5baea
7
+ data.tar.gz: 9b8b8b08728f9c987b7041d1e9b1053c6dfab936eb1553dd1674cc07e0ed11080aea410db656593372eaa8fa2a26b754118ff2589577f5a5cb31a26b13c2e8fb
data/README.md CHANGED
@@ -36,7 +36,20 @@ Once installed, you can use the provided Rake task to sort your Gemfile:
36
36
  rake gemfile:sort
37
37
  ```
38
38
 
39
- You can also run the gem_sorter globally, without needing to add it to your Gemfile:
39
+ ### Inside a Rails application
40
+ When you add `gem_sorter` to a Rails app's `Gemfile`, the `gemfile:sort` task is
41
+ registered automatically through a Railtie, using Rails' own task-loading
42
+ pipeline. This means the task is reliably available under both `bin/rails` and
43
+ `bin/rake`, and the gem no longer defines tasks during application boot:
44
+
45
+ ```bash
46
+ bin/rails gemfile:sort
47
+ # or
48
+ bin/rake gemfile:sort
49
+ ```
50
+
51
+ ### Standalone (global)
52
+ You can also run gem_sorter globally, without adding it to your Gemfile:
40
53
 
41
54
  ```bash
42
55
  rake -r gem_sorter gemfile:sort
@@ -0,0 +1,13 @@
1
+ require 'rails/railtie'
2
+
3
+ module GemSorter
4
+ # Registers the gem's rake tasks through the Rails task-loading pipeline.
5
+ # Using a Railtie ensures the tasks are available reliably inside a Rails
6
+ # application (under both `bin/rails` and `bin/rake`) without defining tasks
7
+ # during `Bundler.require`, which is order-dependent and could break boot.
8
+ class Railtie < Rails::Railtie
9
+ rake_tasks do
10
+ load File.expand_path('../tasks/gem_sorter.rake', __dir__)
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module GemSorter
2
- VERSION = '0.5.3'
2
+ VERSION = '0.5.7'
3
3
  end
data/lib/gem_sorter.rb CHANGED
@@ -4,7 +4,14 @@ require 'cgi'
4
4
  require 'openssl'
5
5
  require 'json'
6
6
 
7
- load File.expand_path('tasks/gem_sorter.rake', __dir__) if defined?(Rake)
7
+ # Inside a Rails app, let the Railtie register the rake tasks through Rails'
8
+ # own task-loading pipeline (reliable and not tied to require order). When used
9
+ # standalone (e.g. `rake -r gem_sorter gemfile:sort`), load the tasks directly.
10
+ if defined?(Rails::Railtie)
11
+ require 'gem_sorter/railtie'
12
+ elsif defined?(Rake)
13
+ load File.expand_path('tasks/gem_sorter.rake', __dir__)
14
+ end
8
15
 
9
16
  module GemSorter
10
17
  class Sorter
@@ -132,36 +139,37 @@ module GemSorter
132
139
  gem_name = extract_gem_name(gem_block[:gem_line])
133
140
  next if @config.ignore_gems.include?(gem_name) || @config.ignore_gem_versions.include?(gem_name)
134
141
 
135
- # Try to get current version from lockfile first, then from gem line
136
- current_version = @versions[gem_name] || extract_current_version(gem_block[:gem_line])
142
+ original_line = gem_block[:gem_line]
137
143
  latest_version = fetch_latest_version(gem_name)
138
-
144
+
139
145
  next unless latest_version
140
146
 
141
- extra_params = extract_params(gem_block[:gem_line])
142
- new_gemfile_text = fetch_gemfile_text(gem_name, latest_version, gem_block[:gem_line])
143
-
144
- next unless new_gemfile_text && new_gemfile_text != gem_block[:gem_line]
145
-
147
+ extra_params = extract_params(original_line)
148
+ new_gemfile_text = fetch_gemfile_text(gem_name, latest_version, original_line)
149
+
150
+ next unless new_gemfile_text && new_gemfile_text != original_line
151
+
146
152
  gem_block[:gem_line] = [new_gemfile_text.strip, extra_params].select { |value| !value.nil? && !value.empty? }.join(',')
147
-
148
- # Track version update if version changed
149
- # Compare semantic versions (x.y.z) for accurate comparison
150
- current_semantic = current_version&.match(/(\d+\.\d+\.\d+)/)
151
- current_semantic = current_semantic ? current_semantic[1] : nil
152
- latest_semantic = latest_version.match(/(\d+\.\d+\.\d+)/)
153
- latest_semantic = latest_semantic ? latest_semantic[1] : nil
154
-
155
- if current_semantic != latest_semantic
156
- @version_updates << {
157
- gem_name: gem_name,
158
- from_version: current_version || 'no version specified',
159
- to_version: latest_version
160
- }
161
- end
153
+
154
+ next unless version_changed?(original_line, new_gemfile_text)
155
+
156
+ @version_updates << {
157
+ gem_name: gem_name,
158
+ from_version: extract_current_version(original_line) || 'no version specified',
159
+ to_version: latest_version
160
+ }
162
161
  end
163
162
  end
164
163
 
164
+ # Detects whether a gem line actually changed version between what is declared
165
+ # in the Gemfile and what RubyGems returns. The comparison is based purely on
166
+ # the version constraint, ignoring cosmetic differences (e.g. quote style), so
167
+ # re-running the task does not report the same update again. The lockfile is
168
+ # intentionally not consulted here: it stays stale until `bundle install` runs.
169
+ def version_changed?(original_line, new_gemfile_text)
170
+ extract_current_version(original_line) != extract_current_version(new_gemfile_text)
171
+ end
172
+
165
173
  def remove_versions(gems)
166
174
  gems.each do |gem_block|
167
175
  gem_name = extract_gem_name(gem_block[:gem_line])
@@ -300,10 +308,10 @@ module GemSorter
300
308
  raise "Error: Could not fetch gem information from RubyGems for #{gem_name} version #{version}. Status: #{response.code}"
301
309
  end
302
310
 
303
- match = response.body.match(/<input[^>]*id=["']gemfile_text["'][^>]*value=["']([^"']+)["']/)
311
+ gemfile_text = extract_gemfile_text_from_html(response.body)
304
312
 
305
- if match
306
- CGI.unescapeHTML(match[1])
313
+ if gemfile_text
314
+ gemfile_text
307
315
  else
308
316
  raise "Error: Could not extract Gemfile text for #{gem_name} version #{version}."
309
317
  end
@@ -315,6 +323,23 @@ module GemSorter
315
323
  end
316
324
  end
317
325
 
326
+ # Extracts the ready-to-paste Gemfile line from a RubyGems gem/version page.
327
+ #
328
+ # RubyGems renders it inside an <input id="gemfile_text"> element. The markup
329
+ # lists the attributes as `value="..." id="gemfile_text"` (value first), and
330
+ # the value itself may contain both single quotes and ">" characters, e.g.
331
+ # <input type="text" value="gem 'rails', '>= 8.0'" id="gemfile_text" ...>
332
+ # so the value is captured by its own surrounding quote character rather than
333
+ # by relying on tag boundaries or attribute order. A second pattern covers the
334
+ # reverse `id="gemfile_text" ... value="..."` ordering just in case.
335
+ def extract_gemfile_text_from_html(body)
336
+ match = body.match(/\svalue=(["'])(.*?)\1(?=[^>]*\bid=["']gemfile_text["'])/m) ||
337
+ body.match(/\bid=["']gemfile_text["'][^>]*?\svalue=(["'])(.*?)\1/m)
338
+ return nil unless match
339
+
340
+ CGI.unescapeHTML(match[2])
341
+ end
342
+
318
343
  def fetch_versions_from_lockfile(lockfile_path)
319
344
  return {} unless File.exist?(lockfile_path)
320
345
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_sorter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Renan Garcia
@@ -47,6 +47,7 @@ extra_rdoc_files: []
47
47
  files:
48
48
  - README.md
49
49
  - lib/gem_sorter.rb
50
+ - lib/gem_sorter/railtie.rb
50
51
  - lib/gem_sorter/version.rb
51
52
  - lib/task_config.rb
52
53
  - lib/tasks/gem_sorter.rake
@@ -70,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
71
  - !ruby/object:Gem::Version
71
72
  version: '0'
72
73
  requirements: []
73
- rubygems_version: 3.6.8
74
+ rubygems_version: 3.6.9
74
75
  specification_version: 4
75
76
  summary: Sort gems in the Gemfile alphabetically
76
77
  test_files: []