Gambas Scripting
Introduction
The Gambas Scripter is a text based front end for the Gambas interpreter.
The applications/Scripts are simple text files editable by any Linux editor.
These scripts are an excellent way to write scripts where BASH does not provide the complex data types and data
handling required by the programmer. Gambas script's mime type are recognized by the OS in the same way BASH or DASH scripts are recognized.
Scripter is well integrated into the Linux shell environment with env[<env variable>] giving direct access to the shell environment variables.
Scripter does not require the complex interface provided by the full Gambas IDE. In fact, the IDE is not required at all to use Gambas scripts.
Scripter is an excellent alternative to BASH for implementing complex system management procedures quickly.
Bringing the full breadth of a well implemented programming language to the programmer.
This allows scripts to use graphic and text base interfaces.
Gambas scripts are optimized as they are compiled, and the compiled script is cached and recompiled only if the script is changed.
This vastly improves system performance and response when running Gambas scripts.
Scripter can also be used to compile and execute the more traditional Gambas project.
Since 3.16
Scripter may also be used as a component to a Gambas Application allowing the application to dynamically load or
create text based scripts which can be directly loaded and executed by the application. The loaded script will have access
to the applications classes and public class variables.
Note:
Throughout this document Scripter and gbs3 are used interchangeably.
The actual Linux executable is gbs3
Scripter - How it works
The Scripter(gbs3) works by:
creating a temporary project from your script,
compiling it,
and running it.
Since 3.16
The Gambas Scripter gbs3 can also directly execute a project without the use of the IDE.
The compiled project is cached so that it is executed immediately if you run the project again.
The Scripter can also be used to generate a component which can be loaded and used at runtime.
Example: directly execute a script file
> gbs3 ~/myscripts/script1.gbs
> ./script1.gbs
Since 3.16
Example: directly execute a project
> gbs3 ~/myprojects/project1
Creating a Script
To create a Gambas script file, make it executable and write this preamble at the beginning:
The Scripter can execute free-form programs with ease.
To achieve this, Scripter will collect your free-form commands into a Main() subroutine automatically
while maintaining the integrity of subroutines/structures/class separately.
sub PrintBye()
print "Bye"
end
dim sHello as string = "Hello"
Print sHello
PrintBye()
The Gambas script can also be written like a module in a common Gambas project,
the interpreter automatically executes a Main() subroutine when included in the script.
TIP: Scripts execute more quickly if your code includes a Sub Main() subroutine rather
than using the free-form method of writing a script.
This is due to the Scripter not having to collect the free-form code and create a Main() subroutine.
Since 3.17
A script will return the script name from application.name
rather than the temporary file name created when compiling the script.
#!/usr/bin/env gbs3
Public Sub Main()
DoPrintHello()
End
Private Sub DoPrintHello()
Print "Hello"
End
The code can be organized with private and public subs and functions, and
constants and variables just like in Gambas modules inside Gambas projects.
Installing Scripter - gbs3
Scripter is not installed by default when the IDE is installed onto your system. It must explicitly be installed before it is available.
It needs to be installed through your distributions package manager.
For example on Mint/Ubuntu the following command could be used
sudo apt install gambas3-gb-scripter
See your distribution package manager for specifics.
To use Scripter it is not required to have the Gambas3 IDE installed.
Scripter can be installed standalone. When installed Scripter will cause the gambas-devel package
containing the compiler linker and archiver to be installed and also the gb.pcre component
if they are not already present on the system.
When installed standalone, the user will be required to individually install any components needed by executed scripts.
Defining Classes and Structures within a Gambas script
Unlike a Gambas project, Scripts support Classes and Structures in a script-specific way.
Classes are defined inline within your script code, structures must be public and defined before any reference to them in the script.
Defining a class inline
To define a class the following format is used:
Public oMyClass as new MyClass
class MyClass
sub sub1()
print "hello"
end
end class
A Class's data and functions are defined in the same way as in the IDE except you must add the Class and End Class statement.
Notice that the class does not have to be defined before it is used.
Defining a structure inline
Structures, which are a special case of class, must be defined before any reference to that structure.
All structures must be declared as Public and are Global.
Examples of defining Structures
#!/usr/bin/env gbs3
Public sMyVar1 as string
Public oMystruct as new MyStruct
Public Struct MyStruct
sText as string
end struct
oMystruct.sText = "hello"
The above example will fail!
The correct method is
#!/usr/bin/env gbs3
Public sMyVar1 as string
public struct MyStruct
sText as string
end struct
Public oMystruct as new MyStruct
oMystruct.sText = "hello"
Executing a Gambas script
There are two ways to execute a Gambas script
You may create a non-executable file as in the example below.
From a file named MyScript.gbs containing:
Public Sub Main()
DoPrintHello()
End
Private Sub DoPrintHello()
Print "Hello"
End
This may be executed with:
An alternative to this, and most commonly used, is to provide the command inside the file and make it executable.
From the file myscript.gbs containing the following:
#!/usr/bin/env gbs3
Public Sub Main()
DoPrintHello()
End
Private Sub DoPrintHello()
Print "Hello"
End
If the file is made executable with
Then it can be executed with the simple command:
from the current directory. If we want to make this a command for general personal use
it can be copied to:
or for more general use to:
Passing Arguments To The Script
There is an ARGS[] array which contains arguments passed by command line.
#!/usr/bin/env gbs3
Dim arg as String
Dim i as Integer
for each arg in ARGS
Print "Argument Nr. " & i & " = " & arg
Inc i
next
See that position 0 of ARGS is used by Gambas itself, it contains the path to the cached compiled project:
$ ./test.gbs ding dong
Argument Nr. 0 = /tmp/gambas.1000/script-cache/b1826db433d3855de7e021ca9ad34b87/test.gbs
New for 3.15.3 Arg 0 now reports the name of the script correctly as test.gbs
Argument Nr. 1 = ding
Argument Nr. 2 = dong
Note: It is possible to get the name of your original script using file.name(args[0])
Using Scripter gbs3 as a component in your project
Since 3.16
It is possible to use Scripter gbs3 as a component in your project.
Scripter provides three interfaces:
The first is for dynamically loading plugins and is defined as follows:
'' This allows integration of scripter into an application that uses plugins
'' the call would be ScripterPlugin(MyScript,"-b -c etc these are other parameters")
'' This returns the instantiated class of the plugin script
ScripterPlugin(ScriptPath As String, Optional CompileParameters As String[] = [],
PluginNewParameters As Variant[] = Null) As Variant
ScripterPlugin.fromString(ScriptName As String,ScriptText as string,
Optional CompileParameters As String[] = [],
PluginNewParameters As Variant[] = Null) As Variant
ScripterPlugin.SetVerbose() 'Turns on verbose information
The second allows the execution of a script from text and return its output
ScripterExecute(ScriptName as string,ScriptText As String,
Optional CompileParameters As String[] = [],
PluginNewParameters As Variant[]) as variant
and the third is for executing a script directly returning the exit code and is defined as follows:
'' execute a script and return the exit code
'' aArgs[0] being the script name
Scriptmain.ScripterMain(aArgs As String[]) As Integer
When plugin Compile Fails using ScripterPlugin/ScripterExecute
Since 3.16
When a plugin load fails the result returned will be null
the return code from the compiler is available from the class static
variables :
ScripterPlugin error access:
Static Public CompileResult As Integer = 0 '' Result return by the gambas compiler
Static Public CompileErrorText As String = "" '' will contain the list of errors found
ScripterPlugin.CompileErrorText
ScripterPlugin.CompileResult
ScripterExecute error access:
Static Public $sLastError As String = ""
ScripterExecute.$sLastError
Loading the gbs3 component
Since 3.16
To include gbs3 as a component in your application the following code is required
dim Scripter,ScriptMain,ScriptExecute as object
component.load(system.find("gbs3"))
Scripter = class.load("ScripterPlugin").new()
ScriptExecute = class.load("ScripterExecute").new()
Scriptmain = class.load("ScriptMain").new()
once this is done it is just a matter of calling the interface
dim myplugin1 as object = Scripter("~/myplugins/MyPlugin1")
myPlugin1()
dim myplugin2 as object = Scripter.fromString("MyClass","print \"Hello World\"")
myPlugin2()
or to execute a text script and get the output
dim result as variant
result = ScriptExecute("MyClass2","Print \"hello world\"\nPrint \"This is also returned\"")
or to execute a script by passing the command line parameters returning the exit code for example:
dim result as integer
result = ScriptMain.ScripterMain(["-v","-f","~/myscripts/MyScript1.gbs","Script parm1","Parm2"])
Creating Plugins using Scripter --plugin
Since 3.16
Scripter can create plugins that can be used by other scripts or Gambas applications after being built using the
--plugin or -p option. The term plugin is synonymous with the term component throughout this document.
Plugins are created in a user-selected directory and are also executed from and cached in this
directory, unlike a normal script, in which executables are created in the temp directory and are executed from
there. This allows plugins to persist after the Scripter exits.
When a plugin script is cached it will not be recompiled Scripter will return with no error.
If no output destination is specified, then the plugin is created in the:
~/.local/lib/gambas directory.
Plugins may be loaded from there using the component.load() function.
Scripts being used as plugins are generated with the entry point defined as
with a class of the same name as the base name of the script
_Call(...) as variant
by default.
A Scripter generated plugin source may look like this for a plugin script
from:
to:
Class MyPlugin1
public sub _Call(...) as variant
print "hello"
end
end class
So inside your script the parameters are accessed using the param gambas class.
It is also possible to define the entry point yourself with fixed parameters.
_Call(counter as integer) as integer
from:
public sub _Call(count as integer) as integer
print count
end
to:
class MyPlugin1
public sub _Call(count as integer) as integer
print count
end
end class
Example: Building an App that uses plugins
Since 3.16
Define some simple plugins/components for testing
~/myscripts/MyPlugin1.gbs:
print "The Parameter was",param[0]
return "This was done"
~/myscripts/MyPlugin2.gbs:
print "Number of parameters passed=",param.count
return "So was this"
~/myscripts/MyPlugin3.gbs:
public sub _Call(counter as integer) as integer
for i as integer = 0 to counter
print i;
next
return i
end
Execute gbs3 to create a component plugin.
> gbs3 --plugin ~/myscripts/MyPlugin1.gbs ~/myplugins
> gbs3 --plugin ~/myscripts/MyPlugin2.gbs ~/myplugins
> gbs3 --plugin ~/myscripts/MyPlugin3.gbs ~/myplugins
Now in the script that requires the plugin, they can be loaded as in the following script:
#!/usr/bin/env gbs3
dim MyPlugin1,MyPlugin2,MyPlugin3 as object
' Make sure we have the latest version, assume all compiles are perfect..
exec ["gbs3","--plugin","~/myscripts/MyPlugin1.gbs","~/myplugins"] 'if already in cache and no change then just returns
exec ["gbs3","--plugin","~/myscripts/MyPlugin2.gbs","~/myplugins"]
exec ["gbs3","--plugin","~/myscripts/MyPlugin3.gbs","~/myplugins"]
' Load the plugins
component.load(User.home &/ "/myplugins/MyPlugin1")
MyPlugin1 = class.load("MyPlugin1").new()
component.load(User.home &/ "/myplugins/MyPlugin2")
MyPlugin2 = class.load("MyPlugin2").new()
component.load(User.home &/ "/myplugins/MyPlugin3")
MyPlugin3 = class.load("MyPlugin3").new()
' Now lets access and call the plugin
print MyPlugin1("some parameter")
print MyPlugin2("one","two","three")
print MyPlugin3(100)
This ability is most useful in an application which creates the script on the fly and then incorporates it
into the application with access to all application classes.
#!/usr/bin/env gbs3
dim thenewone as object
file.save("~/myscripts/thenewone","For i as integer = 0 to 100\nprint i;;\nnext\nprint classes.count")
exec ["gbs3","--plugin","~/myscripts/thenewone","~/myplugins"]
component.load(User.home &/ "/myplugins/thenewone")
thenewone = class.load("thenewone").new()
thenewone()
Example: Combining gbs3 as a component and using script based plugins
Since 3.16
Now in this example if we combine using gbs3 as a component and using plugins we have the following:
#!/usr/bin/env -S gbs3 -a
dim MyPlugin1,MyPlugin2,MyPlugin3,thenewone as object
dim Scripter as object
component.load(system.find("gbs3"))
Scripter = class.load("ScripterPlugin").new()
MyPlugin1 = Scripter("~/myscripts/MyPlugin1.gbs")
MyPlugin2 = Scripter("~/myscripts/MyPlugin2.gbs")
MyPlugin3 = Scripter("~/myscripts/MyPlugin3.gbs")
TheNewOne = Scripter.fromString("TheNewOne","For i as integer = 0 to 100\nprint i;;\nnext\nreturn classes.count")
' Now lets access and call the plugins
print MyPlugin1("some parameter")
print MyPlugin2("one","two","three")
print MyPlugin3(100)
print thenewone()
Filtering Script Text for plugins
Since 3.16
When using loading or generating script based plugins within an application it is possible to filter the text
in the script in order to restrict access to classes or functions in that script.
This can be accomplished by creating a filter table and passing it to the Scripter class.
The filter table is a collection that is defined as follows:
dim filter as collection = [ "Error message 1":"regular expression to match as error check",
"Error message 2": "regular expression 2",
.... etc ]
Each entry in the table defines and error set and the regular expression that would cause that error.
So to prevent some action or access in a script it may have defined:
dim filter as collection = ["Print statement not allowed":"(?:^|\\W)print(?:$|\\W)", ' yes this is a very simple example no printing!
"Write statement not allowed":"(?:^|\\W)write(?:$|\\W)", ' don't allow a write
"Access forbidden classes":"^.* classes[ .]"] ' prevent accessing the classes[]
This filter may be activated by calling:
ScriptSetKeywordFilter(filter)
Scripter will print the error text and line number within the script and then halt the building of the plugin.
Components and Libraries - use
Gambas Components and Libraries can be used with the command
USE
Including Other Gambas Script Files - #include
The Include keyword has been replaced with #Include preprocessor keyword
Since 3.16
For backwards compatibility Include will continue to be support until the next release.
Programmers should convert all code to use #Include before that release.
Other Gambas script files can be included with the command
INCLUDE or #INCLUDE
Using the Gambas Jit feature with scripts
It is possible to Compile and execute your scripts more quickly in some cases
using the Gambas Just in Time Compiler feature.
These featured may be enabled with the:
-f fast option - use the jit
and
-u Unsafe option - remove any validation checks from code.
There are Three ways to invoke this with a script the first is from the command line
Or as part of the #! in your script:
#!/usr/bin/env -S gbs3 -f -u
Public Sub Main()
DoPrintHello()
End
Private Sub DoPrintHello()
Print "Hello"
End
Or simply at the beginning of your script:
#!/usr/bin/env gbs3
Fast Unsafe
Public Sub Main()
DoPrintHello()
End
Private Sub DoPrintHello()
Print "Hello"
End
Script Naming Convention
By convention gambas scripts will have the .gbs extension, but this is not a requirement
your script may be named anything with almost any extension or no extention at all.
The script is actually recognized by the shell at execution time by the:
as the first line of your script.
Using Command Line Scripts with -e option
It is possible to execute a quick Gambas3 script from the command line with the format:
gbs3 -e "dim i as integer:for i = 0 to 100 : print i: next"
Note that it is possible to have multiple statements separated by the : character.
gbs3 -e 'dim b as collection = ["a":"b"]:dim i as integer:for i = 0 to 100 : print i: next'
If you need to pass a string from command line then you will need to use ' not " to surround the program.
In bash and sh etc. the command line script should be encased in ".." or '..'
Using Short form Variable declaration on command line
NOTE: This feature is no longer supported
Since 3.16
When writing a command line script it is possible to add a short hand for the definition of variables.
The above example could be rewritten as:
gbs3 -e -p "for {i}counter = 0 to 100 : print counter: next"
With the -p or preprocess option when any variable name is preceded by a {} and contains one of the following supported variable types.
"i": "Integer"
"s": "String"
"f": "Float"
"d": "Date"
"b": "Boolean"
"v": "Variant"
"o": "Object"
"l": "Long"
"p": "Pointer"
When this notation is used then gbs3 will generate the correct dim statement for the variable.
#Script keyword
Since 3.16
This keyword is used to add information to your script,
which will be used by Scripter to construct the Gambas project
from the inline source file.
The format of this keyword is
Currently the following keywords are supported
KeyWord
|
Description
|
Content
|
TYPE
|
type of project
|
Defaults to " " normal | can be Library, Component
|
VERSION
|
project version number
|
Defaults to "0.0.1"
|
DESCRIPTION
|
Description of the project
|
Any text
|
MAINTAINER
|
person maintaining app
|
name of person
|
AUTHOR or AUTHORS
|
Who Wrote This
|
Coma separated list
|
VENDOR
|
Vendor name
|
Defaults to "Ordinary"
|
LICENSE
|
Type of license
|
Defaults to "General Public License 2.0"
|
TITLE
|
Text of project title
|
Defaults to "Gambas Script"
|
NAME
|
Name of script
|
Defaults to Script file basename
|
STARTUP
|
defines the class/module to start.
Scripter uses this name to identify/create the default class or module.
When the script/Plugin executes this will be the class-_Call()/module-main() that is started.
|
Defaults to Scripts = "MMAIN", Plugins = BaseName(file name without extension)
|
HEADER
|
The first line of the generated project file
|
Defaults to "# Gambas Project File 3.0"
|
Converting a Script to a project with --convert-script
Since 3.16
Using the --convert-script parameter with gbs3 will allow the user to create a project directory from an existing script.
There are some limitations to this conversion. In general most gambas source file type are supported by the
script conversion. Form, Connection, WebPage, WebForm file formats are very Gambas specific, so be careful with these
file formats
The project is created in the specified directory and the directory has the same basename as the script file
Example
gbs3 --convert-script ~/myscripts/project1.gbs ~/myprojects
will take the script project1.gbs and create the project directory ~/myprojects/project1
Converting a project to a script with --convert-project
Since 3.16
Using the --convert-project parameter with gbs3 will allow the user to create a script file from an existing project.
There are some limitations to this conversion. In general most gambas source file type are supported by the
project conversion. Form, Connection, WebPage, WebForm file formats are very Gambas specific, so be careful with these
file formats.
The output script file is placed in the defined directory and is named the same as the project directory with the .gbs extension
Example
gbs3 --convert-project ~/myprojects/project1 ~/myscripts
will take as input the project1 directory and output a script ~/myscripts/project1.gbs
Supported source file types
Since 3.16
In General for use only Classes and main module are defined. in most cases the other supported types are
only used by the automated project to script conversions.
The following definitions are supported for script files
Class className
....
End Class
Module ModuleName
...
end Module
The following Types are experimental:
Form FormName
...
End Form
Connection ConnectionName
...
End Connection
WebForm FormName
...
End WebForm
End WebPage
Executing web forms and web apps from command line
Since 3.16
Web form and web app scripts me be launched using the following bash command line.
These are limited to simple display functions as scripts.
./TestWebApp.gbs > ~/webpage1.html && firefox ~/webpage1.html
./TestWebForm.gbs > ~/webpage1.html && firefox ~/webpage1.html
To Use a Web App correctly goto
Gambas Web App
Getting a list of components installed and available on your system with -l Component
Since 3.15
To get the list displayed on the console then execute Scripter with -l parameter
Getting a list of libraries installed and available on your system with -l Library
Since 3.15
To get the list display on the console then execute Scripter with -l Library
Scripter command line args
Since 3.16
Usage:
gbs3 [options][--] [<script file> | <project directory> | - ]
gbs3 --convert-project <input project directory> <output script directory>
gbs3 --convert-script <input script> <output project directory>
gbs3 --plugin <input script> [<output plugin cache directory>]
Options:
-b --buildonly process and compile the script without executing it
-c --nocache force the script compilation (do not check cache)
-e execute the source code provided by the command line (
:
separator )
-g --debug add debugging information to application
-f --fast use just-in-time compiler
-h --help display this help
-l --list Display the list of available
-l component
or
-l library
-L --license display license
-p --plugin Compile the script, no main, define the class name as script base name entry point _Call(...)
-S --strict fail if
Public
or
Sub
are defined without a
main
function
-t --trace turn on tracing option during execution
-T --terse-listing only print a very terse error report on compile errors
-u --use
force component loading (comp1,comp2...
)
-U --unsafe allows jit compiler to generate unsafe faster code
-v --verbose be verbose
-V --version display version
-w --warnings display warnings during compilation
--convert-project convert a simple project to a script
--convert-script convert a simple script to a project
-- stop any further option processing
- read the script from standard input
-b --buildonly
Since 3.16
Process and compile the script without executing it. This will also generate the cache version if
successfully compiled. So when the script is executed it directly executes the Gambas
executable previously generated for the script.
An application can execute Scripter with this option verify the compile completed without error
then execute the script with very little penalty in performance.
-c --nocache
Forces the script compilation (do not check cache)
-e
Execute the source code provided by the command line (
:
separator )
-g --debug
Add debugging information to the generated Gambas application executable
-f --fast, -U --unsafe
use just-in-time compiler, -U allows jit compiler to generate unsafe faster code
-S --strict
Since 3.16
Fail if
Public
or
Sub
are defined without a
main
for scripts or _Call for plugins
-T --terse-listing
Since 3.16
Only print a very terse error report on compile error. Normally the Scripter will
print a full listing of the offending file and mark the line and location of the error.
In this mode it will only display the offending line and mark the error location on the line.
-u --use
Force component loading (
comp1,comp2...
)
-v --verbose
Be Verbose. When enabled the Scripter prints information about the creation of the project and final
Executable file. It will also display a start of execution message with a start time stamp.
When the script ends execution it will display an end of execution message with an end time stamp.
It will then display the total execution time of the script.
-w --warnings
Display warnings during Script compilation and project build activities.
-l library
Display the list of libraries accessible by your script
-l component
Display the list of components accessible by your script