Paepoi

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

Gjs, JXA, Node.js

# 最終更新日 2019.03.30

スタンドアロン(単独で利用できる)の JavaScript 実行環境での基本機能の覚書

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

※ jjs は非推奨になったので削除しました
※ Windows は無視しています

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

const GLib = imports.gi.GLib;
 
// stdin=0 stdout=1 
let channel = GLib.IOChannel.unix_new(0);
 
if (channel.get_flags() == GLib.IOFlags.IS_READABLE) {
    let [status, str_return] = channel.read_to_end();
    // toString が必要、\n を取り除く
    let line = str_return.toString().trim();
    print(`${line} がパイプから渡されました`);
} else {
    channel.write_chars('何か入力して Enter : ', -1);
    let [status, str_return] = channel.read_line();
    let line = str_return.toString().trim();
    print(`${line} が入力されました`);
}

/**
 * JXA
 */

ObjC.import("Cocoa");
ObjC.import("unistd");
 
if ($.isatty(0)) {
    let prpt = $('何か入力して Enter :').dataUsingEncoding($.NSUTF8StringEncoding);
    $.NSFileHandle.fileHandleWithStandardOutput.writeData(prpt);
    let data = $.NSFileHandle.fileHandleWithStandardInput.availableData;
    let res = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js.trim();
    console.log(`${res} が入力されました`);
} else { 
    let data = $.NSFileHandle.fileHandleWithStandardInput.availableData;
    let res = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js.trim();
    console.log(`${res} がパイプから渡されました`);
}

/**
 * Node.js
 */

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

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

if (Tty.isatty(0)) {
    readline.question('何か入力して Enter : ', function(line) {
        console.log(`${line} が入力されました`);
        readline.close();
    });
} else {
    readline.question('', function(line) {
        console.log(`${line} がパイプから渡されました`);
        readline.close();
    });
}

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

const GLib  = imports.gi.GLib;

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

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;
let res = app.doShellScript('ls -l');
console.log(res);

/**
 * Node.js
 */

const exec = require("child_process").exec;
exec('ls -l', function(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, function() {
    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 --- 2020.