NAME
Text::Starfish.pm and starfish - A Perl-based System for Text-Embedded Programming and Preprocessing
SYNOPSIS
starfish [ -o=outputfile ] [ -e=initialcode ] [ -replace ] [ -mode=mode ] file...
where files usually contain some Perl code, delimited by <?
and !>
.
DESCRIPTION
(The documentation is probably not up to date.)
Starfish is a system for Perl-based text-embedded programming and preprocessing relying on a unifying regular expression rewriting methodology. If you know Perl and php, you probably know the basic idea: embed Perl code inside the text, execute it is some way, and interleave the output with the text. Very similar projects exist and some of them are listed in "SEE ALSO". Starfish is, however, unique in several ways.
There are two files in this package: a module (Starfish.pm) and a small script (starfish) that relies on the module. The earlier name of this module was SLePerl (Something Like ePerl), but it was changed it to starfish
-- sounds better and easier to type. One option was `oyster,' but some people are thinking about using it for Perl beans, and there is a (yet another) Perl module for embedded Perl Text::Oyster
, so it was not used.
The idea with the `starfish
' name is: the Perl code is embedded into a text, so the text is equivalent to a shellfish containing pearls. A starfish comes by and eats the shellfish... Unlike a natural starfish, this starfish
is interested in pearls and does not normally touch most of the surrounding meat.
An important difference between starfish
and similar programs (e.g. php) is: the output does not necessarily replace the code, it follows the code by default.
To produce output to be inserted into the file, use variable $O
or function echo
.
EXAMPLES
A simple example
A simple example, after running starfish
on a file containing:
<? $O= "Hello world!" !>
we get the following output:
<? $O= "Hello world!" !>
#+
Hello world!
#-
The output will not change after running the script several times. The same effect is achieved with:
<? echo "Hello world! !>
The function echo simply appends its parameters to the special variable $O.
Some parameters can be changed, and they vary according to style, which depends on file extension. Since the code is not stable, they are not documented, but here is a list of some of them (possibly incorrect):
- code prefix and suffix (e.g., <? !> )
- output prefix and suffix (e.g., \n#+\n \n#-\n )
- code preparation (e.g., s/\\n(?:#+|%+\/\/+)/\\n/g )
HTML Examples
Example 1
If we have an HTML file, e.g., 7.html
with the following content:
<HEAD>
<BODY>
<!--<? $O="This code should be replaced by this." !>-->
</BODY>
then after running the command
starfish -replace -o=7out.html 7.html
the file 7out.html
will contain:
<HEAD>
<BODY>
This code should be replaced by this.
</BODY>
The same effect would be obtained with the following line:
<!--<? echo "This code should be replaced by this." !>-->
Output file permissions
The permissions of the output file will not be changed. But if it does not exist, then:
starfish -replace -o=7out.html -mode=0644 7.html
makes sure it has all-readable permission.
Example 2
Input file 21.html
:
<!--<? use CGI qw/:standard/;
echo comment('AUTOMATICALLY GENERATED - DO NOT EDIT');
!>-->
<HTML><HEAD>
<TITLE>Some title</TITLE>
</HEAD>
<BODY>
<!--<? echo "Put this." !>-->
</BODY>
</HTML>
Output:
<!-- AUTOMATICALLY GENERATED - DO NOT EDIT -->
<HTML><HEAD>
<TITLE>Some title</TITLE>
</HEAD>
<BODY>
Put this.
</BODY>
</HTML>
Example from a Makefile
LIST=first second third\
fourth fifth
<? echo join "\n", getmakefilelist $Star->{INFILE}, 'LIST' !>
#+
first
second
third
fourth
fifth
#-
Beside $O, $Star is another predefined variable: It refers to the Starfish object currently processing the text.
Example from a TeX file
% <? $Star->Style('TeX') !>
% For version 1 of a document
% <? #$Star->addHook("\n%Begin1","\n%End1",'s/\n%+/\n/g');
% #$Star->addHook("\n%Begin2","\n%End2",'s/\n%*/\n%/g');
% #For version 2
% $Star->addHook("\n%Begin1","\n%End1",'s/\n%*/\n%/g');
% $Star->addHook("\n%Begin2","\n%End2",'s/\n%+/\n/g');
% !>
%Begin1
%Document 1
%End1
%Begin2
Document 2
%End2
Example with Test/Release versions (Java)
Suppose you have a stanalone java file p.java, and you want to have two versions:
p_t.java -- for complete code with all kinds of testing code, and
p.java -- clean release version.
Solution:
Copy p.java to p_t.java and modify p_t.java to be like:
/** Some Java file. */
//<? $O = defined($Release) ?
// "public class p {\n" :
// "public class p_t {\n";
//!>//+
public class p_t {
//-
public static int main(String[] args) {
//<? $O = " ".(defined $Release ?
//qq[System.out.println("Test version");] :
//qq[System.out.println("Release version";]);
//!>//+
System.out.println("Release version";//-
return 0;
}
}
In Makefile, add lines for updating p_t.java, and generating p.java (readonly, so that you do not modify it accidentally):
p.java: p_t.java
starfish -o=$@ -e='$$Release=1' -mode=0400 $<
tmp.ind: p_t.java
starfish $<
touch tmp.ind
Macros
Starfish includes a set of macro features (primitive, but in progress). There are two modes, hidden macros and not hidden, which are indicated using variable $Star->{HideMacros}, e.g.:
starfish -e='$Star->{HideMacros}=1' *.sfish
starfish *.sfish
Macros are activated with:
<? $Star->defineMacros() !>
In Java mode, a macro can be defined in this way:
//m!define macro name
...
//m!end
After //m!end, a newline is mandatory. After running Starfish, the definition will disapear in this place and it will be appended as an auxdefine at the end of file.
In the following way, it can be defined and expanded in the same place:
//m!defe macro name
...
//m!end
A macro is expanded by:
//m!expand macro name
When macro is expanded it looks like this:
//m!expanded macro name
...
//m!end
Macro is expanded even in hidden mode by:
//m!fexpand macro name
and then it is expanded into:
//m!fexpanded macro name
...
//m!end
Hidden macros are put at the end of file in this way:
//auxdefine macro name
...
//endauxdefine
Old macro definition can be overriden by:
//m!newdefe macro name
...
//m!end
OPTIONS
- -o=outputfile
-
specifies an output file. By default, the input file is used as the output file.
- -e=initialcode
-
specifies the initial Perl code to be executed.
- -replace
-
will cause the embedded code to be replaced with the output. WARNING: Normally used only with -o.
- -mode=mode
-
specifies the mode for the output file. By default, the mode of the source file is used (the first one if more outputs are accumulated using -o). If an output file is specified, and the mode is specified, then
starfish
will set temporarily the u+w mode of the output file in order to write to that file, if needed.
PREDEFINED VARIABLES
$O
-
After executing a snippet, the contents of this variable are inserted into the file.
- $Star
-
The Starfish object processing this file (this).
- $Star->{INFILE}
-
Name of the current input file.
PREDEFINED FUNCTIONS
- appendfile filename, list
-
appends list elements to the file.
- echo
-
appends stuff to the special variable $O.
- file_modification_time
-
Returns modification time of this file (in format of Perl time).
- file_modification_date
-
Returns modification date of this file (in format: Month DD, YYYY).
- getfile file
-
grabs the content of the file into a string or a list.
- getmakefilelist makefile, var
-
returns a list, which is a list of words assigned to the variable var; e.g.,
FILE_LIST=file1 file2 file3\ file4 <? echo join "\n", getmakefilelist $Star->{INFILE}, 'FILE_LIST' !>
Embedded variables are not handled.
- htmlquote string
-
The following definition is taken from the CIPP project (http://aspn.activestate.com/ASPN/CodeDoc/CIPP/CIPP/Manual.html):
This command quotes the content of a variable, so that it can be used inside a HTML option or <TEXTAREA> block without the danger of syntax clashes. The following conversions are done in this order:
& => & < => < " => "
- putfile filename, list
-
opens file, writes the list elements to the file, and closes it. `
putfile
filename' "touches" the file. - read_records string
-
The function takes one string argument. If it starts with 'file=' then the rest of the string is treated as a file name, which contents replaces the string in further processing. The string is translated into a list of records (hashes) and a reference to the list is returned. The records are separated by empty line, and in each line an attribute and its value are separated by the first colon (:). A line can be continued using backslash (\) at the end of line, or by starting the next line with a space or tab. Ending a line with \ effectively removes the "\\\n" string at the end of line, but "\n[ \t]" combination is replaced with "\n". Comments, starting with the hash sign (#) are allowed between records. An example is:
id:1 name: J. Public phone: 000-111 id:2 etc.
If an attribute is repeated, it will be renamed to an attribute of the form att-1, att-2, etc.
- read_starfish_conf
-
Reads recursively (up the dir tree) configuration files
starfish.conf
.
LIMITATIONS AND BUGS
The script swallows the whole input file at once, so it may not work on small-memory machines and with huge files.
THANKS
I'd like to thank Steve Yeago for comments.
AUTHOR
Copyright 2001-2005 Vlado Keselj www.cs.dal.ca/~vlado
This script is provided "as is" without expressed or implied warranty. This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The latest version can be found at http://www.cs.dal.ca/~vlado/srcperl/.
SEE ALSO
There are many similar projects to this. When I was thinking whether I should start this project to use an existing one, I found only ePerl at http://www.engelschall.com/sw/eperl/. However, that was the whole new binary package and it was/is the overkill for my purposes. I learned later about the others, and I am including a list below:
- ePerl
-
This script is somewhat similar to ePerl, about which you can read at http://www.engelschall.com/sw/eperl/. Actually, if you go to this site, and follow the link "Related,", you will see that there are a whole bunch of similar projects.
- Text::Template
-
Text::Template is module with very similar, if not exactly the same purpose. I took a closer look on it on Jun 9, 2003, and was amazed with how many similar ideas I found. For example, the output variable is called $OUT, while it is called $O in Starfish.
- php
-
http://www.php.net