Issue #18285 has been updated by zverok (Victor Shepelev).
I understand I am late to the party, but I am extremely concerned with how the discussion in this ticket went.
From my understanding:
1. There are many contexts, especially with designing, experimenting, and prototyping with Ruby, where "what object the problem happened with" frequently saves minutes, if not hours, of head-scratching (I give one trivial example below)
2. `#inspect` is a method that is dedicated to reasonable introspection and helping debugging; I believe it kinda implies that the user classes are advised to implement it in an efficient way, so it would be cheap to embed it into diagnostics
3. As far as I understand, the problem originates in Rails, which (as they do) doesn't try to follow good practices for `#inspect` (which is honestly frequently irritating)
4. So, by solving the Rails problem, we are making the life of _all_ Rubyists worse?..
Why I believe it would be worse—in response to:
> NoMethodError is typically because the method isn't defined on the class of that instance, and very rarely because it's not defined on the singleton class of that instance (except if it's a Module/Class). Hence showing data of that specific instance seems not so valuable, might as well just show the class. (@Eregon)
>
> The content of the hash here isn't really helpful, in the context of a `NoMethodError` all I really care about is the type of the object, so why not. (@byroot)
Those statements are relevant for typo-originated `NoMethodError` accidents (like `some_hash.deelte`), but not as relevant for duck/dynamic-typing originated ones.
Say, in a complicated algorithm working with nested data structures, `undefined method transform_keys for object Array` is significantly worse than `undefined method transform_keys for [{id: 1, name: 'John'}]`. Or, `undefined method punctuation? for TokenGroup` is worse than `undefined method punctuation? for [Token['def'] Token['end']]:TokenGroup`
The latter indicates immediately which piece of data defies the initial assumption about the structure (some `users:` are passed as an array, maybe after API version change; some particular fragment of parsed data produced a group of tokens where a singular token was expected), the former requires starting debugging and printing intermediate values.
Honestly, I would much rather prefer users to be advised "make sure your `#inspect` is efficient" than make everybody suffer.
PS: The [problem of too-long error messages](https://bugs.ruby-lang.org/issues/18285#note-6) is also interesting—but I don't believe that "just never use `#inspect` is a good solution for it either.
----------------------------------------
Feature #18285: NoMethodError#message uses a lot of CPU/is really expensive to call
https://bugs.ruby-lang.org/issues/18285#change-101039
* Author: ivoanjo (Ivo Anjo)
* Status: Open
* Priority: Normal
----------------------------------------
Hello there! I'm working at Datadog on the ddtrace gem -- https://github.com/DataDog/dd-trace-rb and we ran into this issue on one of our internal testing applications. I also blogged about this issue in <https://ivoanjo.me/blog/2021/11/01/nomethoderror-ruby-cost/>.
### Background
While testing an application that threw a lot of `NoMethodError`s in a Rails controller (this was used for validation), we discovered that service performance was very much impacted when we were logging these exceptions. While investigating with a profiler, the performance impact was caused by calls to `NoMethodError#message`, because this Rails controller had a quite complex `#inspect` method, that was getting called every time we tried to get the `#message` from the exception.
### How to reproduce
```ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'benchmark-ips'
end
puts RUBY_DESCRIPTION
class GemInformation
# ...
def get_no_method_error
method_does_not_exist
rescue => e
e
end
def get_runtime_error
raise 'Another Error'
rescue => e
e
end
def inspect # <-- expensive method gets called when calling NoMethodError#message
Gem::Specification._all.inspect
end
end
NO_METHOD_ERROR_INSTANCE = GemInformation.new.get_no_method_error
RUNTIME_ERROR_INSTANCE = GemInformation.new.get_runtime_error
Benchmark.ips do |x|
x.config(:time => 5, :warmup => 2)
x.report("no method error message cost") { NO_METHOD_ERROR_INSTANCE.message }
x.report("runtime error message cost") { RUNTIME_ERROR_INSTANCE.message }
x.compare!
end
```
### Expectation and result
Getting the `#message` from a `NoMethodError` should be no costly than getting it from any other exception.
In reality:
```
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]
no method error message cost
115.390 (± 1.7%) i/s - 580.000 in 5.027822s
runtime error message cost
6.938M (± 0.5%) i/s - 35.334M in 5.092617s
Comparison:
runtime error message cost: 6938381.6 i/s
no method error message cost: 115.4 i/s - 60130.02x (± 0.00) slower
```
### Suggested solutions
1. Do not call `#inspect` on the object on which the method was not found (see <https://github.com/ruby/ruby/blob/e0915ba67964d843832148aeca29a1f8244ca7b1/…>)
2. Cache result of calling `#message` after the first call. Ideally this should be done together with suggestion 1.
--
https://bugs.ruby-lang.org/
Issue #19308 has been updated by hsbt (Hiroshi SHIBATA).
Status changed from Closed to Open
Oh, sorry. I'm working to upgrade redis server for bugs.ruby-lang.org. Now, It works.
----------------------------------------
Bug #19308: Fix `OpenSSL::X509::CertificateError: invalid digest` on CentOS 9 / RHEL 9
https://bugs.ruby-lang.org/issues/19308#change-101031
* Author: vo.x (Vit Ondruch)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
* Backport: 2.7: DONTNEED, 3.0: DONTNEED, 3.1: DONTNEED, 3.2: REQUIRED
----------------------------------------
CentOS 9 / RHEL 9 requires prohibits SHA1 for signing purposes, therefore these specs fail:
~~~
1)
OpenSSL::X509::Name.verify returns true for valid certificate ERROR
OpenSSL::X509::CertificateError: invalid digest
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:15:in `sign'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:15:in `block (2 levels) in <top (required)>'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:4:in `<top (required)>'
2)
OpenSSL::X509::Name.verify returns false for an expired certificate ERROR
OpenSSL::X509::CertificateError: invalid digest
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:31:in `sign'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:31:in `block (2 levels) in <top (required)>'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:4:in `<top (required)>'
~~~
I have opened PR [here](https://github.com/ruby/spec/pull/990), but I'd also like see this backported into 3.2, hence also reporting here.
--
https://bugs.ruby-lang.org/
Issue #19308 has been updated by vo.x (Vit Ondruch).
Just FTR, I have received the same error also after closing this ticket ...
----------------------------------------
Bug #19308: Fix `OpenSSL::X509::CertificateError: invalid digest` on CentOS 9 / RHEL 9
https://bugs.ruby-lang.org/issues/19308#change-101027
* Author: vo.x (Vit Ondruch)
* Status: Closed
* Priority: Normal
* ruby -v: ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
* Backport: 2.7: DONTNEED, 3.0: DONTNEED, 3.1: DONTNEED, 3.2: REQUIRED
----------------------------------------
CentOS 9 / RHEL 9 requires prohibits SHA1 for signing purposes, therefore these specs fail:
~~~
1)
OpenSSL::X509::Name.verify returns true for valid certificate ERROR
OpenSSL::X509::CertificateError: invalid digest
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:15:in `sign'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:15:in `block (2 levels) in <top (required)>'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:4:in `<top (required)>'
2)
OpenSSL::X509::Name.verify returns false for an expired certificate ERROR
OpenSSL::X509::CertificateError: invalid digest
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:31:in `sign'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:31:in `block (2 levels) in <top (required)>'
/builddir/build/BUILD/ruby-3.2.0/spec/ruby/library/openssl/x509/name/verify_spec.rb:4:in `<top (required)>'
~~~
I have opened PR [here](https://github.com/ruby/spec/pull/990), but I'd also like see this backported into 3.2, hence also reporting here.
--
https://bugs.ruby-lang.org/
Issue #8088 has been updated by Eregon (Benoit Daloze).
One way nowadays to do this is to use the `Primitive.foo` system and define the method in Ruby code.
Another would be to add a new `rb_define_method` variant to which the parameters can be passed.
That could then be used for all core methods.
As a note, `rb_define_method` does give `parameters` if the passed arity is >= 0 (e.g., `Process.method(:gid=).parameters # => [[:req]]`), but not if the passed arity is -1, which is this issue.
Having parameter names is valuable notably for `Method#inspect` e.g.:
```
> "".method(:gsub)
CRuby:
=> #<Method: String#gsub(*)>
TruffleRuby:
=> #<Method: String#gsub(pattern, replacement=..., &block) <internal:core> core/string.rb:844>
```
----------------------------------------
Feature #8088: Method#parameters (and friends) should provide useful information about core methods
https://bugs.ruby-lang.org/issues/8088#change-101001
* Author: headius (Charles Nutter)
* Status: Open
* Priority: Normal
----------------------------------------
I was wiring up #parameters to work for native methods today when I realized MRI doesn't give very good information about variable-arity native methods:
```
$ ruby2.0.0 -e "p ''.method(:gsub).to_proc.parameters"
[[:rest]]
$ jruby -e "p ''.method(:gsub).to_proc.parameters"
[[:req], [:opt]]
```
I think MRI should present the same as JRuby here; gsub is obviously not a rest-arg method and you can't call it with less than 1 or more than 2 arguments. JRuby's presenting the right output here.
I'm probably going to have to change JRuby to do the less-helpful version so we're compliant and tests pass, but I think the specification of #parameters should be that it presents the JRuby version about rather than the MRI version.
--
https://bugs.ruby-lang.org/
Issue #19301 has been reported by bkuhlmann (Brooke Kuhlmann).
----------------------------------------
Bug #19301: Fix Data class to report keyrest instead of rest parameters
https://bugs.ruby-lang.org/issues/19301
* Author: bkuhlmann (Brooke Kuhlmann)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.2.0 (2022-12-25 revision a528908271) [arm64-darwin22.2.0]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
## Overview
Hello and Happy New Year. 👋
With the new `Data` class, I'm seeing a discrepancy in parameter behavior compared to a `Struct`. I understand the original `Data` [feature](https://bugs.ruby-lang.org/issues/16122) request made design choices to only accept keyword arguments for the `#initialize` method but reporting `[[rest]]` parameters seems misleading to me because it doesn't share the more flexible `Struct#initialize` behavior and would like to request `Data#initialize` answer `[[keyrest]]` for parameters for improved metaprogramming accuracy.
## Steps to Recreate
To reproduce, consider the following:
``` ruby
DataExample = Data.define :one, :two
StructExample = Struct.new :one, :two
argument_array = [one: 1, two: 2]
argument_hash = {one: 1, two: 2}
puts "Data (parameters): #{DataExample.method(:initialize).parameters}"
puts "Struct (parameters): #{StructExample.method(:initialize).parameters}"
puts "Data (argument hash): #{DataExample[**argument_hash]}"
puts "Struct (argument array): #{StructExample[*argument_array]}"
puts "Struct (argument hash): #{StructExample[**argument_hash]}"
```
The above will output the following:
```
Data (parameters): [[:rest]]
Struct (parameters): [[:rest]]
Data (argument hash): #<data DataExample one=1, two=2>
Struct (argument array): #<struct StructExample one={:one=>1, :two=>2}, two=nil>
Struct (argument hash): #<struct StructExample one=1, two=2>
```
The `Struct` class -- as far as I know -- has always reported `[[rest]]` parameters even though it can accept positional or keyword arguments without error. ...but *this is definitely not the case with* the `Data` class which can be seen when running the following modification to the above:
``` ruby
DemoExample[*argument_array]
# missing keyword: :two (ArgumentError)
```
The above clearly betrays the `[[rest]]` parameters response (granted a `Struct` is slightly devious too but at least happily accepts positional or keyword arguments). With this in mind, could `Data#initalize` be fixed to at least report `[[keyrest]]` so we'd have a better chance of metaprogramming the correct argument format based on the `#parameters` response for initializing a `Data` instance correctly?
Thanks. 🙇🏻♂️
## Environment
`ruby 3.2.0 (2022-12-25 revision a528908271) [arm64-darwin22.2.0]`
--
https://bugs.ruby-lang.org/
Issue #8088 has been updated by bkuhlmann (Brooke Kuhlmann).
I've been bitten by this same issue (see #19301) in Ruby 3.2.0 with the introduction of the new [Data](https://www.alchemists.io/articles/ruby_data) class. At the time of opening that issue, I didn't fully realize how *untruthful* `Method#parameters` is with C-based implementations since it answers `[[rest]]` for parameters which is incorrect and *very hard* to *dynamically* build the *correct* argument list when given wrong parameters. In case it helps, here's a code snippet that demonstrates the issue when using only `Data` and `Struct` objects:
``` ruby
DataExample = Data.define :one, :two
StructAny = Struct.new :one, :two
StructKeywordOnly = Struct.new :one, :two, keyword_init: true
models = [DataExample, StructAny, StructKeywordOnly]
arguments = [{one: 1, two: 2}]
models.each do |model|
puts "#{model}#initialize parameters: #{model.method(:initialize).parameters}"
end
puts
models.each do |model|
print "#{model}: "
puts model[*arguments]
rescue ArgumentError => error
puts error.message
end
# DataExample#initialize parameters: [[:rest]]
# StructAny#initialize parameters: [[:rest]]
# StructKeywordOnly#initialize parameters: [[:rest]]
#
# DataExample: missing keyword: :two
# StructAny: #<struct StructAny one={:one=>1, :two=>2}, two=nil>
# StructKeywordOnly: #<struct StructKeywordOnly one=1, two=2>
```
In all three models, messaging `model.method(:initialize).parameters` will always answer `[[rest]]` for parameters so when I build my arguments (i.e. `[{one: 1, two: 2}]`) in the same format as dictated from the `Method#parameters` then the only model that gives me the correct instance is the `StructKeywordOnly` model because using `keyword_init: true` does that coercion for me. 😅
My C knowledge is pretty terrible so I don't know how hard this would be to fix but would definitely welcome having accurate and truthful `Method#parameters` information for C-based implementations.
----------------------------------------
Feature #8088: Method#parameters (and friends) should provide useful information about core methods
https://bugs.ruby-lang.org/issues/8088#change-100998
* Author: headius (Charles Nutter)
* Status: Open
* Priority: Normal
----------------------------------------
I was wiring up #parameters to work for native methods today when I realized MRI doesn't give very good information about variable-arity native methods:
ext-jruby-local ~/projects/jruby $ ruby2.0.0 -e "p ''.method(:gsub).to_proc.parameters"
[[:rest]]
ext-jruby-local ~/projects/jruby $ jruby -e "p ''.method(:gsub).to_proc.parameters"
[[:req], [:opt]]
I think MRI should present the same as JRuby here; gsub is obviously not a rest-arg method and you can't call it with less than 1 or more than 2 arguments. JRuby's presenting the right output here.
I'm probably going to have to change JRuby to do the less-helpful version so we're compliant and tests pass, but I think the specification of #parameters should be that it presents the JRuby version about rather than the MRI version.
--
https://bugs.ruby-lang.org/
Issue #19269 has been reported by andrykonchin (Andrew Konchin).
----------------------------------------
Bug #19269: Constant lookup and #instance_eval
https://bugs.ruby-lang.org/issues/19269
* Author: andrykonchin (Andrew Konchin)
* Status: Open
* Priority: Normal
* ruby -v: 3.1.3
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
I've noticed a confusing behaviour of `#instance_eval` (and `#instance_exec` as well). In some cases it doesn't see constants defined in the object class.
Examples:
```ruby
C = 1
class A
C = 2
end
```
When `#instance_eval` is called with a String - `A::C` constant is visible, that is pretty expected:
```ruby
A.new.instance_eval("C") # => 2
```
But when it's called with a block - `A::C` isn't visible:
```ruby
A.new.instance_eval { C } # => 1
```
If we define a method that returns a constant (defined in the class), then `A::C` is visible in both cases:
```ruby
C = 1
class A
C = 2
def c; C; end
end
A.new.instance_eval("c") # => 2
A.new.instance_eval { c } # => 2
```
So we see that when `#instance_eval` called with a block and a constant is assessed directly is the only case when a class constant isn't visible.
Wondering whether it's an expected behaviour and the reason to behave this way.
--
https://bugs.ruby-lang.org/
Issue #19115 has been updated by thomthom (Thomas Thomassen).
I built Ruby 3.1.2 that we use in our product with this patch applied, and it worked on our systems. Would be nice to see it backported.
----------------------------------------
Bug #19115: RubyGems fails to detect OpenSSL in --with-static-linked-ext builds
https://bugs.ruby-lang.org/issues/19115#change-100995
* Author: thomthom (Thomas Thomassen)
* Status: Closed
* Priority: Normal
* ruby -v: 3.1.2, 3.2.0dev
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
Related discussion: https://bugs.ruby-lang.org/issues/18876
We are seeing OpenSSL failing to autoload with the Ruby build we've been using. (We first observed this when using `Gem.install` that relies on autoload of OpenSSL). Our last working build was Ruby 2.7.2 with similar config.
This causes RubyGems' `HAVE_OPENSSL` constant to be incorrectly initialized, and subsequent calls to `Gem.install` fails. There might be other scenarios that fail as a result of that, but we've not managed to identified that.
```
module Gem
HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc:
```
Our Ruby 3.1.2 config:
```
'--prefix=/Users/user/.conan/data/ruby/3.1.2/sketchup/stable/build/bd95825b99dcb274d0e577fbdc953653a9ea0fb9'
'--with-openssl-dir=/Users/user/.conan/data/openssl/1.1.1q/sketchup/stable/package/93ae0b0e7eebe0611c04d3e0d9bbf49fbce92332'
'--with-libyaml-dir=/Users/user/.conan/data/libyaml/0.2.5/sketchup/stable/package/a56a950abed2e10dbdc26845400f0a034d97c454'
'--disable-install-doc'
'--disable-install-rdoc'
'--enable-shared'
'--enable-load-relative'
'--with-static-linked-ext'
'--without-debug'
'--without-gdbm'
'--without-gettext'
'--without-irb'
'--without-mkmf'
'--without-rdoc'
'--without-readline'
'--without-tk'
'--bindir=${prefix}/bin'
'--sbindir=${prefix}/bin'
'--libexecdir=${prefix}/bin'
'--libdir=${prefix}/lib'
'--includedir=${prefix}/include'
'--oldincludedir=${prefix}/include'
'--datarootdir=${prefix}/share' 'cflags=-mmacosx-version-min=10.14 -fdeclspec' 'cxxflags=-mmacosx-version-min=10.14 -fdeclspec' 'LDFLAGS=-mmacosx-version-min=10.14 -fdeclspec'
```
We also tested with latest build from master (November 8th 2022):
```
./ruby -ve 'p RbConfig::CONFIG["configure_args"]'
ruby 3.2.0dev (2022-11-07T19:35:21Z master b14f133054) [x86_64-darwin20]
" '--prefix=/Users/vmehta/ruby/ruby-master/' '--with-openssl-dir=/Users/vmehta/.conan/data/openssl/1.1.1q/sketchup/stable/package/f2d937af1fa19d5fc4095849a65d1927e9e75ae7/' '--with-libyaml-dir=/Users/vmehta/.conan/data/libyaml/0.2.5/sketchup/stable/package/3fc084e254210603a5c5aece184b2d45e2509b30' '--disable-install-doc' '--disable-install-rdoc' '--enable-shared' '--enable-load-relative' '--with-static-linked-ext' '--without-debug' '--without-gdbm' '--without-gettext' '--without-irb' '--without-mkmf' '--without-rdoc' '--without-readline' '--without-tk'"
```
Using an RVM of Ruby 3.1.2 this appear to work as expected. But using out configuration, that we've used for the Ruby 2.x versions are now failing. We haven't been able to figure out the reason for this.
--
https://bugs.ruby-lang.org/
Issue #19270 has been reported by andrykonchin (Andrew Konchin).
----------------------------------------
Bug #19270: Constants lookup and a singleton class issue
https://bugs.ruby-lang.org/issues/19270
* Author: andrykonchin (Andrew Konchin)
* Status: Open
* Priority: Normal
* ruby -v: 3.1.3
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
I've noticed that a constant declared in a singleton class may be not visible on an object:
```ruby
class A
def c; C; end
end
a = A.new
klass = (class << a; self; end)
klass.const_set(:C, 1)
a.c
# (irb):2:in `c': uninitialized constant A::C (NameError)
```
I would expect that such constant is visible and accessible on an object. It is expected and intentional behaviour?
--
https://bugs.ruby-lang.org/
Issue #19244 has been reported by larskanis (Lars Kanis).
----------------------------------------
Bug #19244: Windows: USERPROFILE should be preferred over HOMEPATH
https://bugs.ruby-lang.org/issues/19244
* Author: larskanis (Lars Kanis)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x64-mingw-ucrt]
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
Create a new local user on Windows called "testuser".
Then switch to the new user per runas:
```
C:\> runas /user:testuser cmd
```
Then in the new window:
```
C:\>ruby -e "p Dir.home"
"C:/WINDOWS/system32"
C:\>echo %HOMEDRIVE%
C:
C:\>echo %HOMEPATH%
\WINDOWS\system32
C:\>echo %USERPROFILE%
C:\Users\testuser
```
`Dir.home` should return the home directory of the user.
Instead it returns `C:/WINDOWS/system32`.
HOMEPATH is set to "\WINDOWS\system32" when running per "runas" session.
This directory is not writable by ordinary users, leading to errors with many ruby tools.
Also config files in the home directory are not recognized.
All versions of ruby until current master branch are affected.
--
https://bugs.ruby-lang.org/