From: Ruby-Lang@... Date: 2018-10-28T09:10:04+00:00 Subject: [ruby-core:89599] [Ruby trunk Feature#14145] Proposal: Better Method#inspect Issue #14145 has been updated by jwmittag (J��rg W Mittag). guilhermereiscampos (Guilherme Reis Campos) wrote: > zverok (Victor Shepelev) wrote: > > ```ruby > > # We can't extract default values, but at least we can say they are there > > Addressable::URI.method(:heuristic_parse) > > # => #)> > > ``` > I wonder why is not possible to extract the default values? Because they can be arbitrary Ruby code and Ruby is a Turing-complete language, which means that figuring out statically what the default value is, is equivalent to solving the Halting Problem. Additionally, Ruby is also capable of I/O and other side-effects, which means that the value can depend on external entities not visible to the documentation generator. What would `Method#inspect` show for these: ```ruby def foo(a = while true do; end) end def bar(a = Time.now) end def baz(a = if rand < 0.5 then 23 else 'fourty-two' end) end def qux(a = File.read('somefile.txt')) end ``` And what about this: ```ruby def crazy(a = FileUtils.rm_rf('/')) end ``` Would you expect `Method#inspect` to evaluate the default argument in order to be able to display its value? Also, `Method#inspect` returns a `String`, but that loses all information about the type and structure of the default value: ```ruby class Foo def inspect; '42' end end def foo(a = Foo.new) end def bar(a = 42) end method(:foo).inspect #=> # method(:bar).inspect #=> # ``` We could copy the source text used to define the default argument into the output of `Method#inspect`, but that would require the source code to be available at runtime, which is a massive memory overhead (one `String` for every optional parameter in the entire system, and there is no upper bound on the size of that `String`, since a default argument can be any arbitrarily large Ruby program). Plus, there is the additional complication that not all methods in a Ruby system even *have* (Ruby) source code. ---------------------------------------- Feature #14145: Proposal: Better Method#inspect https://bugs.ruby-lang.org/issues/14145#change-74637 * Author: zverok (Victor Shepelev) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- The idea: When investigating (in example scripts, debugger or console) the library you are unfamiliar with, Ruby's reflection is very useful mechanism to understand "what it can": classes, modules, their constants, methods and so on. I propose to expose a bit more information Ruby has internally in `Method#inspect`: ```ruby # before: some_interesting_object.method(:foo) # => # # after: some_interesting_object.method(:foo) # => # ``` Dead-naive implementation: ```ruby class Method def signature recv = case receiver when Module "#{receiver.name}." else "#{receiver.class}#" end parameters.map.with_index { |(type, name), i| case type when :req then "#{name || "param#{i+1}"}" when :opt then "#{name || "param#{i+1}"} = " when :keyreq then "#{name || "kw#{i+1}"}:" when :key then "#{name || "kwparam#{i+1}"}: " when :rest then "*#{name || "rest"}" when :keyrest then "**#{name || "kwrest"}" end }.join(', ').prepend("#{recv}#{name}(") << ")" end def inspect "#<#{self.class.name} #{signature}>" end end ``` This works "sub-optimal" for methods implemented in C, yet pretty decently for Ruby-implemented methods: ```ruby # C method, default param names [1,2,3].method(:at) # => # # Ruby method, proper param names CGI.method(:escape) # => # Addressable::URI.method(:parse) # => # Addressable::URI.method(:join) => # # We can't extract default values, but at least we can say they are there Addressable::URI.method(:heuristic_parse) # => #)> ``` If the proposal is accepted, I am ready to implement it properly in C (for all callable objects: `Method`, `UnboundMethod`, `Proc`) -- https://bugs.ruby-lang.org/ Unsubscribe: