Archive

概要

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

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

Memo

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

(org-timer-set-timer 5)

発表用フォントサイズ。

★伝えたいこと★

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

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

自己紹介

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

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

2つの方法

2つの方法があります。

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

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

names = %w[aaa bbb]             # => ["aaa", "bbb"]
e = names.to_enum               # => #<Enumerator: ["aaa", "bbb"]:each>
e.class                         # => Enumerator

外部ツール編

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

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

[:all?, :any?, :chain, :chunk, :chunk_while, :collect, :collect_concat, :count, :cycle, :detect, :drop, :drop_while, :each_cons, :each_entry, :each_slice, :each_with_index, :each_with_object, :entries, :filter, :filter_map, :find, :find_all, :find_index, :first, :flat_map, :grep, :grep_v, :group_by, :include?, :inject, :lazy, :map, :max, :max_by, :member?, :min, :min_by, :minmax, :minmax_by, :none?, :one?, :partition, :reduce, :reject, :reverse_each, :select, :slice_after, :slice_before, :slice_when, :sort, :sort_by, :sum, :take, :take_while, :tally, :to_a, :to_h, :uniq, :zip]

SQLもわかりやすくなる

  • (とくにSQLは実行結果が出ないとコードを把握しにくい感じがします)
  • TO_CHAR を使って日付→文字列へ変換する
SELECT customer_name, customer_id, TO_CHAR(birth_day, 'YYYY年MM月DD日')
FROM customer
LIMIT 10
customer_name customer_id to_char
大野 あや子 CS021313000114 1981年04月29日
六角 雅彦 CS037613000071 1952年04月01日
宇多田 貴美子 CS031415000172 1976年10月04日
堀井 かおり CS028811000001 1933年03月27日
田崎 美紀 CS001215000145 1995年03月29日
宮下 達士 CS020401000016 1974年09月15日
奥野 陽子 CS015414000103 1977年08月09日
釈 人志 CS029403000008 1973年08月17日
松谷 米蔵 CS015804000004 1931年05月02日
安斎 遥 CS033513000180 1962年07月11日

まとめ

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

࿐おわり࿐

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

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 金>

やっていること(途中)

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)を作りました。

作ったもの

  • 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が来ました。 褒めてくれてテンション上がる。 https://github.com/kijimaD/create-link/pull/7

    I like this package, is simple and useful.

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

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

ロードマップ

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