zsh-users
 help / color / mirror / code / Atom feed
* Factoring out code
@ 2005-09-05 11:42 DervishD
  2005-09-05 20:08 ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: DervishD @ 2005-09-05 11:42 UTC (permalink / raw)
  To: Zsh Users

    Hi all :)

    Most (probably all...) of my scrips start like this:

---- cut here ---- 8< ----

    emulate -L zsh

    # Not all of them have this:
    [[ $# -eq 0 ]] && set -- --help

    # But almost all have this:
    [[ $# -gt 0 && $argv[(i)--help] -le $# ]] && {
        # Show help output here
        return 0
    }

    # ...and this:
    [[ $# -gt 0 && $argv[(i)--doc] -le $# ]] && {
        # Show internal documentation here
        return 0
    }

---- cut here ---- >8 ----


    OK, so I've factored out code:

---- cut here ---- 8< ----
# This is "common.sh", and MUST BE SOURCED!
emulate -L zsh
# Dummy stubs, just in case the caller didn't gave them.
function doc() {
    print "This script doesn't have internal documentation yet!"
    return 0
}

function help() {
    print "This script doesn't have help output yet!"
    return 0
}

# We make argv global so we really are messing with the
# argv of OUR CALLER
typeset -gx argv

# Handle a couple of options
[[ $# -gt 0 && $argv[(i)--help] -le $# ]] && help
[[ $# -gt 0 && $argv[(i)--doc] -le $# ]] && doc

# Delete handled options, that is, MODIFY caller's argv!
# ...
---- cut here ---- >8 ----


    My scripts now look like this:

---- cut here ---- 8< ----

    . common.sh

    # We want to make '--help' the default option for this script:
    [[ $# -eq 0 ]] && set -- --help

    function help() {
        # Here goes the real help output
    }

    function doc() {
        # Here goes the real doc output
    }

    # Do the rest of the job
    # We should source "common.sh" here, really,
    # in order to make it work...
---- cut here ---- >8 ----   

    Of course this doesn't work, because the sourceing of 'common.sh'
should be done AFTER the function declarations and AFTER the default
argv setting. But then, there will be some code that I won't be able
to factor out :(, because some things (not factored out yet) MUST be
done BEFORE any other code is run, that is, before of declaring
funcions and the like. I cannot put in a function the code needed to
be run AFTER the function declarations, because then the argv thing
won't work, and I cannot pass argv as a parameter because it has to
be modified :(

    How can I make "common.sh" to run code BEFORE and AFTER some
point in the script which sources it, if that code must modify global
variables in the caller and work like a cut'n'paste (I mean, for the
'sourcer' script the code should run like if was cut from "common.sh"
and pasted into the file, just like a macro)?

    The only solution I've found so far is to source "common.sh"
after declaring the functions and running other code, but then I
loose the ability of factoring out the 'emulate -L zsh' code, some
options settings and additional code that must be factored, and this
will lead to the same maintenance problems I have right now :(

    Thanks a lot in advance, and if you need more information I can
provide more examples. I'm afraid I haven't explained the issue quite
well :(((

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736 | http://www.dervishd.net
http://www.pleyades.net & http://www.gotesdelluna.net
It's my PC and I'll cry if I want to...


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Factoring out code
  2005-09-05 11:42 Factoring out code DervishD
@ 2005-09-05 20:08 ` Bart Schaefer
  2005-09-06 10:37   ` DervishD
  0 siblings, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2005-09-05 20:08 UTC (permalink / raw)
  To: Zsh Users

On Sep 5,  1:42pm, DervishD wrote:
}
}     How can I make "common.sh" to run code BEFORE and AFTER some
} point in the script which sources it

Have you considered splitting common.sh into two files, the first called
(for example) emulate.sh and the second common.sh, and then start the
rest of your scripts with (again for example)

    . emulate.sh
    function help { ... }
    function doc { ... }
    . common.sh

??  This sort of thing is done quite frequently in languages like PHP
that are used for writing web applications.  You should probably also
put all of these "include files" in a common subdirectory, so that you
typically write

    . inc/emulate.sh
    function help { ... }
    function doc { ... }
    . inc/common.sh

Another approach would be to have common.sh define a bunch of variables
whose contents are snippets of shell code; e.g.

    . common.sh
    function help { ... }
    function doc { ... }
    eval ${_common_parse_argv:?'common.sh not sourced'}

(See the manual for ${name:?message} semantics.)

} if that code must modify global
} variables in the caller and work like a cut'n'paste (I mean, for the
} 'sourcer' script the code should run like if was cut from "common.sh"
} and pasted into the file, just like a macro)?

You have to be careful with this unless you're doing something like

    eval "$(<inc/common.sh)"

because the argv array CAN become local to a sourced file.  If you pass
multiple arguments to the dot or source commands, as in

    . foo.sh bar baz

then argv becomes a local with value (bar baz) in foo.sh, just as it
would in a function, and e.g. `set -- ...' no longer affects the argv
of the caller.

By the way, 'typeset -gx argv' has no effect whatsoever.  You cannot
cause argv to change from local to global under any circumstances.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Factoring out code
  2005-09-05 20:08 ` Bart Schaefer
@ 2005-09-06 10:37   ` DervishD
  2005-09-06 14:58     ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: DervishD @ 2005-09-06 10:37 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

    Hi Bart :)

 * Bart Schaefer <schaefer@brasslantern.com> dixit:
> On Sep 5,  1:42pm, DervishD wrote:
> }     How can I make "common.sh" to run code BEFORE and AFTER some
> } point in the script which sources it
> Have you considered splitting common.sh into two files, the first called
> (for example) emulate.sh and the second common.sh, and then start the
> rest of your scripts with (again for example)
> 
>     . emulate.sh
>     function help { ... }
>     function doc { ... }
>     . common.sh

    Yes, I've considered it, but it's my last resort, I prefer just
one file, it's easier to maintain (otherwise I have to decide where
should I put new code, in emulate or in common).
 
> Another approach would be to have common.sh define a bunch of variables
> whose contents are snippets of shell code; e.g.
> 
>     . common.sh
>     function help { ... }
>     function doc { ... }
>     eval ${_common_parse_argv:?'common.sh not sourced'}
> 
> (See the manual for ${name:?message} semantics.)

    That's a bit messy, too, using eval and the like. Looks like I'm
going to make syntax errors everytime I use it O:) OTOH, making
"_common_parse_argv" a function won't work since it has to modify
argv.

> } if that code must modify global
> } variables in the caller and work like a cut'n'paste (I mean, for the
> } 'sourcer' script the code should run like if was cut from "common.sh"
> } and pasted into the file, just like a macro)?
> You have to be careful with this unless you're doing something like
> 
>     eval "$(<inc/common.sh)"
> 
> because the argv array CAN become local to a sourced file.  If you pass
> multiple arguments to the dot or source commands, as in
> 
>     . foo.sh bar baz
> 
> then argv becomes a local with value (bar baz) in foo.sh, just as it
> would in a function, and e.g. `set -- ...' no longer affects the argv
> of the caller.

    Yes, I know, while I was trying combinations I noticed that,
thanks for pointing :)

> By the way, 'typeset -gx argv' has no effect whatsoever.  You cannot
> cause argv to change from local to global under any circumstances.

    Oops, that's true, but I swear that didn't work when I first
tested, obviously I made some mistake. Thanks :)

    So, how can I make a function to use the *global* argv and not
the local one? Can a function modify the global argv?

    Thanks a lot for your answer, Bart :)

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736 | http://www.dervishd.net
http://www.pleyades.net & http://www.gotesdelluna.net
It's my PC and I'll cry if I want to...


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Factoring out code
  2005-09-06 10:37   ` DervishD
@ 2005-09-06 14:58     ` Bart Schaefer
  2005-09-06 15:27       ` DervishD
  0 siblings, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2005-09-06 14:58 UTC (permalink / raw)
  To: Zsh Users

On Sep 6, 12:37pm, DervishD wrote:
}
}     So, how can I make a function to use the *global* argv and not
} the local one? Can a function modify the global argv?

You can't, and no.

The only thing you could do would be to establish a convention, such
as the one with reply/REPLY, and always remember to "set -- $reply"
after calling one of those functions.

If you don't like using eval on a variable that contains a code
fragment, how about using a set of aliases?  Each alias would "run
like [it] was cut ... and pasted into the file, just like a macro."
Your scripts would still end up looking more like the example with
multiple dot-commands, but you can put all the alias definitions
in one file.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Factoring out code
  2005-09-06 14:58     ` Bart Schaefer
@ 2005-09-06 15:27       ` DervishD
  0 siblings, 0 replies; 5+ messages in thread
From: DervishD @ 2005-09-06 15:27 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

    Hi Bart :)

 * Bart Schaefer <schaefer@brasslantern.com> dixit:
> On Sep 6, 12:37pm, DervishD wrote:
> }
> }     So, how can I make a function to use the *global* argv and not
> } the local one? Can a function modify the global argv?
> 
> You can't, and no.
> 
> The only thing you could do would be to establish a convention, such
> as the one with reply/REPLY, and always remember to "set -- $reply"
> after calling one of those functions.

    That's exactly what I was testing right now ;) But the aliases
solution is better for most of the commands, which are simple
oneliners. I need to do a bit more coding to see what things to put
in each alias.

> Your scripts would still end up looking more like the example with
> multiple dot-commands, but you can put all the alias definitions
> in one file.

    I'll do that way, thanks a lot Bart :))))

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736 | http://www.dervishd.net
http://www.pleyades.net & http://www.gotesdelluna.net
It's my PC and I'll cry if I want to...


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-09-06 15:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-09-05 11:42 Factoring out code DervishD
2005-09-05 20:08 ` Bart Schaefer
2005-09-06 10:37   ` DervishD
2005-09-06 14:58     ` Bart Schaefer
2005-09-06 15:27       ` DervishD

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).