Paepoi

Paepoi » JavaScript Tips » Gjs, JXA, Node.js

Gjs, JXA, Node.js

# 最終更新日 2020.07.19

スタンドアロン(単独で利用できる)の JavaScript 実行環境での基本機能の覚書
UNIX 系(macOS 含む)のみで動作確認

通称コマンド名動作環境コア
GjsgjsGNOMESpiderMonkey
JXAosascriptmacOSJavaScriptCore
Node.jsnodeマルチV8

標準入出力
echo ほげ | gjs test.js
のようなパイプ入力も考慮しました
/**
 * Gjs
 */

const GLib = imports.gi.GLib;

// readline は自作してみた
let readline = function(prpt) {
    // stdin=0 stdout=1 
    let channel = GLib.IOChannel.unix_new(0);
    let prefix = '端末入力';
      
    if (channel.get_flags() == GLib.IOFlags.IS_READABLE) {
        prefix = 'パイプ';
    } else {
        channel.write_chars(prpt, -1);
    }
    let [status, str_return] = channel.read_line();
    let line = str_return.toString().trimEnd();
    return [prefix, line];
}

let [prefix, line] = readline('何か入力して Enter :');
print(`${prefix}から ${line} が渡されました`);

/**
 * JXA (GNU readline 同様に使える)
 */

ObjC.import('readline');
ObjC.import('unistd');

let prefix = $.isatty(0) ? '端末入力' : 'パイプ';
let line = $.readline('何か入力して return :');
console.log(`${prefix}から ${line} が渡されました`);

/**
 * Node.js
 */

const ReadLine = require('readline');
const Tty = require('tty');

let readline = ReadLine.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false
});

let [prpt, prefix] = Tty.isatty(0) ? ['何か入力して return :', '端末入力'] : ['', 'パイプ'];
readline.question(prpt, (line)=> {
    console.log(`${prefix}から ${line} が渡されました`);
    readline.close();
});

ファイルの読み書き
Gjs は Gio を使ったほうがいいけどそれは別のページにて
/**
 * Gjs
 */

const GLib  = imports.gi.GLib;

const FILE = 'write_gjs.txt';
const TEXT = '日本語を書き込むよ\n改行もしてみるよ';

let result = GLib.file_set_contents(FILE, TEXT); // Write
if (result) {
    print('Write Success');
}
let [result, contents] = GLib.file_get_contents(FILE); // Read
if (result) {
    print(contents.toString());
}

/**
 * JXA
 */

ObjC.import('Cocoa');

const FILE = $('write_jxa.txt');
const TEXT = $('日本語を書き込むよ\n改行もしてみるよ');
let nil = $();

// Write
let res = TEXT.writeToFileAtomicallyEncodingError(FILE, true, $.NSUTF8StringEncoding, nil);
if (res) {
    console.log('Write Success!');
}

// Read
let s = $.NSString.alloc.initWithContentsOfFileEncodingError(FILE, $.NSUTF8StringEncoding, nil);
console.log(s.js);

/**
 * Node.js
 */

const FILE = 'write_node.txt';
const TEXT = '日本語を書き込むよ\n改行もしてみるよ';

let fs = require('fs');
fs.writeFile(FILE, TEXT, (err)=> {
    if (err == null) console.log('Write Success!');
});

fs.readFile(FILE, 'utf8', (err, content)=> {
    if (err != null)
        console.log(err);
    else
        console.log(content.trim());
});

起動パラメータ
Node.js は Python と同様なパラメータになる、他は全部パラメータのみの配列
/**
 * Gjs (1.52 からUNICODE 化されました)
 */

if (ARGV.length == 0) {
    print('No argv');
} else {
    for (let s of ARGV) {
        print(s)
        //print(decodeURIComponent(escape(s))); // under 1.52
    }
}

/**
 * JXA
 */

function run(argv) {
    if (argv.length == 0) {
        console.log('No argv');
    } else {
        for (let s of argv) {
            console.log(s);
        }
    }
}

/**
 * Node.js (実行ファイル名, スクリプトファイル名, argv[0], argv[1], ...)
 */

if (process.argv.length == 0) {
    console.log('No argv');
} else {
    for (let s of process.argv) {
        console.log(element);
    }
}

環境変数
$HOME を表示する例
/**
 * Gjs
 */

const GLib = imports.gi.GLib;
print(GLib.getenv('HOME'));

/**
 * JXA
 */

ObjC.import('stdlib');
console.log($.getenv('HOME'));

/**
 * Node.js
 */

console.log(process.env.HOME);

シェルコマンドの実行
ls -l の結果を得て表示する例
/**
 * Gjs
 */

const GLib = imports.gi.GLib;

let output = GLib.spawn_command_line_sync('ls -l')[1];
print(output);

/**
 * JXA
 */

let app = Application.currentApplication();
app.includeStandardAdditions = true;

// alteringLineEndings オプション無しだと改行が CR に変換される
let res = app.doShellScript('ls -l', {alteringLineEndings: false});
console.log(res);

/**
 * Node.js
 */

const exec = require('child_process').exec;

exec('ls -l', (err, stdout, stderr)=> {
    console.log(stdout);
});

タイマー
setInterval, setTimeout はウエブブラウザからしか使えない
と思ったら Node.js は使えるんだね
/**
 * Gjs (メインループが必要)
 */

const GLib = imports.gi.GLib;
 
let count = 1;
let mainloop = new GLib.MainLoop(null, false);
 
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, ()=> {
    if (count == 5) {
        mainloop.quit();
        return false;
    }
    print(count);
    count ++;
    return true;
});
mainloop.run();

/**
 * JXA
 */

ObjC.import('Cocoa');

let count = 1;
let operation = $.NSBlockOperation.blockOperationWithBlock(
    function() {
        if (count == 5)
            timer.invalidate;
        console.log(count);
        count++;
    }
);
let timer = $.NSTimer.timerWithTimeIntervalTargetSelectorUserInfoRepeats(
    1, operation, 'main', null, true);
$.NSRunLoop.currentRunLoop.addTimerForMode(timer, 'timer');
// 戻り値が表示されるので変数に入れる
let r = $.NSRunLoop.currentRunLoop.runModeBeforeDate('timer', $.NSDate.distantFuture);

/**
 * Node.js (ブラウザと同じ)
 */

let count = 1;
let id = setInterval(()=> {
    if (count == 5) clearInterval(id);
    console.log(count);
    count++;
}, 1000);

Copyright(C) sasakima-nao All rights reserved 2002 --- 2023.