Why does Kernel#p print to standard out? - ruby

Why does Kernel#p print to standard out? Isn't printf debugging supposed to output to standard error?

You can define a global function "q", which works just like "p" except it prints to $stderr.
#!/usr/bin/ruby1.8
module Kernel
def q(*stuff)
stuff.each { |thing| $stderr.print(thing.inspect + "\n")}
end
end
q 'foo' # => "foo"
You may be tempted to use puts instead of print ... + "\n". This code uses print to make it thread-safe: puts can be interrupted between the time it prints its arguments and the time it prints the new-line, causing output from two threads to appear on one line. It's seldom that you have code from multiple threads writing to $stdout/$stderr at the same time, so it's not usually an issue. But this being a debugging tool, you will certainly end up using it to find out what is going on in threads.

Why are you assuming Kernel#p is intended for debugging? It writes to stdout just like Kernel#print or printf in C.
If you want to write to standard error you could do:
$stderr.puts(x.inspect)
By the way, if you really want to use printf debugging I suggest you read this article about debugging techniques

Related

Handle ARGV in Ruby without if...else block

In a blog post about unconditional programming Michael Feathers shows how limiting if statements can be used as a tool for reducing code complexity.
He uses a specific example to illustrate his point. Now, I've been thinking about other specific examples that could help me learn more about unconditional/ifless/forless programming.
For example in this cat clone there is an if..else block:
#!/usr/bin/env ruby
if ARGV.length > 0
ARGV.each do |f|
puts File.read(f)
end
else
puts STDIN.read
end
It turns out ruby has ARGF which makes this program much simpler:
#!/usr/bin/env ruby
puts ARGF.read
I'm wondering if ARGF didn't exist how could the above example be refactored so there is no if..else block?
Also interested in links to other illustrative specific examples.
Technically you can,
inputs = { ARGV => ARGV.map { |f| File.open(f) }, [] => [STDIN] }[ARGV]
inputs.map(&:read).map(&method(:puts))
Though that's code golf and too clever for its own good.
Still, how does it work?
It uses a hash to store two alternatives.
Map ARGV to an array of open files
Map [] to an array with STDIN, effectively overwriting the ARGV entry if it is empty
Access ARGV in the hash, which returns [STDIN] if it is empty
Read all open inputs and print them
Don't write that code though.
As mentioned in my answer to your other question, unconditional programming is not about avoiding if expressions at all costs but about striving for readable and intention revealing code. And sometimes that just means using an if expression.
You can't always get rid of a conditional (maybe with an insane number of classes) and Michael Feathers isn't advocating that. Instead it's sort of a backlash against overuse of conditionals. We've all seen nightmare code that's endless chains of nested if/elsif/else and so has he.
Moreover, people do routinely nest conditionals inside of conditionals. Some of the worst code I've ever seen is a cavernous nightmare of nested conditions with odd bits of work interspersed within them. I suppose that the real problem with control structures is that they are often mixed with the work. I'm sure there's some way that we can see this as a form of single responsibility violation.
Rather than slavishly try to eliminate the condition, you could simplify your code by first creating an array of IO objects from ARGV, and use STDIN if that list is empty.
io = ARGV.map { |f| File.new(f) };
io = [STDIN] if !io.length;
Then your code can do what it likes with io.
While this has strictly the same number of conditionals, it eliminates the if/else block and thus a branch: the code is linear. More importantly, since it separates gathering data from using it, you can put it in a function and reuse it further reducing complexity. Once it's in a function, we can take advantage of early return.
# I don't have a really good name for this, but it's a
# common enough idiom. Perl provides the same feature as <>
def arg_files
return ARGV.map { |f| File.new(f) } if ARGV.length;
return [STDIN];
end
Now that it's in a function, your code to cat all the files or stdin becomes very simple.
arg_files.each { |f| puts f.read }
First, although the principle is good, you have to consider other things that are more importants such as readability and perhaps speed of execution.
That said, you could monkeypatch the String class to add a read method and put STDIN and the arguments in an array and start reading from the beginning until the end of the array minus 1, so stopping before STDIN if there are arguments and go on until -1 (the end) if there are no arguments.
class String
def read
File.read self if File.exist? self
end
end
puts [*ARGV, STDIN][0..ARGV.length-1].map{|a| a.read}
Before someone notices that I still use an if to check if a File exists, you should have used two if's in your example to check this also and if you don't, use a rescue to properly inform the user.
EDIT: if you would use the patch, read about the possible problems at these links
http://blog.jayfields.com/2008/04/alternatives-for-redefining-methods.html
http://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/
Since the read method isn't part of String the solutions using alias and super are not necessary, if you plan to use a Module, here is how to do that
module ReadString
def read
File.read self if File.exist? self
end
end
class String
include ReadString
end
EDIT: just read about a safe way to monkey patch, for your documentation see https://solidfoundationwebdev.com/blog/posts/writing-clean-monkey-patches-fixing-kaminari-1-0-0-argumenterror-comparison-of-fixnum-with-string-failed?utm_source=rubyweekly&utm_medium=email

Ruby stdin/stdout on HackerRank

I've been trying to complete an exercise on HackerRank but am having trouble with the initial stage of "Read input from STDIN. Print output to STDOUT". I've tried a couple of methods, among which this seems to work the best:
myArray = ARGF.read
newarr = myArray.split(" ").map! do |n|
n.to_i
end
This returns an array, but when I run closestNumbers(newarr), I get "
~ no response on stdout ~". My code works in IRB. Any ideas on where I might be going wrong?
IRB shows you the result of the last computation. For Hackerrank you need to put it in STDOUT explicitly. In a word - use puts for return values.
UPD: Just for reference. There is STDOUT.write method as well.

Shortest Ruby one-liner to execute a statement exactly once

I'm looking for the shortest, most simple Ruby one-liner to execute a statement exactly once. Idea is to use this while debugging to quickly add a debug statement to a loop that gets executed exactly once.
Best I've come up with so far:
puts "do something interesting exactly once!" if (once ||= "0").next! == "1"
Can you come up with something even shorter?
Added for clarification:
The idea for the questions was to focus on the "do it once" part and not so much on the "do something interesting" part. It should be assumed that the code do be executed once could be anything, not just a puts statement.
The ideal solution would also work in different kinds of loop constructs. E.g. as was pointed out my initial solution only works if the once variable is already defined outside the loop context or if the loop context used doesn't create a new lexical scope.
The original use case that triggered this question was slightly different - it looked more like below. But I though the above, simpler example would more easily explain the kind of solution I was looking for.
def process
do_some_preprocessing()
raise SomeError if <once> # added temp. for debugging purposes - the <once> part is what this question is about!
dangerous_operation() # this can raise SomeError under certain conditions
rescue SomeError
attempt_to_rescue() and retry
end
Well, you could abuse lambdas and closures.
->{puts "do something interesting exactly once!";x=->{x}}[][]
#=> do something interesting exactly once!
#=> #<Proc:0x5465282c#(irb):10 (lambda)>
The original contents of the lambda are only run once; any subsequent invocations will simply return an empty proc.
You could alternately abuse globals for a more true "one-liner", but it's awful.
$x ||= puts("do something interesting exactly once!") || 1
debug = ["do something interesting exactly once!"]
puts debug.pop # "do something interesting exactly once!"
puts debug.pop # nil
(answer edited to reflect the discussion in comments)
Your code won't do what you want it to do, it will depend of the looping construct you use.
This will work:
puts "do something interesting exactly once!" if once = once.nil?
But with this one, you'll have to define once before: once = nil (same thing for your own code). This is because otherwise, the scope of the once variable will be restrained to the block within an each loop, causing it to fail. This would work just fine within a for loop (the way you must have tested it):
(1..3).each do # 3.times would behave just the same
puts "once has not been defined before! Won't work!" if once = once.nil?
end
# >once has not been defined before! Won't work!
# once has not been defined before! Won't work!
# once has not been defined before! Won't work!
for i in 1..3 do
puts "Works because of the way for loops treat vars within loop" if once = once.nil?
end
# >Works because of the way for loops treat vars within loop
To avoid that problem without having to initialize the variable first, you can make once global:
(1..3).each do
puts "$once's scope is not restrained to the 'each' loop! Works!" if $once = $once.nil?
end
# >$once's scope is not restrained to the 'each' loop! Works!
The original idea generates code-smell. It results in code that will leave someone else scratching their head, which isn't a good thing. Generating code that is obvious and easy to understand will make your, and other programmer's, job easier.
Writing code that takes a while to figure out will take you a while to figure out in the future if you're debugging so be kind to your future self.
I'd stick with the standard way, using a simple flag:
once = false
2.times do
puts "do something interesting exactly once!" unless once
once ||= true
end
Which results in this output:
# >> do something interesting exactly once!

Ruby - how to read first n lines from file into array

For some reason, I can't find any tutorial mentioning how to do this...
So, how do I read the first n lines from a file?
I've come up with:
while File.open('file.txt') and count <= 3 do |f|
...
count += 1
end
end
but it is not working and it also doesn't look very nice to me.
Just out of curiosity, I've tried things like:
File.open('file.txt').10.times do |f|
but that didn't really work either.
So, is there a simple way to read just the first n lines without having to load the whole file?
Thank you very much!
Here is a one-line solution:
lines = File.foreach('file.txt').first(10)
I was worried that it might not close the file in a prompt manner (it might only close the file after the garbage collector deletes the Enumerator returned by File.foreach). However, I used strace and I found out that if you call File.foreach without a block, it returns an enumerator, and each time you call the first method on that enumerator it will open up the file, read as much as it needs, and then close the file. That's nice, because it means you can use the line of code above and Ruby will not keep the file open any longer than it needs to.
There are many ways you can approach this problem in Ruby. Here's one way:
File.open('Gemfile') do |f|
lines = 10.times.map { f.readline }
end
File.foreach('file.txt').with_index do |line, i|
break if i >= 10
puts line
end
File inherits from IO and IO mixes in Enumerable methods which include #first
Passing an integer to first(n) will return the first n items in the enumerable collection. For a File object, each item is a line in the file.
File.open('filename.txt', 'r').first(10)
This returns an array of the lines including the \n line breaks.
You may want to #join them to create a single whole string.
File.open('filename.txt', 'r').first(10).join
You could try the following:
`head -n 10 file`.split
It's not really "pure ruby" but that's rarely a requirement these days.

Override '+' method

In the process of understanding ruby, I was trying to overide '+' with a default argument value. Something like this.
class C
def something(a = 5)
puts "Received: #{a}"
end
def +(b = 10)
puts "Received: #{b}"
end
end
Now
x = C.new
x.something #=> Received: 5
x.something(88) #=> Received: 88
x.+ #=> IRB shows ? whereas I was expecting an output 'Received: 10'
Is this because of operator precedence?
Problem with IRB (look like it doesn't handle such cases). If you create separate .rb file and run it you will get expected output:
Received: 5
Received: 88
Received: 10
IRB is parsing the + and expecting a second parameter for the binary operation. If you provide parenthesis it works correctly:
x.+() #=> Received: 10
IRb uses a different parser than Ruby does. So, in some weird corner cases, IRb may parse code differently than Ruby. If you want to see whether something is valid Ruby or not, you should ask Ruby not IRb.
The reason for this is mainly that Ruby always parses the entire file at once, so it always knows when an expression ends. IRb on the other hand, has to "guess" every time when you press ENTER whether you simply want to continue the expression on a new line or whether you wanted to evaluate the expression as-is. As a result, IRb cannot just use the Ruby parser, it needs to have its own. And Ruby's grammar is so complex that writing your own parser is really really hard. That's why such bugs and corner cases pop up from time to time even in a piece of software as old and as widely used as IRb.

Resources