perl
This commit is contained in:
parent
0bf5ac0fa8
commit
909b776235
@ -164,7 +164,7 @@ gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm
|
||||
If the program succeeded, the CSV contents will be printed to console and the
|
||||
file `sheetjsw.xlsb` will be created. That file can be opened with Excel.
|
||||
|
||||
#### Flow Diagram
|
||||
### Flow Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
@ -229,4 +229,55 @@ sequenceDiagram
|
||||
C->>F: Write File
|
||||
end
|
||||
deactivate C
|
||||
```
|
||||
|
||||
## Bindings
|
||||
|
||||
Duktape is easily embeddable. Bindings exist for many languages.
|
||||
|
||||
### Perl
|
||||
|
||||
The Perl binding for Duktape is available on CPAN:
|
||||
|
||||
```bash
|
||||
cpan install JavaScript::Duktape
|
||||
```
|
||||
|
||||
The Perl binding does not have raw `Buffer` ops, so Base64 strings are used.
|
||||
With the [Extendscript](/docs/getting-started/installation/extendscript) build:
|
||||
|
||||
```perl SheetJSDuk.pl
|
||||
# usage: perl SheetJSDuk.pl path/to/file
|
||||
use JavaScript::Duktape;
|
||||
use File::Slurp;
|
||||
use MIME::Base64 qw( encode_base64 decode_base64 );
|
||||
|
||||
# Initialize
|
||||
my $js = JavaScript::Duktape->new( max_memory => 1024 * 1024 * 1024 );
|
||||
$js->eval("var global = (function(){ return this; }).call(null);");
|
||||
|
||||
# Load the ExtendScript build
|
||||
my $src = read_file('xlsx.extendscript.js', { binmode => ':raw' });
|
||||
$src =~ s/^\xEF\xBB\xBF//;
|
||||
my $XLSX = $js->eval($src);
|
||||
|
||||
# Print version number
|
||||
$js->set('log' => sub { print $_[0], "\n"; });
|
||||
$js->eval("log('SheetJS library version ' + XLSX.version);");
|
||||
|
||||
# Parse File
|
||||
my $raw_data = encode_base64(read_file($ARGV[0], { binmode => ':raw' }), "");
|
||||
$js->set("b64", $raw_data);
|
||||
$js->eval(qq{
|
||||
global.wb = XLSX.read(b64, {type: "base64"});
|
||||
global.ws = wb.Sheets[wb.SheetNames[0]];
|
||||
});
|
||||
|
||||
# Print first worksheet CSV
|
||||
my $csv = $js->eval('XLSX.utils.sheet_to_csv(global.ws)');
|
||||
print $csv
|
||||
|
||||
# Write XLSB file
|
||||
my $xlsb = $js->eval("XLSX.write(global.wb, {type:'base64', bookType:'xlsb'})");
|
||||
write_file("SheetJSDuk.xlsb", decode_base64($xlsb));
|
||||
```
|
188
docz/docs/03-demos/31-engines/11_perl.md
Normal file
188
docz/docs/03-demos/31-engines/11_perl.md
Normal file
@ -0,0 +1,188 @@
|
||||
---
|
||||
title: Perl + JE
|
||||
pagination_prev: demos/cli
|
||||
pagination_next: demos/clipboard
|
||||
---
|
||||
|
||||
:::warning
|
||||
|
||||
In a production application, it is strongly recommended to use a binding for a
|
||||
C engine like [`JavaScript::Duktape`](/docs/demos/engines/duktape)
|
||||
|
||||
:::
|
||||
|
||||
JE is a pure-Perl JavaScript engine.
|
||||
|
||||
The [Extendscript build](/docs/getting-started/installation/extendscript) can be
|
||||
parsed and evaluated in a JE context.
|
||||
|
||||
|
||||
## Integration Details
|
||||
|
||||
The engine deviates from ES3. Modifying prototypes can fix some behavior:
|
||||
|
||||
```js
|
||||
/* String#charCodeAt is missing */
|
||||
var string = "";
|
||||
for(var i = 0; i < 256; ++i) string += String.fromCharCode(i);
|
||||
String.prototype.charCodeAt = function(n) {
|
||||
var result = string.indexOf(this.charAt(n));
|
||||
if(result == -1) throw this.charAt(n);
|
||||
return result;
|
||||
};
|
||||
|
||||
/* workaround for String split bug */
|
||||
Number.prototype.charCodeAt = function(n) { return this + 48; };
|
||||
|
||||
/* String#match bug with empty results */
|
||||
String.prototype.old_match = String.prototype.match;
|
||||
String.prototype.match = function(p) {
|
||||
var result = this.old_match(p);
|
||||
return (Array.isArray(result) && result.length == 0) ? null : result;
|
||||
};
|
||||
```
|
||||
|
||||
When loading the ExtendScript build, the BOM must be removed:
|
||||
|
||||
```perl
|
||||
## Load SheetJS source
|
||||
my $src = read_file('xlsx.extendscript.js', { binmode => ':raw' });
|
||||
$src =~ s/^\xEF\xBB\xBF//; ## remove UTF8 BOM
|
||||
my $XLSX = $je->eval($src);
|
||||
```
|
||||
|
||||
### Reading Files
|
||||
|
||||
Data should be passed as Base64 strings:
|
||||
|
||||
```perl
|
||||
use File::Slurp;
|
||||
use MIME::Base64 qw( encode_base64 );
|
||||
|
||||
## Set up conversion method
|
||||
$je->eval(<<'EOF');
|
||||
function sheetjsparse(data) { try {
|
||||
return XLSX.read(String(data), {type: "base64", WTF:1});
|
||||
} catch(e) { return String(e); } }
|
||||
EOF
|
||||
|
||||
## Read file
|
||||
my $raw_data = encode_base64(read_file($ARGV[0], { binmode => ':raw' }), "");
|
||||
|
||||
## Call method with data
|
||||
$return_val = $je->method(sheetjsparse => $raw_data);
|
||||
```
|
||||
|
||||
### Writing Files
|
||||
|
||||
Due to bugs in data interchange, it is strongly recommended to use a simple
|
||||
format like `.fods`:
|
||||
|
||||
```perl
|
||||
use File::Slurp;
|
||||
|
||||
## Set up conversion method
|
||||
$je->eval(<<'EOF');
|
||||
function sheetjswrite(wb) { try {
|
||||
return XLSX.write(wb, { WTF:1, bookType: "fods", type: "string" });
|
||||
} catch(e) { return String(e); } }
|
||||
EOF
|
||||
|
||||
## Generate file
|
||||
my $fods = $je->method(sheetjswrite => $workbook);
|
||||
|
||||
## Write to filesystem
|
||||
write_file("SheetJE.fods", $fods);
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note
|
||||
|
||||
This demo was tested on 2023 February 12 against JE 0.066
|
||||
|
||||
:::
|
||||
|
||||
1) Install `JE` through CPAN:
|
||||
|
||||
```bash
|
||||
cpan install JE
|
||||
```
|
||||
|
||||
2) Download the [ExtendScript build](/docs/getting-started/installation/extendscript):
|
||||
|
||||
```bash
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.extendscript.js
|
||||
```
|
||||
|
||||
3) Save the following to `SheetJE.pl`:
|
||||
|
||||
```perl title="SheetJE.pl"
|
||||
use JE;
|
||||
use File::Slurp;
|
||||
use MIME::Base64 qw( encode_base64 );
|
||||
|
||||
## Initialize
|
||||
say STDERR "Initializing Engine";
|
||||
my $je = new JE;
|
||||
$je->eval("var global = (function(){ return this; }).call(null);");
|
||||
$je->eval(<<'EOF');
|
||||
Number.prototype.charCodeAt = function(n) { return this + 48; };
|
||||
var string = ""; for(var i = 0; i < 256; ++i) string += String.fromCharCode(i);
|
||||
String.prototype.charCodeAt = function(n) {
|
||||
var result = string.indexOf(this.charAt(n));
|
||||
if(result == -1) throw this.charAt(n);
|
||||
return result;
|
||||
};
|
||||
String.prototype.old_match = String.prototype.match;
|
||||
String.prototype.match = function(p) {
|
||||
var result = this.old_match(p);
|
||||
return (Array.isArray(result) && result.length == 0) ? null : result;
|
||||
};
|
||||
EOF
|
||||
|
||||
## Load SheetJS source
|
||||
say STDERR "Loading SheetJS Library";
|
||||
my $src = read_file('xlsx.extendscript.js', { binmode => ':raw' });
|
||||
$src =~ s/^\xEF\xBB\xBF//;
|
||||
my $XLSX = $je->eval($src);
|
||||
|
||||
## Set up conversion method
|
||||
$je->eval(<<'EOF');
|
||||
function sheetjsparse(data) { try {
|
||||
return XLSX.read(String(data), {type: "base64", WTF:1});
|
||||
} catch(e) { return String(e); } }
|
||||
function sheetjscsv(wb) { try {
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
return XLSX.utils.sheet_to_csv(ws);
|
||||
} catch(e) { return String(e); } }
|
||||
function sheetjswrite(wb) { try {
|
||||
return XLSX.write(wb, { WTF:1, bookType: "fods", type: "string" });
|
||||
} catch(e) { return String(e); } }
|
||||
EOF
|
||||
|
||||
## Read file
|
||||
say STDERR "Parsing " . $ARGV[0];
|
||||
my $raw_data = encode_base64(read_file($ARGV[0], { binmode => ':raw' }), "");
|
||||
$workbook = $je->method(sheetjsparse => $raw_data);
|
||||
|
||||
## Convert to CSV
|
||||
say STDERR "Converting to CSV";
|
||||
my $csv_data = $je->method(sheetjscsv => $workbook);
|
||||
print $csv_data;
|
||||
|
||||
## Write to SheetJE.fods
|
||||
say STDERR "Writing to SheetJE.fods";
|
||||
my $fods = $je->method(sheetjswrite => $workbook);
|
||||
write_file("SheetJE.fods", $fods);
|
||||
```
|
||||
|
||||
4) Download a test file and run:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/data/cd.xls
|
||||
perl SheetJE.pl cd.xls
|
||||
```
|
||||
|
||||
After a short wait, the contents will be displayed in CSV form. It will also
|
||||
write a file `SheetJE.fods` that can be opened in LibreOffice.
|
@ -63,7 +63,7 @@ Duktape is an embeddable JS engine written in C. It has been ported to a number
|
||||
of exotic architectures and operating systems.
|
||||
|
||||
This demo has been moved [to a dedicated page](/docs/demos/engines/duktape).
|
||||
|
||||
The demo includes examples in C and Perl.
|
||||
|
||||
### Goja
|
||||
|
||||
|
@ -142,7 +142,7 @@ const config = {
|
||||
prism: {
|
||||
theme: lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
additionalLanguages: [ "swift", "java", "csharp" ],
|
||||
additionalLanguages: [ "swift", "java", "csharp", "perl" ],
|
||||
},
|
||||
liveCodeBlock: {
|
||||
playgroundPosition: 'top'
|
||||
|
Loading…
Reference in New Issue
Block a user