Skip to content

Latest commit

 

History

History
591 lines (505 loc) · 26.9 KB

20210703105033-archive.org

File metadata and controls

591 lines (505 loc) · 26.9 KB

Archive

:header-args+: :results output :wrap

概要

単発の発表用原稿などを置く。

発表用フォントサイズセット。

Memo

Tech Nightスライド <2021-10-08 Fri>

(org-timer-set-timer 5)

発表用フォントサイズ。

★伝えたいこと★

コードのメモをするとき、 コメント/コード/実行結果を1つにまとめる とわかりやすい。

→ うまくやるための道具があります。

自己紹介

貴島 大悟 資格スクエア プログラマー

外観は もう中学生 (吉本興業のお笑い芸人)に似ているようです。

2つの方法

2つの方法があります。

  • gem(ライブラリ)
  • 外部ツール

gem編 xmpfilter で実行結果を出力する方法

  • Rubyには実行結果をコードに出力するgemがある
  • Ruby gem rcodetools/rcodetoolsに同梱されている
names = %w[aaa bbb]             # => ["aaa", "bbb"]
e = names.to_enum               # => #<Enumerator: ["aaa", "bbb"]:each>
e.class                         # => Enumerator

外部ツール編

(Markdownに読み替えても同じことができるはずです)

  • クラスが定義するインスタンスメソッドを調べる方法
p Enumerable.instance_methods.sort

SQLもわかりやすくなる

:header-args+: :engine postgresql :header-args+: :dbhost localhost :header-args+: :dbuser postgres :header-args+: :dbpassword postgres12345 :header-args+: :database dsdojo_db :header-args+: :results table
  • (とくにSQLは実行結果が出ないとコードを把握しにくい感じがします)
  • TO_CHAR を使って日付→文字列へ変換する
SELECT customer_name, customer_id, TO_CHAR(birth_day, 'YYYY年MM月DD日')
FROM customer
LIMIT 10

まとめ

  • コードのメモは文脈がなく、後から見て意味不明、ということがよくある
  • メモ実行コード実行結果 を同じ場所に書くとわかりやすい
  • だが普通にやるとめんどくさい
  • ツールでかんたんにできる

࿐おわり࿐

ご清聴ありがとうございました。

textlint-plugin-orgプラグイン発表用スライド <2021-07-02 金>

TextLint GitHub - kijimaD/textlint-plugin-org GitHub - textlint/textlint

textlintのプラグインを作成しました。 npmに登録+公式のREADMEにリンクしました。 npm install textlint-plugin-org

orgファイル(Emacs独自のアウトライン形式)で使えるようにしました。 (orgデモ)

TextLintの説明

TextLintはその名の通り自然言語用のLintです。 単純な間違いや、わかりづらい言い回し、語数制限などを検知してくれます。たくさんルールがあって面白いです。

Markdownは標準、ほかにもHTMLなどは対応してます。

対応してないフォーマットの場合、たとえば見出しで がないとか、コードブロックに対して検知をしてまともに使用できません。

どうしても orgで使いたかったので作成することにしました。

Lintについて学ぶ

https://azu.github.io/JavaScript-Plugin-Architecture/

中段の動作イメージがとてもわかりやすい。

AST変換というのが重要だということがわかります。

ESLintはコードをパースしてASTにして、そのASTをJavaScriptで書いたルールを使いチェックするという大まかな仕組みは分かりました。

textlint-plugin-org/test/OrgProcessor-test.ts テストから実際にASTオブジェクトの中身を見てみます。

    it('heading should Header', () => {
      const result = parse(`
** Heading
      `);
      const section = result.children[0];
      const header = section.children[0];
      assert.equal(header.type, Syntax.headline);
    });

console.log(section)

{
    type: 'UNKNOWN',
    level: 2,
    properties: {},
    children: [
        {
            type: 'Header',
            actionable: false,
            content: 'Heading',
            children: [Array],
            level: 2,
            loc: [Object],
            range: [Array],
            raw: '** Heading\n'
        },
        type: 'UNKNOWN'
    ],
    loc: { start: { line: 2, column: 0 }, end: { line: 3, column: 0 } },
    range: [ 1, 12 ],
    raw: '** Heading\n'
}

console.log(header)

{
    type: 'Header',
    actionable: false,
    content: 'Heading',
    children: [
        {
            type: 'UNKNOWN',
            level: 2,
            loc: [Object],
            range: [Array],
            raw: '**'
        },
        {
            type: 'Str',
            value: 'Heading',
            loc: [Object],
            range: [Array],
            raw: 'Heading'
        },
        { type: 'UNKNOWN', loc: [Object], range: [Array], raw: '\n' },
        type: 'UNKNOWN'
    ],
    level: 2,
    loc: { start: { line: 2, column: 0 }, end: { line: 3, column: 0 } },
    range: [ 1, 12 ],
    raw: '** Heading\n'
}

Lintは、このASTオブジェクトのTypeに基づいてそれぞれのルールを適用してます。 なので見出しの星は対象外にできます。

AST変換器を調べる

  • ファイル形式の文字列 → (ここが必要) → AST → Lint

やる必要があるのは、オブジェクトの形式を揃えることです。 typeの名前がtextlintに対応したシンボルへマッピングします。

変換器はすでにあります。

orgajs
https://github.com/orgapp/orgajs

なので、本質的に必要なことはこのマッピングです(ほかにも位置や範囲を付加する必要がありますが、HTMLとかとほぼ同じ)。

export const nodeTypes = {
  document: ASTNodeTypes.Document,
  paragraph: ASTNodeTypes.Paragraph,
  list: ASTNodeTypes.List,
  'list.item': ASTNodeTypes.ListItem,
  headline: ASTNodeTypes.Header,
  block: ASTNodeTypes.CodeBlock,
  hr: ASTNodeTypes.HorizontalRule,
  // inline block
  'text.plain': ASTNodeTypes.Str,
  'text.code': ASTNodeTypes.Code,
  'text.bold': ASTNodeTypes.Emphasis,
  link: ASTNodeTypes.Link,
  footnote: 'FootnoteReference',
};

テストを書く

orgajsがどんな名前で出力するかは実行しないとわからなかったので、ちゃんとすべてテストを書いて調べました。上流の不慮の変更も検知できます。

ということで使えるようになりました🎉。

便利です。

まとめ

Emacsエコシステムを少し広げることができました。

digger発表用スライド <2021-07-02 金>

digger

やっていること(途中)

GitHub - kijimaD/digger CLIのゲームを作っています(WIP)。

(デモ)

まだ移動しかできない。

前回の反省を踏まえた要件

  • 画像表示はあきらめる or 見下ろし
  • ターン制にする。リアルタイムではなく。
  • テストを書く(テストが書ける構造にする)

利点

時代に逆行した開発ですが、よいところもあります。

  • 真のRubyだけに集中できる(ライブラリすら必要ではない。CLI用のCursesくらい)
  • オブジェクト指向をやらなければならない状況。ゲームそのものがゲームオブジェクトの相互作用なので、オブジェクト指向でないと条件ありすぎて死ぬ。フツーに命令的に書けるプログラムが二者間だとしたら、ゲームは三者間。
壁に当たるのは自キャラだけでない。敵キャラや銃弾も当たる。各オブジェクトに判断してもらわないといけない。
弾がヒットしたら、誰のスコアになるのか => その銃弾オブジェクトを生成したキャラクターオブジェクト。みたいな。
毎ターンフィールドにあるすべてのオブジェクトを更新+新描画したい => すべて入れ物オブジェクトに入れておいて、mapですべてを一括処理しよう、とか。

まとめ

1ヶ月くらい頑張ってみます(宣言)。

ボツ

ローグライクになる予定です。↓みたいなゲーム。超好きなジャンルです。

Cataclysm-DDA
ゾンビサバイバル 参考
Dwarf Fortress
サバイバル/シミュレーション 参考
Elona
RPG風 参考

これらは商業的な作品ではなく、貧弱なグラフィックですが、超濃密なゲーム世界を作り上げています。 個人がめざす(めざせる)のはこういう方向性だと考えてます。

前回の反省

仕事につく前、何度か作りはじめては挫折してきました。

直近だと去年開発してましたが、開発が進まなくなってやめました↓。

GitHub - kijimaD/ban-ban-don
rubyのゲームライブラリGosuを使った、シューティングゲーム。
  • (本に載ってたコードをベースに開発しました。根本部分のコード構造はほとんどオリジナル性ないです)

これの問題点、挫折した理由…。

  • 要件を高望みしすぎた。
    • 疑似3Dにした。座標に、ひし形の画像を敷き詰めると疑似3Dができます…画面確認が大変だった。特に重なりとか、接触判定が…。
    • アニメーションする画像の用意が大変すぎた。方向分の画像を作る必要がある。
    • リアルタイムなので再現しにくい。
    • パフォーマンスを考えないとまともに動かなくなる。黒魔術がある(四分木とか)。
  • つらい目視確認開発。
    • 新機能を作るときも、いちいち起動して該当箇所までいって開発していた。
    • テストがない、lintがない(まだ知らなかった)
    • いつのまにかどこかが壊れて動かなくなること多数

=> ムリ \(^o^)/

create-link 発表用スライド

Emacsパッケージ(#2)を作りました。

https://github.com/kijimaD/create-link

作ったもの

Chrome拡張CreateLinkをEmacsに移植した

CreateLink というChrome拡張があります。

それのEmacs版を作成しました。 公式パッケージ集での審査中(まだ返信来ない)。

元になったCreateLinkの説明🔗

現在のページの名前のついたリンクを取得する拡張です。GitHubとかSlackに貼り付けるとき、便利なやつです。

  • CreateLinkのリンク(Chromeウェブストア)

https://chrome.google.com/webstore/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm?hl=ja

  • 例: Markdownリンクだと、

https://www.google.com ->[Google](https://www.google.com/) みたいな。

(ブラウザのデモ)

作成したcreate-linkの紹介

  • Emacs上の各種ブラウザeww, w3m
  • 各種フォーマットHTML(default), LaTeX, Markdown, MediaWiki, Org-mode
  • ブラウザ以外のときはローカルファイルのパスを取得する

に対応してます。

(実行・オプション操作のデモ)

コード

ライセンスの部分を除くと、90行くらいしかありません。

半分くらいはユーザ設定のための決まりきった記述のため、実際は40行ほど。

;;; Code:

(require 'eww)
(require 'w3m)

(defgroup create-link nil
  "Generate a formatted current page link."
  :group 'convenience
  :prefix "create-link-")

(defcustom create-link-default-format 'html
  "Default link format."
  :group 'create-link
  :type '(choice (const :tag "html" html)
                 (const :tag "markdown" markdown)
                 (other :tag "org" org)
                 (other :tag "media-wiki" media-wiki)
                 (other :tag "latex" latex)))

;; 🌟オプション設定

;; Format keywords:
;; %url% - http://www.google.com/
;; %title% - Google
(defcustom create-link-format-html "<a href='%url%'>%title%</a>"
  "HTML link format."
  :group 'create-link
  :type 'string)

(defcustom create-link-format-markdown "[%title%](%url%)"
  "Markdown link format."
  :group 'create-link
  :type 'string)

(defcustom create-link-format-org "[[%url%][%title%]]"
  "Org-mode link format."
  :group 'create-link
  :type 'string)

(defcustom create-link-format-media-wiki "[%url% %title%]"
  "Media Wiki link format."
  :group 'create-link
  :type 'string)

(defcustom create-link-format-latex "\\href{%url%}{%title%}"
  "Latex link format."
  :group 'create-link
  :type 'string)

(defun create-link-raw-format ()
  "Choose a format type by the custom variable."
  (pcase create-link-default-format
    (`html
     create-link-format-html)
    (`markdown
     create-link-format-markdown)
    (`org
     create-link-format-org)
    (`media-wiki
     create-link-format-media-wiki)
    (`latex
     create-link-format-latex)))

(defun create-link-replace-dictionary ()
  "Convert format keyword to corresponding one."
  `(("%url%" . ,(cdr (assoc 'url (create-link-get-information))))
    ("%title%" . ,(cdr (assoc 'title (create-link-get-information))))))

(defun create-link-make-format ()
  "Fill format keywords."
  (seq-reduce
   (lambda (string regexp-replacement-pair)
     (replace-regexp-in-string
      (car regexp-replacement-pair)
      (cdr regexp-replacement-pair)
      string))
   (create-link-replace-dictionary)
   (create-link-raw-format))) ;; <a href='%url%'>%title%</a> とか。ループのinitial value。

;; <a href='%url%'>%title%</a>
;; <a href='https://...'>%title%</a> 前の値を保持
;; <a href='https://...'>Google</a> さらに置換

#+begin_comment
;; ここを綺麗に書くのが一番むずかしかった。...複数の文字列置換
;; 一つの置換(replace-regexp-in-string)は関数があるが、複数指定はできない。

;; (seq-reduce)の第一引数はコードブロックに相当するところ。ループ一回で何をするか。
;; stringはraw-format(<a href='%url%'>%title%</a>など)を受け取る。
;; regexp-replacement-pairはreplace-dictionaryのイテレーション分が入る。ブロック引数。
#+end_comment

;; 🌟ブラウザやその他をラップしてtitle, urlを返す!
(defun create-link-get-information ()
  "Get keyword information on your browser."
  (cond ((string-match-p "eww" (buffer-name))
         `((title . ,(plist-get eww-data :title))
           (url . ,(plist-get eww-data :url))))
        ((string-match-p "w3m" (buffer-name))
         `((title . ,w3m-current-title)
           (url . ,w3m-current-url)))
        ;; otherwise, create-link to the file-buffer
        (t
         `((title . ,(buffer-name))
           (url . ,(buffer-file-name))))))

;; 🌟エントリーポイント
;;;###autoload
(defun create-link ()
  "Create formatted link."
  (interactive)
  (message "Copied! %s" (create-link-make-format))
  (kill-new (create-link-make-format)))

(provide 'create-link)

;;; create-link.el ends here

知見

短くても問題なし

大きなパッケージに比べてこれはゴミみたいなもんだな、と思ってました。

でもコードやアイデアの参考にするため使っているパッケージのコードを眺めていて、こういう短いものでも自分が日々使ってたり、多くの人に使われているパッケージはけっこうあることに気づきました。

たとえば。

add-node-modules-path.el

  • node環境の読み込み 86行

org-bullets.el

  • リストをいい感じに表示する 109行

define-word.el

  • オンライン辞書 132行

rubocop.el

  • rubocopをいい感じに 267行
  • 重要なのは1つのことをうまくやること。

他の人に使ってもらえるとうれしい

使ってくれた+PRが来ました。 褒めてくれてテンション上がる。 kijimaD/create-link#7

I like this package, is simple and useful.

審査にむけてやったこと。

  • わかりやすいコンセプト。
  • 空気を読んだ動作をする、限られたインタフェース(create-link)という関数1つで、複数フォーマット・ブラウザに対応できる。
  • ちゃんとドキュメントを用意したkijimaD/create-link
  • オプションを用意した。フォーマットの種類やブラウザを増やすのは、とても簡単です。

ロードマップ

フォーマットリンクを取得するだけのシンプルなコードではありますが、拡張はいろいろ考えられます。

入出力のバリエーションを増やす

エクスポート形式増加 HTML,LaTeX,Markdown,MediaWiki,Org-mode
ユーザ定義のフィルター … chromeの拡張の方にはある
PDF(ページを取ることはできそう。リンクでページ番号を表現できるか)
やらない。

コンテクストによる動作のバリエーションを増やす

テキスト選択中だと、タイトルに選択したところを入れる
選択URLにアクセスして、Titleをスクレイピング。リンクを完成させる
手動で形式選択できるように
helmから選べたらベスト。選択をどうやってやればいいのかよくわからない org-roamのファイル選択で出てくるhelmなど参考になりそう。
とりあえず標準のcompletionだけ追加
checkdocをCIで走らせるようにする
elisp-checkはcask環境のためうまくできない。 なので、elisp-check.elを直に読み込んで実行するようにすればよさそう。

elisp-lintというパッケージに同梱されてたのでそれで一気にできるようになった。

テスト追加 + CI

ユーザの拡張性を増やす

フックを追加…たとえばリンク生成 → {フック} → コピー前としておく。
フックでは式が使えるのでなんでもできる。動的にタイムスタンプを加えたり、連番を振ったりとか。単なる文字列フィルターよりはるかに強力。誰かがもっと便利な使い方を編み出してくれる。

make-formatと、message+killの前にフックを差し込むか。 でも、文字列を受け取れないからあまり意味ない気がしてきた。 フックはその処理に追加するというより、別の処理を差し込むためのものだ(ある関数を実行すると、別の全く関係ない)モードをオンにするとか。その意味でいうと、フックする処理はまったく思いつかない。

リンク変換
別のフォーマットに変換するのもあっていいな。 すでに書式があるから、そこからURL, Titleを取り出せればいい。
  • 判定関数

thing-at-pointの拡張だな。フォーマットリンク上にカーソルがある場合、タイトルとURLを取得して変換…。 どのフォーマットか判定できれば、タイトルとURLを取れる。 markdown-mode.elの(markdown-kill-thing-at-point)が参考になりそう。

別に独自実装しなくても、各modeのregexpを使えばいいかな。いや、フル装備でめちゃくちゃ複雑だし、いろんな依存(5つも増えるのはさすがに…)があるので独自でやろう。 https://ayatakesi.github.io/emacs/25.1/Regexps.html

フォーマットごとの特殊ルールを追加する
たとえばlatexの場合、ファイルリンクにはプレフィクスrun:がつくらしい。 今のコードだとファイルリンクだという検知はget-informationでしかできないのでそこに書くしかない。 一般的関数に特定のファイルフォーマットの処理が挟まれると非常に醜い。 なので、最終的な個別変換を分離する。そうするとhtmlがついてないときはrunをつけるとか、好きに追加できるだろう。
Magit(Gitクライアント)の場合。(すでにGitHubリンクの生成はある)

git-link の整形バージョン。 そこまではちょっとやりすぎ感。依存が増えすぎるのも微妙な感じか。でも欲しいよな…。 各PRまではいいけど、少なくともリポジトリのホームページくらいならいいかな。

シェルだったらカレントディレクトリを取る

ブラウザみたく、変数が用意されてはない模様。まあこれについてはあまりいらないか。 パスを取得したいときはあるけど、それをhtmlリンクにしたいってあまりないしな。

パスはdefault-directoryで取れる。

タイトルはないときバージョンを作るか

つまりパスだけ。 主題とはずれる気がする。シェルとかだとタイトルの取りようがないのでこれを追加するのが必要。

Gitリポジトリのときは、相対ディレクトリを取得するオプション

リポジトリからリンクを辿れるようになる。でもEmacs上でどうなんだろう。 辿れないけど、人にディレクトリを示すときには使える。今は絶対パスで取って前のを削除している。めんど い。 うむむ。リモートリポジトリのURLがわかるなら意味はありそう。git-linkとあまり変わらないけどな。 git-linkのコードを見てるけど、まだあまりよくわからない。

ホームディレクトリを~で出すようにする

今は /home/kijima... で出てるからな。汎用性があまりよくない。あとで絶対変わるし、ほかで使えない。

実行関数を出力

たとえばivyのinfoページにいたとする。(info “ivy”) を出力する。 これを実行するとivyに飛べるので、リンクといえそう。環境も関係ない。

infoバッファからの検索キーワードの割り出し方… 実行ディレクトリをdefault-directoryか何かで取る。(.*).infoというファイルがあるはずなのでそのファイル名をinfoの引数に渡す。

まとめ

  1. 移植技を覚えました。要件が明確+元ソースを読むことができると楽。プログラムに集中できて美味しい。
  2. ちょっとした不便さは少ないコードで解決できる。
  3. ごく単純なコンセプトでも、拡張の方向性は意外と多いです。

おわり。