Feature #19484
Updated by joel@drapper.me (Joel Drapper) over 1 year ago
Calling `binding` on a C-level proc (from `&:symbol`) raises an `ArgumentError`, "Can't create Binding from C level Proc" but there is no way to tell if a given proc is a C-level proc before calling `binding` on it. It’s possible to rescue this error, but rescuing an exception is slow.
Given that a C-level proc doesn't have a binding, would it make more sense to respond to `binding` with `nil` rather than raise an error? That would allow us to, for example, look up the receiver and fall back to self, e.g. `block.binding&.receiver || self`.
Alternatively, it would be useful to be able to check whether a given proc is a C-Level proc using something like this.
```ruby
case block
when CProc
block.call(self)
else
block.call
end
```
An example use case is an interface that takes a hash of conditions and tokens. If the condition is valid, we do something with the token. Otherwise, we ignore it.
```ruby
some_interface(-> { true } => "foo", -> { false } => "bar" )
```
With literal Procs, it makes sense to call them and check their truthiness.
```ruby
def some_interface(**conditional_tokens)
conditional_tokens.each do |condition, token|
do_something_with(token) if condition.call
end
end
```
When given C-Level procs, it makes sense to call them with `self` to evaluate the corresponding method.
```ruby
some_interface(&:foo? => "foo", &:bar? => "bar" )
```
```ruby
def foo? = true
def bar? = false
def some_interface(**conditional_tokens)
conditional_tokens.each do |condition, token|
case condition
when CProc
do_something_with(token) if condition.call(self)
else
do_something_with(token) if condition.call
end
end
end
```