Reading multiple lines at time from a file - ruby

How can I read multiple lines at a time from a file in Ruby?
I tried using each_slice(2) and also did: require 'enumerator', but it doesn't work. I get the following error:
undefined method `each_slice' for #<String:0x877d12c> (NoMethodError)

Both IO and String have a lines enumerator, which you can call each_slice on:
irb(main):004:0> STDIN.lines.each_slice(2).take(2)
a
a
b
c
=> [["a\n", "a\n"], ["b\n", "c\n"]]
Of course you can substitute STDIN with any other IO instance (open file). Demo with a string:
irb(main):005:0> "a\na\nb\nc".lines.each_slice(2).to_a
=> [["a\n", "a\n"], ["b\n", "c"]]
Both of these work in Ruby >= 1.8.7

Related

`File.enum_for(:readlines, ...)` not enumerating

Why does this enumerator unexpectedly return an empty array:
> File.enum_for(:readlines, '/usr/share/dict/words').take(1)
=> []
while this one returns properly:
File.enum_for(:readlines, "/usr/share/dict/words").each{}.take(1)
=> ["A\n"]
For comparison, other enumerators will work without the each:
> "abc".enum_for(:each_byte).take(1)
=> [97]
What's really odd in the File.readlines case is that the body of the each doesn't actually get executed:
File.enum_for(:readlines, "/usr/share/dict/words").
each{|e| p e; raise "stop" }.take(2)
=> ["A\n", "a\n"]
This is on ruby 2.5.3. I tried the code both in pry and in a ruby -e one-liner, with the same results.
Apparently enum_for/to_enum only works with a method that yields. Credit goes to #Anthony for making me realize this.
This is the equivalent of what I was trying to do:
# whoops, `to_a` doesn't yield
[1,2,3].enum_for(:to_a).take(1)
=> []
# Works, but `enum_for` isn't really meant for this, and it's very possible this should be
# considered undefined behavior.
# In this case, as in `File.readlines`, the `each` block isn't really executed.
> [1,2,3].enum_for(:to_a).each{}.take(1)
=> [1]
Another interesting thing is that calling each{} on one of these "weird enumerators" seems to act as though the enum-ed method (e.g. to_a) were called directly. But of course this is pointless.
> arr = [1,2,3]
> arr.object_id
=> 70226978129700
> arr.to_a.object_id
=> 70226978129700
# same as calling `to_a` - doesn't create a new array!
> arr.enum_for(:to_a).each{}.object_id
=> 70226978129700
In the case of File.readlines, its implementation simply reads in the lines and returns them in a single array; it doesn't yield anything.

TryRuby raises undefined method `[]=' for String

I am working to replace a character in a string, changing "cat" into "hat".
Here's my code:
str = "cat"
str[0] = 'h'
puts str
But when I run this code in TryRuby I get this error:
NoMethodError: undefined method `[]=' for "cat"
l am using Try ruby's editor
ruby.github.io/TryRuby uses Opal (a Ruby-to-JavaScript compiler) to evaluate the code in the browser. Opal provides its own String class which doesn't implement []=.
This seems to be a known limitation (among others). From the documentation: (emphasis added)
For performance and ease of runtime features, all strings in Opal are immutable, i.e. #<<, #gsub!, etc. do not exist.
You can use the gsub method and do it like this:
str = 'cat'
puts str.gsub(str[0], 'h')

Ruby - cannot convert individual chars in string to ASCII

I am trying to run the following code on http://repl.it/languages/Ruby/, but I am encountering a NoMethodError:
a = "string"
a.each_char do |c|
puts c.ord
end
The error details are as follows:
(eval):1: undefined method `ord' for "s":String (NoMethodError)
from (eval):0:in `each_char'
from (eval):0
Please could somebody explain to me why my code does not work?
The each_char method of String yields each character as a separate String.
The Ruby version running on repl.it is quite old (1.8.7). The String class in that version of Ruby doesn't define an ord method, so your code fails to run with a NoMethodError.
ord was added to String in Ruby 1.9, so your code will run on newer versions of Ruby.
On Ruby 1.8.7 (and repl.it), you could use one of the following alternatives instead:
a = "string"
a.each_char do |c|
puts c[0]
end
a = "string"
a.each_byte do |c|
puts c
end
However, please note that these examples won't behave identically to your original code if your string uses a multi-byte encoding. The ord method returns a Unicode code point. The Ruby 1.8.7 examples will give you individual bytes.
The code as is will print the ascii code of each letter. Perhaps you're looking at the return value which would be the original string "string"?

Couldn't understand the difference between `puts{}.class` and `puts({}.class)`

As the anonymous block and hash block looks like approximately same. I was doing kind of playing with it. And doing do I reached to some serious observations as below:
{}.class
#=> Hash
Okay,It's cool. empty block is considered as Hash.
print{}.class
#=> NilClass
puts {}.class
#=> NilClass
Now why the above code showing the same as NilClass,but the below code shows the Hash again ?
puts ({}.class)
#Hash
#=> nil
print({}.class)
#Hash=> nil
Could anyone help me here to understand that what's going one above?
I completely disagree with the point of #Lindydancer
How would you explain the below lines:
print {}.class
#NilClass
print [].class
#Array=> nil
print (1..2).class
#Range=> nil
Why not the same with the below print [].class and print (1..2).class?
EDIT
When ambiguity happens with local variable and method call, Ruby throws an error about the fact as below :
name
#NameError: undefined local variable or method `name' for main:Object
# from (irb):1
# from C:/Ruby193/bin/irb:12:in `<main>'
Now not the same happens with {} (as there is also an ambiguity between empty code block or Hash block). As IRB also here not sure if it's a empty block or Hash. Then why the error didn't throw up when IRB encountered print {}.class or {}.class?
The precedence rules of ruby makes print{}.class interpreted as (print{}).class. As print apparently returns a nil the class method returns #NilClass.
EDIT: As been discussed on other answers and in the updates to the question, print{} it of course interpreted as calling print with a block, not a hash. However, this is still about precedence as {} binds stronger than [] and (1..2) (and stronger than do ... end for that matter).
{} in this case is recognized as block passed to print, while [] unambiguously means empty array.
print {}.class # => NilClass
print do;end.class # => NilClass
You are running into some nuances of Ruby, where characters mean different things depending on context. How the source code is interpreted follows rules, one of which is that {} is a closure block if it follows a method call, and otherwise a Hash constructor.
It's common throughout the language to see characters mean different things depending on context or position within the statement.
Examples:
Parens () used for method call or for precedence
print(1..5).class => NilClass
print (1..5).class => Range <returns nil>
Square brackets [] used to call :[] method or for Array
print[].class => NoMethodError: undefined method `[]' for nil:NilClass
print([].class) => Array <returns nil>
Asterisk * used for multiplication or splatting
1 * 5 => 5
[*1..5] => [1, 2, 3, 4, 5]
Ampersand & used for symbol -> proc or logical and
0 & 1 => 0
[1, 2, 3].map(&:to_s) => ["1", "2", "3"]
Or in your case, braces used for block closures or for a hash
... hope it makes sense now ...

Catching line numbers in ruby exceptions

Consider the following ruby code
test.rb:
begin
puts
thisFunctionDoesNotExist
x = 1+1
rescue Exception => e
p e
end
For debugging purposes, I would like the rescue block to know that the error occurred in line 4 of this file. Is there a clean way of doing that?
p e.backtrace
I ran it on an IRB session which has no source and it still gave relevant info.
=> ["(irb):11:in `foo'",
"(irb):17:in `irb_binding'",
"/usr/lib64/ruby/1.8/irb/workspace.rb:52:in `irb_binding'",
"/usr/lib64/ruby/1.8/irb/workspace.rb:52"]
If you want a nicely parsed backtrace, the following regex might be handy:
p x.backtrace.map{ |x|
x.match(/^(.+?):(\d+)(|:in `(.+)')$/);
[$1,$2,$4]
}
[
["(irb)", "11", "foo"],
["(irb)", "48", "irb_binding"],
["/usr/lib64/ruby/1.8/irb/workspace.rb", "52", "irb_binding"],
["/usr/lib64/ruby/1.8/irb/workspace.rb", "52", nil]
]
( Regex /should/ be safe against weird characters in function names or directories/filenames )
( If you're wondering where foo camefrom, i made a def to grab the exception out :
>>def foo
>> thisFunctionDoesNotExist
>> rescue Exception => e
>> return e
>>end
>>x = foo
>>x.backtrace
You can access the backtrace from an Exception object. To see the entire backtrace:
p e.backtrace
It will contain an array of files and line numbers for the call stack. For a simple script like the one in your question, it would just contain one line.
["/Users/dan/Desktop/x.rb:4"]
If you want the line number, you can examine the first line of the backtrace, and extract the value after the colon.
p e.backtrace[0].split(":").last
Usually the backtrace contains a lot of lines from external gems
It's much more convenient to see only lines related to the project itself
My suggestion is to filter the backtrace by the project folder name
puts e.backtrace.select { |x| x.match(/HERE-IS-YOUR-PROJECT-FOLDER-NAME/) }
And then you can parse filtered lines to extract line numbers as suggested in other answers.
Throwing my $0.02 in on this old thread-- here's a simple solution that maintains all the original data:
print e.backtrace.join("\n")
It is possible that in Ruby 1.9.3 you will be able to get access to not only this information in a more structured, reliable, and simpler way without using regular expressions to cut strings.
The basic idea is to introduce a call frame object which gives access to information about the call stack.
See http://wiki.github.com/rocky/rb-threadframe/, which alas, requires patching Ruby 1.9. In RubyKaigi 2010 (late August 2010) a meeting is scheduled to discuss introducing a frame object into Ruby.
Given this, the earliest this could happen is in Ruby 1.9.3.

Resources