JXA」タグアーカイブ

Dinamic Import: Gjs and JXA

現在の JavaScript はダイナミックインポートが可能。
下記ページで Chrome や Safari で動くと解りますね。

全モダンブラウザで使えるJavaScriptのdynamic import(動的読み込み) – Qiita

GNOME の Gjs は imports 関数があるので関係ないんだけど。
そういえば macOS の JXA はファイル分割ができないのが困る。
コレを利用してクラス毎に分割できるかな。

#!/usr/bin/osascript

import('./sub.js')
	.then((module) => {
        console.log('Start!');
		const sub = new module.Sub();
        sub.subMethod();
	});

main.js

export class Sub {
    subMethod() {
        console.log('this is Sub Class Method');
    }
}

sub.js

osa

なんでだよ!
Promise だと認識はしているけど動作しないってことみたい。
JavaScriptCore が全部やってくれるってわけじゃないんかい。

Gjs でも同じかな?
console.log を print に書き換えて実験。

#!/usr/bin/gjs

import('./sub.js')
	.then((module) => {
		const sub = new module.Sub();
        sub.subMethod(); 
	});

main.js

export class Sub {
    constructor(app) {
        print('Hello');
    }
    subMethod() {
        print("this is Sub Class Method");
    }
}

gjs

動いたのでコンストラクタも入れてみた、普通に Class ですね。
いや Gjs は imports を使ったほうが簡単ですけど。
というか、Apple は内製スクリプトには本当にヤル気が無いなって。

macOS Monterey JXA

macOS Monterey の JXA は NSRect のバグが無くなった。
ということで、今の知識で NSWindow を作ってみたらどうなるか。

いや PyObjC のほうが簡単なんだけど、デフォルトで入っていないのが。
JXA ならどんな Mac でもそのまま動かせるという利点があるので捨て難い。

ただ JXA では PyObjC みたいに class にできないんだよなぁ。
ネットで簡単に見つかる方法では全部グローバル変数にするしかないのが。
そもそも JavaScript の class は他の言語の class とは違うし。
なので GNOME の Gjs もアクロバットな手段で class っぽくしている。

ObjC.registerSubclass を上手く利用してソレっぽくやってみよう。
追加メソッドはどう書けばいいのかな?とか。

#!/usr/bin/osascript

ObjC.import('Cocoa');

//let wins = [];

ObjC.registerSubclass({
    name: 'AppDelegate',
    protocols: ['NSApplicationDelegate'],
    methods: {
        'applicationDidFinishLaunching:': function (notification) {
            let window = $.MyWindow.alloc.initWithContentRectStyleMaskBackingDefer(
                $.NSMakeRect(0, 0, 300, 100),
                $.NSTitledWindowMask
                | $.NSClosableWindowMask
                | $.NSMiniaturizableWindowMask
                | $.NSResizableWindowMask,
                $.NSBackingStoreBuffered,
                false
            );
            window.makeKeyAndOrderFront(window);
            $.NSApp.activateIgnoringOtherApps(true);
            //wins.push(window);
        }
    }
});

ObjC.registerSubclass({
    name: 'WinDelegate',
    protocols: ['NSWindowDelegate'],
    methods: {
        'windowWillClose:': function(notification) {
            console.log('MyApp Close !');
            return $.NSApp.terminate(0);
        }
    }
});

ObjC.registerSubclass({
    name: 'MyWindow',
    superclass: 'NSWindow',
    propertyies: {},
    methods: {
        'initWithContentRect:styleMask:backing:defer:': function
        (contentRect, style, backingStoreType, flag) {
            let _this = ObjC.super(this).initWithContentRectStyleMaskBackingDefer(
               contentRect, style, backingStoreType, flag);
           _this.title = $('JXA NSWindow');
           _this.delegate = $.WinDelegate.new;
           // Button
           let button = $.NSButton.buttonWithTitleTargetAction('button', this, 'onButtonClick:');
           button.setFrame($.NSMakeRect(10, 10, 200, 36));
           _this.contentView.addSubview(button);
           // return
            return _this;
        },
        'onButtonClick:': {
            types: ['void', ['id']],
            implementation: function(sender) {
                sender.setTitle('Clicked!');
            }
        }
    }
});

/**
 * Application
 */
$.NSApplication.sharedApplication;
$.NSApp.setActivationPolicy($.NSApplicationActivationPolicyRegular);
$.NSApp.mainMenu = function() {
    let mainMenu = $.NSMenu.new;
    let itemApp  = $.NSMenuItem.new;
    mainMenu.addItem(itemApp);
    let menuApp  = $.NSMenu.new;
    itemApp.setSubmenu(menuApp);
    // quit menu
    let itemQuit = $.NSMenuItem.new;
    itemQuit.initWithTitleActionKeyEquivalent('Quit App', 'terminate:', 'q');
    menuApp.addItem(itemQuit);
    return mainMenu;
}();
$.NSApp.setDelegate($.AppDelegate.new);
$.NSApp.run;

nswindow

こんな感じになった、
ボタンのハンドラは delegate ではなく this に届くようだ。
オーバーライドは types 指定不要なのね、ふむふむ。
これだけ解れば応用でなんとかなりそう。

ただ PyObjC と違って NSWindow がガベージコレクションされないんだが。
let 指定ならばハンドラを抜けたら破棄されるはずなんだけど、何故だ?
Python とは破棄対象の選定方法が違うんだろう、知らんけど。

ところで Monterey で今頃気がついたんだけど。

power

iOS みたいに充電の保留機能が付いたんだね。
筆者は滅多に持ち歩かないんで意味はないかもだがけど。

macOS Monterey

macOS を Monterey に遅ればせながらアップグレード。
Fedora とは違ってスッゲェ時間が掛かると解っているので休日まで待った。
12.13GB か、前の 14GB より減ったとはいえ酷い。

そろそろ全部終わったかな?
って画面を表示させると「インストールします」ダイアログ。
ガックリ。。。。。

[続ける]-[同意] って感じでボタンを押さないとインストールが始まらない。
今度こそ終わったかな?って見ると「再起動」ダイアログ。
ションボリ。。。。。

その再起動が又時間が掛かる。
終わった!と思ったらフェイントだった。
ゲンナリ。。。。。

M1 でコレだぞ、Intel Air だったらドンダケだったんだ?
アップグレードくらいボタン一発でスパッとやってくださいよ。
あーやっとこさ終わった。

それはいいとして。

Apple、macOS 12 MontereyにPython 2.7.18などを同梱してリリース。Big Surまで同梱されていたphpは削除されるので注意を。

マジで PHP は削除されるのね。
httpd.conf が初期化されるのはいつものこと。

php

WordPress の時代にコレって macOS を Web 開発に使うなってメッセージ?
Fedora のように dnf コマンドで即座に導入できるってわけでもないのにさ。
いったいどんな政治的なやりとりがあったのか、みたいな。
これだから Fedora も併用しなきゃなんだよ、macOS で開発は自由が無い。

自力で Python3 を入れている人は残る。
3.10 になっているのか、アップグレードしとこ。
macOS 64-bit unibersal2 installer で M1 ネイティブだよ。

Python Release Python 3.10.0 | Python.org

Lightroom は問題なく動く、コレのために Mac を使っているのだし。

それと Fedora から SSH てか SFTP で簡単アクセスする用の
~/.ssh/id_rsa.pub
とか設置していたものも普通に残っているしアクセスもできる。

そんなことより何より。

#!/usr/bin/osascript

ObjC.import('Cocoa');
let r = $.NSMakeRect(0, 0, 10, 10);

console.log(`width = ${r.size.width}`);

jxa

JXA での NSRect バグがやっと、ついに修正されたぞ!
Big Sur アップデート毎にコレ動かしてションボリしてたのよね。
待ちわびた、待ちすぎて PyObjC 万歳になっちゃった。

M1 Mac JXA and PyObjC

会社の都合で休日出勤は無しなので M1 Air をしっかり試す。
たしかパワーは 2019 Air の五倍なので筆者の 2018 からだと八倍くらいか。
ログイン画面まで 15 秒、パスワードを打ち込みプラス 15 秒でもう使える。
他に Web でベタ褒めされている件、あれらは全部本当だった。
こんなの筆者の知っている Macbook Air じゃない、怪物にも程がある。

とりあえず再構築、Atom を公式サイトから入れよう。
起動しようとすると Rosetta2 をインストールしますか?とアラートが。
インストールを選ぶと一瞬で入ったから内部で有効化しただけだと思うけど。
ぶっちゃけ来年くらいまでは全員が入れると思う。

Atom を Gedit のように使う – Paepoi

再構築完了、書いてて良かった自前カスタムのすべて。
早速 JXA を試そう、ES2020 は対応されているか。
?? 演算子と BigInt と globalThis をまとめてテスト。

#!/usr/bin/osascript

const p = globalThis.print ?? console?.log;
p(12341234123412341234n *2n);

atom_run

動くじゃないの。

GNOME 3.38 Gjs | Paepoi Blog
import 関数は使えない。
Promise も動いた、ただ筆者には便利さが解らない。
matchAll も動く、Gjs と同じく詳細は出力されないけど。

だいたい Gjs と同じって感じ。
ただし、NSMakeRect のバグはそのまんまだ、やっぱりやる気無いのね。

しかしマジで Python2 がデフォルトで入っているのがなんとも。
PHP は 7.3.22 か、さくらインターネットでさえ 7.4.10 なのに。
perl と ruby はどうでもいい。

端末で python3 と打ち込むと CommandLineTools のダイアログ。
インストールすると Python3 が使える、3.8.2 だ。
普通に使えるけど、PyObjC が pip3 でインストールできない。

Python Release Python 3.9.1 | Python.org

macOS 64-bit universal2 installer
というものが公式にあった、これならイケるかな。
CommandLineTools を先に入れないと 3.8 に上書きされるので注意。
インストーラに従うだけで 3.9 にアップグレードできる。
んで、pip3 のアップグレードを行う必要があった。

# pip upgrade
pip3 install --upgrade pip
# install
pip3 install -U pyobjc

PyObjC Tips – Paepoi

PyObjC

PyObjC もコレで問題なく動くじゃないの。
少し面倒だったけど混迷期だからしかたがないね。

JXA readline

現在本サイトの JXA Tips を書き換えしている。
以下の Objective-C Bridge の所を見ていたんだけーが。

OS?X 10.10 Release Notes

あれ、readline が import できるみたい。

GNU Readline – Wikipedia

stdio や unistd のように C と同じように使えるのかな。

#!/usr/bin/osascript

ObjC.import('readline');

console.log('May I ask your name?');
let s = $.readline('>> ');
console.log(`Hello ${s} san`);

jxa_readline

JXA の stdin ってこんなに簡単だったんだ!
世界中探しても見つからなかったのにこんちくしょう。