Redefining Float#/ appears to have no effect:
class Float
def /(other)
"magic!"
end
end
puts 10.0/2.0 # => 5.0
But when another infix operator Float#* is redefined, Float#/ suddenly takes on the new definition:
class Float
def /(other)
"magic!"
end
def *(other)
"spooky"
end
end
puts 10.0/2.0 # => "magic!"
I would love to hear if anybody can explain the source of this behavior and if anybody else gets the same results.
Ruby: ruby 2.0.0p353 (2013-11-22) [x64-mingw32]
To quickly confirm the bug, run this script.
This appears to be a bug in the implementation of Ruby. A bug report has been filed here.
In the mean time, you may either switch implementations or switch versions. 1.8.7 appears to be bug free.
EDIT
This bug was fixed with revision 44127
Related
I'm working on an upgrade from Ruby 2.7 to 3.0 and faced an issue with the keyword arguments change.
Previously we used define_method in our code for some purposes. However, with the keyword arguments change, it can no longer handle an array of arguments properly anymore.
class Foo
def test(a: 1, b: 2)
puts a
puts b
end
old_method = instance_method(:test)
define_method(:test) do |*args, &block|
old_method.bind(self).call(*args, &block)
end
end
Foo.new.test(a: 1)
This will raise wrong number of arguments (given 1, expected 0) (ArgumentError). And it previously worked in Ruby 2.7. Is there anything we can do to get the *args to work again?
Try
define_method(:test) do |*args, **kwords, &block|
old_method.bind(self).call(*args, **kwords, &block)
end
Ruby 3.0 is changing the handling of method arguments which give a deprecation warning in 2.7. There is some unexpected behavior including a keywords in a *args array. This had to be done using a hash and there needs to be more of a distinction between a hash argument and keywords. So in ruby 3.x you need to capture an arbitrary collection of keywords in a double splat because they cannot be included in the splat argument.
Mostly my understanding is shaky but I read this as an explicit example in the explanation of the changed to the arguments in the release notes for ruby 3.0.
We often shorten a block using the & notation on a symbol like this:
some_array.group_by(&:foo)
Is there a similar way to shorten expressions like {|x| x}?
some_array.group_by{|x| x}
If there were a method Object#self that returns self, then we can do
some_array.group_by(&:self)
but unfortunately, there is no such method. In terms of the number of characters, it may be longer, but readability improves.
Yes. #itself was implemented in Ruby 2.2.0.
You can access the Ruby core team discussion about this feature here.
As an interesting analogue, the #ergo method has been proposed, which would yield the receiver to a given block.
If you haven't yet upgraded to Ruby 2.2.0, you may wish to backport #itself and/or define #ergo as follows:
class Object
def itself; self end
def ergo
fail ArgumentError, "Block expected!" unless block_given?
yield self
end
end
And then:
some_array.group_by &:itself
Well, there's no built-in as far as I know, but you can make a reusable identity block:
id = Proc.new {|x| x}
some_array.group_by(&id)
And then if you really wish this were a language feature:
class Object
def it
Proc.new {|x| x}
end
end
And then you can do:
some_array.group_by(&it)
wherever you like. This may void your warranty.
Yes! The method Kernel#itself was added in Ruby 2.2.0. This method simply returns the object it was called on, so you can write:
some_array.group_by(&:itself)
You can see the extensive discussion of this feature here: https://bugs.ruby-lang.org/issues/6373. The patch was submitted by Rafael França in message #53. You can see it in the official Ruby source by looking in object.c.
If you are using a version of Ruby older than 2.2.0, you can easily add Kernel#itself into your project by putting this code somewhere in your project and making sure it gets required:
module Kernel
def itself
self
end
end if !Kernel.instance_methods.include?(:itself)
However, monkey-patching a part of the Ruby core like that can be dangerous and I would not recommend it if you are making reusable code, like a gem. Instead I would recommend just making your own identity function, as suggested by user2246674:
module MyLibrary
IDENT = Proc.new { |x| x }
array.group_by(&IDENT)
end
Sorry for the strange title, I'm not really sure how to classify this issue. I'm in the process of updating some ruby code to 1.9.3, and am seeing some strange behavior. Distilling the issue, I get:
def convert(exception)
raise exception.message
end
begin
convert(StandardError.new(StandardError))
rescue => e
puts e.class
end
In 1.9.2, the output is
StandardError
and in 1.9.3, te output is
RuntimeError
Looking though the ruby docs and release notes hasn't really given me any clues as to what could be going on here, and any help is appreciated!
The issue seems to be that prior to 1.9.3, Exception#message returned an object of class Class, not String, which causes weird things to happen and it ends up raising an exception with an unexpected class (i.e., not RuntimeError).
This bug was fixed in this commit, and it is present in the 1.9.3 changelog.
Ultimately, you do want to raise exception, not raise exception.message.
On testing with ruby debugger block_given? gives false but still executes, can someone explain me how its executed?.It is anything related to context(Is debugger changing context)?
if yes then how to find current context.
Now instead of ruby-debug when used pry then block_given? returns true.
def test
debugger
if block_given?
yield(4)
else
puts "ss"
end
end
test {|el| puts "#{el}" }
This looks like a bug in ruby-debug, specifically Kernel#binding_n which is what is getting used by the debugger.
You don't need to go into the debugger read/eval/print loop to see the bug. Here is a non-interactive example example replacing the debugger() call with binding_n(0):
require 'rubygems'; require 'ruby-debug'
Debugger.start
def test
puts eval("block_given?", binding_n(0))
if block_given?
yield(4)
else
puts "ss"
end
end
test {|el| puts "#{el}" }
Pry doesn't have this problem probably because it uses Ruby's binding() rather than binding_n(). Of course that is the most reliable.
In the case above this is clearly a win here since binding() is what is exactly wanted. But as awesome as Pry is, it can't evaluate expressions in any stack frame context except the current (or most recent) stack frame.
See also http://banisterfiend.wordpress.com/2011/01/27/turning-irb-on-its-head-with-pry/#comment-274 for differences between Pry and a debugger such as ruby-debug.
Lastly, I'll note that I tried this both in the patched MRI 1.9.2 trepanning debugger as well as rbx-trepanning for Rubinius 1.2-ish.
Both of them work as expected. In both, the equivalent of binding_n is done differently with more help from the Ruby runtime. That leaves rb8-trepanning which has the bug because it uses binding_n as well.
Shoes wraps it's own Ruby install, right?
I can't use Fiber which is a Ruby1.9 feature. And, I want to use a Fiber for creating a generator.
Here's my code (so you can make sure the problem isn't with my code):
class BrownianGenerator
def initialize
#x = 0
#fiber = Fiber.new do
loop do
#x = #x+rand;
Fiber.yield #x
end
end
end
def next; #fiber.resume end
def rewind; #x=0 end
end
and if I made a shoes app like this:
Shoes.app do
#b = BrownianGenerator.new
end
if I pull up the shoes console, I see the error:
uninitialized constant #<class:0xblah>::BrownianGenerator::Fiber
Since, it's saying Fiber is an uninitialized constant, either something is wrong with my code or this Ruby version doesn't know about the Fiber class - the latter should be the case.
I saw this question on determining the version of Ruby (which is 1.8 for my mac install), but I don't know how I would change the version.
Check out Green Shoes.
It's functionality is based off of _why's original implementation, but it's packaged as a Gem and built specifically for 1.9.
or you could use aman gupta's "poor man's fibers" or try doing ::Fiber
or what not.
GL!
-r
So I jumped into freenode #shoes and found out that the nightly build of shoes is using Ruby1.9. I haven't had time to try building it yet, but that should solve my problem.