月別アーカイブ: 2016年3月

Gjs pipe

今回は Gjs で標準入力とパイプ入力の振り分けをやってみよう。
ちなみに Python だと標準の os モジュールだけで可能。

#!/usr/bin/env python3

import os

if os.isatty(0):
    # stdin
    s = input("何か入力してください >")
    print("[{0}]が入力されました".format(s))
else:
    # pipe
    with os.fdopen(0) as f:
        s = f.read()[:-1]
        print("[{0}]がパイプから渡されました".format(s))

コレと同様の動作ができるものを Gjs で作りたいということで。

Gjs は当然 GLib を使う、しかし GLib に isatty 関数は無い。
そういえば Gjs は stdout で行末から入力させる簡単な手段も無い。
よく考えたら標準入力も、Python に対し Gjs は print 以外は何もない。
これらを全部 GLib で行う必要がある。

#!/usr/bin/gjs

const GLib = imports.gi.GLib;

let channel = GLib.IOChannel.unix_new(0)
if (channel.get_flags() == GLib.IOFlags.IS_READABLE) {
    /* --  Pipe -- */
    [res, str_return] = channel.read_to_end();
    // byte to string
    let s = str_return.toString();
    // Remove '\n'
    s = s.slice(0, -1);
    print("[" + s + "]がパイプから渡されました");
} else {
    /* -- stdin -- */
    // Input
    channel.write_chars("何か入力してください >", -1);
    // Flush Console
    channel.shutdown(true);
    // readline
    let in_channel = GLib.IOChannel.unix_new(1);
    [res, str_return] = in_channel.read_line();
    // byte to string
    let s = str_return.toString();
    // Remove '\n'
    s = s.slice(0, -1);
    print("[" + s + "]が入力されました");
    in_channel.shutdown(true);
}

gjs_pipe

GIOChannel だけでなんとかなった。
Gio を使う別の手段も色々あるけどコレが一番単純な手段だと思う。
正しいかどうかは解らないけど動けばいいんだよ。

g_io_channel_shutdown

でコンソール表示をフラッシュする必要に気が付くまで少し、いやかなり時間が掛かった。
コレを呼ぶまで何一つリアクションしないツンデレなコンソールに萌え…(嘘です

使っているライブラリが同じなので PyGObject で書き換えても動く。
というか PyGObject で書いて変換したのは内緒だよ。
だって PyGObject の例外表示のほうが桁違いに親切なんだもん。

しかし戻り値が配列(タプル)になるという仕様は Python と同じなのね。
これはある程度 Python の経験がある人でないと理解に苦しむと思うのですが。
現状ではそんな人しか Gjs を使うという選択はしないので問題ないけど…

それにしても中括弧やセミコロンだけでなく何もかもが面倒臭い。
うーん、やっぱり Python 屋のままなほうが幸せかも。

Mac JavaScript getenv

Linux 屋が Mac を使うと環境変数が少ないなぁと感じる。

env

そのせいか osascript で環境変数を得る方法がなかなか見つからなかった。
いくら検索してもパスを通すことばかり、Windows と変わらないじゃん。
三時間くらい探し続けてやっと見つけた。

CotEditor :: ひまつぶし雑記帖

鳶嶋工房 / AppleScript / JavaScript for Automation (JXA)

osascript って stdlib のインクルードも可能なのか。
なら stdio もイケるかも、よしやってみよう。

#!/usr/bin/osascript

ObjC.import("stdlib");
ObjC.import("stdio");

var user = $.getenv("USER");
//console.log("ユーザー名は " + user + " です");
// 戻り値が出力されるので変数に入れている
// printf って転送バイト数が戻るとは知らなかった...
// 自動改行されるので \n を省いています
var dev_null = $.printf("ユーザー名は %s です", user);

/* //ShellScript から得るという手段もある
app = Application.currentApplication();
app.includeStandardAdditions = true;
var path = app.doShellScript("echo $LANG");
console.log("$LANG は " + path + " です");
*/

getenv

なんだよ、glibc の関数が普通に使えるじゃないか。
しかし今まで何気に使っていた printf にこんな罠が。

ただ printf と console.log は混在させないほうがいい。
上記下側のコメントアウトを外してみよう。

output_pointer

出力が上下で入れ替わってしまった、ように見えますが。
単に printf と console.log で出力ポインタ管理が違う。
つまり console.log の出力は行先頭のままになる。
結果、最初の出力が console.log の出力に押し出されてこうなる。

#!/usr/bin/osascript

ObjC.import("string");

var nae = "優木苗";
console.log(nae.length); //=>3
console.log($.strlen(nae)); //=>9

おぉ日本語のバイト数も C 標準関数を使えば得られる。
Gjs で GLib 関数がフルに使えるのとほぼ同じことができるのね。
Mac で JavaScript も想像していたより便利そうです。

jjs and gjs

jjs という JavaScript 実行コマンドがあることを今更知った。
JVM 上で動く、Jython みたいなものという解釈でいいのかな。
Open 含む JDK 1.8 の付属品で nashorn が実行エンジン。

openjdk_jjs

Fedora 23 にはデフォルトで入っている。
更に /etc/alternatives/jjs へのリンクが最初から /usr/bin にある。

Oracle Blogs 日本語のまとめ: [Java, JavaScript] Oracle Nashorn: A Next-Generation JavaScript Engine for the JVM

なんか起動が遅い、Java だから当然なのだが。
これでも IronPython より全然マシだ、てか DLR は完全に失敗作。

Gjs 同様に引数無しならインタラクティブシェルとして使える。
Ctrl+D で同様に終了できるけど改行してくれないな、別にイイけど。
引数に *.js を与えれば実行エンジンになる、まんま Gjs だな。

Gjs との違いは何だろう、遅くてもメリットがあるならヨシだし。

Nashorn(Java8のJavaScriptエンジン)でシェルスクリプト – よしなしごと

ってナンジャコリャ!ってくらい拡張されている。
ただこのシェル関連はインタラクティブシェルでは使えないようだ。

gjs, osascript で試すと全部できなかった、あたりまえか。
ヒアドキュメントだけでも他の実装に反映してほしいな。

Java Platform, Standard Edition Nashornユーザーズ・ガイド、リリース8

なんと JavaFX まで使えてしまうようです。
ただ OpenJDK には含まれていないので正規の Java8 が必要。

Changes/Java8 – FedoraProject

let は使えない。
実行引数の取得方法が実装毎で違うのはしかたがないが。
arguments オブジェクトが実行引数にも使えるのってコレ混乱しないかな?
引数指定に “–” が必要なのはどうなんだろう。
コレを忘れると引数を全部実行しようとするようだ。

#!/usr/bin/jjs

// gjs @ ARGV
// jjs @ $ARG or arguments (./hoge.js -- arg1 arg2)
// osascript @ function run(argv){}

var argv = $ARG;
//let argv = ARGV

if (argv.length == 0) {
    print("No argv");
} else {
    argv.forEach(function(element) {
        print(element);
    });
}

jjs, gjs とも console.log() は使えず print() で標準出力。
function run は AppleScript の機能なので当然 osascript のみ。
他色々あるけど、そもそもインポートできるものがバラバラ。
シバンを書いておかないとワケワカになるかも。

色々あるけど Java の資産があるなら便利だよね。
それよりバイトコードにビルドせず jre が使えることのほうが大きいかも。

ってドンダケ筆者はコンパイルが嫌いなの!と思われそう。
しかしなんか本格的に JavaScript の時代になってきているNE!

Mac Script (No Terminal.app)

Mac で AppleScript/JavaScript を端末起動無しで使う手段があった。

OSXのアプリケーションをJavaScriptで作る – Qiita

Mac には osacompile なんてスクリプトコンパイラがあったのか。
これで Mac でもスクリプトを使う時にターミナルを開かずに使えるぞ!

っっって、それじゃ意味無いジャン。

スクリプト言語はコンパイルせずにスパッと使えるのがメリットなんだから。
つかコンパイルするなら Swift とかで作ったほうが絶対に楽だし。

世の中にはそうしたい奇妙な人が結構いることは置いておいて。
特に IronPython でコンパイルしたい人の多さにドン引きDESU。

うーん、コンパイルせずにターミナルを開かない方法は…
あ、Automator という手があった。

Automatorで簡単にコマンド実行アプリを作る|MacFan

この程度ならシェルスクリプトのほうが圧倒的に簡単だと思うんですけど…
それはいいとして。

この手段で端末を開かずに bash 等のシェルが使えるようだ。
本当に上手くいくのかな?
JavaScript でウインドウを作って試してみよう。

いや、筆者はまだ Cocoa がよく解っていない。
なので上のリンク先にあるウインドウを作るスクリプトをコピペ。

app_create

と Bash から osascript にスクリプトのフルパスを与えて。
JavaScript でも -l オプションは必要無かったのね。
/Applications 内に保存して Finder から W クリックしてみる。

app_exec

よしスクリプトのまま端末起動無しで実行できた。
しっかり Dock にも表示される、アイコンは自前で入れればイケそう。

実行パーミッションを付ける必要もないしメンテも簡単そう。
シェルで起動しているだけだから Python でも何でもイケるな。
何より書き換えしてもコンパイルのやりなおしをする必要が無い。

いいことづくめに感じるけど、ただただ面倒臭い!
Linux と PyGObject コンビがドンダケ神がかっているか思い知るだけだった。