Does IronRuby have an issue with each_for_index? - ironruby

I'm working on some stuff in IronRuby, but I've run into a bit of a snag. This chunk of code:
def func
b = #b
b.each_with_index do |element, index|
<some stuff in here>
end
end
gives the following error:
./myfile.rb:<line number>:in 'func': wrong number of arguments (0 for 1) (ArgumentError)
from IronRuby.Libraries:0:in '<EachWithIndex>b__9'
from IronRuby.Libraries:0:in 'each'
from IronRuby.Libraries:0:in 'Each'
from ./myfile.rb:<line number>:in 'each_with_index'
from ./myfile.rb:<line number>:in 'func'
Am I doing anything wrong here? I'm using IronRuby 1.0 (the .NET 2.0 version). It's probably something ridiculously obvious, but I just haven't been able to find the answer.
As a note: I've thrown a bunch of puts statements in there, and b is definitely an Array, so it's not like I'm trying to do this on something it shouldn't work on.

Ah, I figured it out, IronRuby targets Ruby 1.8.6, and apparently each_for_index didn't return an enumerator in 1.8.6. I've changed it to:
require 'enumerator'
b.enum_for(:each_with_index) do |element, index|
and it seems to work fine.

Related

Is there a short way to write `{|x| x}`?

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

Iterator.each: why is this working

I was refactoring a bit of code in a project for work when I came across an odd bit of syntax. I confirmed it has been in the file since it was first created and the bit of code is being called.
worksheet.each 1 do |row|
Dashboard::LocalizedMessagingField.create({blah blah blah})
end
When I run something like the following in irb it complains about 1 for 0 parameters on each.
[1,2,3].each 1 do |i|
puts i
end
Why does it work in the RoR application? Anyone ever see something like this before?
I found the answer after a bit of digging. We have the Spreadsheet gem installed and it provides an each method that takes a parameter to skip the first n rows of a spreadsheet.
def each skip=dimensions[0], &block
skip.upto(dimensions[1] - 1) do |idx|
block.call row(idx)
end
end

How can I splattify an anonymous object so I can use &method on it?

I'm wanting to use the &method(:method_name) idiom when there's more than one object required by method_name. Can I do this under Ruby 1.9?
For example, if I've got
def move_file(old_filename, new_filename)
STDERR.puts "Moving #{old_filename.inspect} to #{new_filename.inspect}"
# Implementation for careful moving goes here
end
old_filenames = ["foo.txt", "bar.txt", "hoge.ja.txt"]
new_filenames = ["foo_20110915.txt", "bar_20110915.txt", "hoge_20110915.ja.txt"]
the code
old_filenames.zip(new_filenames).each(&method(:move_file))
works under Ruby 1.8, but not under Ruby 1.9. Under Ruby 1.9, it's trying to do move_file(["foo.txt", "foo_20110915.txt"]) instead of move_file("foo.txt", "foo_20110915.txt").
How do I splattify it so it has the correct arity?
Workarounds I'm aware of:
Replace def move_file(old_filename, new_filename) with def move_file(*arguments)
Replace each(&method(:move_file)) with
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
Instead
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
you should be able to do
each{|pair| move_file(*pair)}
But I don't know how you'd pull off blockless variant (I needed it couple of times as well). I guess &-shorthand was made to make the syntax simpler, and is not meant to be clogged much (whether it will be passed an array as an array, or splatted, for example). :)
How do I splattify it so it has the correct arity?
I don't think there is a way to do this while being compatible to both Ruby versions. What you could do is wrap it into a lambda
move_from_to = Proc.new {|*both| move_files(*both) }
The thing is - block and proc arity is something that got addressed in Ruby 1.9 so there might be a difference in behavior there. Also see prc.lambda? here http://www.ruby-doc.org/core/classes/Proc.html for info on what it does to the arity.
This question is also related to what you want to do (the solution there is to resplat and unsplat manually): Inconsistency of arity between Hash.each and lambdas

Ruby 1.9.1 with rspec "can't modify frozen object"

I just updated to Ruby 1.9.1 and nearly all my rspec are broken giving me a "can't modify frozen object". Even the Rspec sample code from a generate rspec_controller fails.
RuntimeError in 'DownloadsController should use DownloadsController'
can't modify frozen object
/usr/local/lib/ruby19/1.9.1/timeout.rb:44:in `timeout'
Generated by the following code:
it "should use DownloadsController" do
controller.should be_an_instance_of(DownloadsController)
end
Can anyone help ?
Are you use you aren't trying to stub something that is nil.
In 1.8 nil wasn't frozen. It is however frozen in ruby 1.9.
Try opening /usr/local/lib/ruby19/1.9.1/timeout.rb and replace line 44 with the following:
begin
return yield(sec) if sec == nil or sec.zero?
rescue => e
puts e.backtrace.join("\n")
raise e
end
Though this seems odd, in some cases I've found that this gives me more detailed information on the actual source of the problem. If you still don't know how to fix the problem, paste your results here and maybe it will help us track down the issue.

How do I use Ruby1.9 with Shoes?

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.

Resources