c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud 等に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開発中です。

Develop Google Apps Script in ClojureScript

qiita.com🎂

What is Google Apps Script?

f:id:Kureduki_Maari:20181223190842p:plain

Google Apps Script (以下 Apps Script) は、Google の server 上での serverless な JavaScript 實行環境です。serverless な JavaScript 實行環境ですので Cloud Function の仲間です。函數を起動できる event の種類が限られている、また SLA (Service Level Agreement) が不明である為、Cloud Function のやうに大規模な servise を作る事は、できません。代はりに、Docs や Gmail 等[など]の Google Apps と連携するやう簡單に設定できる為、この意味で VBA (Visual Basic for Applications) の仲間でもあります。更に Google Apps が使へる環境であれば無料です。その代はり一日当りの實效囘數等が制限されてゐます。

Apps Script と云へば Google Apps 向けの VBA である、と思はれる向きもあり、Gmail と Spreadsheet を同時に見たり更新したりできると云ふ使ひ途もあるのですが、cron の代はりとして Google Apps に全く觸らない函數も作れます。であるので、Google Apps account で使へる serverless FaaS (Function as a Service) だと見るのがよいです。今の所書ける言語は JavaScript だけです。

Google Apps の web site 上に Apps Script の editor があるのですが、ただの text editor であり、version 管理も難しく、複數人で編集したり test を書いたり library を使ったりする事ができません。programmer ですので、日々使ってゐる editor (Emacs) で書き、日々使ってゐる version 管理 system (Git) で管理し、人間にも讀める code を書きたいものです。これをお膳立てしてくれるのが clasp です。

github.com

Apps Script 用の CLI tool であり、local の script を upload する、Google Apps 上の script を download する、Google Apps 上の script を實行する、Google Apps 上の現在の version に tag を打つ、Apps Script が吐いた log を見る、等の事ができます。まともな開發に要る事はできさうです。人間でゐませう (發狂せずとも濟みさうと云ふ意)。

What is ClojureScript?

f:id:Kureduki_Maari:20181223190914p:plain:w128

ClojureScript (a.k.a. cljs) は Clojure の實裝の一つです。Clojure と云へば JVM 上の Lisp の一つとして生まれましたが、その後.NET CLR 上でも實裝され、JavaScript への transpiler も作られました。この二つは Clojure と同じ或いは近しい community で作られてゐます。他にも Erlang VM 上で動くclojerlや、C に transpile するclojurec (これの開發は停まってゐます) もあります。廣く實行環境を見れば、Android 上で動かすlein-droid (これも開發が停まってゐます)、React Native で動かすRe-Natal、Unity で動くArcadia等があり、更には Graal で JVM 用の Clojure を native code に落とせるので (Graal が MySQL に搭載されたらそこでも動く) (clojure-clr を Mono LLVM に流すと云ふ手も在ります)、どこででも動きますね (Ethereum の contract 自體を書く方法は見附からないので EthereumVM では動きませんね)。CloduinoArduino も弄れるみたいです。珍しい所ではQuilから Processing で映像を描けたり、Overtoneから SuperCollider で音樂を生成したりできます。

Clojure は immutable な data を基礎とし、vector や map 等の data 構造 & 使ひ易い記法を持った Lisp です。Lisp である事が我々にとってはまづ一つの利点ですし、data が immutable ですから、program を抽象化し易く、concurrency を簡單に扱へます。ClojureScript は Clojure から JavaScript への transpiler です。JVMAPI は使へませんが、Clojure の core API の大半が使へますし、JavaScript を簡單に呼び出せます。無論 NPM も使へます。

Isomorphic と云ふ言葉は懐かしいですが、懐かしくなったからといって重要で無くなった譯ではありません。Reagent 等便利な Web frontend framework が在ります。

Develop Apps Script in ClojureScript.

以下の二つを install します。

  • cljs : Mac であればbrew install clojurescriptで ClojureScript を、或いはbrew install leiningenで Leiningen を入れて project 毎に install します。
  • clasp : NPM を入れ、npm install -g @google/claspで入れます。

私は Leiningen で project を作ったので、こんなproject.cljができます。

(defproject apple-is-dead "0.1.0"
  :description "Appleの障害情報を監視し通知する"
  :url "〜〜〜"
  :license {:name "Do What The F*ck You Want To Public License"
            :url "http://sam.zoy.org/wtfpl/COPYING"}
  :plugins [[jonase/eastwood "0.3.3"]
            [lein-ancient "0.6.15"]
            [lein-cljfmt "0.5.7"]
            [lein-cljsbuild "1.1.7"]]
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [org.clojure/clojurescript "1.10.439"]]
  :hooks [leiningen.cljsbuild]
  :aliases {"lint" ["run", "-m" "apple-is-dead.tasks.lint/go"]
            "release" ["run", "-m" "apple-is-dead.tasks.release/go"]}
  :cljsbuild {:builds
              [{:source-paths ["src"]
                :compiler {:main apple-is-dead.main
                           :output-to "release/main.js"
                           :output-dir "target"
                           :optimizations :advanced
                           :pretty-print false
                           :foreign-libs [{:file "src/entrypoint.js"
                                           :provides ["apple-is-dead.entrypoint"]}]
                           :externs ["src/extern.js"]}}]})

lein-cljsbuild が、Leiningen に ClojureScript を build するやり方を教えます。

  :hooks [leiningen.cljsbuild]
  :cljsbuild {:builds
  〜〜〜

と hook すると、lein compileで ClojureScript の file である*.cljsを探して JavaScript に transpile します。

:aliasesの lint では

prettier --write src/*.js
lein cljfmt fix
lein ancient check
lein eastwood

のやうな事をさせてゐ、release では

lein compile
clasp push

のやうな事をさせてゐます。

作った ClojureScript の project 内でclasp create 〜〜〜を叩き、Apps Script project を作ります。この時に作られる file 達が大切なので、これらを cp しておき、これらが在る diractory で以後clasp command を叩きます。

あとは ClojureScript と Apps Script の referense を御覽ください。Apps Script では log を見たり error を mail に通知する事ができますので、そこを適切に作ると運用が樂になります。error を catch する時は(js/console.error err)で log を吐く、實行の重要な step 毎に(js/console.info message)で log を吐く、catch すべきでない error を catch しない、retry されてもよいやうに冪等にする等、batch 處理を書く時と似た事を注意する筈です。

:foreign-libs:externsは載せておきます。

                           :foreign-libs [{:file "src/entrypoint.js"
                                           :provides ["apple-is-dead.entrypoint"]}]
                           :externs ["src/extern.js"]

:foreign-libsJavaScript から ClojureScript を呼ぶ時に要ります。Apps Script は書かれたものが JavaScript であらうと前提して呼び出しますから、JavaScript 側から呼べる interface を開けておかなければなりません。ここに指定した file に JavaScript を書いておくと、それは Closure Compiler (ClojureScript が Closure Compiler を呼び出して、code を圧縮したり dead code を消したりします) で變換されずに、出力される JavaScript にそのまま載ります。

// entrypoint.js
function main(evt) {
  apple_is_dead.main.main();
}
; main.cljs
(defn ^:export main []
  (doseq [service ((apple.get-status) :services)]
    (check-apple-service service)))

これで Apps Script はmain()を呼び出せ、それによりapple_is_dead.main.main()、すなはち(apple-is-dead.main.main)を實行できます。

:externsは、Closure Compiler が圧縮してはいけない變數名を列擧する file です。これらは外の環境に global に定義されてゐるから、このままの名前で呼び出さなければならない、例えば JavaScript の core に定義された module 達ですが、これらはどうやら Closure Compiler が既に知ってゐます。しかし Closure Compiler は Apps Script の事は知りません。それでも Closure Compiler はたいていうまくやりますが、一部見逃してしまふやうです。私の場合はCacheServiceの事は教えてやらねばなりませんでした (他にも色々呼び出したのですが、これ以外はうまく、圧縮せずにゐてくれました) (Closure Script の實裝を読んでゐないのが惡いのですが)。

// extern.js
var CacheService = {};
CacheService.getScriptCache = function () {};

これで ClojureScript で Apps Script を開發できると思ひます。