summaryrefslogtreecommitdiff
path: root/lib
AgeCommit message (Collapse)Author
2026-03-26[ruby/did_you_mean] [DOC] Fix linksBurdetteLamar
https://github.com/ruby/did_you_mean/commit/0b35da6496
2026-03-25[ruby/rubygems] Fallback to copy symlinks on WindowsLars Kanis
(https://github.com/ruby/rubygems/pull/9296) Symlinks are not permitted by default for a Windows user. To use them, a switch called "Development Mode" in the system settings has to be enabled. ## What was the end-user or developer problem that led to this PR? Ordinary users as well as administrators are unable per default to install gems using symlinks. One such problematical gem is `haml-rails-3.0.0`. It uses symlinks for [files and directories](https://github.com/haml/haml-rails/tree/9f4703ddff0644ba52529c5cf41c1624829b16a7/lib/generators/haml/scaffold/templates). The resulting error message is not very helpful: ``` $ gem inst haml-rails Fetching haml-rails-3.0.0.gem ERROR: While executing gem ... (Gem::FilePermissionError) You don't have write permissions for the directory. (Gem::FilePermissionError) C:/ruby/lib/ruby/4.0.0/rubygems/installer.rb:308:in 'Gem::Installer#install' C:/ruby/lib/ruby/4.0.0/rubygems/resolver/specification.rb:105:in 'Gem::Resolver::Specification#install' C:/ruby/lib/ruby/4.0.0/rubygems/request_set.rb:192:in 'block in Gem::RequestSet#install' C:/ruby/lib/ruby/4.0.0/rubygems/request_set.rb:183:in 'Array#each' C:/ruby/lib/ruby/4.0.0/rubygems/request_set.rb:183:in 'Gem::RequestSet#install' C:/ruby/lib/ruby/4.0.0/rubygems/commands/install_command.rb:207:in 'Gem::Commands::InstallCommand#install_gem' C:/ruby/lib/ruby/4.0.0/rubygems/commands/install_command.rb:223:in 'block in Gem::Commands::InstallCommand#install_gems' C:/ruby/lib/ruby/4.0.0/rubygems/commands/install_command.rb:216:in 'Array#each' C:/ruby/lib/ruby/4.0.0/rubygems/commands/install_command.rb:216:in 'Gem::Commands::InstallCommand#install_gems' C:/ruby/lib/ruby/4.0.0/rubygems/commands/install_command.rb:162:in 'Gem::Commands::InstallCommand#execute' C:/ruby/lib/ruby/4.0.0/rubygems/command.rb:326:in 'Gem::Command#invoke_with_build_args' C:/ruby/lib/ruby/4.0.0/rubygems/command_manager.rb:252:in 'Gem::CommandManager#invoke_command' C:/ruby/lib/ruby/4.0.0/rubygems/command_manager.rb:193:in 'Gem::CommandManager#process_args' C:/ruby/lib/ruby/4.0.0/rubygems/command_manager.rb:151:in 'Gem::CommandManager#run' C:/ruby/lib/ruby/4.0.0/rubygems/gem_runner.rb:56:in 'Gem::GemRunner#run' C:/ruby/bin/gem.cmd:20:in '<main>' ``` ## What is your fix for the problem, implemented in this PR? Instead of working around the situation in the affected gem or to skip symlinks completely, I think the better solution would be to make copies of the files in question. This would allow Windows users to install and use the gem smoothly. The switch for the "Developer Mode" is available in the Windows registry under `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock` entry `AllowDevelopmentWithoutDevLicense` https://github.com/ruby/rubygems/commit/ca6c5791fe
2026-03-25[ruby/rubygems] Cache package version selection:Edouard CHIN
- ### Problem Selecting a version for a given package is a extremelly hot path. In a very large gemfile and a deep dependency tree (like the one we have in our monolith at Shopify), this codepath is hit around 3.2 million times in total during the resolution phase. ### Context When the resolution starts, Bundler fetch and turn every possible versions of a gem that was ever released on Rubygems.org into a possible candidate. We end up with a massive matrix of possibilites that PubGrub has to go through. In the case of a large Gemfile like we have, we end up with ~55,000 candidates. Many of this candidate have conflicting dependencies requirements and as pubgrub progress, it will continously ask over and over the same things: "Return the possible candidates given this version constraint" (`range.select_versions(@sorted_versions[package])`). Since this path is called so frequently (sometimes more than 8000 times for a single candidate and the same constraint), the returned value can be cached for faster access. ### Solution Cache the selected versions for a given constraint in a hash. The key being an array where the first element is the package we want to resolve and the second element is the constraint. The associated value is all possible candidates matching. If the resolver end up not finding a candidate (in example you run `bundle install --prefer-local`) then Bundler will allow finding candidates on the remote. In this case we need to invalidate the cache as otherwise the candidates from the remotes will not be considered. ### Benchmark This change has a huge impact on resolution time. Those measures were taken on Shopify monolith by removing the lockfile and measuring only resolution time (no network or external factors affect these results.) ┌─────┬──────────┬───────────┬─────────┐ │ Run │ Original │ Optimized │ Speedup │ ├─────┼──────────┼───────────┼─────────┤ │ 1 │ 19.20s │ 10.32s │ 46.3% │ ├─────┼──────────┼───────────┼─────────┤ │ 2 │ 19.17s │ 10.46s │ 45.4% │ ├─────┼──────────┼───────────┼─────────┤ │ 3 │ 18.95s │ 10.29s │ 45.7% │ ├─────┼──────────┼───────────┼─────────┤ │ 4 │ 19.17s │ 10.37s │ 45.9% │ ├─────┼──────────┼───────────┼─────────┤ │ 5 │ 19.26s │ 10.30s │ 46.5% │ ├─────┼──────────┼───────────┼─────────┤ │ Avg │ 19.15s │ 10.35s │ 46.0% │ └─────┴──────────┴───────────┴─────────┘ https://github.com/ruby/rubygems/commit/a4f5973f95
2026-03-25[ruby/rubygems] Check happy path first when comparing gem version:Edouard CHIN
- During resolution, Gem::Version are compared against each other. Since comparing versions is a very hot path we can micro optimize it to check the happy path first. The speed gain on the overall resolution isn't significant but the ips gain is quite substantial. The diff chunk is small so I figure it's worth it anyway. ```ruby a = Gem::Version.new("5.3.1") b = Gem::Version.new("5.3.1") Benchmark.ips do |x| x.report("equal regular:") { a <=> c } x.report("equal optimized:") { a <=> c } x.hold!("equal_temp_results") x.compare!(order: :baseline) end ``` ``` Warming up -------------------------------------- equal optimized: 1.268M i/100ms Calculating ------------------------------------- equal optimized: 12.738M (± 1.5%) i/s (78.50 ns/i) - 64.680M in 5.078754s Comparison: equal regular:: 9866605.0 i/s equal optimized:: 12738310.3 i/s - 1.29x faster ``` ruby 3.4.8 (2025-12-17 revision https://github.com/ruby/rubygems/commit/995b59f666) +PRISM [arm64-darwin25] https://github.com/ruby/rubygems/commit/c940f7a547
2026-03-25[ruby/rubygems] Use Array#join to build error message instead of string ↵Hiroshi SHIBATA
concatenation https://github.com/ruby/rubygems/commit/7c30560939 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25[ruby/rubygems] Show only mismatched dependencies in lockfile error messageHiroshi SHIBATA
Instead of listing all dependencies from both gemspec and lockfile, show only the ones that actually differ to make it easier to identify the source of the discrepancy. https://github.com/ruby/rubygems/commit/8c551a3621 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25[ruby/rubygems] Include detailed gemspec vs. lockfile dependency discrepanciesHiroshi SHIBATA
When the lockfile dependencies don't match the gemspec, display both sets of dependencies so users can easily identify which ones differ. https://github.com/ruby/rubygems/commit/c90d7784f8
2026-03-25[ruby/rubygems] Implement relative path handling for plugin paths in ↵Hiroshi SHIBATA
Bundler::Plugin::Index https://github.com/ruby/rubygems/commit/dd50b93622
2026-03-25[ruby/rubygems] code refactor: addresing peer commentsJonathan Barquero
https://github.com/ruby/rubygems/commit/b63c5a77a8
2026-03-25[ruby/rubygems] feat: default_cli_command for config what command bundler ↵Jonathan Barquero
runs when no specific command is provided. https://github.com/ruby/rubygems/commit/67b6b4257e
2026-03-25[ruby/rubygems] Workaround a memory corruption issue on Windows Ruby 3.3:Edouard CHIN
- Disclaimer: I honestly wasn't able to understand the problem and why this solution works. I don't have a windows machine and relying on CI machines is a bit painful. When introducing https://github.com/ruby/rubygems/pull/9414, master CI started to fail only on windows 3.3. I confirmed that running the failing spec in isolation multiple times reproduce the problem consistently. The error being either a segfault or a Bundler error along the line of "Illformed requirement `~> false.1.3.pre`". I triggered some CI with debugging output and the corruption seem to happen when `version.release` is called. It somehow modifies the previously defined variable `segments` (it's not a mutation). This is the debugging output I added https://github.com/Shopify/rubygems/commit/6a147a0f8fec000f9f59b2067ef25dd7e5d29637 and the associated CI run is at https://github.com/Shopify/rubygems/actions/runs/23465022092/job/68275229509#step:7:177 Pasting here in case the CI log get cleared: ``` segments variable is [0, 12, 3, "pre"]. Object ID is 25820 version.segments is [0, 12, 3, "pre"]. ======== AFTER ======== Segments is [-1, 12, 3, "pre"]. Object ID is 25820 version.segments is [0, 12, 3, "pre"]. ``` In this patch, I opted to reference the `version.segments` object directly, again, I don't know why it fixes the issue. https://github.com/ruby/rubygems/commit/532c9733aa
2026-03-25[ruby/rubygems] Bundler: ignore patchlevel kwarg in ruby DSLTakuya Noguchi
Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com> https://github.com/ruby/rubygems/commit/bc40cc6ef6
2026-03-25[ruby/rubygems] Respect Gemfile bundler setting in `Bundler.setup`Lin Jen-Shin
When we run `bundle exec` it'll look at `Bundler.settings[:gemfile]` and respect the Gemfile setting. However, when we just require `bundler/setup` or run `Bundle.setup`, it'll not look through that. This should make this behaviour consistent. More details can be found at: https://gitlab.com/gitlab-org/gitlab/-/issues/339939#note_667461354 https://github.com/ruby/rubygems/commit/5e6333108b
2026-03-24[PRISM] Replace MissingNode with ErrorRecoveryNodeKevin Newton
2026-03-24[ruby/prism] Visit block locals in lambda definitionsEarlopain
They may not be part of `on_param` but ripper still calls `on_ident` for them https://github.com/ruby/prism/commit/fb5303f2b8
2026-03-24[ruby/prism] Fix double-visiting on some constant path node typesEarlopain
`::X &&= 1` for example emitted `on_int` twice https://github.com/ruby/prism/commit/44d064c2bc
2026-03-24[ruby/prism] Emit `on_comment` with a newline when availableEarlopain
https://github.com/ruby/prism/commit/894f395449
2026-03-24Refactor bundled gem warning suppressor (#16512)Mau Magnaguagno
* Refactor bundled gem warning suppressor Related to #16369 * Accept suggestion Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org> --------- Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org>
2026-03-23Use latest RDoc (#16506)Stan Lo
The latest RDoc contains https://github.com/ruby/rdoc/pull/1657, which fixes install-doc failures on some platforms.
2026-03-21[ruby/prism] Clean up types on node findKevin Newton
https://github.com/ruby/prism/commit/6f597d3ff7
2026-03-20[ruby/prism] Ensure Source#offsets is set correctly in all casesBenoit Daloze
* See https://github.com/ruby/prism/issues/3861 https://github.com/ruby/prism/commit/3f6014dc53
2026-03-20[ruby/prism] Prism.findKevin Newton
Take a method, unbound method, proc, or thread backtrace location. This is our equivalent to RubyVM::AbstractSyntaxTree.of, and could be leveraged in something like error highlight. Note that this uses CRuby-specific APIs on CRuby, and falls back to using location-based APIs when those aren't available. https://github.com/ruby/prism/commit/02a93356a3
2026-03-20[ruby/prism] Lazily build offsets from a packed arrayKevin Newton
https://github.com/ruby/prism/commit/3cffc44510
2026-03-20[ruby/rubygems] Introduce a fast for comparing Gem::Version:Edouard CHIN
- ### Problem Comparing Gem::Version objects is slow. It's particularly a problem because `Gem::Version#<=>` is called million of times during resolution when using a real world Gemfile in a large application. The comparison has to compare all segments between the two objects, enter conditional branches and check lexicographical order when version is a prerelease. ### Solution I'd like to provide a fast path for the simple scenarios by turning a version into an integer. By "simple scenario" I mean version up to 4 segments which represents the vast majority of the version scheme released by maintainers. For sake of simplicity and understability of the code I opted to not include prelease version ("1.0.0.alpha") in the fast path. We'd need to turn the "pre" string into a integer while keeping lexicographical order (`1.0.0.beta` > `1.0.0.alpha`) and I felt it wasn't worth the complexity. Overall, this change makes comparing version up to 5x faster (when one version is higher than the other) There is no speed gain when 2 versions are the same as there is already a fast path implemented. Checking prerelease version is a bit slower now due to a `nil` check we are doing. ### Benchmarks ```ruby require "benchmark/ips" a = Gem::Version.new("5.3.1") b = Gem::Version.new("5.3.2") c = Gem::Version.new("5.3.1") d = Gem::Version.new("2.0.0.alpha") Benchmark.ips do |x| x.report("less than regular:") { a <=> b } x.report("less than optimized:") { a <=> b } x.hold!("lesser_than_temp_results") x.compare!(order: :baseline) end Benchmark.ips do |x| x.report("greater than regular:") { b <=> a } x.report("greater than optimized:") { b <=> a } x.hold!("greater_than_temp_results") x.compare!(order: :baseline) end Benchmark.ips do |x| x.report("equal regular:") { a <=> c } x.report("equal optimized:") { a <=> c } x.hold!("equal_temp_results") x.compare!(order: :baseline) end Benchmark.ips do |x| x.report("prerelase regular:") { a <=> d } x.report("prerelease optimized:") { a <=> d } x.hold!("prerelease_temp_results") x.compare!(order: :baseline) end ``` ``` Warming up -------------------------------------- less than optimized: 1.352M i/100ms Calculating ------------------------------------- less than optimized: 13.599M (± 0.8%) i/s (73.53 ns/i) - 68.947M in 5.070279s Comparison: less than regular:: 2622912.7 i/s less than optimized:: 13599139.2 i/s - 5.18x faster _________________________ Warming up -------------------------------------- greater than optimized: 1.355M i/100ms Calculating ------------------------------------- greater than optimized: 13.581M (± 0.6%) i/s (73.63 ns/i) - 69.120M in 5.089497s Comparison: greater than regular:: 2637899.0 i/s greater than optimized:: 13581319.7 i/s - 5.15x faster _________________________ Warming up -------------------------------------- equal optimized: 1.360M i/100ms Calculating ------------------------------------- equal optimized: 13.577M (± 0.7%) i/s (73.65 ns/i) - 68.010M in 5.009445s Comparison: equal regular:: 13885209.5 i/s equal optimized:: 13576932.0 i/s - same-ish: difference falls within error _________________________ Warming up -------------------------------------- prerelease optimized: 358.680k i/100ms Calculating ------------------------------------- prerelease optimized: 3.595M (± 0.6%) i/s (278.17 ns/i) - 18.293M in 5.088687s Comparison: prerelase regular:: 4174692.2 i/s prerelease optimized:: 3594907.8 i/s - 1.16x slower ``` https://github.com/ruby/rubygems/commit/6ef9f279d9
2026-03-20[ruby/prism] Remove currently deprecated functionalityEarlopain
The method for marking something as deprecated is currently unused but seems fine leave as is. https://github.com/ruby/prism/commit/5b523dfe6e
2026-03-20[ruby/prism] Rename strings to stringy because of linux conflictsKevin Newton
https://github.com/ruby/prism/commit/eb1d518736
2026-03-20[ruby/prism] Fix up FFI in Ractors reading internal ivarKevin Newton
https://github.com/ruby/prism/commit/b5683c8708
2026-03-20[ruby/prism] Fix up gemspec buildKevin Newton
https://github.com/ruby/prism/commit/75eb63e102
2026-03-20[ruby/prism] Introduce pm_source_tKevin Newton
https://github.com/ruby/prism/commit/f50c25b5c1
2026-03-20[ruby/prism] Fix up bindingsKevin Newton
https://github.com/ruby/prism/commit/1c1e94849e
2026-03-20[ruby/prism] Clean up rake buildKevin Newton
https://github.com/ruby/prism/commit/b66fbf9f85
2026-03-20[ruby/prism] Make some token logic internalKevin Newton
https://github.com/ruby/prism/commit/06a944a08f
2026-03-20[ruby/prism] Move parse_success_p into serialization functionsKevin Newton
https://github.com/ruby/prism/commit/f02d270409
2026-03-20[ruby/prism] Inline comments and magic comments, they do not need their own TUsKevin Newton
https://github.com/ruby/prism/commit/fb0d1369f4
2026-03-20[ruby/prism] Fold node_new into node/astKevin Newton
https://github.com/ruby/prism/commit/ee6f320689
2026-03-20[ruby/prism] Fix up buildKevin Newton
https://github.com/ruby/prism/commit/bbc2023d0b
2026-03-20[ruby/prism] Move encoding entirely internalKevin Newton
https://github.com/ruby/prism/commit/10ebcaf908
2026-03-20[ruby/prism] Move static literals entirely internalKevin Newton
https://github.com/ruby/prism/commit/7cb8b59590
2026-03-20[ruby/prism] Update pm_parse_stream API to make parser opaqueKevin Newton
https://github.com/ruby/prism/commit/035061c506
2026-03-20[ruby/prism] pm_string_free -> pm_string_cleanupKevin Newton
https://github.com/ruby/prism/commit/92b48ce940
2026-03-20[ruby/prism] Move string query into its own fileKevin Newton
https://github.com/ruby/prism/commit/88a247a486
2026-03-20[ruby/prism] Make buffer an opaque pointerKevin Newton
https://github.com/ruby/prism/commit/1b594e10da
2026-03-20[ruby/prism] pm_buffer_free -> pm_buffer_cleanupKevin Newton
https://github.com/ruby/prism/commit/2b5298128e
2026-03-20[ruby/prism] Split node.h headersKevin Newton
https://github.com/ruby/prism/commit/a4a44cb14a
2026-03-20[ruby/prism] Move file system into compiler headersKevin Newton
https://github.com/ruby/prism/commit/323f7f16f8
2026-03-20[ruby/prism] Move allocator to internal headersKevin Newton
https://github.com/ruby/prism/commit/1e3ec12adc
2026-03-20[ruby/prism] Move compiler detection stuff into include/prism/compilerKevin Newton
https://github.com/ruby/prism/commit/01d575aa2f
2026-03-20[ruby/prism] Remove definesKevin Newton
https://github.com/ruby/prism/commit/400b217393
2026-03-20[ruby/prism] More splitting of headersKevin Newton
https://github.com/ruby/prism/commit/8ad880255d
2026-03-20[ruby/prism] Split out excludes into its own headerKevin Newton
https://github.com/ruby/prism/commit/2496b0105b