First version of documentation

gh-pages
Hauke D 7 years ago
parent bf56a58135
commit 4e2cddc82e

@ -0,0 +1,36 @@
#!/usr/bin/env perl
use warnings;
use strict;
use open qw/:std :utf8/;
use FindBin ();
# Generate a preview of the site using `markdown`
# (I use this mostly just to check for any Markdown syntax mistakes)
#TODO Later: Use a markdown processor that handles GitHub's markdown enhancements?
my $dir = $FindBin::Bin.'/..';
opendir my $dh, $dir or die $!;
my @files = grep { ! -d } map { "$dir/$_" } sort grep {/\.md\z/i} readdir $dh;
close $dh;
print <<'ENDHTML';
<!doctype html>
<html lang="en-us">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebPerl Site Preview</title>
</head>
<body>
ENDHTML
print "<hr/>\n";
for my $f (@files) {
system('markdown',$f)==0
or die "markdown failed, \$?=$?";
print "<hr/>\n";
}
print <<'ENDHTML';
</body>
</html>
ENDHTML

@ -9,7 +9,145 @@ Building -
===================
Nothing here just yet - come back soon!
Prerequisites
-------------
- Linux, a fairly modern release is strongly recommended, and `bash`
(tested on a minimum of Ubuntu 16.04)
- `git` (e.g. Ubuntu/Debian: `sudo apt-get install git-core`)
- Build tools for `perl`; for example on Ubuntu:
`sudo apt-get install build-essential` and `sudo apt-get build-dep perl`
- Perl, at least v5.26 (for example via [Perlbrew](http://perlbrew.pl/))
- [Emscripten](http://emscripten.org) SDK, 1.38.10 and up,
please see the prerequisites and installation instructions at
<http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#installation-instructions>
- The build script has several CPAN dependencies. One way to install them
is using [lazy](https://metacpan.org/pod/lazy): first,
install "lazy", then run e.g. `perl -Mlazy build.pl --help`.
Otherwise, the modules used by `build.pl` can be seen in
[its source](https://github.com/haukex/webperl/blob/master/build/build.pl)
grouped near the top of the file.
- A working Internet connection is needed for installation and the first build.
Source Code
-----------
The source code is in two repositories:
- <https://github.com/haukex/webperl> - the main WebPerl repository
- <https://github.com/haukex/emperl5> - a fork of the Perl 5 source
repository where the WebPerl-specific patches are applied
You only need to check out the first of the two, the `emperl5` repository
is checked out by the build script.
Running the Build
-----------------
1. Fetch the source code.
$ git clone https://github.com/haukex/webperl.git
$ cd webperl
2. Install the [prerequisites](#Prerequisites).
3. Edit the configuration file, `./build/emperl_config.sh`, to fit
your system. For a first build, just make sure the path to
`emsdk_env.sh` is correct.
4. Source the configuration file to set the environment variables.
Remember to do this anytime you change variables. You may also
add the sourcing of the configuration file to your `~/.bashrc`.
$ . ./build/emperl_config.sh
5. Run the build script:
$ build/build.pl
6. If the build succeeds, the output files `emperl.*` will be
copied to the `web` directory of the repository. You can
then use the files in the `web` directory as described in
[Using WebPerl](using.html).
Build Process Overview
----------------------
The build script `build.pl` tries to take care of as much of the build process as
possible. Most of the work happens in a subdirectory `work` of the repository.
Similar to `make`, it tries to not run build steps that don't need to be rerun.
> A brief note on naming:
>
> - *`emperl`* is generally used for the build products of Emscripten
> - *`emperl5`* is the Perl 5 source tree modified for WebPerl
> - *WebPerl* is the finished product, including `emperl`
> and the WebPerl APIs (`WebPerl.pm` and `webperl.js`)
The steps in the build process are roughly as follows.
Since WebPerl is still in beta, they are subject to change.
See
[the source of the `build.pl` script](https://github.com/haukex/webperl/blob/master/build/build.pl)
for the current details.
1. Patch Emscripten
(currently just a minor patch, but important for Perl)
2. Fetch/update the `emperl5` Perl source tree
3. If necessary, build "host Perl" - in Perl's cross-compilation system,
this is the Perl that is built for the host system architecture,
i.e. in the case of Linux, a normal build of Perl for Linux. The
`miniperl` from the host Perl will be used for some of the build
steps for the target architecture.
(Note: This step can take quite a while, but it usually only needs
to be run once.)
4. Download and extract any CPAN modules, such as the required `Cpanel::JSON::XS`,
into the Perl source tree so that they will be built as part of the normal
build process and any XS extensions linked statically into the `perl` binary.
(See ["Adding CPAN Modules"](#adding-cpan-modules))
5. Run Perl's `Configure` script using the custom "hints" file for the Emscripten
architecture.
6. Run `make` to compile `perl`. This produces a file `perl.bc` with LLVM IR
bitcode, which the Emscripten compiler will then compile to JavaScript/WebAssembly.
Because some steps in the build process require a working `perl` binary,
Emscripten's compiler is used together with a supporting JavaScript file to
generate JavaScript code that can be run with `node.js` (called `nodeperl_dev.js`).
8. Run the equivalent of `make install`, which copies all the Perl modules
etc. into the target directory that will become part of the Emscripten
virtual file system. Then, we clean this directory up by deleting anything
that we don't need for WebPerl: additional binaries (it's a single-process
environment), `*.pod` files, as well as stripping the POD out of `*.pm`
files, etc. to reduce the download size.
9. The Emscripten compiler is used to take the previously compiled `perl.bc`
and build the final output, `emperl.js` along with the corresponding
`.wasm` and `.data` file.
Adding CPAN Modules
-------------------
In the configuration file `emperl_config.sh`, the variable `EMPERL_EXTENSIONS`
is a whitespace-separated list of module names. `build.pl` will fetch these
from CPAN and extract them into the `ext` directory of the Perl source tree
so that they are compiled along with Perl. Any XS modules that need to be
linked into `perl` need to be added to the variable `EMPERL_STATIC_EXT` in
the format expected by Perl's `static_ext` configuration variable,
so for example `Cpanel/JSON/XS` instead of `Cpanel::JSON::XS`
(see <http://perl5.git.perl.org/perl.git/blob/HEAD:/Porting/Glossary>).
Note that the build script does **not** automatically fetch modules'
dependencies, for now you will need to resolve them and add them to
`EMPERL_EXTENSIONS` yourself. (This may be improved upon in the future.)
***
@ -17,3 +155,11 @@ Nothing here just yet - come back soon!
Additional notes on building WebPerl may be found in the
[GitHub Wiki](https://github.com/haukex/webperl/wiki/Building-WebPerl).
***
Copyright (c) 2018 Hauke Daempfling (haukex@zero-g.net)
at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB),
Berlin, Germany, <http://www.igb-berlin.de>
Please see the ["Legal" page](legal.html) for details.

@ -10,23 +10,61 @@
WebPerl uses the power of [WebAssembly](https://webassembly.org/) and
[emscripten](http://emscripten.org/) to let you run Perl 5 in the browser!
[Emscripten](http://emscripten.org/) to let you run Perl 5 in the browser!
**Notice: WebPerl is in beta.**
**Notice: WebPerl is very much in beta.**
Some things may not work yet, and parts of the API may still change.
Your feedback is always appreciated!
```html
<script src="webperl.js"></script>
<script type="text/perl">
use WebPerl qw/js/;
print "Hello, Perl World!\n";
print "Hello, Perl World!\n"; # goes to JavaScript console by default
js('document')->getElementById('my_button')
->addEventListener("click", sub {
print "You clicked 'Testing!'\n";
->addEventListener('click', sub {
js('window')->alert("You clicked the button!");
} );
</script>
```
- [**Download `webperl_prebuilt_v0.01-beta.zip`**](https://github.com/haukex/webperl/releases/download/v0.01-beta/webperl_prebuilt_v0.01-beta.zip)
- [**Get the sources on GitHub**](https://github.com/haukex/webperl)
Quick Start
-----------
- Prerequisites: `perl` (a recent version is recommended, e.g. v5.26 and up),
[`plackup` from Plack](https://metacpan.org/pod/distribution/Plack/script/plackup),
and [Cpanel::JSON::XS](https://metacpan.org/pod/Cpanel::JSON::XS).
- In a shell:
$ wget https://github.com/haukex/webperl/releases/download/v0.01-beta/webperl_prebuilt_v0.01-beta.zip
$ unzip webperl_prebuilt_v0.01-beta.zip
$ cd webperl_prebuilt_v0.01-beta
$ plackup webperl.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/
- Then point your browser at
<http://localhost:5000/webperl_demo.html> or
<http://localhost:5000/mini_ide/webperl_mini_ide.html>
You may also host the contents of the above ZIP archive on a webserver of your choice,
as described in [Using WebPerl](using.html). (Note: In `webperl_demo.html`, you'll
likely see "AJAX Failed!", which is to be expected since your webserver won't
know how to handle the example AJAX request.)
Have fun! ️🐪
***
Copyright (c) 2018 Hauke Daempfling (haukex@zero-g.net)
at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB),
Berlin, Germany, <http://www.igb-berlin.de>
Please see the ["Legal" page](legal.html) for details.

@ -9,12 +9,14 @@ Notes -
=========================
TODOs
-----
To-Dos
------
- <https://github.com/haukex/webperl/blob/master/ToDo.md>
- <https://github.com/haukex/webperl/issues>
- <https://github.com/haukex/webperl/pulls>
- See also To-Dos in the source tree by grepping for `TODO`
or using the included `findtodo.sh`.
Possible Improvements
@ -24,7 +26,9 @@ Possible Improvements
- Test/Support sockets/WebSockets
- for example, can we compile a DBD:: module to connect to a DB on the server?
- A RPC module for communicating between client and server Perls
- Support some of the Emscripten API (like wget?)
- I think it's probably best to not have WebPerl prescribe a specific RPC mechanism,
since there's a big variety and many are pretty simple to implement using e.g. jQuery
- Support some of the Emscripten C API (like wget?)
- Try to shrink the download size more (exclude more modules, ...?)
@ -39,8 +43,8 @@ Limitations
- (`system` and `qx` support could theoretically be added by patching `pp_system`/`pp_backtick` in `pp_sys.c`)
- No signals (except `SIGALRM`)
- In the current configuration, `exit` is not supported, and therefore `atexit` handlers aren't supported
(see discussion in `webperl.js`, and `NO_EXIT_RUNTIME` in the Emscripten documentation - currently it
seems to make the most sense to build with `NO_EXIT_RUNTIME=1`)
(see discussion in [Using WebPerl](using.html), and `NO_EXIT_RUNTIME` in the Emscripten documentation -
currently it seems to make the most sense to build with `NO_EXIT_RUNTIME=1`)
- Static linking, requires rebuild to add modules
(Emscripten apparently only supports asm.js dynamic linking when dynamic memory growth is disabled, which is not very useful)
@ -54,3 +58,12 @@ Several people have built microperl with Emscripten:
- Shlomi Fish <https://github.com/shlomif/perl5-for-JavaScript--take2>
- FUJI Goro <https://github.com/gfx/perl.js>
***
Copyright (c) 2018 Hauke Daempfling (haukex@zero-g.net)
at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB),
Berlin, Germany, <http://www.igb-berlin.de>
Please see the ["Legal" page](legal.html) for details.

@ -9,7 +9,385 @@
================
Nothing here just yet - come back soon!
Basic Usage
-----------
### Serving WebPerl
You should serve WebPerl via a webserver of your choice, or you can
use the included simple `webperl.psgi` for testing. You can run it using
[`plackup` from Plack](https://metacpan.org/pod/distribution/Plack/script/plackup)
by simply saying `plackup webperl.psgi`.
The following four files make up WebPerl:
- `webperl.js` - Contains the WebPerl JavaScript API and supporting code.
- `emperl.js` - Emscripten-generated supporting JavaScript.
- `emperl.wasm` - The `perl` binary and libraries compiled to WebAssembly.
- `emperl.data` - The Emscripten virtual file system data (`.pm` files etc.).
I strongly recommend you add a MIME type of `application/wasm` for `.wasm` files,
otherwise you may see warnings like
"wasm streaming compile failed: TypeError: Response has unsupported MIME type" and
"falling back to ArrayBuffer instantiation".
For example, in an Apache `.htaccess` file, you can say: `AddType application/wasm .wasm`
Note that opening the files locally (via `file://`) will likely not work
due to browsers' Same-Origin Policy.
See also the Emscripten deployment notes at
<http://kripken.github.io/emscripten-site/docs/compiling/Deploying-Pages.html>,
in particular I'd recommended using gzip encoding to serve the WebPerl files.
### Including Perl code in your HTML
In your HTML file, add the following (usually inside the `<head>` tags):
<script src="webperl.js"></script>
Then, you can add one or more `<script type="text/perl">` tags containing embedded Perl code,
or a single `<script type="text/perl" src="foo.pl"></script>` tag which loads a
Perl script from the server - but not both! The code from multiple
`<script type="text/perl">` tags will be concatenated and run as a single script.
If you use embedded `<script type="text/perl">` tags, then the function `js` from
`WebPerl.pm` will be imported automatically. If you want to customize the import
list, then add `use WebPerl ...;` as one of the first five lines of your Perl code
(to be exact, WebPerl will look for `/^\s*use\s+WebPerl(\s|;)/m`).
If you don't have any such script tags in the document, Perl won't be run
automatically, and you can control Perl in detail via the JavaScript `Perl`
object provided by [webperl.js](#webperl.js).
Note that unlike JavaScript, which is run immediately, WebPerl will always be loaded
and run asynchronously from the page load. If you use `<script type="text/perl">` tags,
these will always be run after the document is ready, and if you use the `Perl` object
as described below, you will have control over when Perl is initialized and run, but
it will still be asynchronous because files need to be fetched from the server.
The Perl Interpreter and its Environment
----------------------------------------
The `perl` compiled for WebPerl is mostly a standard build of Perl, except
for a few patches to make things compile properly, and the major differences
described here.
[Emscripten](http://emscripten.org/) provides emulation for a number of system
calls, most notably, it provides a virtual filesystem from which Perl can
load its modules, since of course JavaScript in the browser is a sandboxed
environment (no access to hardware, the local filesystem, etc.).
However, because Perl is the *only* Emscripten process running in the browser,
there are **several things that won't work** either because Emscripten doesn't
support them (yet) or because they are simply not possible in this
single-process environment:
- Running other programs via e.g. `system`, backticks (`qx`), piped `open`, etc.
- No `fork` or multithreading, no `kill`, `wait`, `waitpid`, etc.
- There is experimental support for pthreads, but this is not tested with WebPerl yet.
See also <http://kripken.github.io/emscripten-site/docs/porting/pthreads.html>.
- No signals (except `SIGALRM`)
Like many UI frameworks, scripting in the browser is usually **asynchronous and event-driven**.
In addition, in Emscripten it is currently not easy to run a program multiple times.
In order to better support these circumstances, WebPerl's C `main()` function has been
patched to *not* end the runtime. This means that once the main Perl script is run,
the interpreter is *not* shut down, meaning `END` blocks and global destruction are not run,
and instead control is passed back to the browser.
This way, you can write Perl in an event-driven manner: in your main code, you can register
callbacks as event handlers for events such as button clicks, network communication, etc., and
then control is passed back to the browser. When the events occur, your Perl callbacks will be run.
In order to allow for this mode of execution, WebPerl is built with Emscripten's
`NO_EXIT_RUNTIME` option enabled. When this option is enabled, `atexit` handlers are
not supported, and calls to `exit` will result in a warning. For this reason, WebPerl
is patched to not call `exit` when the exit code is zero. As a result of all this,
in your scripts, I strongly recommend you **don't use Perl's `exit;`/`exit(0);`**,
as it will not likely do what you want.
Remember that in the browser, the user may leave a page at any time, and there is little
a script can do to prevent this. Although it's possible to ask Perl to end early as follows,
I would still recommend that you **don't rely on `END` blocks or global destruction**.
If your program is doing things like saving files (e.g. via an asynchronous network request),
then you should provide some kind of feedback to your user to know that a process is still
going on, and possibly install your own "beforeunload" handler.
WebPerl includes a C function `int emperl_end_perl()` which will perform the normal
Perl interpreter shutdown (but as mentioned above, not call `exit` if the exit code is zero).
This function is accessible in several ways:
- From JavaScript, set `Perl.endAfterMain` before calling `Perl.init()`
(this enables a "hack" that calls `emperl_end_perl()` after `main()` returns)
- From JavaScript, call `Perl.end()`
- From Perl, call `WebPerl::end_perl()`
These options might be useful if you're porting an existing script to run in WebPerl.
(In addition, WebPerl currently registers an "beforeunload" handler that attempts to call
the "end" function, but since this will be happening as the page is being unloaded,
do *not* rely on this being able to do very much, or even being called at all!)
### Memory Management and Anonymous `sub`s
**Anonymous `sub`s passed from Perl to JavaScript must be explicitly freed**
**when you are done using them, or else this is a memory leak.**
Please read this section!
When JavaScript arrays, objects, and functions are passed to Perl, they are not
copied, instead they are given an ID and placed in a table so that when Perl
wants to access them, it only needs to remember the ID, and pass the ID and the
corresponding operation to JavaScript. In JavaScript, these objects are kept alive
because of the entry in the table. Once the object goes out of scope in Perl,
its `DESTROY` method lets JavaScript know that it can free that entry from the
table, so JavaScript is free to garbage collect it if there are no other references.
When Perl values are passed to JavaScript, they are generally copied, except
for anonymous `sub`s, where a mechanism similar to the above is used, and a reference
to the `sub`s is kept alive using a table in Perl. *However,* JavaScript has
no equivalent of the `DESTROY` method, which means that even if you are done
using a `sub` in JavaScript, Perl will not know when it can free the table
entry, unless you explicitly tell it to!
WebPerl provides two mechanisms for freeing `sub`s:
- `WebPerl::unregister()` (can be exported), which takes a single argument that is
a reference to an anonymous sub previously passed to JavaScript. If you
`use 5.028;` or `use feature 'current_sub';`, anonymous `sub`s can refer to
themselves using the special `__SUB__` identifier, so for example, you can say:
use 5.028;
js( sub {
print "I was called, now I am going away\n";
WebPerl::unregister(__SUB__);
} )->();
- `WebPerl::sub_once` aka `WebPerl::sub1` are wrappers for `sub`s that essentially
call the `sub` once and then immediately `unregister` it. The above example can be
written as:
use WebPerl qw/js sub1/;
js( sub1 { print "Single-use sub called\n"; } )->();
`unregister` is still useful for anonymous `sub`s that need to be called multiple
times before falling out of use.
Of course, it is often the case that anonymous `sub`s need to persist for the
entire run of a program (like for example click handlers for buttons), or that
you may only have a handful of anonymous `sub`s in your program overall.
In such cases, you probably don't need to `unregister` them. However, there are
cases where this is very important to keep in mind - for example anonymous
`sub`s generated via stringy `eval`s.
If you want to check how many anonymous `sub`s are registered, you can say
`print scalar(keys %WebPerl::CodeTable);` (*do not* modify this hash).
Note that the above only applies to *anonymous* `sub`s. `sub`s that exist
in Perl's symbol table will persist in Perl's memory anyway, and no table entry
is generated for them, because it is assumed you won't delete them from the
symbol table - so please don't do that. Also, don't rename or redefine `sub`s
after having passed them to JavaScript, as that will probably cause mysterious behvaior.
### Virtual File System
Emscripten provides a virtual file system that also provides a few "fake" files such
as `/home/web_user`, `/dev`, and others, so that it resembles a normal *NIX file system.
Perl's libraries (`*.pm`) are installed into this virtual file system at `/opt/perl`.
Note that because the `perl` binary is compiled to WebAssembly and XS libraries
statically linked into it, you won't find any `perl` binary or library files in the
virtual file system, or for that matter any other binaries, since this is a
single-process environment.
The virtual filesystem is reloaded every time WebPerl is reloaded, so any changes are lost!
The exception is the "`IDBFS`", which stores files in an `IndexedDB`, so they persist
in the browser's storage across sessions. WebPerl mounts an instance of this filesystem
at `/mnt/idb`. However, remember that users may clear this storage at any time as well,
so it is not really a permanent storage either.
Additional information may be found at:
- <http://kripken.github.io/emscripten-site/docs/porting/files/file_systems_overview.html>
- <http://kripken.github.io/emscripten-site/docs/api_reference/Filesystem-API.html>
- <http://kripken.github.io/emscripten-site/docs/api_reference/advanced-apis.html#advanced-file-system-api>
The "mini IDE" included with WebPerl includes some code to show possibilities
of getting and sending files from/to the user through the browser. You also have
the possibility of implementing an RPC mechanism to access local files, if you need to.
Note that WebPerl's build process strips any POD from the Perl libraries, to reduce download size.
webperl.js
----------
`webperl.js` provides a JavaScript object `Perl` that can be used to control
the Perl interpreter. Many properties of this object are intended for internal
use by WebPerl only, so please **only use the interface documented here**.
### Controlling Perl
As documented above, if your HTML file contains `<script type="text/perl">`
tags, these will be run automatically, so you should *not* use `Perl.init()`
and `Perl.start()` in this case.
#### `Perl.init(function)`
Initializes the Perl interpreter (asynchronously fetches the `emperl.*` files).
You should pass this function a callback function, which is to be called when
Perl is ready to be run - normally you would call `Perl.start()` from this callback.
#### `Perl.start(argv)`
Runs Perl with the given `argv` array. If `argv` is not provided, uses Emscripten's
`Module.arguments`, which currently defaults to `['--version']`.
#### `Perl.eval(code)`
Evaluates the given Perl code. Currently always returns a string.
#### `Perl.end()`
Ends the Perl interpreter. See the discussion under
["The Perl Interpreter and its Environment"](#the-perl-interpreter-and-its-environment)
for details.
### Options
#### `Perl.output`
Set this to a `function (str,chan) {...}` to handle Perl writing to `STDOUT` or `STDERR`.
`str` is the string to be written, which may consist of a single character, a whole
line, or multiple lines. `chan` will be either 1 for `STDOUT` or 2 for `STDERR`.
If you want to merge the two streams, you can simply ignore the `chan` argument.
Defaults to an implementation that line-buffers and logs via `console.log()`,
prefixing either `STDOUT` or `STDERR` depending on the channel.
See also `Perl.makeOutputTextarea`, which installs a different output handler.
#### `Perl.endAfterMain`
If set to `true` before calling `Perl.init()`, then WebPerl will automatically
end the Perl interpreter after it finishes running the main script. See the
discussion under
["The Perl Interpreter and its Environment"](#the-perl-interpreter-and-its-environment).
Defaults to `false`.
#### `Perl.trace`
Enable this option at any time to get additional trace-level output
to `console.debug()`. Defaults to `false`.
#### `Perl.stateChanged`
Set this to a `function (from,to) {...}` to handle state changes of the Perl interpreter.
Defaults to a simple implementation that logs via `console.debug()`.
### Utility Functions
#### `Perl.makeOutputTextarea(id)`
This function will create a new DOM `<textarea>` element, set up a `Perl.output`
handler that redirects Perl's output into the `<textarea>`, and return the
DOM element. You may optionally pass this function a string argument giving
a DOM ID. You will need to add the `<textarea>` to your DOM yourself
(see `webperl_demo.html` for an example).
WebPerl.pm
----------
`WebPerl.pm` provides the Perl side of the WebPerl API.
Its central function is `js()`, documented below.
It also provides the functions `unregister`, `sub_once`, and `sub1`
(the latter two are aliases for each other), which are documented
in ["Memory Management and Anonymous `sub`s"](#memory-management-and-anonymous-subs).
For convenience, it can also re-export `encode_json`, so you can
request it directly from `WebPerl` instead of needing to `use` another module.
All functions are exported only on request.
Note that WebPerl will also enable autoflush for `STDOUT`.
### `js()`
This function takes a single string argument consisting of JavaScript code to
run, uses JavaScript's `eval` to run it, and returns the result, as follows.
You may also pass an arrayref, hashref, or coderef, and this data structure
will be passed to JavaScript, and a corresponding `WebPerl::JSObject` returned.
Other references, including objects, are currently not supported.
### Mappings from JavaScript to Perl
If the code given to `js()` throws a JavaScript error, `js()` will `die`.
Otherwise, the `js()` function will return:
- JS `undefined` becomes Perl `undef`
- JS booleans become Perl's "booleans" (`!0` and `!1`)
- JS numbers and strings become Perl numbers and strings (values are copied)
- JS "Symbol"s currently cause a warning and and `js()` returns `undef`
- JS functions, objects (hashes), and arrays are returned as
Perl objects of the class `WebPerl::JSObject`.
### `WebPerl::JSObject`
A `WebPerl::JSObject` is a thin wrapper around a JavaScript object.
The contents of the JavaScript object are not copied to Perl, they are kept in
JavaScript and accessed only when requested from Perl.
`JSObject`s support overload array, hash, and code dereferencing, plus
autoloaded method calls. This means that if you have a `WebPerl::JSObject`
stored in a Perl scalar `$foo` pointing to a JavaScript object `foo`:
- Perl `$foo->{bar}` is the equivalent of JavaScript `foo["bar"]`
- Perl `$foo->[42]` is the equivalent of JavaScript `foo[42]`
- Perl `$foo->("arg")` is the equivalent of JavaScript `foo("arg")`
- Perl `$foo->bar("arg")` is the equivalent of JavaScript `foo.bar("arg")`
`JSObject`s provide the following methods:
- `hashref` is the method behind hashref overloading. It returns a reference
to a tied hash which accesses the underlying JavaScript object. The tied
hash should behave like a normal Perl hash, except that all operations
on it are passed to JavaScript.
- `arrayref` is the method behind arrayref overloading. It returns a reference
to a tied array which accesses the underlying JavaScript array. The tied
array should behave like a normal Perl array, except that all operations
on it are passed to JavaScript.
- `coderef` is the method behind coderef overloading. It returns a reference
to a `sub` that, when called, calls the underlying JavaScript function.
- `methodcall` is the method behind method autoloading. Its first argument is
the name of the method, and the further arguments are arguments to the method.
- `toperl` is a method that translates the object from a `JSObject` into a
regular Perl data structure (deep copy). Note that JavaScript functions are
kept wrapped inside anonymous Perl `sub`s.
Method autoloading will of course not work for JavaScript methods that have
the same name as existing Perl methods - these are the above methods,
plus methods named `AUTOLOAD`, `DESTROY`, plus any methods inherited from Perl's
[`UNIVERSAL`](http://perldoc.perl.org/UNIVERSAL.html) class, such as `can` or `isa`.
If you need to call JavaScript methods with any of these names,
use `methodcall`. For example, `$jsobject->methodcall("can", "arg1")` will call
the JavaScript method `can` instead of the Perl method `can`.
Arguments from Perl to JavaScript function or method calls are mapped as follows.
### Mappings from Perl to JavaScript
Unlike the JavaScript to Perl mappings, values are generally *copied* from
Perl to JavaScript, instead of being *referenced*.
The exceptions are Perl `subs`s and `WebPerl::JSObject`s.
- Perl arrayrefs become JavaScript arrays
- Perl hashrefs become JavaScript objects
- Perl coderefs become JavaScript functions -
**Warning:** please see the discussion in
["Memory Management and Anonymous `sub`s"](#memory-Management-and-anonymous-subs)!
- Perl `WebPerl::JSObject`s become references to the wrapped JavaScript objects
- Perl numbers/strings are copied to JavaScript via `Cpanel::JSON::XS::encode_json`
(with its `allow_nonref` option enabled). This means that the choice
for whether to encode a Perl scalar as a JavaScript number or string is
left up to the module, and is subject to the usual ambiguities when
serializing Perl scalars.
- Other references, including objects, are currently not supported.
***
@ -17,3 +395,11 @@ Nothing here just yet - come back soon!
Additional notes on using WebPerl may be found in the
[GitHub Wiki](https://github.com/haukex/webperl/wiki/Using-WebPerl).
***
Copyright (c) 2018 Hauke Daempfling (haukex@zero-g.net)
at the Leibniz Institute of Freshwater Ecology and Inland Fisheries (IGB),
Berlin, Germany, <http://www.igb-berlin.de>
Please see the ["Legal" page](legal.html) for details.

Loading…
Cancel
Save