Managing Paths and Libraries

Fexl does not automatically install in /usr/bin. You simply download Fexl into your own local directory and use it from there. You are free to install it in /usr/bin if you like though.

For example, I have a Fexl installed in /home/patrick/project/fexl. Now let's say I wanted to write a script called "try_fexl" that I could run from a command line regardless of what directory I'm in. Because I have "~/bin" in my PATH environment variable, I can put the script there.

First I do this:

cd ~/bin
touch try_fexl
chmod +x try_fexl
vi try_fexl

Then I put this into the script:

#!/home/patrick/project/fexl/bin/fexl
use "/home/patrick/project/fexl/src/test/lib.fxl" \;

\show=(\list each list (\x put [x " "]) nl)

\list=(append ["f" "a" "c"] ["b" "d" "e"])
\list=(append list list)
\list=(append list list)

show list
show (sort list)

Now I can cd anywhere I like and run:

try_fexl
The output is:
f a c b d e f a c b d e f a c b d e f a c b d e 
a a a a b b b b c c c c d d d d e e e e f f f f 

Possible Objections

First, you may not like having to put the full path name of the Fexl program at the top of the script like this:

#!/home/patrick/project/fexl/bin/fexl

But that's always the case when you're using the "shebang" mechanism in shell: you must put the full path of the executable program. If you don't like that path name, you can put it somewhere else, such as /usr/bin. Then the script looks like this:

#!/usr/bin/fexl

One reason I don't put it in /usr/bin is that I like the flexibility of working with multiple versions. Another reason is that I don't really care where the fexl program is. I typically have a system in place, like a web site, where the specific path to the fexl program is hardcoded in exactly one place.

Second, you may not like having to use the full path to the "lib.fxl" environment:

use "/home/patrick/project/fexl/src/test/lib.fxl" \;

OK, but how else is Fexl supposed to know where the library is? I did not build a complicated library search path feature into the Fexl code because there are better ways of managing that in Fexl itself. In my own applications I typically have library paths isolated in a single place, and I discuss how to do that below. It's really cool.

I should also point out that "test/lib.fxl" is really only part of the test suite. However, it is good code so it's understandable that you'd want to use it directly. In my own applications I typically copy those definitions somewhere else instead of referring to them directly in the Fexl test suite. Of course, I still have to specify the full path to the library no matter where I put it.

A General Fexl Script

I've just given an example "try_fexl" which runs a specific Fexl function regardless of my current directory. But what if I wanted a general purpose "fexl" where I could specify the name of a script to run?

First I do this:

cd ~/bin
touch fexl
chmod +x fexl
vi fexl

Then I put this into the script:

exec ~/project/fexl/bin/fexl "$@"

Now from any directory I can run "fexl" on any script. For example:

cd somewhere
fexl do_stuff.fxl

Or I can run fexl with no script name and I can type in a program, terminated with Ctrl-D:

fexl
\x=49
say [x " squared is " (* x x)]
^D

Possible Objection

You might wonder why I made ~/bin/fexl as a script instead of simply copying the ~/project/fexl/bin/fexl executable right into ~/bin. I do it as a script so that (argv 0) is set to the full path of the executable. For example:

echo "say (argv 0)" | fexl
/home/patrick/project/fexl/bin/fexl

If instead I had simply copied the executable into ~/bin, I would see this:

echo "say (argv 0)" | fexl
fexl

That's not very helpful. The full path could come in handy, for example if I wanted to locate auxiliary library files relative to the full path of the executable.

A General Fexl Script with a Totally Custom Environment

OK so now you want everything to be so easy you don't have to think about it. In fact, not only do you hate having to use the full library path "/home/patrick/project/fexl/src/test/lib.fxl", you hate even having to do the "use" at all at the top of every script you write! You want all the library functions that come with Fexl, and even more library functions that you write yourself, to be available automatically in every Fexl script you write, run from any directory, without having to do a "use" at all!

Are you asking too much? Not at all. What you want is totally do-able.

Go into your ~/bin/fexl script, and instead of this:

exec ~/project/fexl/bin/fexl "$@"

Put this (except with your own user name instead of "patrick"):

#!/home/patrick/project/fexl/bin/fexl
use "/home/patrick/project/fexl/src/test/lib.fxl" \;

\script=(check (argv 2) "")

\context=
(
\fred=(later; say "I am Fred.")
\wilma=(later; say "I am Wilma.")

export;
def "fred" fred;
def "wilma" wilma;
void
)

\fun=(parse_file script context)
fun

Now you're done haranguing around with library paths, or even having to drag in the library at all! Not only that, you've just defined two new built-in functions fred and wilma which are available everywhere you go!

To test this, I went into my own ~/tmp directory and created a "hello.fxl" file with this code in it:

say "Hello."
fred wilma
nl

(@\loop\n
\x=(argv n)
is_void x ();
say ["argv " n " = " x]
\n=(+ n 1)
loop n
) 0
nl

\show=(\list each list (\x put [x " "]) nl)

\list=(append ["f" "a" "c"] ["b" "d" "e"])
\list=(append list list)
\list=(append list list)

show list
show (sort list)
nl

Now I can run that script from anywhere, for example:

cd
fexl tmp/hello.fxl

Here's the output:

Hello.
I am Fred.
I am Wilma.

argv 0 = /home/patrick/project/fexl/bin/fexl
argv 1 = /home/patrick/bin/fexl
argv 2 = tmp/hello.fxl

f a c b d e f a c b d e f a c b d e f a c b d e 
a a a a b b b b c c c c d d d d e e e e f f f f 

As you can see, using Fexl itself to configure your own specialized Fexl environments is a very powerful technique, and extraordinarily flexible.

See Also

Guide to Control Structures