以下に書いてあるとおり。
基本的に sudo do-release-upgrade
を叩いただけ。sshd の config を置き換えていいかみたいなことを聞かれたので、触った覚えがないので不安を覚えつつ置き換えた。後は、質問に答えながら延べで数時間放置していたら終わっていた。
たしかに新しくはなったが、何が変わったかわからないレベル。 emacs がなぜか無くなっていたようなので、
$ sudo apt install emacs25-nox
した。今のとこそのくらい。
songmu さんの WEB+DB の記事を読むのが良い。
リリーステストで、
Hoge.pm requires 5.010 due to explicit requirement
で死んだときは Perl version 指定が正しいか確認する。 //
とか使ってると 5.8 系はサポートできないというか、流石に 5.8 系は平成半ばにしてすでに終わっているのではないか。
xt/minilla/spelling.t ......... skipped: no ~/.spellunker.en
が出てたときは touch ~/.spellunker.en
するとPODのスペルチェックもやってもらえる。
.circleci/config.yml
に以下のように書いておいたら、ある時からキャッシュが効かなくなってハマった。
version: 2 jobs: build: docker: - image: perl:5.28 steps: - checkout - restore_cache: key: cacheminil-v1 - run: name: Install Minilla command: | cpanm Minilla - save_cache: key: cacheminil-v1 paths: - "/usr/local/bin" - "/usr/local/lib/perl5/site_perl/5.28.0" ..以下略..
正しくは以下。いつまでも 5.28.0
のままではないのだ。
paths: - "/usr/local/bin" - "/usr/local/lib/perl5/site_perl"
本当は - image: perl:5.28.0
を指定したいところだが、残念ながら https://hub.docker.com/_/perl を見てもない。
https://hub.docker.com/_/mariadb
10.2 の方では、 MYSQL_USER
で test_
データベースを作れない。
mariadb:10.2
の mysql.db
。
MariaDB [mysql]> SELECT Host, Db, User, Create_priv FROM db; +------+--------------+----------+-------------+ | Host | Db | User | Create_priv | +------+--------------+----------+-------------+ | % | hogehoge_dev | hogehoge | Y | +------+--------------+----------+-------------+ 1 row in set (0.00 sec)
mariadb:10.3
の mysql.db
。
MariaDB [mysql]> SELECT Host, Db, User, Create_priv FROM db; +------+--------------+----------+-------------+ | Host | Db | User | Create_priv | +------+--------------+----------+-------------+ | % | test | | Y | | % | test\_% | | Y | | % | hogehoge_dev | hogehoge | Y | +------+--------------+----------+-------------+ 3 rows in set (0.000 sec)
なんで違うのか調べてもわからなかった。 mariadb:10.3
の挙動が意図的なのかデグレってるのかも。
django ではURLのルーティングを django.urls パッケージで処理している。このパッケージのソースはなかなか読みにくいので、読むための手がかりを記しておく。
バージョンは2.1を仮定していることに注意1。
django.urls
パッケージでは継承もインタフェースも使っていないダックタイピングの見本のようなコードになっており 2 、この点が読みにくくしている一番の要因である。しかも、歴史的な都合なのか、クラスの命名規則にも致命的なわかりにくさが存在している。まずは主要なクラスの構造を説明することで見通しを良くする。
いちばん重要な概念はリゾルバである。リゾルバは自分が解決すべきURL ( PATH_INFO
)と、その解決方法を知っているデータである。 resolve()
メソッドを提供し、入力されたURLに合致するビュー 3 を返す。リゾルバは木構造をなしており、以下の2種類がある。
URLResolver
は他のリゾルバを含むリゾルバである。最上位のリゾルバは URLResolver
となる。また、 path
関数で include
を指定したときにも生成される。
一方、 URLPattern
は末端に位置するリゾルバで、ビューを保持している。 path
関数でビューを指定したときに生成される。
「自分が解決すべきURL」は、パターンクラスによって表されている。
パターンはリゾルバに付属する。URLが自分が扱うべきものであるかを判定し、さらにビューに必要なパラメータを抜き取ることができるクラスである。 match
メソッドを提供し、マッチ後に残ったURL、抽出したパラメータ ( args
または kwargs
)を返す。以下の3種類があるが、 URLPatternはパターンではない ことに注意する。
RegexPattern
はおそらく django 1.x 系の頃使われていたもの。今でも re_path
によって生成することはできるが、利用する必要はないだろう。
RoutePattern
が通常使われるもので、 path
関数を使ってパターンを記述すると生成される。結局入力されたパターン文字列は正規表現に変換されるが、 re_path
のように正規表現で直接記述するよりはわかりやすい記述が可能と言えよう。
LocalePrefixPattern
は特殊なもので、 i18n 対応でURLの先頭に言語 /ja/...
/en/...
などをつけるときに使われる。マッチする文字列は現在の言語設定によって異なる。例えば、現在の設定が日本語の場合、 ja/
という静的な文字列にマッチするパターンとして振る舞う 4 。このパターンを含め、URLの i18n 対応は無理やり突っ込んだ感がかなりある。例えば、このパターンは最上位のリゾルバにしか指定できないが、その判定も include
を使った構築時に 配下となる予定のリゾルバがこのパターンを使っていないかをチェックする と言っただいぶ強引な方法で判定している。後、URLの先頭に含まれる静的な文字列 ja/
は URLの先頭に含まれる文字列から決まったりする のだが、卵が先か鶏が先かよくわからない。国際化対応の実装は他にやりようがなかったんだろうか・・・。
与えられたURLを処理するビューと呼び出しに使うパラメータを得るための resolve
関数のコードを見ると、 最上位のリゾルバに依頼するだけ 。とてもシンプル。他の箇所もこれくらい読みやすければ文句がない。
念のためリゾルバ内の resolve
も読んでみると思ったより長くてウッとなるが、実際は 再帰的にresolveを呼び出している だけ。リゾルバのクラスが成す階層構造さえ知っていれば怖いことはない。ただし、ここにでてくる変数 pattern
は パターンではなくリゾルバ なので注意が必要(自分でも何を言っているかわからない)。
reverse
は resolve
の逆で、ビューの名前と呼び出し時に使うパラメータからURLを生成する。こいつもリゾルバに依頼すれば終了なのではないかと 淡い期待で読み始める と、全くそうではない難解なコードであることがわかる。なんでリゾルバに reverse
させないの・・・マジなの・・・?
reverse
関数内では、リゾルバの階層を潜ってビューを持つ URLResolver
を得る 5 。このとき、途中で現れたパターン(を表す正規表現)を拾う 6 。得られた URLResolver
は 新しいURLResolverでラップされる 。この URLResolver
は集めておいたパターン(正規表現)に紐付けられるので、新しい URLResolver
は完全なURLを再構築できる。
reverse
関数がリゾルバの階層を潜るには URLResolver
が持つ reverse_dict
という辞書が必要になるが、この辞書は _populate というメソッドが生成する。実質、 _populate
が逆引きロジックの本丸になっていると言え、非常に重要な役割を果たすメソッドである。
URLの再構築は、新たな URLResolver
の _reverse_with_prefix メソッドが行う。なんとプライベートメソッドである・・・。このメソッドは一見長いが、 reverse_dict
に入っている再構築に必要な情報を元にURLを再構築し、 パターンに適合するURLができたかをチェック した上で返すだけである。
ということで、URLの再構築に必要な情報は _populate
の中で構築される。 _populate
の実装を見てこのエントリは終わることにしよう。 _populate
は配下のリゾルバをすべて読み込み(再帰的に _populate
が呼ばれる)、ビュー名 ( path
の name
引数)をキーとする辞書を作る。これが reverse_dict
で、 reverse
関数が URLResolver
を見つけるために用いる。
そして、この辞書の値がURLの再構築に必要な情報である。値にはパターンの正規表現(検証用)、引数のデフォルト(穴埋め用)、コンバータの一覧が含まれるが、一番重要なのは正規表現を normalize関数 で変換したフォーマット文字列と引数リストである。例えば <int:year>/<int:month>
のような RoutePattern
からは (?P<year>[0-9]+)/(?P<month>[0-9]+)
のような 正規表現が作られる が、この正規表現から '/%(year)s/%(month)s/'
のようなフォーマット文字列と ['year', 'month']
という引数リストが抽出される。 normalize
の実装は真面目に正規表現をパースしており、利便性のためとは言えここまで頑張るか・・・と思わせる実装になっている。この情報を使うことで、 _reverse_with_prefix
は URL を再構築できるというわけである。長かった。
ところで、 normalize
の戻り値は1つではない。これは、 ?
や *
など、 0 個を許すパターンにおいて、フォーマット文字列の該当する引数があるパターンとないパターンを場合分けする必要があるからだ。URL再構築時にはキーワード引数などからどの引数があるか、ないかをチェックし、利用するフォーマット文字列を決めることになる。また、 .
や [0-9]
などがパターンに使われている場合はいずれの文字を選んでもマッチするので、前者は .
、後者は 0
を含むURLが代表として構築される。
YAPC::Tokyo 2019 に来ましたので、自分用のメモを残します。
$scalar
"0 but true"
は文字列として表示できる
42
join ",", localtime
"".localtime
だと英語表記0+localtime
は 0
to_i
すればよい)say localtime
の出力はドキッとする (現在時刻の数字のリストが連結されて表示される)subset Fizz of Int where * %% 3
というように3で割れる型を作れる
MAIN()
関数がある
MAIN()
MAIN()
を使うと、コマンドライン引数の型チェックができるMAIN
関数を引数によって分けることもUSAGE()
関数を実装できる$*USAGE
に入っている#|
#=
宣言子ブロックで補足ができる#|
は関数の前、 #=
は関数の後open
で書ける.slurp
ファイルの中身を全部取る$fh.slurp
は IO::Handdle
のメソッド、 slurp ""
は IO
role が提供する関数
close
は必要ないspurt
で文字列を一括で書ける.lines
で行ごとに取得。 for
を使う.IO
で IO::Path
インスタンス
IO::Path
はファイルの情報を提供する .e
.d
.s
zef
コマンドでモジュールを管理できる
use
で使える。 require
も一応ある%*ENV
mi6
を使え$GOPATH
の下で開発を行う必要がある
go get
bin/
の下に実行ファイル、 src/
の下にソースmaster
の HEAD を取ってくるgo1
というブランチがあるとそれをみるが、ほとんど浸透していないgo get
使わないgo mod
glide
dep
go
mod
vgo
は go mod
なので要らないMinilla
ExtUtils::makeMaker
とかあって便利だったgo mod
で解決する?var
で型を指定するか :=
で型を推論させるか[]string()
、 map map[string]int
...
が可変長引数panic()
で発生、 recover
で受けるnil
と書くpanic
は推奨されない。コーディングミスとかだけrecover
するくらいが良いerror
インタフェースか、 bool
で返すfile, err = os.Create
、 err != nil
でエラー処理log.Fatalf
は終わるので return
は不要defer file.Close()
などとして終了処理defer
は Perl の Scope::Guard
のようなもの
dismiss
はできない)if
のスコープで defer
しないように注意file.Close
のエラー処理は本当はしないといけない
defer
へ無名関数を指定してエラー処理。面倒gorutine
は説明すると長いので1ページまとめ
context.Context
if
はカッコが要らないrange
使ったりwhile
はないswitch
break
がいあらないので、多少は安心goto
がある。 goto
がない言語は辛いCompiler::Lexer
Data::Validator
を使っている
PerlSubroutinDeclaration
で関数定義を引っこ抜けるPerlQualifiedIdentifier
クォートされてない識別子PerlBlock
ブロック(dothis $foo, $bar)
の評価
(dothis($foo), $bar)
dothis($foo, $bar)
のどれ($foo->dothis, $bar)
dothis($foo, $bar)
sub f { { hoge() => "fuga" } }
{}
はブロック? ハッシュreturn
を書く、ファットカンマの左辺値を文字列にする、 +
をつける、のいずれかで曖昧じゃなくなるreturn
書いたらいいのではないか/
use
BEGIN
など動かさないとわからないものは避ける
Moose
の has
などはそれを解釈する解析機を書けばいいPlack->request->param
を使わない(複数値を指定したときに問題)ResultSet->search
を array コンテキストで受けないcapture
ブロックで囲むと、それがセグメントになるPlack::Middleware::XRay
勝手にトレースが始まるDevel::KYTProf
Devel::KYTprof::Logger::XRay
ロガーを差し替えてX-Rayを送ってもらうAWS_XRAY_DAEMON_ADDRESS
別ホストを指定するX-Amzn-Trace-ID
に 1-[timestamp]-[unique_id]
という形式のIDcapture
を書くと、自動的に親が入っているlocal
を使っているlocal
context.Context
を引数に引き渡すctx
を渡せないと厳しいdir
使えないから ls
を作った話 ( readdir
がある・・・)L
ドキュメントを書いていたら、好意的に受け止められたcronlog
のkazuhoさんはすごいcpm
作者)npm i -S
git のリポジトリ指定ができる
package.json
さえあればうごくでしょうnpm install
でモジュールを落としてこれるデモsed
awk
より高機能。 ruby では足りないかな