Forward references?

Discussion in 'Ruby' started by Lloyd Zusman, Jul 30, 2004.

  1. Lloyd Zusman

    Lloyd Zusman Guest

    Is there a way to define forward references to functions? Due to my own
    personal eccentricities, I like to have the main body of a program
    appear at the top of its source file, and the functions it uses at the
    end.

    By "define forward reference", I mean something analogous to the
    following C construct:

    static char* foo(); /* forward reference */
    static char* bar(); /* forward reference */

    main () {
    printf("%s\n", foo());
    printf("%s\n", bar());
    exit(0);
    }

    char* foo() {
    return ("foo");
    }

    char* bar() {
    return ("bar");
    }

    If I could make use of forward references in ruby, the above program
    could look something like this:

    # somehow, define a forward reference to function foo()

    # somehow, define a forward reference to function bar()

    # program starts here

    x = foo()
    y = bar()
    puts x
    puts y
    exit(0)

    # real function definitions ...

    def foo
    return "foo"
    end

    def bar
    return "bar"
    end

    Am I totally out of luck, or is there some kind of ruby trick I can
    perform which will give me this capability?

    Thanks in advance.


    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Jul 30, 2004
    #1
    1. Advertising

  2. Lloyd Zusman wrote:

    >Is there a way to define forward references to functions? Due to my own
    >personal eccentricities, I like to have the main body of a program
    >appear at the top of its source file, and the functions it uses at the
    >end.
    >
    >By "define forward reference", I mean something analogous to the
    >following C construct:
    >
    > static char* foo(); /* forward reference */
    > static char* bar(); /* forward reference */
    >
    > main () {
    > printf("%s\n", foo());
    > printf("%s\n", bar());
    > exit(0);
    > }
    >
    > char* foo() {
    > return ("foo");
    > }
    >
    > char* bar() {
    > return ("bar");
    > }
    >
    >If I could make use of forward references in ruby, the above program
    >could look something like this:
    >
    > # somehow, define a forward reference to function foo()
    >
    > # somehow, define a forward reference to function bar()
    >
    > # program starts here
    >
    > x = foo()
    > y = bar()
    > puts x
    > puts y
    > exit(0)
    >
    > # real function definitions ...
    >
    > def foo
    > return "foo"
    > end
    >
    > def bar
    > return "bar"
    > end
    >
    >
    >

    Since Ruby doesn't check whether the functions exist until the code that
    calls them is actually run, one way to do this would be

    def main
    puts foo
    puts bar
    exit(0)
    end

    def foo
    return "foo"
    end

    def bar
    return "bar"
    end

    main

    --
    Mark Sparshatt
     
    Mark Sparshatt, Jul 30, 2004
    #2
    1. Advertising

  3. Lloyd Zusman wrote:
    > Is there a way to define forward references to functions? Due to my own
    > personal eccentricities, I like to have the main body of a program
    > appear at the top of its source file, and the functions it uses at the
    > end.
    >
    > By "define forward reference", I mean something analogous to the
    > following C construct:
    >
    > static char* foo(); /* forward reference */
    > static char* bar(); /* forward reference */
    >
    > main () {
    > printf("%s\n", foo());
    > printf("%s\n", bar());
    > exit(0);
    > }
    >
    > char* foo() {
    > return ("foo");
    > }
    >
    > char* bar() {
    > return ("bar");
    > }
    >
    > If I could make use of forward references in ruby, the above program
    > could look something like this:
    >
    > # somehow, define a forward reference to function foo()
    >
    > # somehow, define a forward reference to function bar()
    >
    > # program starts here
    > x = foo()
    > y = bar()
    > puts x
    > puts y
    > exit(0)


    Wrap this code into a END block:

    END {
    x = foo
    y = bar
    ...
    }

    Regards,

    Michael
     
    Michael Neumann, Jul 30, 2004
    #3
  4. Lloyd Zusman

    Lloyd Zusman Guest

    Michael Neumann <> writes:

    > Lloyd Zusman wrote:
    >> Is there a way to define forward references to functions? Due to my own
    >> personal eccentricities, I like to have the main body of a program
    >> appear at the top of its source file, and the functions it uses at the
    >> end.
    >>
    >> [ ... ]

    >
    > Wrap this code into a END block:
    >
    > END {
    > x = foo
    > y = bar
    > ...
    > }


    Aha! And this got me to think of a similar way to do it that is even
    more C-like:

    def main
    puts foo
    puts bar
    exit(0) # or it could be this: return (0)
    end

    def foo
    return "foo"
    end

    def bar
    return "bar"
    end

    END { exit(main) }
    # ... or without the END block as long as the last line of
    # the file is exit(main)


    Thank you very much!


    > Regards,
    >
    > Michael




    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Jul 30, 2004
    #4
  5. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...
    > Is there a way to define forward references to functions? Due to my own
    > personal eccentricities, I like to have the main body of a program
    > appear at the top of its source file, and the functions it uses at the
    > end.
    >
    > By "define forward reference", I mean something analogous to the
    > following C construct:
    >
    > static char* foo(); /* forward reference */
    > static char* bar(); /* forward reference */
    >
    > main () {
    > printf("%s\n", foo());
    > printf("%s\n", bar());
    > exit(0);
    > }
    >
    > char* foo() {
    > return ("foo");
    > }
    >
    > char* bar() {
    > return ("bar");
    > }
    >
    > If I could make use of forward references in ruby, the above program
    > could look something like this:
    >
    > # somehow, define a forward reference to function foo()
    >
    > # somehow, define a forward reference to function bar()
    >
    > # program starts here
    >
    > x = foo()
    > y = bar()
    > puts x
    > puts y
    > exit(0)
    >
    > # real function definitions ...
    >
    > def foo
    > return "foo"
    > end
    >
    > def bar
    > return "bar"
    > end
    >
    > Am I totally out of luck, or is there some kind of ruby trick I can
    > perform which will give me this capability?


    Just define them duplicately, the first time with an empty body:

    # "prototypes"
    def foo;end
    def bar(name)end

    # main stuff
    x = foo()
    y = bar()
    puts x
    puts y
    exit 0

    # "functions"
    def foo
    # foodoo
    end

    def bar(name)
    # bardo
    end

    Regards

    robert
     
    Robert Klemme, Jul 30, 2004
    #5
  6. Lloyd Zusman

    Lloyd Zusman Guest

    "Robert Klemme" <> writes:

    > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > news:...
    >> Is there a way to define forward references to functions? Due to my own
    >> personal eccentricities, I like to have the main body of a program
    >> appear at the top of its source file, and the functions it uses at the
    >> end.
    >>
    >> [ ... ]

    >
    > Just define them duplicately, the first time with an empty body:
    >
    > # "prototypes"
    > def foo;end
    > def bar(name)end
    >
    > # main stuff
    > x = foo()
    > y = bar()
    > puts x
    > puts y
    > exit 0
    >
    > # "functions"
    > def foo
    > # foodoo
    > end
    >
    > def bar(name)
    > # bardo
    > end
    >


    Thank you very much, but this doesn't appear to work. Here's what I
    tried:

    def foo;puts "forward ref of foo";end
    def bar(arg);puts "forward ref of bar(#{arg})";end

    foo()
    bar('abc')
    exit(0);

    def foo
    puts "foo"
    end

    def bar(arg)
    puts "bar: #{arg}"
    end

    When I ran it, it produced the following output:

    forward ref of foo
    forward ref of bar(abc)

    In other words, the second function definitions did not override the
    first ones.



    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Jul 30, 2004
    #6
  7. Lloyd Zusman

    Lloyd Zusman Guest

    Sam McCall <> writes:

    > Lloyd Zusman wrote:
    >> Is there a way to define forward references to functions? Due to my own
    >> personal eccentricities, I like to have the main body of a program
    >> appear at the top of its source file, and the functions it uses at the
    >> end.

    > In ruby, function definitions are code that gets executed, rather than
    > declarations that get found in the source file and put into a table.
    > So basically, the definitions have to come before the code that uses
    > them (but not before the definition of the methods that use them) in the
    > program flow. Therefore, if you want the main code at the top of the
    > file, put it in an END block or a method as already mentioned, or in a
    > separate file etc.
    > Defining stubs at the top won't work, because your main code runs before
    > the methods are redefined.
    > Sam


    Thank you very much, and thanks to all the rest of you for your helpful
    replies. Based on all this, I have settled on the following approach,
    which I have mentioned earlier in this thread:

    def main
    # my main routine
    #
    # ... etc. ...
    #
    return (exitcode) ### or this: exit(exitcode)
    end

    def function1
    # ... etc. ...
    end

    def function2
    # ... etc. ...
    end

    # other functions ...

    # final line ...
    exit(main)



    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Jul 31, 2004
    #7
  8. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...
    > Sam McCall <> writes:
    >
    > > Lloyd Zusman wrote:
    > >> Is there a way to define forward references to functions? Due to my

    own
    > >> personal eccentricities, I like to have the main body of a program
    > >> appear at the top of its source file, and the functions it uses at the
    > >> end.

    > > In ruby, function definitions are code that gets executed, rather than
    > > declarations that get found in the source file and put into a table.
    > > So basically, the definitions have to come before the code that uses
    > > them (but not before the definition of the methods that use them) in the
    > > program flow. Therefore, if you want the main code at the top of the
    > > file, put it in an END block or a method as already mentioned, or in a
    > > separate file etc.
    > > Defining stubs at the top won't work, because your main code runs before
    > > the methods are redefined.
    > > Sam

    >
    > Thank you very much, and thanks to all the rest of you for your helpful
    > replies. Based on all this, I have settled on the following approach,
    > which I have mentioned earlier in this thread:
    >
    > def main
    > # my main routine
    > #
    > # ... etc. ...
    > #
    > return (exitcode) ### or this: exit(exitcode)
    > end
    >
    > def function1
    > # ... etc. ...
    > end
    >
    > def function2
    > # ... etc. ...
    > end
    >
    > # other functions ...
    >
    > # final line ...
    > exit(main)


    Sorry, but I get the feeling that you are trying to make Ruby similar to C
    too much. IMHO the result is worse than straight ruby code. Let Ruby be
    Ruby and C be C. :)

    Kind regards

    robert
     
    Robert Klemme, Jul 31, 2004
    #8
  9. Lloyd Zusman

    Lloyd Zusman Guest

    "Robert Klemme" <> writes:

    > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > news:...
    >>
    >> [ ... ]
    >>
    >> def main
    >> # my main routine
    >> #
    >> # ... etc. ...
    >> #
    >> return (exitcode) ### or this: exit(exitcode)
    >> end
    >>
    >> def function1
    >> # ... etc. ...
    >> end
    >>
    >> def function2
    >> # ... etc. ...
    >> end
    >>
    >> # other functions ...
    >>
    >> # final line ...
    >> exit(main)

    >
    > Sorry, but I get the feeling that you are trying to make Ruby similar to C
    > too much. IMHO the result is worse than straight ruby code. Let Ruby be
    > Ruby and C be C. :)


    I just want to have my program's main body at the top of the program
    file, and the subsidiary functions at the end. The only thing C-like
    about this is the fact that I chose the word "main" for the routine that
    houses the main body of code.

    This construct is not necessary. I could just as easily name the main
    routine as "foobar", and it would look less C-like without losing the
    fact that the main body of the code comes first in the program file.

    Never fear ... the code that I write tends to look ruby-ish and not
    C-like. :)


    > Kind regards
    >
    > robert


    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Jul 31, 2004
    #9
  10. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...
    > "Robert Klemme" <> writes:
    >
    > > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > > news:...
    > >>
    > >> [ ... ]
    > >>
    > >> def main
    > >> # my main routine
    > >> #
    > >> # ... etc. ...
    > >> #
    > >> return (exitcode) ### or this: exit(exitcode)
    > >> end
    > >>
    > >> def function1
    > >> # ... etc. ...
    > >> end
    > >>
    > >> def function2
    > >> # ... etc. ...
    > >> end
    > >>
    > >> # other functions ...
    > >>
    > >> # final line ...
    > >> exit(main)

    > >
    > > Sorry, but I get the feeling that you are trying to make Ruby similar to

    C
    > > too much. IMHO the result is worse than straight ruby code. Let Ruby

    be
    > > Ruby and C be C. :)

    >
    > I just want to have my program's main body at the top of the program
    > file, and the subsidiary functions at the end. The only thing C-like
    > about this is the fact that I chose the word "main" for the routine that
    > houses the main body of code.
    >
    > This construct is not necessary. I could just as easily name the main
    > routine as "foobar", and it would look less C-like without losing the
    > fact that the main body of the code comes first in the program file.


    Here's another idea: put your code into two files and require (or load) the
    helper code.

    Or put your helper code after __END__ and use eval to compile it:

    eval DATA.read

    p foo()
    p bar()

    __END__

    def foo
    "foo"
    end

    def bar
    "bar"
    end


    > Never fear ... the code that I write tends to look ruby-ish and not
    > C-like. :)


    Dare you! :)

    Kind regards

    robert
     
    Robert Klemme, Jul 31, 2004
    #10
  11. Lloyd Zusman

    Lloyd Zusman Guest

    --=-=-=

    "Robert Klemme" <> writes:

    > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > news:...
    >>
    >> [ ... ]
    >>
    >> I just want to have my program's main body at the top of the program
    >> file, and the subsidiary functions at the end. The only thing C-like
    >> about this is the fact that I chose the word "main" for the routine that
    >> houses the main body of code.
    >>
    >> This construct is not necessary. I could just as easily name the main
    >> routine as "foobar", and it would look less C-like without losing the
    >> fact that the main body of the code comes first in the program file.

    >
    > Here's another idea: put your code into two files and require (or load) the
    > helper code.


    I know that I can do that. But often I just want one file. I believe
    that the best use of `require' or `load' is to include code from shared
    libraries. Putting simple subsidiary routines in one or more separate
    files often complicates installation and maintenance.


    > Or put your helper code after __END__ and use eval to compile it:
    >
    > [ ... etc. ... ]


    That can work, but if I ever want to put real data after __END__ and
    read it via the DATA handle, I'd be out of luck.


    >> Never fear ... the code that I write tends to look ruby-ish and not
    >> C-like. :)

    >
    > Dare you! :)


    OK. Attached is a ruby program that I recently wrote. It is a
    specialized "tail -f". In addition to standard "tail -f" capabilities,
    it also can simultaneously tail multiple files, and in addition, it will
    detect if a new file has replaced the one that is being tailed, in which
    case it starts tailing the newly created file automatically.

    The second feature is useful when I'm tailing log files that get
    recycled. For example, if syslog always writes log data to a file
    called, say, "foobar.log", and if once a day the following commands are
    run ...

    /bin/rm -f foobar.log.old
    /bin/mv foobar.log foobar.log.old
    kill -HUP $pid # where $pid is the process ID for syslogd

    ... then after these commands are invoked, syslog will start writing
    log data to a new, empty "foobar.log" file. If I had done this ...

    tail -f foobar.log

    ... then I would keep looking at the no-longer-changing "foobar.log.old"
    file after the log files are recycled. But if I invoke my new command
    (which I call "rtail") as follows ...

    rtail foobar.log

    ... then once the logs are recycled, the data that is being added to
    "foobar.log" will continue to appear in real time.

    Here's the code ...


    --=-=-=
    Content-Type: application/octet-stream
    Content-Disposition: attachment; filename=rtail
    Content-Transfer-Encoding: quoted-printable
    Content-Description: Ruby program 'rtail'

    #!/usr/bin/ruby

    # Do a 'tail -f' simultaneously multiple files, interspersing their
    # output.
    #
    # See the 'usage' routine, below, for a description of the command
    # line options and arguments.

    require 'sync'
    require 'getoptlong'

    $program =3D $0.sub(/^.*\//, '')

    $stdout.extend(Sync_m)
    $stdout.sync =3D 1

    $stderr.sync =3D 1

    $waitTime =3D 0.25

    # Default values for flags that are set via the command line.
    $tailf =3D true
    $fnamePrefix =3D false

    $defLineLen =3D 80
    $defLines =3D 80
    $lineLen =3D (ENV['COLUMNS'] =3D=3D nil ? $defLineLen : ENV['COLUMNS'])=
    to_i
    if $lineLen < 1 then
    $lineLen =3D $defLineLen
    end
    $lines =3D (ENV['LINES'] =3D=3D nil ? $defLines : ENV['LINES']).to_i

    $opts =3D GetoptLong.new(
    [ "--help", "-h", GetoptLong::NO_ARGUMENT ],
    [ "--lines", "-l", GetoptLong::REQUIRED_ARGUMENT ],
    [ "--exit", "-x", GetoptLong::NO_ARGUMENT ],
    [ "--name", "-n", GetoptLong::NO_ARGUMENT ]
    )

    # My list of threads.
    $fileThreads =3D []

    # Main routine
    def rtail

    begin

    # Parse and evaluate command-line options
    $opts.each do

    |opt, arg|

    case opt
    when "--help"
    usage
    # notreached
    when "--lines"
    begin
    $lines =3D arg.to_i + 0
    rescue
    usage
    # notreached
    end
    when "--exit"
    $tailf =3D false
    when "--name"
    $fnamePrefix =3D true
    end
    end
    rescue
    usage
    # notreached
    end

    if ARGV.length < 1 then
    usage
    # notreached
    end

    # Calculate the size of a screen so we can choose a reasonable
    # number of lines to tail.
    if $lines < 1 then
    $lines =3D $defLines
    end

    # One more full line than the maximum that the screen can hold.
    $backwards =3D $lineLen * ($lines + 1)

    # Signal handler.
    [ 'SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGTERM' ].each {
    |sig|
    trap(sig) {
    Thread.critical =3D true
    Thread.list.each {
    |t|
    unless t =3D=3D Thread.main then
    t.kill
    end
    }
    $stderr.puts("\r\n!!! aborted")
    Thread.critical =3D false
    exit(-1)
    }
    }

    # Start a thread to tail each file whose name appears on
    # the command line. The threads for any file that cannot
    # be opened for reading will die and will be reaped in
    # the main loop, below.
    ARGV.each {
    |arg|
    Thread.critical =3D true
    $fileThreads << Thread.new(arg, $tailf, &$fileReadProc)
    Thread.critical =3D false
    }

    # Main loop: reap dead threads and exit once there are no more
    # threads that are alive.
    loop {
    Thread.critical =3D true
    tcount =3D $fileThreads.length
    Thread.critical =3D false
    if tcount < 1 then
    break
    else
    # Don't eat up too much of my CPU time
    waitFor($waitTime)
    end
    }

    # Bye-bye
    exit(0)
    end

    # Add my own 'textfile?' method to the IO class.
    class IO

    private
    # List of items that I want to treat as being normal text
    # characters. The first line adds a lot of European characters
    # that are not normally considered to be text characters in
    # the traditional routines that distinguish between text and
    # binary files. This is used within the 'textfile?' method.
    @@textpats =3D [ "^=E1=E9=ED=F3=FA=E0=E8=EC=F2=F9=E4=EB=EF=F6=FC=F8=E7=F1=
    =C1=C9=CD=D3=DA=C0=C8=CC=D2=D9=C4=CB=CF=D6=DC=D8=C7=D1=A1=BF",
    "^ -~",
    "^\b\f\t\r\n" ]

    public
    # This is my own, special-purpose test for text-ness. I don't want
    # to treat certain European characters as binary. If the
    # 'restorePosition' argument is true, make sure that the the position
    # pointer within the IO handle gets repositioned back to its initial
    # value after this test is performed.
    def textfile?(testsize, restorePosition =3D false)
    if restorePosition then
    pos =3D self.pos
    else
    pos =3D nil
    end
    begin
    block =3D self.read(testsize)
    rescue
    return false
    end
    len =3D block.length
    if len < 1 then
    return true # I want to treat a zero-length file as a text file.
    end
    result =3D (block.count(*@@textpats) < (len / 3.0) and=20
    block.count("\x00") < 1)
    unless pos.nil?
    begin
    self.seek(pos, IO::SEEK_SET)
    rescue
    return false
    end
    end
    return result
    end
    end


    # Do a timed 'wait'.
    def waitFor(duration)
    startTime =3D Time.now.to_f
    select(nil, nil, nil, duration)
    Thread.pass
    # We could be back here long before 'duration' has passed.
    # The loop below makes sure that we wait at least as long
    # as this specified interval.
    while (elapsed =3D (Time.now.to_f - startTime)) < duration
    select(nil, nil, nil, 0.001)
    Thread.pass
    end
    # Return the actual amount of time that elapsed. This is
    # guaranteed to be >=3D 'duration'.
    return elapsed
    end

    # We make sure that $stdout is syncrhonized so that lines of
    # data coming from different threads don't garble each other.
    def syncwrite(text)
    begin
    $stdout.synchronize(Sync::EX) {
    $stdout.write(text)
    }
    rescue
    # Fall back to normal, non-sync writing
    $stdout.write(text)
    end
    end

    # Decide whether to output a block as is, or with a prefix
    # at the beginning of each line. In the "as is" case, just
    # send the whole block to `syncwrite'; otherwise, split into
    # lines and prepend the prefix before outputting. In other
    # words, we only incur the cost of splitting the block when
    # we absolutely have to.
    def output(item)
    prefix, block =3D item
    if prefix.nil? or prefix.length < 1 then
    syncwrite(block)
    else
    block.split(/\r*\n/).each {
    |line|
    syncwrite(prefix + line + "\n")
    }
    end
    end

    # Remove myself from the thread list and kill myself.
    def abortMyself
    t =3D Thread.current
    Thread.critical =3D true
    $fileThreads.delete(t)
    Thread.critical =3D false
    t.kill
    end

    # The main thread proc for tailing a given file
    $fileReadProc =3D Proc.new do
    |item, follow|

    # Open the file, make sure it's a text file, read the last bit
    # at the end, and output it. Kill the containing thread if any
    # of this fails.
    begin
    f =3D File.open(item, 'r')
    rescue
    output([nil, "!!! unable to open: #{item}\n"])
    abortMyself()
    end
    # Get some info about the open file
    begin
    f.sync =3D true
    bytesize =3D f.stat.size
    blocksize =3D f.stat.blksize
    inode =3D f.stat.ino
    rescue
    f.close
    output([nil, "!!! unable to stat: #{item}\n"])
    abortMyself()
    end
    # Blocksize will be nil or zero if the device being opened
    # is not a disk file. Bytesize will also be nil in this case.
    if blocksize.nil? or blocksize < 1 or bytesize.nil? then
    f.close
    output([nil, "!!! invalid device: #{item}\n"])
    abortMyself()
    end
    # Test for text-ness using one blocksize unit, or the length
    # of the file if that is smaller.
    testsize =3D (blocksize < bytesize ? blocksize : bytesize)
    unless f.textfile?(testsize) then
    f.close
    output([nil, "!!! not a text file: #{item}\n"])
    abortMyself()
    end
    if $fnamePrefix then
    prefix =3D File.basename(item) + ': '
    else
    prefix =3D nil
    end

    # Position to a suitable point near the end of the file,
    # and then read and output the data from that point until
    # the end.
    begin
    if bytesize > $backwards then
    pos =3D bytesize - $backwards
    else
    pos =3D 0
    end
    f.seek(pos, IO::SEEK_SET)
    if pos > 0 then
    f.gets # discard possible line fragment
    end
    output([prefix, f.read])
    rescue
    end

    # If we have made it here, we've read the last bit of the file
    # and have output it. Now, if we're not in 'follow' mode, we
    # just exit.
    unless follow then
    f.close
    abortMyself()
    end

    # We can only be here if we're in 'follow' mode. In this case,
    # we keep looping to test if there is any more data to output.
    loop {
    # Get the current inode of the file. This is used to test whether
    # or not the file has disappeared and whether or not there is a
    # new file by the same name. This is not 100-percent conclusive,
    # since a new file might accidentally end up with the same inode
    # of an older, deleted file.
    begin
    newinode =3D File.stat(item).ino
    rescue
    newinode =3D nil
    end
    begin
    if newinode.nil? or newinode !=3D inode then
    # If we're here, the file disappeared or was replaced by
    # a new file of the same name. We try to reopen the new
    # version before continuing with the loop.
    begin
    f.close
    waitFor($waitTime) # Wait a bit before trying to reopen
    f =3D File.open(item, 'r')
    f.sync =3D true
    unless f.textfile?(testsize, true) then
    f.close
    output([nil, "!!! reopenable, but not a text file: #{item}\n"])
    abortMyself()
    end
    inode =3D newinode
    output([nil, "!!! reopened: #{item}\n"])
    rescue
    output([nil, "!!! disappeared: #{item}\n"])
    begin
    f.close
    rescue
    end
    abortMyself()
    end
    elsif f.eof? then
    # If we're here, we're at EOF.
    f.seek(0, IO::SEEK_CUR)
    waitFor($waitTime)
    elsif f.pos < f.stat.size then
    # If we're here, more data was added to the file since the last
    # time we checked. Output this data, relinquish control to
    # other threads, and then repeat the loop.
    output([prefix, f.read])
    Thread.pass
    else
    # If we're here, the file hasn't changed since last time.
    # Wait a bit so as to not eat up too much CPU time.
    waitFor($waitTime)
    end
    rescue
    # Can we ever get here?
    end
    } # end of loop.
    end # end of thread proc

    # Print a usage message and exit.
    def usage
    warn <<EOD

    usage: #{$program} [ options ] file [ ... ]

    options:

    --help, -h print this usage message

    --lines=3D<n>, -l <n> tail <n> lines of each file (default #{$defLines})

    --exit, -x exit after showing initial tail

    --name, -n prepend file basename on each line that is output
    EOD
    exit(1)
    end

    # Run it
    exit(rtail)

    __END__

    --=-=-=



    --
    Lloyd Zusman

    God bless you.

    --=-=-=--
     
    Lloyd Zusman, Jul 31, 2004
    #11
  12. Lloyd Zusman

    Mark Hubbart Guest

    On Jul 30, 2004, at 7:31 AM, Lloyd Zusman wrote:

    > Is there a way to define forward references to functions? Due to my
    > own
    > personal eccentricities, I like to have the main body of a program
    > appear at the top of its source file, and the functions it uses at the
    > end.
    >
    > By "define forward reference", I mean something analogous to the
    > following C construct:
    >
    > static char* foo(); /* forward reference */
    > static char* bar(); /* forward reference */
    >
    > main () {
    > printf("%s\n", foo());
    > printf("%s\n", bar());
    > exit(0);
    > }
    >
    > char* foo() {
    > return ("foo");
    > }
    >
    > char* bar() {
    > return ("bar");
    > }
    >
    > If I could make use of forward references in ruby, the above program
    > could look something like this:
    >
    > # somehow, define a forward reference to function foo()
    >
    > # somehow, define a forward reference to function bar()
    >
    > # program starts here
    >
    > x = foo()
    > y = bar()
    > puts x
    > puts y
    > exit(0)
    >
    > # real function definitions ...
    >
    > def foo
    > return "foo"
    > end
    >
    > def bar
    > return "bar"
    > end
    >
    > Am I totally out of luck, or is there some kind of ruby trick I can
    > perform which will give me this capability?


    One other way is to use blocks:

    # code that does this:
    def chunk(&block) ($CHUNKS||=[]) << block end
    END{ $CHUNKS.reverse_each{|ch| ch[] } }
    # end special code :)

    chunk do

    x = foo()
    y = bar()
    puts x
    puts y
    exit(0)

    end

    chunk do

    def foo
    return "foo"
    end

    def bar
    return "bar"
    end

    end

    Of course, you'd name it something other than chunk. And there's probly
    a one liner for it, too, but I didn't have enough time to clean it up
    much.

    cheers,
    Mark
     
    Mark Hubbart, Jul 31, 2004
    #12
  13. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...

    > > Here's another idea: put your code into two files and require (or load)

    the
    > > helper code.

    >
    > I know that I can do that. But often I just want one file. I believe
    > that the best use of `require' or `load' is to include code from shared
    > libraries. Putting simple subsidiary routines in one or more separate
    > files often complicates installation and maintenance.


    True. It's a tradeoff: it seemed to me that having prototypes was a
    paramount requirement of you.

    > > Or put your helper code after __END__ and use eval to compile it:
    > >
    > > [ ... etc. ... ]

    >
    > That can work, but if I ever want to put real data after __END__ and
    > read it via the DATA handle, I'd be out of luck.


    Yes, of course.

    > >> Never fear ... the code that I write tends to look ruby-ish and not
    > >> C-like. :)

    > >
    > > Dare you! :)

    >
    > OK. Attached is a ruby program that I recently wrote. It is a
    > specialized "tail -f". In addition to standard "tail -f" capabilities,
    > it also can simultaneously tail multiple files, and in addition, it will
    > detect if a new file has replaced the one that is being tailed, in which
    > case it starts tailing the newly created file automatically.

    <snip/>
    > Here's the code ...


    Very nice! I like especially the documentation. Some remarks from cursory
    glancing though:

    - I would not use Thread.critical since it is error prone. *If* you use
    it, you should use this idiom, because it ensures that Thread.critical is
    reset properly:

    Thread.critical = true
    begin
    # stuff
    ensure
    Thread.critical = false
    end

    But, in your example this is superior:

    require 'monitor'
    # My list of threads.
    $fileThreads = [].extend MonitorMixin
    # later
    $fileThreads.synchronize do
    # do stuff with $fileThreads
    end

    - You are using exit a bit too much IMHO, especially since you have
    "exit(rtail)" but rtail invokes exit, too. Usage of exit reduces
    reusability of code and thus I would limit it to the to level of the script,
    something like

    begin
    # do MAIN stuff
    exit 0
    rescue Exception => e
    $stderr.puts e
    exit 1
    end

    And within the rest of the script I'd use exceptions. Patterns like this
    are inferior

    begin
    block = self.read(testsize)
    rescue
    return false
    end
    # further code that works with block

    Instead put all the code for the clean case into the block or leave the
    rescue completely out here and handle the exception on a higher level. That
    makes things much easier.


    - There is File.split:

    # old: $program = $0.sub(/^.*\//, '')
    $dir, $program = File.split $0


    I hope, that was not too frustrating... :)

    Regards

    robert
     
    Robert Klemme, Aug 1, 2004
    #13
  14. Lloyd Zusman

    Lloyd Zusman Guest

    "Robert Klemme" <> writes:

    > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > news:...
    >>
    >> [ ... ]
    >>
    >> [ ... ] Putting simple subsidiary routines in one or more separate
    >> files often complicates installation and maintenance.

    >
    > True. It's a tradeoff: it seemed to me that having prototypes was a
    > paramount requirement of you.


    Well, actually, what's important (or at least desirable) to me is not
    prototypes in and of themselves, but rather, just to have the main body
    of the code near the top of the file.


    > [ ... ]
    >
    > Very nice! [ ... ]


    Thank you.


    > [ ... ] I like especially the documentation. Some remarks from cursory
    > glancing though:
    >
    > require 'monitor'
    > # My list of threads.
    > $fileThreads = [].extend MonitorMixin
    > # later
    > $fileThreads.synchronize do
    > # do stuff with $fileThreads
    > end


    Why not just use the 'sync' module that is already being utilized in
    the program? i.e. ...

    $fileThreads = [].extend(Sync_m)


    > - You are using exit a bit too much IMHO, especially since you have
    > "exit(rtail)" but rtail invokes exit, too. Usage of exit reduces
    > reusability of code and thus I would limit it to the to level of the script,
    > something like
    >
    > begin
    > # do MAIN stuff
    > exit 0
    > rescue Exception => e
    > $stderr.puts e
    > exit 1
    > end


    Thanks. But how about this slight variation? Since I had exit(rtail),
    I could just do it this way ...

    # at the bottom of the script ...
    begin
    rtail
    result = 0
    # or if I want: result = rtail
    rescue Exception => e
    $stderr.puts("!!! #{e}")
    result = 1
    end
    exit(result)

    ... and then raise exceptions every other place where I was using 'exit'.


    > And within the rest of the script I'd use exceptions. Patterns like this
    > are inferior
    >
    > begin
    > block = self.read(testsize)
    > rescue
    > return false
    > end
    > # further code that works with block
    >
    > Instead put all the code for the clean case into the block or leave the
    > rescue completely out here and handle the exception on a higher level. That
    > makes things much easier.


    Yes, that's a good approach in many cases, and I will do so in those
    instances. However, in a few places, I have different kinds of 'rescue'
    responses for different steps within the flow of control. Look at
    $fileReadProc in my program, for example. I want my error message to
    distinguish between "unable to open", "unable to stat", "invalid
    device", etc., and I want to use my own error message text for each of
    these instances. I don't see how to avoid a series of short
    begin/rescue/end blocks in this case.

    Hmm ... well, I could do this, but I don't like it:

    $errorMessage = 'unknown error'
    begin
    $errorMessage = 'unable to open'
    # open the file
    $errorMessage = 'invalid device'
    # do stuff that fails if the item is not a file
    $errorMessage = 'unable to stat'
    # do stat-related stuff
    $errorMessage = 'message for next likely exception to be raised'
    # ... etc. ...
    rescue
    begin
    f.close
    rescue
    # file may or may not be open when exception occurs
    end
    output([nil, "!!! #{$errorMessage}: #{item}]")
    abortMyself()
    end

    In the case I have shown here, I prefer the smaller begin/rescue/end
    blocks, even though that's more verbose. It will be clearer to future
    maintainers.


    > - There is File.split:
    >
    > # old: $program = $0.sub(/^.*\//, '')
    > $dir, $program = File.split $0


    Yes. I'm just in the habit of doing this myself, especially when I
    don't want the '$dir' part.


    > I hope, that was not too frustrating... :)


    No, not at all. Everything is much appreciated.



    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Aug 1, 2004
    #14
  15. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...

    <snip/>

    > > [ ... ] I like especially the documentation. Some remarks from cursory
    > > glancing though:
    > >
    > > require 'monitor'
    > > # My list of threads.
    > > $fileThreads = [].extend MonitorMixin
    > > # later
    > > $fileThreads.synchronize do
    > > # do stuff with $fileThreads
    > > end

    >
    > Why not just use the 'sync' module that is already being utilized in
    > the program? i.e. ...
    >
    > $fileThreads = [].extend(Sync_m)


    Oh, I overlooked that. Is that std Ruby? (Monitor and Mutex are)

    > > - You are using exit a bit too much IMHO, especially since you have
    > > "exit(rtail)" but rtail invokes exit, too. Usage of exit reduces
    > > reusability of code and thus I would limit it to the to level of the

    script,
    > > something like
    > >
    > > begin
    > > # do MAIN stuff
    > > exit 0
    > > rescue Exception => e
    > > $stderr.puts e
    > > exit 1
    > > end

    >
    > Thanks. But how about this slight variation? Since I had exit(rtail),
    > I could just do it this way ...
    >
    > # at the bottom of the script ...
    > begin
    > rtail
    > result = 0
    > # or if I want: result = rtail
    > rescue Exception => e
    > $stderr.puts("!!! #{e}")
    > result = 1
    > end
    > exit(result)


    I prefer this:

    # at the bottom of the script ...
    begin
    exit rtail
    rescue Exception => e
    $stderr.puts("!!! #{e}")
    exit 1
    end

    because it's more robust if you change your mind and want to do different
    things (like not exiting). It keeps information more local. Maybe this is
    a habit I got from Java because compilers can warn you if you put the exit
    (or return for methods) into their respective neighborhood and forget one of
    them.

    > .. and then raise exceptions every other place where I was using 'exit'.


    Yes, definitely.

    > > And within the rest of the script I'd use exceptions. Patterns like

    this
    > > are inferior
    > >
    > > begin
    > > block = self.read(testsize)
    > > rescue
    > > return false
    > > end
    > > # further code that works with block
    > >
    > > Instead put all the code for the clean case into the block or leave the
    > > rescue completely out here and handle the exception on a higher level.

    That
    > > makes things much easier.

    >
    > Yes, that's a good approach in many cases, and I will do so in those
    > instances. However, in a few places, I have different kinds of 'rescue'
    > responses for different steps within the flow of control. Look at
    > $fileReadProc in my program, for example. I want my error message to
    > distinguish between "unable to open", "unable to stat", "invalid
    > device", etc., and I want to use my own error message text for each of
    > these instances. I don't see how to avoid a series of short
    > begin/rescue/end blocks in this case.
    >
    > Hmm ... well, I could do this, but I don't like it:
    >
    > $errorMessage = 'unknown error'
    > begin
    > $errorMessage = 'unable to open'
    > # open the file
    > $errorMessage = 'invalid device'
    > # do stuff that fails if the item is not a file
    > $errorMessage = 'unable to stat'
    > # do stat-related stuff
    > $errorMessage = 'message for next likely exception to be raised'
    > # ... etc. ...
    > rescue
    > begin
    > f.close
    > rescue
    > # file may or may not be open when exception occurs
    > end
    > output([nil, "!!! #{$errorMessage}: #{item}]")
    > abortMyself()
    > end
    >
    > In the case I have shown here, I prefer the smaller begin/rescue/end
    > blocks, even though that's more verbose. It will be clearer to future
    > maintainers.


    It will be even clearer if you break this code up into multiple method
    invocations. Then you'll have methods like:

    begin
    File.open("foo.txt") do |io|
    # IO is open here
    # do more stuff
    end
    rescue Errno::Enoent => e
    $stderr.puts "ERROR: ..."
    rescue OtherError => e
    ...
    end

    Reusing a global (!) for the current error message looks irritating to me.
    A global is not really needed here. And having a single rescue clause for
    multiple errors doesn't look good to me either.

    > > - There is File.split:
    > >
    > > # old: $program = $0.sub(/^.*\//, '')
    > > $dir, $program = File.split $0

    >
    > Yes. I'm just in the habit of doing this myself, especially when I
    > don't want the '$dir' part.


    Then you can do
    $prog = File.split($0)[1]

    Advantage of File.split is that it's platform independend. Only introduce
    platform dependencies that are really necessary - that might make your life
    much easier in the future.

    Kind regards

    robert
     
    Robert Klemme, Aug 1, 2004
    #15
  16. Lloyd Zusman

    Lloyd Zusman Guest

    "Robert Klemme" <> writes:

    > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > news:...
    >>
    >> [ ... ]
    >>
    >> Why not just use the 'sync' module that is already being utilized in
    >> the program? i.e. ...
    >>
    >> $fileThreads = [].extend(Sync_m)

    >
    > Oh, I overlooked that. Is that std Ruby? (Monitor and Mutex are)


    Sync_m has been around ever since 1.6.x, and it's excplicitly mentioned
    in the Pickaxe book (on page 120, the last line of the "Condition
    Variables" section of Chapter 11, "Threads and Processes"). You can see
    the code in RUBYINSTALLDIR/lib/sync.rb


    >> Thanks. But how about this slight variation? Since I had exit(rtail),
    >> I could just do it this way ...
    >>
    >> # at the bottom of the script ...
    >> begin
    >> rtail
    >> result = 0
    >> # or if I want: result = rtail
    >> rescue Exception => e
    >> $stderr.puts("!!! #{e}")
    >> result = 1
    >> end
    >> exit(result)

    >
    > I prefer this:
    >
    > # at the bottom of the script ...
    > begin
    > exit rtail
    > rescue Exception => e
    > $stderr.puts("!!! #{e}")
    > exit 1
    > end
    >
    > because it's more robust if you change your mind and want to do different
    > things (like not exiting). It keeps information more local. Maybe this is
    > a habit I got from Java because compilers can warn you if you put the exit
    > (or return for methods) into their respective neighborhood and forget one of
    > them.


    ??? In your case, the problem you mentioned (forgetting exit or return)
    seems _more_ likely, since you explicitly code 'exit' in two places. In
    my version, it only appears once. Using your construct ...

    # at the bottom of the script ...
    begin
    exit rtail
    rescue Exception => e
    $stderr.puts("!!! #{e}")
    ###exit 1
    accidentally_forget_to_exit()
    end

    If I want to do something other than exiting, then I can do the
    following with my construct:

    # at the bottom of the script ...
    begin
    result = rtail
    rescue Exception => e
    $stderr.puts("!!! #{e}")
    result = 1
    end
    ###exit(result)
    do_something_other_than_exiting(result)


    > It will be even clearer if you break this code up into multiple method
    > invocations. Then you'll have methods like:
    >
    > begin
    > File.open("foo.txt") do |io|
    > # IO is open here
    > # do more stuff
    > end
    > rescue Errno::Enoent => e
    > $stderr.puts "ERROR: ..."
    > rescue OtherError => e
    > ...
    > end


    Yes, I often do that. It just seems like overkill in my small app.


    > Reusing a global (!) for the current error message looks irritating to
    > me.


    Yep. That's why I said that I don't like it. I gave that example to
    show how undesirable it is.


    > Then you can do
    > $prog = File.split($0)[1]
    >
    > Advantage of File.split is that it's platform independend. Only introduce
    > platform dependencies that are really necessary - that might make your life
    > much easier in the future.


    Good point. I have now replaced the $0.sub(...) call with this:

    File.basename($0)

    I believe that it's better than the File.split version, because it is
    giving me exactly what I want: the basename of the file. That makes the
    code more self-documenting; and besides, I already use File.basename
    elsewhere in the code for the same purpose.


    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Aug 1, 2004
    #16
  17. Lloyd Zusman

    Lloyd Zusman Guest

    Mark Hubbart <> writes:

    > [ ... ]
    >
    > One other way is to use blocks:
    >
    > # code that does this:
    > def chunk(&block) ($CHUNKS||=[]) << block end
    > END{ $CHUNKS.reverse_each{|ch| ch[] } }
    > # end special code :)
    >
    > chunk do
    >
    > x = foo()
    > y = bar()
    > puts x
    > puts y
    > exit(0)
    >
    > end
    >
    > chunk do
    >
    > def foo
    > return "foo"
    > end
    >
    > def bar
    > return "bar"
    > end
    >
    > end
    >
    > Of course, you'd name it something other than chunk. And there's probly
    > a one liner for it, too, but I didn't have enough time to clean it up
    > much.


    This is probably a bit hard to maintain due to its not-so-obvious
    algorithm. But it's clever!

    Thank you very much.


    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Aug 2, 2004
    #17
  18. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...
    > "Robert Klemme" <> writes:
    >
    > > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > > news:...
    > >>
    > >> [ ... ]
    > >>
    > >> Why not just use the 'sync' module that is already being utilized in
    > >> the program? i.e. ...
    > >>
    > >> $fileThreads = [].extend(Sync_m)

    > >
    > > Oh, I overlooked that. Is that std Ruby? (Monitor and Mutex are)

    >
    > Sync_m has been around ever since 1.6.x, and it's excplicitly mentioned
    > in the Pickaxe book (on page 120, the last line of the "Condition
    > Variables" section of Chapter 11, "Threads and Processes"). You can see
    > the code in RUBYINSTALLDIR/lib/sync.rb


    Oh, once again learned something new. But as far as I can see it's only
    mentioned at this single location - no examples no additional
    explanations.

    > >> Thanks. But how about this slight variation? Since I had

    exit(rtail),
    > >> I could just do it this way ...
    > >>
    > >> # at the bottom of the script ...
    > >> begin
    > >> rtail
    > >> result = 0
    > >> # or if I want: result = rtail
    > >> rescue Exception => e
    > >> $stderr.puts("!!! #{e}")
    > >> result = 1
    > >> end
    > >> exit(result)

    > >
    > > I prefer this:
    > >
    > > # at the bottom of the script ...
    > > begin
    > > exit rtail
    > > rescue Exception => e
    > > $stderr.puts("!!! #{e}")
    > > exit 1
    > > end
    > >
    > > because it's more robust if you change your mind and want to do

    different
    > > things (like not exiting). It keeps information more local. Maybe

    this is
    > > a habit I got from Java because compilers can warn you if you put the

    exit
    > > (or return for methods) into their respective neighborhood and forget

    one of
    > > them.

    >
    > ??? In your case, the problem you mentioned (forgetting exit or return)
    > seems _more_ likely, since you explicitly code 'exit' in two places. In
    > my version, it only appears once. Using your construct ...
    >
    > # at the bottom of the script ...
    > begin
    > exit rtail
    > rescue Exception => e
    > $stderr.puts("!!! #{e}")
    > ###exit 1
    > accidentally_forget_to_exit()
    > end


    Yeah, but you'll soon recognize that the program does not exit. While
    it's more difficult ro recognize that it exits in both cases but you
    wanted it to do something else in once case IMHO. Maybe it's a matter of
    taste or my usage to Eclipse's excellent Java support which gives you
    compile error messages and warnings that help a lot. Of course, Ruby is
    not compiled... :)

    > If I want to do something other than exiting, then I can do the
    > following with my construct:
    >
    > # at the bottom of the script ...
    > begin
    > result = rtail
    > rescue Exception => e
    > $stderr.puts("!!! #{e}")
    > result = 1
    > end
    > ###exit(result)
    > do_something_other_than_exiting(result)


    Yeah, but that treats both cases (ok and error) the same and you have to
    make a distinction in do_something_other_than_exiting(). That's typically
    bad; it's better to have separate methods that handle each case
    individually because methods then do just *one* thing and not two. Of
    course, if you do the same in every case it's reasonable to have a single
    method.

    > > It will be even clearer if you break this code up into multiple method
    > > invocations. Then you'll have methods like:
    > >
    > > begin
    > > File.open("foo.txt") do |io|
    > > # IO is open here
    > > # do more stuff
    > > end
    > > rescue Errno::Enoent => e
    > > $stderr.puts "ERROR: ..."
    > > rescue OtherError => e
    > > ...
    > > end

    >
    > Yes, I often do that. It just seems like overkill in my small app.


    Personally I prefer that kind of "overkill" over other strategies.

    > > Reusing a global (!) for the current error message looks irritating to
    > > me.

    >
    > Yep. That's why I said that I don't like it. I gave that example to
    > show how undesirable it is.


    Ah, ok.

    > Good point. I have now replaced the $0.sub(...) call with this:
    >
    > File.basename($0)
    >
    > I believe that it's better than the File.split version, because it is
    > giving me exactly what I want: the basename of the file. That makes the
    > code more self-documenting; and besides, I already use File.basename
    > elsewhere in the code for the same purpose.


    Yeah, much better. I didn't think of File#basename.

    Kind regards

    robert
     
    Robert Klemme, Aug 2, 2004
    #18
  19. Lloyd Zusman

    Lloyd Zusman Guest

    "Robert Klemme" <> writes:

    > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > news:...
    >>
    >> [ ... ]
    >>
    >> Sync_m has been around ever since 1.6.x, and it's excplicitly mentioned
    >> in the Pickaxe book (on page 120, the last line of the "Condition
    >> Variables" section of Chapter 11, "Threads and Processes"). You can see
    >> the code in RUBYINSTALLDIR/lib/sync.rb

    >
    > Oh, once again learned something new. But as far as I can see it's only
    > mentioned at this single location - no examples no additional
    > explanations.


    Yes, sync.rb (containing Sync_m and Synchronizer_m) is not mentioned or
    documented anywhere else that I can find. I'm not sure where I stumbled
    upon it ... I probably saw it used in someone else's code and then
    investigated it. Although the mutex and monitor classes also can work
    here, I prefer Sync_m in this case because its name reflects the exact
    use to which I am putting it: synchronization.


    > [ ... ]
    >
    > Yeah, but you'll soon recognize that the program does not exit. While
    > it's more difficult ro recognize that it exits in both cases but you
    > wanted it to do something else in once case IMHO. Maybe it's a matter of
    > taste or my usage to Eclipse's excellent Java support which gives you
    > compile error messages and warnings that help a lot. Of course, Ruby is
    > not compiled... :)
    >
    >> If I want to do something other than exiting, then I can do the
    >> following with my construct:
    >>
    >> # at the bottom of the script ...
    >> begin
    >> result = rtail
    >> rescue Exception => e
    >> $stderr.puts("!!! #{e}")
    >> result = 1
    >> end
    >> ###exit(result)
    >> do_something_other_than_exiting(result)

    >
    > Yeah, but that treats both cases (ok and error) the same and you have to
    > make a distinction in do_something_other_than_exiting(). That's typically
    > bad; it's better to have separate methods that handle each case
    > individually because methods then do just *one* thing and not two. Of
    > course, if you do the same in every case it's reasonable to have a single
    > method.


    Yes. Here I always want to exit. If I wanted to do something different
    on exit and on error, I would structure this code snippet differently.


    >> [ ... ]
    >>
    >> Yes, I often do that. It just seems like overkill in my small app.

    >
    > Personally I prefer that kind of "overkill" over other strategies.


    Adding a number of small methods would decrease maintainability of my
    particular program, IMO. That is not true in general, and I indeed do
    this on other kinds of projects. However, think that it does apply in
    this case.

    But there is plenty of room to differ here.


    I refactored the code even more, based on our discussions and some ideas
    of my own. If you're interested, I can privately email you the latest
    version.


    --
    Lloyd Zusman

    God bless you.
     
    Lloyd Zusman, Aug 2, 2004
    #19
  20. "Lloyd Zusman" <> schrieb im Newsbeitrag
    news:...
    > "Robert Klemme" <> writes:
    >
    > > "Lloyd Zusman" <> schrieb im Newsbeitrag
    > > news:...
    > >>
    > >> [ ... ]
    > >>
    > >> Sync_m has been around ever since 1.6.x, and it's excplicitly

    mentioned
    > >> in the Pickaxe book (on page 120, the last line of the "Condition
    > >> Variables" section of Chapter 11, "Threads and Processes"). You can

    see
    > >> the code in RUBYINSTALLDIR/lib/sync.rb

    > >
    > > Oh, once again learned something new. But as far as I can see it's

    only
    > > mentioned at this single location - no examples no additional
    > > explanations.

    >
    > Yes, sync.rb (containing Sync_m and Synchronizer_m) is not mentioned or
    > documented anywhere else that I can find. I'm not sure where I stumbled
    > upon it ... I probably saw it used in someone else's code and then
    > investigated it. Although the mutex and monitor classes also can work
    > here, I prefer Sync_m in this case because its name reflects the exact
    > use to which I am putting it: synchronization.


    Monitor and Mutex are also fixed terms in the MT community. It looks,
    like everyone put his term in here. :) As far as I remember the
    difference between Monitor and Mutex is that Monitor is reentrant while
    Mutex is not. As far as I can see Sync and Sync_m are reentrant, too:

    require 'thread'
    require 'monitor'
    require 'sync'

    [Monitor, Sync, Mutex].each do |cl|
    x = cl.new
    puts "outside"; p x
    begin
    x.synchronize { puts "first"; p x; x.synchronize { puts "nest"; p
    x } }
    rescue Exception => e
    puts e
    end
    end

    > Adding a number of small methods would decrease maintainability of my
    > particular program, IMO. That is not true in general, and I indeed do
    > this on other kinds of projects. However, think that it does apply in
    > this case.
    >
    > But there is plenty of room to differ here.


    Yeah, often these things are at least partly a matter of taste and
    individual habit.
    :)

    > I refactored the code even more, based on our discussions and some ideas
    > of my own. If you're interested, I can privately email you the latest
    > version.


    [x] interested [ ] not interested

    Cheers

    robert
     
    Robert Klemme, Aug 2, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. qazmlp
    Replies:
    1
    Views:
    605
    Jonathan Turkanis
    Feb 15, 2004
  2. Boris Du¹ek
    Replies:
    3
    Views:
    375
    Juha Nieminen
    May 2, 2009
  3. Lorenzo Di Gregorio

    Inheritance and forward references (prototypes)

    Lorenzo Di Gregorio, Jun 20, 2009, in forum: Python
    Replies:
    14
    Views:
    478
    Lorenzo Di Gregorio
    Jun 22, 2009
  4. Peter Seebach

    Forward references?

    Peter Seebach, May 26, 2007, in forum: Ruby
    Replies:
    2
    Views:
    116
    Jeremy Henty
    May 26, 2007
  5. mathog
    Replies:
    7
    Views:
    238
    Martin Shobe
    May 31, 2013
Loading...

Share This Page