読者です 読者をやめる 読者になる 読者になる

help-formatter#add-argument! についてなにか書いてみる

scheme

比較的よく書けたな〜って思う help-formatter-add-argument! について書いてみる。

(define-method help-formatter-add-argument! ((self <help-formatter>) (action <argument-action>))
  (unless (equal? (help-of action) +suppress+)
          (let* ((get-invocation# (ref self format-action-invocation))
                 (invocations# (hash-table-get get-invocation# action)))
            (map (lambda (subaction)
                   (push! invocations# (hash-table-get get-invocation# subaction)))
                 (help-formatter-iter-indented-subactions self action))
            ;; アイテムの最大長を更新します。
            (let* ((invocation-length# (fold max 0 (map string-length invocations#)))
                   (action-length# (+ invocation-length# (ref current-indent self)))
                   (action-max-length# (ref action-max-length self)))
              (set! (ref action-max-length self) (max action-max-length# action-length#)))
            (help-formatter-add-item! self (ref format-action self) `(action)))))

define-method は後で書くことにして (equal? (help-of action) +suppress+) について。
unless で囲まれているので、(help-of action) の戻り値が +suppress+ じゃない場合に以降の処理を評価する。

+suppress+ のような + のイヤーマフ*1の付いたシンボルは定数*2であることを示す。
この定数は argparse.scm のかなり上の方で定義されており:

(define-constant +suppess+ "==SUPPRESS==")

となっている。
これがどういった意味を持つのかは不明。

let 変数の末尾の # は Clojure がそう書いていたので書いてみた。 今気づいたんだけど、get-invocation# の:

(ref self format-action-invocation)

は:

(help-formatter-format-action-invocation self action)

なんじゃないかと思ってきた。
でも、見なおしたら違ったので format-action-invocation というスロットを新たに書かないといけない。

次の:

(map (lambda (subaction)
       (push! invocations# (hash-table-get get-invocation# subaction)))
     (help-formatter-iter-indented-subactions self action))

Ruby で書くと:

self.indented_subactions.map do |subaction|
  invocations.push get_invocation[subaction]
end

とおそらく同じ。
おそらくなのは help-formatter-iter-indented-subactions を書いていないのでw
get-invocation#lambda だってことも考えられるのでうにょーん。
help-formatter-iter-indented-subactions はインデントされているサブアクションをのリストを返しそうなので map にしたんだけど…違うおそれもあるよね……( ◞‸◟)
itr とか書いてあるし…δ(・ω・`)ウーン…

それじゃ次:

;; アイテムの最大長を更新します。
(let* ((invocation-length# (fold max 0 (map string-length invocations#)))
       (action-length# (+ invocation-length# (ref current-indent self)))
       (action-max-length# (ref action-max-length self)))
  (set! (ref action-max-length self) (max action-max-length# action-length#)))

invocation-length# の値である (fold max 0 (map string-length invocations#)) は何をするか分かるかな?

(l ω l〃) わかるー!
╰( ´◔ ω ◔ `)╯ そりゃお前はな…

じゃあ、サンプルコード:

(let ((invocations '("help" "version" "quiet" "verbose")))
  (fold max 0 (map string-length invocations)))

は文字列のリストの各要素の文字列長で最大の値を返すよ。

7

まあ、そんな感じで。

*1:小須田部長が付けているような耳あてのこと。

*2:正確にはユーザー定義の定数。