User interrupt in Ruby infinite loop (multiple classes)? - ruby

I found another question very similar to mine with a solution that worked for me when I wrote it all in one simple script. I even wrote a second simple example sort of simulating what I'm trying to do, and it seemed to still work.
My simulation was:
class A
def looper(&block)
Thread.new do
loop do
exit if gets.chomp == 'q'
end
end
loop do
block.call
end
end
end
class B < A
def looper
super do
puts 'howddyyyy from B'
end
end
end
This works fine, exiting when you press q<Enter>. However, when I tried to implement this into my actual project, it fails to work. I'll post the code from the method in question in the child class, as the parent class is literally exactly the same as the example above.
def looper
super do
if obj = Object.first(:process_status => STATUS_UNPROCESSED)
puts "[Object ##{obj.id}] Processing..."
puts "-" * 60
obj.set_failed
if #obj.process(obj)
obj.set_processed
end
puts "-" * 60
puts "[Object ##{obj.id}] Finished!"
puts
puts
else
sleep 10
end
end
end
So, for some reason, this doesn't work. I put a puts into the new Thread (listening for q), and it seems to output the puts before every loop of block.call. Maybe it just isn't able to get the key, by which I mean, maybe the timeframe in which you have to enter q<Enter> is way too small? I'm not sure, which is why I'm asking some advice here. My only other guess is that it has something to do with the methods called within this method (process, or possible the Sequel calls to the database) blocking the other thread(s)?
I'm new to threading, so I have no clue.

Okay, everybody. I feel a little stupid for typing all that up, as I came to a solution not five minutes later (and one I had overlooked here on Stack Overflow).
For anyone facing a similar issue in the future, this is what I ended up doing (in the parent class):
def looper(&block)
interrupted = false
trap("INT") { interrupted = true }
until interrupted do
block.call
end
exit
end
This manages to achieve what I was essentially trying to do.
Thanks for reading!

Related

How to optimize Ruby method

I have a ruby method
def get_status(creds)
client = create_client(creds)
status = client.account_status
client.close_session
status
end
Usually, I optimize this kind of code by tap or yield_self, but here I can't find a nice way to optimize it.
The only solution I have come up:
def get_status(creds)
create_client(creds).yeild_self do |client|
[client, client.account_status]
end.yield_self do |client, status|
client.close_session
status
end
end
But it doesn't better than the original solution, is it?
One could write the following.
class Client
def account_status
"Overdrawn!"
end
def close_session
puts "It's closed"
end
end
def create_client(creds)
Client.new
end
def get_status(creds)
begin
client = create_client(creds)
client.account_status
ensure
client.close_session if client
end
end
get_status("Anything")
It's closed
#=> "Overdrawn!"
Do I prefer this to #1 in the question? No.
Do I prefer this to #2 in the question? Yes!
Do I prefer this to #max's answer? No.
I understand a finalizer could be created using the class method ObjectSpace::define_finalizer.
class Client
def initialize
ObjectSpace.define_finalizer(self, proc { puts "It's finalized!" })
end
def account_status
"Overdrawn!"
end
end
def create_client(creds)
Client.new
end
def get_status(creds)
create_client(creds).account_status
end
get_status("Anything")
#=> "Overdrawn!"
exit
It's finalized!
One must be careful when creating finalizers, as explained Here. I understand a technique sometimes used is to have finalizer's proc reference class-level objects. See, for example, this article, #Amadan's comments below and #Matt's comments on the question. I am not advocating the use of a finalizer. I merely thought readers unfamiliar with finalizers (as I was before writing this) would find this useful.
Let's list the goal of the function:
Open connection
Read value (and return it)
Close connection
I would consider this a "temporary connection", and that leads me to think it could be refactored to a separate method.
Reasoning: The get_status method is concerned with getting the status from a connection - it doesn't have to handle the details of actually closing/opening the connection itself.
def open_temporary_connection(creds, &block)
client = create_client(creds)
result = block.call(client)
client.close_session
result
end
def get_status(creds)
open_temporary_connection(creds, &:account_status)
end
Also, I should mention, I think yield_self is a bit of a trap. Unless you're dead set on making all of your code into a single expression, it makes the code look awkward without offering a lot of benefit.
I like your first version because it is short, easy to read, and easy to understand. I would not change it.
Nevertheless, an alternative version using tap might look like this:
def get_status(creds)
client = create_client(creds)
client.account_status.tap { client.close_session }
end

NilCheck fix on safe navigation operator (&.)

This simple method on a class just run the status method using the safe navigation operator.
def current_status
account&.status
end
But reek report this warning:
MyClass#current_status performs a nil-check [https://github.com/troessner/reek/blob/master/docs/Nil-Check.md]
How can I properly write methods like this to avoid Nil Check?
I've also verified this post from thoughtbot but it seem like "too much" for just a safe navigation operator.
Ruby 2.3.1
The advice from "Example 4" in the linked post is verbose but pretty good :
class MyClass
def initialize(with_account = nil)
#account = Account.new if with_account
end
def current_status
account.status
end
def account
#account || NilAccount.new
end
end
class Account
def status
"Up!"
end
end
class NilAccount
def status
"Down!"
end
end
puts MyClass.new(:with_account).current_status
#=> "Up!"
puts MyClass.new.current_status
#=> "Down!"
If it's "too much" for you, account&.status might be just fine.
Whatever you do : you'll need to test your code as much as possible!
well, tell-dont-ask looks pretty good, but Example 4 looks like an overkill to resolve this specific case.
#andredurao I think, we can use this workaround to pass checks, for some reason reek is fine with it:
def current_status
return unless account
account.status
end

Why the program pass all tests if I use regular if statement in the method but says `stack level too deep` when using a ternary operator instead?

I was working on coding challenge called Robot name. I also had tests for that. The program passed all the tests. The code is below..
class Robot
attr_accessor :name
##robots = []
def initialize
#name = self.random_name
##robots << self.name
end
def random_name
name = ''
2.times do
name << ('a'..'z').to_a.sample
end
3.times do
name << (1..9).to_a.sample.to_s
end
no_duplicate(name.upcase)
end
def reset
#name = self.random_name
end
def no_duplicate(name)
if ##robots.include? name
reset
else
name
end
end
end
If you need to see the tests file you can look it up here robot_name_tests.
Then I started to refactor and one of the first things was to refactor no_duplicate method. So after refactoring the code looked like this
class Robot
...
# the rest of code stayed the same
def no_duplicate(name)
##robots.include? name ? reset : name
end
end
With this version all tests showed SystemStackError: stack level too deep. Why does it give this error and what is going on behind the scenes in both cases considering the code provided? Thanks!
I like your poetry mode code but it has led you into trouble here.
One way to kinda keep it in poetry mode but fix your operator priority issue is to do this:
def no_duplicate(name)
(##robots.include? name) ? reset : name
end
Update: if you work in Big Corporation With Coding Standards you will need to make it a bit more boring. I thought this was obvious but the gallery is correctly noting the usual solution:
##robots.include?(name) ? reset : name

Script stops while waiting for user input from STDIN.gets

I'm trying to do something like this, where I have two loops going in seperate threads. The problem I am having is that in the main thread, when I use gets and the script is waiting for user input, the other thread is stopped to wait as well.
class Server
def initialize
#server = TCPServer.new(8080)
run
end
def run
#thread = Thread.new(#server) { |server|
while true
newsock = server.accept
puts "some stuff after accept!"
next if !newsock
# some other stuff
end
}
end
end
def processCommand
# some user commands here
end
test = Server.new
while true do
processCommand(STDIN.gets)
end
The above is just a sample of what I want to do.
Is there a way to make the main thread block while waiting for user input?
You might want to take a look at using the select method of the IO class. Take a look at
good select example for handling select with asynchronous input. Depending upon what version of ruby you're using you might have issues with STDIN though, I'm pretty sure it always triggers the select in 1.8.6.
I'm not sure if this is what you are looking for, but I was looking for something similar and this example does exactly what I wanted. The thread will continue processing until the user hits enter, and then the thread will be able to handle your user input as desired.
user_input = nil
t1 = Thread.new do
while !user_input
puts "Running"
end
puts "Stopping per user input: #{user_input}"
end
user_input = STDIN.gets
t1.join

testing threaded code in ruby

I'm writing a delayed_job clone for DataMapper. I've got what I think is working and tested code except for the thread in the worker process. I looked to delayed_job for how to test this but there are now tests for that portion of the code. Below is the code I need to test. ideas? (I'm using rspec BTW)
def start
say "*** Starting job worker #{#name}"
t = Thread.new do
loop do
delay = Update.work_off(self) #this method well tested
break if $exit
sleep delay
break if $exit
end
clear_locks
end
trap('TERM') { terminate_with t }
trap('INT') { terminate_with t }
trap('USR1') do
say "Wakeup Signal Caught"
t.run
end
see also this thread
The best approach, I believe, is to stub the Thread.new method, and make sure that any "complicated" stuff is in it's own method which can be tested individually. Thus you would have something like this:
class Foo
def start
Thread.new do
do_something
end
end
def do_something
loop do
foo.bar(bar.foo)
end
end
end
Then you would test like this:
describe Foo
it "starts thread running do_something" do
f = Foo.new
expect(Thread).to receive(:new).and_yield
expect(f).to receive(:do_something)
f.start
end
it "do_something loops with and calls foo.bar with bar.foo" do
f = Foo.new
expect(f).to receive(:loop).and_yield #for multiple yields: receive(:loop).and_yield.and_yield.and_yield...
expect(foo).to receive(:bar).with(bar.foo)
f.do_something
end
end
This way you don't have to hax around so much to get the desired result.
You could start the worker as a subprocess when testing, waiting for it to fully start, and then check the output / send signals to it.
I suspect you can pick up quite a few concrete testing ideas in this area from the Unicorn project.
Its impossible to test threads completely. Best you can do is to use mocks.
(something like)
object.should_recieve(:trap).with('TERM').and yield
object.start
How about just having the thread yield right in your test.
Thread.stub(:new).and_yield
start
# assertions...

Resources