※ 2023年に思い出しながら書いてます。
Google Driveベースの作業が多くなってきたので環境を見直したい
問題意識:OmniGraffle起点だけだと弱い
- 2019年に重い腰をあげて PlantUML を使い始めたが、概念図を描くにはやはり OmniGraffle であーでもないこーでもないするのが便利
- 一方で OmniGraffle スタートだと画像とドキュメントを取り出してドキュメント化するのが手間で、ついそのまま PDF にしちゃいがち
- ただ見せるだけならそれでもいいけど、再利用性は間違いなく落ちるし、OmniGraffle が必要なほど複雑でない図で伝えたいだけの場合も増えてきた
手法:まずVS CodeのMarkdown拡張を知る
文書を起点にするならそういう記法を使うのもアリか。もう少しこれまでよりも自然言語ライティング自体を加速させるような取り組みをしたい。1
Markdown Preview Enhanced - Visual Studio Marketplace
- Google Drive だけでなく日記の更新や薄い本みたいなある程度の分量のドキュメントを書きやすくはしておきたい
- Markdown Preview Enhancement という拡張を知る
- PlantUML も拡張でレンダーできる
- esa などでも Markdown の中に埋め込めるのは知っていたけど、esa 限定だと面白くないと思っていた
- Markdown はそんなに記述力ない(割と簡単に HTML 生書きに陥る)のがネックけど、内容によっては割と耐えられるかも?
課題:Google Drive へどうやって持っていくか
書くだけなら Google Drive よりまともなエディタで書ける方がありがたい。一方で Google Docs は Markdown エディタではないので、Markdown で書いたものをどうにかして Google Docs の形式に変換しないとそのままでは普通の人には見慣れない記号にまみれた無愛想なドキュメントになってしまう。
ネック
- 画像。PlantUML で描いたとしてそれをラスタ画像として取り出せないと Google Docs へ添付できない
- Google Docs は Markdown 記法に直接対応はしていないのでなんらかの変換が必要
変換方法
とりあえず見つけた方法。
※ ご存知の通り無駄が多いです。
- Asciidoc ← Markdown ( kramdoc / kramdown の機能 )
- DocBook ← Asciidoc ( asciidoctor の機能 )
- bocx ←DocBook ( Pandoc の機能 )
- Google Docs ← docx ( Google Drive の機能 )
PlantUML を書いて PlantUML をそのまま変換して画像を出力できる方法は知っていたが、一連の流れの中で書けると嬉しいと思い、試行錯誤してみる。この過程で気づきがいろいろある。
Markdown Preview Enhancement の中で Pandoc を呼べるが、Markdown + PlantUML → Pandoc → docx を直接実行すると PlantUML 画像内の日本語が化けるなど、拡張内の各ツールの設定が練れていない。
一方で Asciidoctor は面白い。
Asciidoctorよいかも
Asciidoc も名前だけは以前から知っていたが、特段 Asciidoc を使うメリットは感じていなかった。表現力は Markdown より上なんだろうけど、やはり Markdown は利用できるシーンが非常に多いため、あえて普段使いに Asciidoc を使う理由を見つけるのは難しい。
そんななか、上の docx 生成で Pandoc に繋ぐ際に asciidoc を経由する方法もあるなと思い、手を出してみたら思いのほか手応えを感じる。
AsciiDoc - Visual Studio Marketplace
- 拡張が Asciidoctor2 本家からリリースされていて安心
- Markdown ではサポートされていない画像埋め込みの機能が記法自体にある
- asciidoctor + asciidoctor-diagram で変換するとそのまま画像を取り出すことができる
- Pandoc で直接処理するよりも Asciidoctor 経由で処理した方が docx 変換もスムーズ
- asciidoctor 自体で ePub や PDF 生成の機能を持っており、最初から AsciiDoc で書いておけば HTML 以外に出力にも向いている
docx 変換については以下の sh スクリプトを用意した。
asciidoctorとasciidoctor-diagramとpandocを使ってasciidocからdocxを作る
OOXML の template を作るのはある程度コツが要る割に期待した仕上がりまで持っていくのはかなり大変なので、ある程度までになってます…。
今のところ微妙?
Markdown で書き始めるのはよいが、その後ラスタ画像を作るのはやはり億劫。それでも画像作成の機会と Markdown スタートでの環境の書きやすさのどちらがマシかというとやはり後者の方に軍配が上がる。
面倒は面倒。特に PNG 出力が思ったより解像度が悪いので、いったん SVG にしてから PNG に変換する部分でかなりの手間を要する。
もう一つ、docx ( OOXML ) 変換向けのテンプレートを頑張って作ったが、これなら Google Docs のデフォルトスタイルに合わせつつ margin とか文字サイズの設定だけすればだいたい満足なのでは?という感じがしている。
すると asciidoctor + asciidoctor-diagram は画像の取り出しのためだけに使う、みたいな感じになっていて手間の割に嬉しみが少ない。
図のない Google Docs を Markdown から一手間(行頭の記号の入力に応じて変換が走るので)掛けて作る、みたいな運用がほとんどになっている。
※ 2023年夏時点で Script API はサービスアカウントで利用することができないため、安全に安定的に CD を実現するのは難しく、そこまでするメリットが薄いのではないかと考えています。
Introduction | Apps Script | Google for Developers
Apps Script API はサービス アカウントでは動作しません。
Script API 登場以降、ずっとこの話題はありましたが、2021年に結論リポジトリができています。
背景
- Google Apps Script 開発もモダンになっており、Git + GitHub + CI/CD な構成は実現できることが分かった
- でもやはり master ブランチ以外は staging 環境の方へ deploy したい
- しかし gas-manager などによる Google Drive API を利用した deploy の際には、deploy 先となるプロジェクトの Drive ID が必要になるので、Drive ID の切り替えが必要。しかもこの ID などの情報は JSON ファイル で保存されているのが前提
対処方法の基本的な考え方
- deploy 前に (gas-managerで言う)gas-project.json や必要となる Spreadsheet の ID を差し替える仕組みを動かす ( preprocess )
- 実行時に必要なパラメータは実行時にスイッチする仕組みを入れてもよいが、どうせ書き換えが必要な ID があるし、実行時の if スイッチが増えるのはバグが増えるのと同義なので、build 時に書き換えができるようにすればよい
具体的な方法
- パラメータの詰まった JSON を用意する
- gas-project.json などはこの 1 の JSON と template をもとに upload 前に生成する
- Browserify で実行コードを生成する際に、1 で用意した JSON から必要な環境の分だけを抽出した JSON を生成し、これを require する
これで実行時に必要なパラメータは実行時にコードの中に詰まっている状態になる。秘密情報でなければこの方法で埋め込んでしまうのがリーズナブルな解決方法だと思う。
gas-project.json の template は以下のような感じ。{{mustache}}
gas-project.json.mjs
{
"src": {
"fileId": "",
"files": {
"<scriptname>": {
"path": "src/code.js",
"type": "server_js"
}
}
}
}
パラメータの詰まった JSON はこんな感じ。
gas-components.json
{
"production": {
"fileId": "",
"targetBook": ""
},
"staging": {
"fileId": "",
"targetBook": ""
}
}
全体像を図にすると以下のような感じ。
Promiseを受け取るコードの練習が狙い
今回のコードは裏では動作の確認はしてるけど全体的には雰囲気を味わうものです。Promise がなんだかよく分からないので適当に sleep して返事を返すだけのサーバをでっち上げて、これまた普段使っていないのになぜか jQuery.deferred から試してみてます。既存の道具からのステップを小さくしておくことで理解しやすくなることを狙います。
また Promise そのものや Promsie を作る部分は注目してません。あくまで Promise を利用するのはそんなに難しくないな、という雰囲気を知るためのものです。
Node.js に詳しい人は 2015年リリースの v4 から使えるので、いちいち遠回りする必要はないと思いますし、すでに動いているコードを今回のように書き換える意味はないと思います。
jQuery.deferred
jQuery.Deferred() | jQuery API Documentation
まずは jQuery.deferred で実験。
実は jQuery はかなり古い 1.5 の時代から Deferred という機能を持っていて、ajax() や getJSON() などはこの Deferred オブジェクトを返しています。そしてこの Deferred オブジェクトが Promise とよく似た動作をします。ただし fail() は jQuery 用語で、ES2015 だと catch() になります。
1) 単純な成否
$.getJSON('/api1')
.then(function() {
// success
})
.fail(function() {
// failure
});
これだけだと if then else のように動く。
2) エラーをまとめて拾う
$.getJSON('/api1')
.then(function() {
return $.getJSON('/api2');
})
.fail(function() {
// failure for api1 and api2
});
then() の中で非同期処理を実行して「Promiseを返せば」どちらで失敗しても同じ fail() を通過する。
3) 異なるPromiseのをエラーを別々に拾う
$.getJSON('/api1')
.then(function() {
$.getJSON('/api2')
.then(function() {
// success
})
.fail(function() {
// failure for api2
});
})
.fail(function() {
// failure for api1
});
非同期ではあるけど if then の入れ子のような感じで書ける。中の fail() でエラーを拾っておけば外の fail() まで伝播することはない。
Promise ( ES2015 )
今度は jQuery のように使えて jQuery より小さいけど、Deferred を持っていない UmbrellaJS を使ったうえで、Promise の部分だけ ES2015 で補います。
※ IE 対応が必要な場合はトランスパイラや Polyfill が要ります。
まずはjQuery の $.getJSON() とほぼ同じ動きをして Promise を返す wrapper 関数 u.getJSON() を定義します。1ES2015 の Promise は jQuery.deferred と違って失敗時は catch() で拾います。
※ くりかえしますが、実際のプロダクトではこんなコードは必要ないです。
wrapper
u.getJSON = function(url) {
return new Promise(function(resolve, reject) {
u.ajax(url,
{method: 'GET'},
function(err, data) {
if ( err ) {
reject(err);
} else {
resolve(data);
}
}
);
});
}
1) 単純な成否
u.getJSON('/api1')
.then(function(data) {
// success
})
.catch(function(e) {
// failure
console.log(e + ' : api failed.');
});
2) エラーをまとめて拾う
u.getJSON('/api1')
.then(function() {
// success
return u.getJSON('/api2');
})
.catch(function() {
// failure for api1 and api2
});
3) 異なるPromiseのエラーを別々に拾う
u.getJSON('/api1')
.then(function() {
u.getJSON('/api2')
.then(function() {
// success
})
.catch(function() {
// failure for api2
});
})
.catch(function() {
// failure for api1
});
参考
- 爆速でわかるjQuery.Deferred超入門 - Yahoo! JAPAN Tech Blog
- JavaScript の Promise: 概要 | Web | Google Developers
- あなたが読むべきJavaScript Promises - JSer.info
- JavaScript Promiseの本
応用編
ちなみに u.ajax() は特に指定しなくても JSON string だったら自動的に parse してくれる謎機能が付いてます。 ↩
「アクセス」がそれなりの数あるということなのか Lv 36 にはなったけど、「評価」がグッと下がった。次は「話題度」が下がるかな? 話題になんかなってないよ。
ただ急激に増減することのない購読数の 144やクリップ数の 376は自分で思っていたよりは多い。塵も積もればこれくらいにはなるんだなー。
時代は RSS リーダーとアフィリエイトなのに、どうも書いているときはそういうことはあまり意識していないのでとりあえずそのまま書いちゃって、公開し終わってふーっと一息ついたあとに慌てて amazon のアフィリエイトを引っ張り出してきてるオレがいるorz
こんなんじゃうまいこと誘導できっこねーよなぁ。明らかにあとから amazon へのリンクが増えてるんだもの。 RSS の更新を監視してればすぐにどういう意図をもって記事を修正しているかバレる。もっとこう、書いてる最中から文章を解析してそれっぽい商品を検索しまくって教えてくれる機能とか tDiary にあればいいのに。あれですよ、Ajax ですよ。書いてる裏で検索して textarea の隣とかにバババっと商品が出てくるの。そんでよーしこれとこれ買わせちゃれ、ってポチポチしていくとそいつらが文章の中にうまいこと埋め込まれていくの。
もちろんこれらのリクエストは「よーしパパあさましエントリ書いちゃうぞー」って意思表示したときだけね。なんかそういう checkbox があるの。そこチェックするとバババって出てくるの。普段からそんなリクエスト飛ばしまくってるとうざいからね。意思表示したときだけね。
出ないかなぁ、そういうの。
「それ以前に影響力のあるblogじゃないじゃん」ていうツッコミはなしね。単に楽したいってだけの話だから。あと、サイドバーとかタイトルのすぐあととか、エントリの切れ目とかに自動的に入るやつにすれば?ってのも却下。あれは自分が読むときうざいだけだから。あくまでうまいことエントリに馴染んでないとダメなの。そういうのが美しいと思うから。
日立 水をためない洗濯機 (@2ch.net)
229 :目のつけ所が名無しさん :2005/04/14(木) 19:57:02
節水できる、に釣られて買ったビートウォッシュ。
黒い綿シャツが綿埃と糸くずで白っぽくなるし、
これまで何度も洗ってたタオルがTシャツに色移り。
(衣類を擦り合わせるかららしいが……)
一週間で返品、他機種に交換しました。
265 :目のつけ所が名無しさん :2005/06/09(木) 09:43:16
ビートウォッシュ使ってますが、ノーマルモードでは糸くず(綿埃のようなもの)が
衣服に残るので注水すすぎなどを使って回避しています。節水の意味がないな。
大量の水にくぐらせないので糸くず系の汚れが落ちないという話。
洗濯する前に手で取れるような汚れは落としておけってことだよな、逆に言うと。考えたら洗濯の基本というか。
Re:非常に素朴な質問。 (MasterCardなどのカード情報4000万枚分が大量流出@/.-j)
なるへそ。この von_yosukeyan 氏は以前からスラド日記でたくさん金融系の話を書かれていてすげーなぁとは思っていたんだけど、今後もちょこちょこ勉強させてもらいます。
乗っちゃったのですが…。うなぎのぼりなんですよ最近。なんか以前より平均ストローク上がってるし。頑張りすぎですか。別に Orca 目的で余計なことしてるわけじゃないんですけどね。まーよくやった、おれ。頑張れ、おれ。頑張りすぎるな、おれ。