I'm have a multithreaded program that prints to the console in hundreds of places. Unfortunately, instead of
Line 2
Line 1
Line 3
I get
Line2Line1
Line3
I am trying to make puts thread safe.
In Python (which I don't think has this problem, but suppose it did), I'd do
old_print = print
print_mutex = threading.Lock()
def print(*args, **kwargs):
print_mutex.acquire()
try:
old_print(*args, **kwargs)
finally:
print_mutex.release()
I'm trying this in Ruby,
old_puts = puts
puts_mutex = Mutex.new
def puts(*args)
puts_mutex.synchronize {
old_puts(*args)
}
But this doesn't work: "undefined method old_puts"
How can I make thread-safe (i.e. not print partial lines)?
alias old_puts puts
or more modern way:
module MyKernel
PutsMutex = Mutex.new
def puts(*)
PutsMutex.synchronize{super}
end
end
module Kernel
prepend MyKernel
end
The reason for this behaviour is that puts internally calls the underlying write function twice - one for the actual value to be written, and one for the newline to be written. (Explained in Ruby's puts is not atomic)
Here's a hack to make puts call write exactly once: Append \n to the string you're writing. Here's what this looks like in my code:
# Threadsafe `puts` that outputs text and newline atomically
def safe_puts(msg)
puts msg + "\n"
end
puts internally checks whether the object being written has a newline at the end, and only calls write again if that isn't true. Since we've changed the input to end with a newline, puts ends up making only one call to write.
Related
Can anyone tell me why this program is not producing an output? The output it should be producing is: Line read: 0
Line read: 1 Line read: 2 Line read: 3 and so on.
So far, I am not getting an output even though I have fixed a number of bugs. Any help or suggestions would be much appreciated.
# takes a number and writes that number to a file then on each line
# increments from zero to the number passed
def write(aFile, number)
# You might need to fix this next line:
aFile.puts(number)
index = 0
while (index < number)
aFile.puts(index.to_s)
index += 1
end
end
# Read the data from the file and print out each line
def read(aFile)
# Defensive programming:
count = aFile.gets
if (is_numeric?(count))
count = count.to_i
index = 0
while (index < count)
line = aFile.gets
puts "line read: " + line
index+=1
end
end
end
# Write data to a file then read it in and print it out
def main
aFile = File.new("mydata.txt", "w") # open for writing
write(aFile, 10)
aFile.close
aFile = File.new("mydata.txt", "r")
read(aFile)
aFile.close
end
# returns true if a string contains only digits
def is_numeric?(obj)
if /[^0-9]/.match(obj) == nil
true
end
false
end
main
Your code isn't written in the Ruby way.
This is how I'd write it if I wanted to closely mimic your code's logic:
# takes a number and writes that number to a file then on each line
# increments from zero to the number passed
def write_data(fname, counter)
File.open(fname, 'w') do |fo|
fo.puts(counter)
counter.times do |n|
fo.puts n
end
end
end
# returns true if a string contains only digits
def is_numeric?(obj)
obj[/^\d+$/]
end
# Read the data from the file and print out each line
def read_data(fname)
File.open(fname) do |fi|
counter = fi.gets.chomp
if is_numeric?(counter)
counter.to_i.times do |n|
line_in = fi.gets
puts 'Line read: %s' % line_in
end
end
end
end
# Write data to a file then read it in and print it out
DATA_FILE = 'mydata.txt'
write_data(DATA_FILE, 10)
read_data(DATA_FILE)
Which outputs:
Line read: 0
Line read: 1
Line read: 2
Line read: 3
Line read: 4
Line read: 5
Line read: 6
Line read: 7
Line read: 8
Line read: 9
Notice these things:
Method (or variable) names are not in camelCase in Ruby, they're snake_case. ItsAReadabiltyThing.
Ruby encourages us to use a block when opening files for reading or writing, to automatically close the file when we're finished with it. Leaving danging file handles opened then not closed, in a loop, in a long-running program, is a great way for your program to crash in a way that's hard to figure out. SO has many questions that resulted from doing that. This is from the IO#open documentation:
With no associated block, ::open is a synonym for ::new. If the optional code block is given, it will be passed io as an argument, and the IO object will automatically be closed when the block terminates. In this instance, ::open returns the value of the block.
Usually you'll see code use File.open instead of IO.open, mostly out of habit in Ruby coders. File inherits from IO and adds some additional file-oriented methods to the class, so it's a little more full-featured.
Ruby has many methods that help us avoid using while loops. Getting the counters wrong or missing a condition that should terminate the loop, is all too common in programming, so Ruby makes it easy to loop "n times" or to iterate over all the elements in an array. The times method accomplishes that nicely.
String's [] method is really powerful and makes it easy to look at the contents of a string and apply a pattern or a slice. Using /^\d+$/ checks the entire string to make sure all characters are digits, so some_string[/^\d+$/] is a shorter version than what you're doing and accomplishes the same thing, returns a "truthy" value.
We don't use a main method. That's old-school Pascal, C or Java and is artificially structured. Ruby's a little more friendly than that.
Instead of using
3.times do |n|
puts n
end
# >> 0
# >> 1
# >> 2
I'd probably use
puts (0..(3 - 1)).to_a * "\n"
# >> 0
# >> 1
# >> 2
just because I tend to think in Perl terms. It's another old habit.
I found 2 errors. Fixing those errors gives you desired output.
Error #1.
Your method is_numeric? always returns false. Even if your condition is true. The last line of the method is false and therefore the whole method ALWAYS returns false.
You can fix it in 2 steps.
Step #1:
if /[^0-9]/.match(obj) == nil
true
else
false
end
It's not a good practice to return booleans within conditional. You can simplify it this way:
def is_numeric?(obj)
/[^0-9]/.match(obj) == nil
end
or even better
def is_numeric?(obj)
/[^0-9]/.match(obj).nil?
end
Error #2 is inside your read method. If you try to output the value of count after you read it from the file it gives you "10\n". That \n at the end messes you up.
To get rid of \n when you read from the file you could possibly use chomp. So then your reading line would be:
count = aFile.gets.chomp
and the rest works like magic
I am attempting to learn Ruby by converting a Java program to Ruby, but I've been coming up with an error surrounding this block of code:
def create
#user_input = String.new()
# #word_arr = Array.new
print "Enter the text to be converted to pig latin, EOF to quit: "
while gets do
STDOUT.flush
#user_input = gets.chomp
#word_arr = #user_input.string.split(' ')
#word_arr.each { |x| puts x.engToLatin() + ' '}
print "EOF to Quit"
#user_input = ""
end
end
I've been getting this error:
EnglishToPigLatin.rb:14:in `create': private method `chomp' called for nil:NilClass (NoMethodError)
from EnglishToPigLatin.rb:60
This is the area around line 60:
#if __FILE__ == $0
mg = EnglishToPigLatin.new
mg.create
#end
Essentially what I am trying to do is while there is still input, get that input, split it up into individual words, and run each word through a Pig Latin conversion method.
It looks like you're trying to get input inside of your loop.
Try
loop do
user_input = gets.chomp!
word_arr = user_input.to_s.split(' ')
word_arr.each { |x| puts x.engToLatin() + ' '}
puts "EOF to Quit"
end
Otherwise you're trying to get the next line of input when there isn't one. Additionally, do isn't necessary for a while statement.
You also don't need to reset #user_input to ''.
And since this is all in a block, you don't need to use instance variables, unless the methods you call need them.
Also your conditional is always true. gets will block until it gets a line of input. You can use loop for an infinite loop that ends on an interrupt.
Also, you needn't flush STDOUT if you use a puts for the last line there instead of a print.
The whole thing could be a script or a method in a module. An instance doesn't even need to be made. And if you do, instead of using two lines with your mg.create, you should define an initialize method. This is used as a constructor then, and whatever you set when you create an instance should be put there.
It can all be done like this:
loop do
puts gets.chomp.split(' ').map{ |x| x.engToLatin() }.join(' ')
puts "EOF to Quit"
end
Mario's answer is right. But I have the following notes.
You can still use the while construction as below.
+' ' implies that you don't want line breaks after each word. I changed that part. map and join is common in similar cases. print does not add a line break while puts does.
I am not sure what you are trying to do with STDOUT.flush. If you wanted to scroll to the top of the screen before each output, use system('clear').
You have a method entToLatin, and it should work, but it is a ruby convention to use underscore, like eng_to_latin for methods (although there are a few exceptions).
So a more rubyish way would be:
def create
print "Enter the text to be converted to pig latin, EOF to quit: "
while input = gets.strip and input != 'EOF'
system('clear')
puts input.split(/\s+/).map{|x| x.engToLatin}.join(' ')
puts "EOP to Quit"
end
end
And if you are using ruby 1.9.2, you can shorten map so that:
def create
print "Enter the text to be converted to pig latin, EOF to quit: "
while input = gets.strip and input != 'EOF'
system('clear')
puts input.split(/\s+/).map(:engToLatin).join(' ')
puts "EOP to Quit"
end
end
This is my code:
def block
puts "from block"
yield
end
block do
puts "from command line"
block do
end
end
Here is the output:
from block
from command line
from block
I wonder how the second block could detect that its inside another block (of the same method).
So that the output will be this instead:
from block 1
from command line
from block 2
Is this possible? Because I want the nested block to be aware of this and run some additional code.
Thanks!
You could keep track of the block level with an instance variable, increment it whenever you enter a block, and decrement it whenever you leave a block:
def block
#block_level ||= 0
#block_level += 1
puts "from block ##block_level"
yield
#block_level -= 1
end
This answer is mostly just for fun, I don't suggest you use it.
Ruby lets you inspect the call stack in the form of a backtrace, but only when an exception is raised. So let's raise an exception and then stick out our arm and catch it before it goes to anyone else, and then: the backtrace is all ours!!
Then all you need to do is search the backtrace (an array) for any method calls to our method named "block", and count them.
class InspectBacktrace < Exception
end
def block
raise InspectBacktrace
rescue InspectBacktrace => e
level = e.backtrace.count { |x| x =~ /in `block'/ }
puts "from block #{level}"
yield
end
block do
puts "from command line"
block do
puts "from command line"
block do
puts "from command line"
end
end
end
Output:
from block 1
from command line
from block 2
from command line
from block 3
from command line
Edit: I've since come across the Kernel#caller method which just gives you the current execution stack with no hassles. So the following code might be acceptable, as long as you don't have two methods named "block" in the same file that call each other:
def block
level = caller.count { |x| x =~ /^#{ Regexp.escape(__FILE__) }:\d+:in `block'$/ } + 1
puts "from block #{level}"
yield
end
What yjerem says, just use ensure to avoid troubles with exceptions, and it sounds like a global variable, not instance variable.
def block
begin
$block_level ||= 0
$block_level += 1
puts "from block #{$block_level}"
yield
ensure
$block_level -= 1
end
end
What are the pipe symbols for in Ruby?
I'm learning Ruby and RoR, coming from a PHP and Java background, but I keep coming across code like this:
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #post }
end
end
What is the |format| part doing? What's the equivalent syntax of these pipe symbols in PHP/Java?
They are the variables yielded to the block.
def this_method_takes_a_block
yield(5)
end
this_method_takes_a_block do |num|
puts num
end
Which outputs "5". A more arcane example:
def this_silly_method_too(num)
yield(num + 5)
end
this_silly_method_too(3) do |wtf|
puts wtf + 1
end
The output is "9".
This was very strange to me too at first, but I hope this explanation/walkthru helps you.
The documentation touches the subject, in a quite good way - if my answer doesn't help I am sure their guide will.
First, fire up the Interactive Ruby interpreter by typing irb in your shell and hitting Enter.
Type something like:
the_numbers = ['ett','tva','tre','fyra','fem'] # congratulations! You now know how to count to five in Swedish.
just so that we have an array to play with. Then we create the loop:
the_numbers.each do |linustorvalds|
puts linustorvalds
end
It will output all the numbers, separated by newlines.
In other languages you'd have to write something like:
for (i = 0; i < the_numbers.length; i++) {
linustorvalds = the_numbers[i]
print linustorvalds;
}
The important things to note are that the |thing_inside_the_pipes| can be anything, as long as you are using it consistently. And understand that it is loops we are talking about, that was a thing I didn't get until later on.
#names.each do |name|
puts "Hello #{name}!"
end
at http://www.ruby-lang.org/en/documentation/quickstart/4/ is accompanied by this explanation:
each is a method that accepts a block of code then runs that block of code for every element in a list, and the bit between do and end is just such a block. A block is like an anonymous function or lambda. The variable between pipe characters is the parameter for this block.
What happens here is that for every entry in a list, name is bound to that list element, and then the expression puts "Hello #{name}!" is run with that name.
The code from the do to the end defines a Ruby block. The word format is a parameter to the block. The block is passed along with the method call, and the called method can yield values to the block.
See any text on Ruby for details, this is a core feature of Ruby that you will see all the time.
The equivalent in Java would be something like
// Prior definitions
interface RespondToHandler
{
public void doFormatting(FormatThingummy format);
}
void respondTo(RespondToHandler)
{
// ...
}
// Equivalent of your quoted code
respondTo(new RespondToHandler(){
public void doFormatting(FormatThingummy format)
{
format.html();
format.xml();
}
});
Parameters for a block sit between the | symbols.
To make it even more clearer, if needed:
the pipe bars essentially make a new variable to hold the value generated from the method call prior. Something akin to:
Original definition of your method:
def example_method_a(argumentPassedIn)
yield(argumentPassedIn + 200)
end
How It's used:
example_method_a(100) do |newVariable|
puts newVariable;
end
It's almost the same as writing this:
newVariable = example_method_a(100)
puts newVariable
where, newVariable = 200 + 100 = 300 :D!
temp = 98.3
begin
print "Your temperature is " + temp.to_s + " Fahrenheit. "
puts "I think you're okay."
temp += 0.1
end while temp < 98.6
In the above example, is everything between begin and end a block?
I'm still confused what a block is.
If you can't call it a block, what would you call that chunk of code between begin and end? Is it ok to call it a chunk?
Block has a special meaning in Ruby. According to Matz, Ruby's creator, you can look at a block as a nameless function - typically something that can be yielded into, and which may also take parameters.
You may see the following kind of disamiguation when describing Ruby syntax:
begin...end (what is called block in other languages) may sometimes be referred to simply as what it is, i.e. an expression (which may in turn contain other expressions - an expression is simply something that has a return value) in Ruby. Some references will still call it a begin/end block, or a code block, adding somewhat to the confusion
do...end or {...} will always be referred to as a block in Ruby
For examples, peruse the the Ruby syntax man page, e.g.
begin expression end
expression while expression
loop block
For further reading, see:
Programming Ruby
Ruby (from other languages)
Much, much more documentation
begin/end are strictly control flow, not blocks.
begin
puts "hi"
end
# => "hi"
The code runs immediately. If it was a block, it would have to been called somehow in order for the code in it to run, as in this example:
def a_method; end
a_method { puts "hi" }
# nothing..
def a_method
yield
end
a_method { puts "Hi!" }
# => "Hi!"