Elegant way to say "try this thing, one at a time, until condition is met"

Example: I need to unmount /usr and /usr2, but currently I can’t because
there are some opened files from those partitions. I am going to try
shutting down daemons or killing some processes (or other things), one
at a time, until I can unmount it.

def kill(process, signal)
…
end

returns false if failed, true if succeeded or already unmounted

def unmount(partition)
…
end

unless unmount("/usr") && unmount("/usr2")
system “/etc/init.d/httpd stop"
system “/etc/init.d/squid stop"
unless unmount(”/usr”) && unmount("/usr2")
kill(“rdiff-backup”, :TERM)
sleep 3
unless unmount("/usr") && unmount("/usr2")
kill(“rdiff-backup”, :KILL)
sleep 3
…
…
end
end
end

I don’t like this since I repeat unmount(). I can rewrite this as:

def cond_met
umount("/usr") && unmount("/usr2")
end

unless cond_met
…
unless cond_met
…
…
end
end

But still it’s not pretty enough. Any more elegant way?

···

–
dave

Lightly skimming the post, but answering the title, will these approaches do?

begin
…
end until condition

loop do
…
break if condition
…
end

catch(:done) do
…
throw :done if condition
…
end

I kind_of dislike the first solution aesthetically, but for simple cases
it’s probably the best. The second and third solutions allow you to emit
a value from the block if that helps. In the third solution, you can
"throw" your way out of the block no matter how deeply you’re nested, even
from another method.

Cheers,
Gavin

Lightly skimming the post, but answering the title, will these approaches do?

begin
…
end until condition

loop do
…
break if condition
…
end

catch(:done) do
…
throw :done if condition
…
end

I kind_of dislike the first solution aesthetically, but for simple cases
it’s probably the best. The second and third solutions allow you to emit
a value from the block if that helps. In the third solution, you can
"throw" your way out of the block no matter how deeply you’re nested, even
from another method.

Cheers,
Gavin

Sorry if that’s not what you want, but i had this idea when I read your post:

emulating condition

$counter = 0
def cond_met
$counter += 1
$counter > 1 ? true : false
end

algo itself, services could be an array of commands to execute

services = %w| httpd squid sendmail |.reverse
begin
serv = services.pop
system “echo /etc/init.d/#{serv} stop”
end until cond_met

···

On Monday 31 May 2004 16:31, David Garamond wrote:

Example: I need to unmount /usr and /usr2, but currently I can’t because
there are some opened files from those partitions. I am going to try
shutting down daemons or killing some processes (or other things), one
at a time, until I can unmount it.
–
sdmitry -=- Dmitry V. Sabanin
MuraveyLabs.
Spam Here → postmaster@sco.com

Hi,

At Mon, 31 May 2004 17:31:24 +0900,
David Garamond wrote in [ruby-talk:101855]:

Example: I need to unmount /usr and /usr2, but currently I can’t because
there are some opened files from those partitions. I am going to try
shutting down daemons or killing some processes (or other things), one
at a time, until I can unmount it.

def kill(process, signal)
…
end

returns false if failed, true if succeeded or already unmounted

def unmount(partition)
…
end

unless unmount(“/usr”) && unmount(“/usr2”)
system “/etc/init.d/httpd stop”
system “/etc/init.d/squid stop”
unless unmount(“/usr”) && unmount(“/usr2”)
kill(“rdiff-backup”, :TERM)
sleep 3
unless unmount(“/usr”) && unmount(“/usr2”)
kill(“rdiff-backup”, :KILL)
sleep 3
…
…
end
end
end

What about:

count = 0
until unmount(“/usr”) && unmount(“/usr2”)
case count += 1
when 1
system “/etc/init.d/httpd stop”
system “/etc/init.d/squid stop”
when 2
kill(“rdiff-backup”, :TERM)
sleep 3
when 3
kill(“rdiff-backup”, :KILL)
sleep 3
end
end

or:

stopper = [
proc {
system “/etc/init.d/httpd stop”
system “/etc/init.d/squid stop”
},
proc {
kill(“rdiff-backup”, :TERM)
sleep 3
},
proc {
kill(“rdiff-backup”, :KILL)
sleep 3
}
]
until unmount(“/usr”) && unmount(“/usr2”)
stopper.shift.call
end

···

–
Nobu Nakada

Received: Mon, 31 May 2004 17:31:24 +0900
And lo, David wrote:

Example: I need to unmount /usr and /usr2, but currently I can’t because
there are some opened files from those partitions. I am going to try
shutting down daemons or killing some processes (or other things), one
at a time, until I can unmount it.
…
But still it’s not pretty enough. Any more elegant way?

Use a flow control that allows arbitrary exits. Such as returns and breaks

def cond_met?
umount(“/usr”) && umount(“/usr2”)
end

if it’s a function:

def myfun

system '/etc/init.d/httpd stop'
system '/etc/init.d/squid stop'
return if cond_met?

system 'killall -INT motherinlaws'
return if cond_met?
... etc

end

else:

loop do

system '/etc/init.d/httpd stop'
break if cond_met?

system '/etc/init.d/squid stop'
break if cond_met?

system 'kill -9 pig ; /bin/fry pig'
break if cond_met?

break # This is needed so it doesn't actually loop :D

end

  • Greg

David Garamond wrote:

unless unmount(“/usr”) && unmount(“/usr2”)
system “/etc/init.d/httpd stop”
system “/etc/init.d/squid stop”
unless unmount(“/usr”) && unmount(“/usr2”)
kill(“rdiff-backup”, :TERM)
sleep 3
unless unmount(“/usr”) && unmount(“/usr2”)
kill(“rdiff-backup”, :KILL)
sleep 3
…
…
end
end
end

Here’s another way. I love how ruby lets you define control structures,
so you can make your code self-documenting:

require ‘goal-attemptor’

GoalAttemptor.attempt_goal do
goal {unmount(“/usr”) && unmount(“/usr2”)}

 attempt do
   system "/etc/init.d/httpd stop"
   system "/etc/init.d/squid stop"
 end

 attempt do
   kill("rdiff-backup", :TERM)
   sleep 3
 end

 attempt do
   kill("rdiff-backup", :KILL)
   sleep 3
 end

end

------ goal-attemptor.rb ------

module GoalAttemptor
class Block
def initialize(attempt_goal_block)
instance_eval(&attempt_goal_block)

   raise "no goal defined" unless @goal_block

   until @goal_block.call
     a = @attempt_blocks.shift
     raise "nothing left to attempt" unless a
     a.call
   end
 end

 def goal(&goal_block)
   @goal_block = goal_block
 end

 def attempt(&attempt_block)
   (@attempt_blocks ||= []) << attempt_block
 end

end

def attempt_goal(&attempt_goal_block)
Block.new(attempt_goal_block)
end
module_function :attempt_goal
end

if FILE == $0

x = 2

include GoalAttemptor

attempt_goal do

 goal {x > 5}

 attempt do
   x += 1
 end

 attempt do
   x += 1
 end

 attempt do
   x += 1
 end

 attempt do
   x += 1
 end

end

p x # ==> 6

end

David Garamond lists@zara.6.isreserved.com writes:

Example: I need to unmount /usr and /usr2, but currently I can’t
because there are some opened files from those partitions. I am going
to try shutting down daemons or killing some processes (or other
things), one at a time, until I can unmount it.

[…]

But still it’s not pretty enough. Any more elegant way?

This is how I’d do it.

solutions = [
proc do
system “/etc/init.d/httpd stop”
system “/etc/init.d/squit stop”
end, proc do
kill(“rdiff-backup”, :TERM)
sleep 3
end, proc do
kill(“rdiff-backup”, :KILL)
sleep 3
end
]

until unmount(“/usr”) && unmount(“/usr2”)
solutions.shift.call
end

Sorry about the eccentric formatting. For some reason, putting the
end' and the proc do’ on different lines gives me the hibbie-jibbies.

···

–
Mikael Brockman

What’s the sense in stopping only two services listed in an array which has
more elements than the two?

Bye,
phil

···

On 2004-05-31, Dmitry V. Sabanin sdmitry@lrn.ru wrote:

$counter = 0
def cond_met
$counter += 1
$counter > 1 ? true : false
end

algo itself, services could be an array of commands to execute

services = %w| httpd squid sendmail |.reverse
begin
serv = services.pop
system “echo /etc/init.d/#{serv} stop”
end until cond_met

–
Please send replys (not followups) to the address set in Reply-To.
Philipp Kern - PK2186-RIPE - http://www.philkern.de

Thanks to all. I like this one best :slight_smile: The 1, 2, 3, … clearly shows
the increasing step (from less to more extreme) which I would take to
meet the condition.

···

nobu.nokada@softhome.net wrote:

count = 0
until unmount(“/usr”) && unmount(“/usr2”)
case count += 1
when 1
system “/etc/init.d/httpd stop”
system “/etc/init.d/squid stop”
when 2
kill(“rdiff-backup”, :TERM)
sleep 3
when 3
kill(“rdiff-backup”, :KILL)
sleep 3
end
end

–
dave

“Dmitry V. Sabanin” sdmitry@lrn.ru schrieb im Newsbeitrag
news:200405311648.43813.sdmitry@lrn.ru…

Example: I need to unmount /usr and /usr2, but currently I can’t because
there are some opened files from those partitions. I am going to try
shutting down daemons or killing some processes (or other things), one
at a time, until I can unmount it.
Sorry if that’s not what you want, but i had this idea when I read your
post:

emulating condition

$counter = 0
def cond_met
$counter += 1
$counter > 1 ? true : false
end

Just a sidenote: you don’t have to convert the result of a boolean
expression to boolean by means of the ternary operator. This will do
exactly the same:

def cond_met
( $counter += 1 ) > 1
end

Regards

robert
···

On Monday 31 May 2004 16:31, David Garamond wrote:

Just guessing, but can’t we somehow utilize, that a block can be
re-executed after catching an exception (with retry, which shows, that
it is not a real loop…)

Gergo

···

On 0601, Mikael Brockman wrote:

–
±[ Kontra, Gergelykgergely@mcl.hu PhD student Room IB113 ]---------+

http://www.mcl.hu/~kgergely “Olyan langesz vagyok, hogy |
Mobil:(+36 20) 356 9656 ICQ: 175564914 poroltoval kellene jarnom” |
±- Magyar php mirror es magyar php dokumentacio: http://hu.php.net --+

Received: Mon, 31 May 2004 19:55:07 +0900
And lo, David wrote:

···

nobu.nokada@softhome.net wrote:

count = 0
until unmount(“/usr”) && unmount(“/usr2”)
case count += 1
when 1
system “/etc/init.d/httpd stop”
system “/etc/init.d/squid stop”
when 2
kill(“rdiff-backup”, :TERM)
sleep 3
when 3
kill(“rdiff-backup”, :KILL)
sleep 3
end
end

Thanks to all. I like this one best :slight_smile: The 1, 2, 3, … clearly shows
the increasing step (from less to more extreme) which I would take to
meet the condition.

By the way …
If you’re looking for processes that have files open on a mounted partition … check the manual page for lsof

lsof # shows all open sockets (files, network, etc) used by programs.
lsof /usr # will show all programs that have open files (and what files they are) inside the filesystem of /usr

  • Greg

“Dmitry V. Sabanin” sdmitry@lrn.ru schrieb im Newsbeitrag
…

emulating condition

$counter = 0
def cond_met
$counter += 1
$counter > 1 ? true : false
end

Just a sidenote: you don’t have to convert the result of a boolean
expression to boolean by means of the ternary operator. This will do
exactly the same:

def cond_met
( $counter += 1 ) > 1
end
Damn C background… I always forget about this thing. Thanks, Robert

···

On Monday 31 May 2004 20:08, Robert Klemme wrote:

Regards

robert

–
sdmitry -=- Dmitry V. Sabanin
MuraveyLabs.
Spam Here → postmaster@sco.com

$counter = 0
def cond_met
$counter += 1
$counter > 1 ? true : false
end

algo itself, services could be an array of commands to execute

services = %w| httpd squid sendmail |.reverse
begin
serv = services.pop
system “echo /etc/init.d/#{serv} stop”
end until cond_met

What’s the sense in stopping only two services listed in an array which has
more elements than the two?
It’s just an emulation of how umount /usr will possibly work, probably it will unmount
partition before everything is killed. I should be more clear next time

···

On Monday 31 May 2004 18:53, Philipp Kern wrote:

On 2004-05-31, Dmitry V. Sabanin sdmitry@lrn.ru wrote:

Bye,
phil

–
sdmitry -=- Dmitry V. Sabanin
MuraveyLabs.
Spam Here → postmaster@sco.com

Gregory Millam wrote:

By the way …
If you’re looking for processes that have files open on a mounted partition … check the manual page for lsof

lsof # shows all open sockets (files, network, etc) used by programs.
lsof /usr # will show all programs that have open files (and what files they are) inside the filesystem of /usr

Of course. Thanks. I tend to forget that too many times already :slight_smile:

···

–
dave

“Dmitry V. Sabanin” sdmitry@lrn.ru schrieb im Newsbeitrag
news:200406010130.24717.sdmitry@lrn.ru…

“Dmitry V. Sabanin” sdmitry@lrn.ru schrieb im Newsbeitrag
…

emulating condition

$counter = 0
def cond_met
$counter += 1
$counter > 1 ? true : false
end

Just a sidenote: you don’t have to convert the result of a boolean
expression to boolean by means of the ternary operator. This will do
exactly the same:

def cond_met
( $counter += 1 ) > 1
end
Damn C background… I always forget about this thing. Thanks, Robert

It’s superfluous to convert a boolean to a boolen in all programming
languages, although special bugs can arise from these conversions only in C
and other languages that don’t have real booleans:

#define TRUE 1
#define FALSE 0

int x; /* a boolean /
…
if ( x == TRUE ) {
/
not always here if x is true! */
}

This should be valid C code that does the expected thing:

/* untested */
int cond_met() {
return ++counter > 1;
}

Regards

robert
···

On Monday 31 May 2004 20:08, Robert Klemme wrote:

Robert Klemme wrote:

It’s superfluous to convert a boolean to a boolen in all programming
languages, although special bugs can arise from these conversions only in C
and other languages that don’t have real booleans:

Agreed, it’s generally wrong in most languages to use equality test for
booleans. I think this is because truth values transcend types (i.e. we
can ask for truth value for many types of values). Thankfully in Ruby
things are simplified: nil and false values are always false, everything
else is true.

···

#define TRUE 1
#define FALSE 0

int x; /* a boolean /
…
if ( x == TRUE ) {
/
not always here if x is true! */
}

This should be valid C code that does the expected thing:

/* untested */
int cond_met() {
return ++counter > 1;
}

–
dave

“David Garamond” lists@zara.6.isreserved.com schrieb im Newsbeitrag
news:40BC6E5F.1010502@zara.6.isreserved.com…

Robert Klemme wrote:

It’s superfluous to convert a boolean to a boolen in all programming
languages, although special bugs can arise from these conversions only
in C
and other languages that don’t have real booleans:

Agreed, it’s generally wrong in most languages to use equality test for
booleans. I think this is because truth values transcend types (i.e. we
can ask for truth value for many types of values).

No. The reason in C is, that there is a single value for ‘false’ but a
lot for ‘true’ and not that a lot of types can be used in a boolean
context (because they can be converted to bool aka int).

The same idiom is safe in Java, because it has boolean - but still
superfluous. In Java you should only use it in the rare case where you
want to compare two boolean expressions:

if ( getBoolX() == getBoolY() ) {…

is simpler and more intuitive than

if ( ( getBoolX() && getBoolY() ) || ( !getBoolX() && !getBoolY() ) ) {
…

Apart from that, there is a minor reason: the performance overhead for
some extra operations. But the main reason remains that it’s superfluous
and extremely error prone. Whenever you see something like this
(regardless of programming language), your alarm bells should ring:

if x > 10
return true
else
return false

return x < 22 ? false : true

return x == true ? false : true

(Safe replacements left as an exercise for the reader. :-))

Thankfully in Ruby
things are simplified: nil and false values are always false, everything
else is true.

From a certain point of view you could say that Ruby is more complicated
than C since it has two values meaning ‘false’ where C has only one. The
fact that all objects can occur in a boolean context just saves you some
explicit conversions you’d have to do in other languages.

Regards

robert

Robert Klemme wrote:

Thankfully in Ruby
things are simplified: nil and false values are always false, everything
else is true.

Alas, I actually didn’t even think about C when writing this :slight_smile: Was
comparing it to Python, PHP, Perl, etc. on my mind.

···

From a certain point of view you could say that Ruby is more complicated
than C since it has two values meaning ‘false’ where C has only one. The
fact that all objects can occur in a boolean context just saves you some
explicit conversions you’d have to do in other languages.

–
dave