私が歌川です

@utgwkk が書いている

おうちで学べるデータベースのきほん

Kindleでセールをしていたので買って読んだ。

SQLを書いてみましょう、分解法的な手法でテーブル設計をしてみましょう、みたいなところはだいたい知ってる内容だった。データベースを使う側としてのことよりも、運用する側としてのことの方があまりよく知らなかった。トランザクションとかバックアップの話あたりは一読しておくとよいと思う。

取っかかりとして読むのにはよいと思うけど、この本だけでデータベースの全てを理解するというわけにもいかない。もっと深い内容については参考文献をあたるとよさそう。

GW6日目

モジュールが対応しているランタイムの最小バージョンの統計に興味があったので調べてみた。他のプログラミング言語だとどういう分布になるのだろうか。EoLが明確に設定されている言語だと傾向が変わってきそう。言語とエコスシテムの未来を考える一助になる?

blog.utgw.net

全自動Test2化ツールのテストを全く書いていないことを思い出したので、整えてCPANに公開した。テスト中で system() 関数を使ってテストが落ちまくっていたので、CLIをラップするクラスを書いたり、proveコマンドを叩くのではなくApp::Proveを使うようにしたり、と工夫が炸裂してなんとかなった。

比較的ずっとコードを書いている一日だったと思う。またもやPARTY☆NIGHTブームが来ている。

PARTY☆NIGHT(パラパラ・アレンジ・バージョン)

PARTY☆NIGHT(パラパラ・アレンジ・バージョン)

  • D.U.P.(真田アサミ・沢城みゆき・氷上恭子)
  • アニメ
  • ¥255
  • provided courtesy of iTunes

CPANに上がっているモジュールが対応しているPerlの最小バージョンの統計情報

CPANに上がっているモジュールが対応しているPerlの最小バージョンの傾向が知りたくなったので、調査することにした。直感では、最低でもPerl 5.8に対応しているモジュールが最も多いと思っていた。

情報を取得する

metacpanにはAPIがある*1ので、これを叩いて情報を取得する。

以下のコマンドで、この記事を書き始めた日までの1年間 (2020/5/4 - 2021/5/4) のリリースのうち、最新バージョンのリリースについて検索した。

$ curl -XPOST https://fastapi.metacpan.org/v1/release/_search -d @query.json > result.json

query.json にはこういうクエリを書いた。Elasticsearchのクエリは普段あまり手書きしないのでちょっと苦労した。

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "status": "latest"
          }
        },
        {
          "range": {
            "date": {
              "gte": "2020-05-04T00:00:00",
              "lt": "2021-05-04T00:00:00"
            }
          }
        }
      ]
    }
  },
  "sort": [
    {
      "date": "asc"
    }
  ],
  "size": 5000
}

2020/5/4 から 2021/5/4 までの間のリリースが3949件見つかったので、これらについて分析する。

Perlの最小バージョンを取得する

以下の jq コマンドで、各モジュールが対応しているPerlの最小バージョンを列挙できる*2。 バージョンが指定されていない場合は null が返るので // empty で除外している。

$ jq -r '.hits.hits[]._source.metadata.prereqs.runtime.requires.perl // empty' result.json

3949個のモジュールのうち、Perlの最小バージョンが指定されているものは2695個あった。

バージョンの表記を正規化する

めでたく2695個のモジュールが対応しているPerlの最小バージョンを抽出することができたが、現状では 5.010001v5.10.1 といった表記が混在しており、扱いづらい。

version モジュールを使うことで、こういったバージョン表記をパース・正規化できる。metacpanでも使われている*3

バージョン表記を正規化してパッチバージョンを落とした上で、辞書順ではなくバージョン順に並べ替えて、個数をTSV形式で出力する。

use strict;
use warnings;
use feature 'say';
use version;
use List::UtilsBy qw(count_by sort_by);

my @versions;

while (my $line = <>) {
    chomp $line;
    my $version = version->new($line);
    my $normalized = $version->normal;
    # パッチバージョンを落とす
    $normalized =~ s/\.[0-9]+$//;
    push @versions, $normalized;
}

my %count_of_version = count_by { $_ } @versions;
for my $version (sort_by { version->new($_) } keys %count_of_version) {
    say join "\t", $version, $count_of_version{$version};
}

バージョン指定にミスっているのか Perl 5.100 を要求しているモジュールもあった。Perl 7を要求しているモジュールもあったけど Acme::Postmodern::Perl というAcmeモジュールなので想定した記述のようだった。CPAN Testers Reportが見たことない色合いになっていて面白い*4

スプレッドシートに取り込む

TSV形式で出力することにしたので、さくっとスプレッドシートに取り込むことができる。取り込んで棒グラフを出力してみたものが以下。

docs.google.com

ライブラリが対応するPerlの最小バージョンの個数の棒グラフ

考察

  • 直近1年間にリリースが行われたモジュールが対応する最小のPerlバージョンで最も多いのは 5.10
    • その次に 5.6、続いて 5.8 という順番になっている
      • 5.8 に対応しているモジュールが一番多いと思っていたので、意外だった
      • 5.6 のほうが 5.8 よりも多いのはもっと意外だった
    • 使われているPerlのバージョンの統計も見れると考察を深められる?
  • 奇数バージョンを指定しているモジュールもあるが、かなり少ない
  • 現行のPerlではどう頑張ってもインストールできないモジュールがある
    • あえてそうなっているものも、ミス? でそうなっているものもある

GW5日目

一昨日の夜から今朝まで2泊3日で市内のホテルに泊まっていた。ホテルのフロントや公園で作業をした結果、かなり捗った。

出かけて帰ってきたら自動的に部屋が掃除されているのがホテルの魅力だと思う。良いことづくめというわけでもなくて、自宅に比べるとインターネット回線が貧弱だった。名前解決に失敗したり、レスポンスが返るのに10秒ぐらいかかったりすることがあった。こういう環境下で満足に働こうとしたら、やりづらいと思う。

引っ越したくなって物件情報サイトを見あさっている。家賃だけなら高くないけど、初期費用を考慮するといきなり高価になって手を出せない。いまの部屋に引っ越したときは敷金ぐらいしか払ってないと思う。敷金礼金以外にもいろいろあるけどこういうものなの?

ちょっとコードを書いて統計を取った。

blog.utgw.net

JSONの所望の値にアクセスするためのキーを逆算する

手元にJSONはあるけど、人間がパースするには大きくて、ぱっと見では所望の値を取得するキーが分からない。値を取得するために人間が試行錯誤しまくるのは不毛なのでもうちょっとなんとかしたい。

2021/5/3 22:15 追記

id:itchyny さんにjqでキーを逆算する方法を教えてもらった。以下で値にアクセスするためのキーの配列 (.foo[1].bar なら ["foo", 1, "bar"]) の列が得られる

$ jq -r -c --arg value foo --stream 'select(.[1] == $value)[0]'

あとはうまく文字列結合をしたりエスケープしたりすれば完成する。

2021/5/3 追記: tojson でエスケープする方法*1id:itchyny さんに教えてもらったので反映しました。

$ jq -r -c --arg value foo --stream 'select(.[1] == $value)[0] | map("[\(tojson)]") | "." + join("")'

jqで実現する方法がおそらくありそう、と思いつつ慣れたプログラミング言語で書いてしまったので、jqで実現できることが分かってよかった。

以下は試行錯誤の跡です。


与えられたJSONの、与えられた値にアクセスするためのキーを逆算するスクリプトを書いた。やっていることは深さ優先探索で、発見したキーを順に全て返す。キーに含まれる文字列によって場合分けするのが面倒なので全部クォートしている。

得られたキーを jq コマンドにそのまま投げることができる。キーから配列のインデックスを消してjqに投げるとうまく列挙できて便利。

import sys
import json

def main():
    input_json = json.load(sys.stdin)
    target_value = sys.argv[1]
    found_keys = find_keys_of(input_json, target_value)
    if found_keys:
        print('\n'.join(found_keys))
    else:
        print('not found', file=sys.stderr)
        sys.exit(1)

# 面倒なので全部クォートする
def encode_json_key(key: str):
    replaced = key.replace('"', r'\"')
    return f'["{replaced}"]'

# sys.argv[1] はstr型なので、よしなに比較する (うまくいかないこともあるかも)
def equal(json_value, input_value):
    if json_value == input_value:
        return True
    else:
        try:
            return json_value == float(input_value)
        except ValueError:
            pass
    return False

def find_keys_of(data, value):
    found_keys = []

    def _find_key_of_list(xs, value, key):
        for idx, v in enumerate(xs):
            next_key = f'{key}[{idx}]'
            _find_key_of_data(v, value, next_key)

    def _find_key_of_dict(dic, value, key):
        for k, v in sorted(dic.items(), key=lambda x: x[0]):
            next_key = f'{key}{encode_json_key(k)}'
            _find_key_of_data(v, value, next_key)

    def _find_key_of_data(data, value, key):
        if isinstance(data, list):
            _find_key_of_list(data, value, key)
        elif isinstance(data, dict):
            _find_key_of_dict(data, value, key)
        elif equal(data, value):
            found_keys.append(key)

    _find_key_of_data(data, value, '.')
    return found_keys

if __name__ == '__main__':
    main()

こういう感じで使うと、 "foo" という値を持つキーを探索して列挙してくれる。けっこう便利だと思う。

$ python3 find_key_of_value.py foo < input.json

true とか false は検索できないけどまあいいか。

*1:sub だけだと正しくエスケープするのが大変

今日の夢

中学校の教室でカップ麺をぶちまける。ティッシュをかき集めて拭き取った。

昼休みにスマブラの1人プレイの様子を見ていたら挑戦者が出現して昼休みをはみ出る。

5限目に体育があることを知らなかった。体操服を借りる時間も相手もいなかったので仕方なく制服のまま体育館に向かう。体育館の場所が思い出せない。

ここでバーサーカーとしての血が騒ぐ。向かってくるモンスターを次々に倒し、バーサク状態になる。暴力性が高まって攻撃力が爆上がりする。

GW4日目

連休中に終わらせたいタスクをなんとか終わらせた。外に出て、屋根のあるところでコードを書いてみると意外と捗る。インターネット回線は貧弱だけど。

ワンルームマンションで暮らしていると、家から出ずに別の場所で仕事をしてみる、というのは不可能だなと痛感する。次に引っ越すなら2部屋以上は欲しい。

気分を変えられない、変える手段がない、というのは苦しいものである。