-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory を解消する

まとめ

(1) .zshrc などで

export LC_CTYPE="ja_JP.UTF-8"

日本語ローカライズに非対応の場合は、

export LC_CTYPE="en_US.UTF-8"

(2) /etc/ssh/ssh_configSendEnv LANG LC_*コメントアウトする

経緯

ssh しようとして以下のエラーが出ることがある。

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

locale を見るとこのように LC_CTYPEUTF-8 となっている。エラーメッセージは UTF-8 という locale がないと言っている。

$ locale
LANG=""
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=

macOS では Terminal.app 起動時に以下の設定がオンな場合、LC_CTYPE="UTF-8" に設定される。

ssh する際に ssh_configSendEnv LANG LC_* が有効で接続先の AcceptEnv LANG LC_* も有効な場合、LC_CTYPE="UTF-8"ssh 先にも送られる。接続先に UTF-8 がない場合は -bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory とエラーになる。

このため解消するには、

  • .zshrc などで export LC_CTYPE する
  • ssh_configSendEnv LANG LC_* を無効にする
  • Terminal.app を使わない
  • Terminal.app の Set locale environment variables on startup をオフにする

という対策が考えられる。なお Terminal.app の設定を変えると日本語入力ができなくなるので注意。

私はたまに Terminal.app を使うのと、日本語ローカライズに対応している場合はその設定を使ってほしいので .zshrcexport LC_CTYPE="ja_JP.UTF-8" を書くことにした。

参考

String#force_encodingは文字コードの強制変換ではない

RubyString#force_encoding は String の encoding を変更するだけで、文字コードの変換を行うわけではありません。そのため、バイト列は変換されません。

force_encoding はどんなメソッドか

String の encoding を変更します。ただし、バイト列は変更せず、encoding に対しバイト列が正しいかどうかは確認しません。

例えば EUC-JP に変換して encode と比較します。

''.encode(Encoding::EUC_JP).encoding
# => #<Encoding:EUC-JP>

''.force_encoding(Encoding::EUC_JP).encoding
# => #<Encoding:EUC-JP>

どちらも encoding は EUC-JP です。

String#valid_encoding? で正当なバイト列かどうか確認できます。

''.encode(Encoding::EUC_JP).valid_encoding?
# => true

''.force_encoding(Encoding::EUC_JP).valid_encoding?
# => false

force_encodingfalse になり、バイト列が正しくないことがわかります。

encodeforce_encoding の返り値を見てみると、

''.encode(Encoding::EUC_JP)
# => "\x{A4A2}"

''.force_encoding(Encoding::EUC_JP)
# => "\xE3\x81\x82"

encodeforce_encoding で結果が異なっています。

どちらも のバイト列ですが、encode の返り値の \xA4\xA2EUC-JP のバイト列で、 force_encoding のほうの \xE3\x81\x82UTF-8 のバイト列です。

''.encode.bytes.map { _1.to_s(16) }
# => ["e3", "81", "82"]

encode は encoding とバイト列を変更しますが、 force_encoding は encoding のみ変更してバイト列は変更しません。

force_encoding はどんなときに使うか

バイト列を変えずに encoding だけを変換したいときに使います。

Array#pack の返り値に対して encoding を設定する場合

Array#pack の返り値の encoding は ASCII-8BIT だったりして人間には読みにくく、また encoding に UTF-8 を期待している場合に使いにくいので、UTF-8 (もしくはお使いの環境の文字コード)の文字列として扱いたい場合 force_encoding をつけると使いやすくなります。

["e38182"].pack("H*")
# => "\xE3\x81\x82"

["e38182"].pack("H*").force_encoding(Encoding::UTF_8)
# => "あ"

バイト列から文字を組み立てる場合

バイト列だけが分かっていて、encoding を後から設定したい場合です。

例えば以下の記事に書いたような、未定義文字に対する変換先の文字を定義する場合です。これを encode で同じことをすると少しややこしくなるので force_encoding したほうがすっきりします。

U+301C from UTF-8 to Windows-31J (Encoding::UndefinedConversionError) に対応する - esm アジャイル事業部 開発者ブログ

str = "\u{2014 301C 2016 2212 00A2 00A3 00AC}"

undefined_signs = {
  "\u2014" => "\x81\x5C".force_encoding(Encoding::Windows_31J), # — EM DASH
  "\u301C" => "\x81\x60".force_encoding(Encoding::Windows_31J), # 〜 WAVE DASH
  "\u2016" => "\x81\x61".force_encoding(Encoding::Windows_31J), # ‖ DOUBLE VERTICAL LINE
  "\u2212" => "\x81\x7C".force_encoding(Encoding::Windows_31J), # − MINUS SIGN
  "\u00A2" => "\x81\x91".force_encoding(Encoding::Windows_31J), # ¢ CENT SIGN
  "\u00A3" => "\x81\x92".force_encoding(Encoding::Windows_31J), # £ POUND SIGN
  "\u00AC" => "\x81\xCA".force_encoding(Encoding::Windows_31J), # ¬ NOT SIGN
}

p str.encode(Encoding::Windows_31J, fallback: undefined_signs)

この場合は String.new でも同じことができます。

String.new("\x81\xCA", encoding: Encoding::CP932)

DB に入れるデータをバイナリ扱いしたい場合

普通にやると別の文字コードに変換されてしまう文字を DB の設定を変えずに DB に格納したいことがあり、そのために encoding に Encoding::ASCII_8BIT をつけてバイナリ扱いして encoding を変換させずに入れるために使ったことがあります。

まとめ

force_encoding では encoding のみを変更し、バイト列は変更しません。また、バイト列が正しいかどうかのチェックも行いません。

encoding に対してバイト列が不正な場合は文字を正しく扱えないため、どうしても force_encoding したい場合は valid_encoding? とセットで正しいバイト列かチェックして使う方が安全だと思います。

参考

Ruby文字コード対応については以下の記事がとても詳しいので、興味のある方はぜひこちらを参照ください。

Ruby M17N の設計と実装

最近の趣味

Rubyist近況 Advent Calendar 2021 - Adventar 7日目

フランス語学習

Duolingo で最近フランス語を勉強している。たしか udzura に英語以外の言語を学習すると面白いと言われたことがきっかけだった気がする。勉強している理由はなくて、英語以外の言語を勉強してみたかったという理由で始めた。これがなかなか癒やしになっている。フランス語に限らず興味本位の学習はとてもワクワクするし、ちょっと俺TUEE感があるので満足感があって楽しい。

執筆時点で Duolingo の英語話者向けフランス語コースの Unit 2 の9割くらいまで進んでいる。日本語話者向けフランス語コースはないので、問題と回答はすべて英語。いまのところ、とても簡単な文を読み書きしているので英語的な面で詰まることはほぼない。あと、英語にはフランス語由来の単語がいくつかあるので、すべてが初見ではない。見た目から「多分こういう意味だろう!」と思うと大概合っていて良い。ただ、単語の見た目は似ていても発音は全然違う事が多い。 詰まるところというと、形容詞の順番をうっかり間違えることがたまによくある。英語は名詞の前に形容詞を置いて修飾するが、フランス語は名詞の後ろに形容詞を置いて修飾するので、フランス語を英語に訳す問題で英語でも形容詞を後ろから修飾したりしてしまう。あと何回やっても動詞の活用を覚えられない。 tu と vous で活用が違うことに最近気がついた。

Duolingo のフランス語コースの全体は Unit 10 まであるので Unit 2 ではまだまだ序盤。日本語話者向け英語コースでは序盤の Unit は簡単すぎると感じたのだが、フランス語コースは Unit 1 が一番難しく感じた。基本的な文法や単語や活用を覚えるところが最初の壁で、全然分からなくて面白く感じられなかった。Unit 2 の途中あたりから基礎的な単語が分かってきて楽しくなってきた。フランス語の場合基本的にラテンアルファベットとアクサンテギュ(アクセント符号)くらいで文字の壁はなかった。韓国語とかだとまず文字を覚えないといけないので文字のハードルがある。

フランス語の発音は難しい。最も基本的な単語の1つである "Je" (= I) の発音がまず難しい。鼻に引っ掛けつつスッと抜けるような音を出さないといけないのだが気を抜くと片仮名の「ジュ」になってしまう。これができないと Duolingo の Audio Lessons で発音問題をなかなかクリアできなくて辛い気持ちになる。Audio Lessons は非常にわかりやすく丁寧に教えてくれるのでとてもおすすめ。Audio Lessons を解くと 20xp (通常の Lesson の1.5〜2倍のxp!) が入るのでお得な感じがする。Duolingo は Lesson 以外も学びの手段があるのがまた飽きなくて良いところ。

フランス語について体系的に知りたくなって一瞬文法書を読んだりNHKラジオのフランス語講座を聞いたりしてみたが、どうも続かなくて結局 Duolingo だけやっている。 Duolingo オンリーで進めると身につく分野が限られているので、いろいろバランスよく摂取したい。ラジオは週3で毎回15分あり、1週間はアプリで聞き逃し配信を聞ける。難易度的にすごくちょうどよかったのだけど、聞き逃し配信を聞き逃してもうだめだ〜となって頓挫してしまった。次の開始(4月とか?)からまた始めたい。

焚き火

某所で宿泊した際にホテルに焚き火体験プランがついていて、その体験をしてから猛烈に焚き火したい人になってしまった。Outer Wilds をプレイしていたこともあり、焚き火とマシュマロがすばらしいものだと感じているのもある。焚き火してマシュマロ焼いて外でコーヒーを飲みたい。ゆるキャン△はけっこうがっつりキャンプしていてすごいと思うようになった。 とりあえず今は冬でキャンプを始めるにはきびしい季節なので、会社のoViceに焚き火BGM無限ループコーナーを作って、テントを立てて、肉を焼いている人のgifを貼るなどの活動を行っている。

お絵かき

今年 iPad Pro と Apple Pencil を購入した。お絵かきのために買ったわけではないけど、せっかく道具が揃ったからとお絵かきを始めることにした。とりあえず人体分かっておけば損はなかろうと思い、ソッカの美術解剖学ノートを模写する活動を始めた。肋骨や頭蓋骨をかけるようになった。iPad Pro はお絵かきしやすいツールだと思う。 しばらく描いて、自分の描きたいものが生き生きしたネコだということがわかってきた。ネコの形は難しくて、写真見ながら描くと耳は平べったくなるし足は立体感がないし胴体は寸胴になってしまう。骨と筋肉と毛はどうなっているんだろう。

GitHubの緑化運動

今年は毎日草生やす!と言っていた人をみかけて私もやってみるかーと思い、"なんでもいいから(issueやPRのopenでも草は生える)1日1つ草を生やす"をモットーに続けてきた。 2021-01-01 から開始したのでそろそろ1年になる。Duolingo の streaks と違って生やしそこねたらもう後がないので、わりと気を張って維持していた。続けると GitHub にコードを push することにまったく抵抗がなくなるのでよかった。あと、dotfiles 弄りを続けていると「そろそろコード書いて草生やしたいな…」と思うようになり、自然とコードを書こうという気持ちになれた。 来年は毎日コードを書いて草を生やそうと思っている。

Vim から esa に日報を投稿できるようにする

ESM Advent Calendar 2021 - Adventar の5日目の記事です。

永和システムマネジメント アジャイル事業部では esa を使ってメンバーが日報を投稿しています。

ですが私は日報をよく後回しにして書かなくなってしまうことがありました。そこで、自分にとってもっと投稿しやすい環境をつくれば日報投稿が捗るのではないかと思い Vim から esa に日報を投稿できるようにしました。

使ったもの

esa のアクセストーク

とにもかくにも POST できる環境が必要です。

esaAPI はこちらにまとまっています。 こちらにも書いてあるとおり、 esa のアクセストークンは https://[team].esa.io/user/applications から作成できます。記事を投稿する目的であれば、 write 権限が必要です。

docs.esa.io

作成したアクセストークンはのちほど使うので、どこかに控えておきます。

スニペットにテンプレートを追加する

日報のテンプレートがあると書きやすいので、テンプレートをすぐに呼び出せるようにします。

私は Alfred というツールでスニペットを管理しています。 Alfred の使い方はここでは割愛しますが、「;nippo」という単語で以下のテンプレートを展開するように設定しています。

## やったこと

- 

## お気持ち

## ひとこと

esa.vim

esa.vim というプラグインをつかって Vim から esa に投稿できるようにします。

github.com

upamune.hatenablog.com

まずチーム名を設定します。

let g:esa_team = 'docs'

日報のタイトルは日付以外ほぼ固定なので、strftime を使って今日の日付のカテゴリを自動で入れるようにします。 また、 ' -w -b' オプションをつけて、 wip で投稿して投稿後にブラウザを開くようにしました。

function! s:esa_nippo()
  let args = ' -w -b'
  let category = strftime(" 日報/%Y/%m/%d/ima1zumi")
  execute ('Esa' . args . category)
endfunction
command! EsaNippo call s:esa_nippo()

初回だけ esa のアクセストークンを聞かれるので、入力します。アクセストークンは ~/esa-vim に保存されます。

~/esa-vim の取り扱いには注意してください。私は念のため .gitignore で Git 管理対象外のファイルにしました。

これで :EsaNippo というコマンドで現在のバッファの文字が 日報/%Y/%m/%d/ima1zumi というカテゴリで wip で投稿されてブラウザが開くようになりました。便利!

Rubyだけで文字コード変換を実装する

Ruby Advent Calendar 2021 - Qiita の5日目の記事です。

こんにちは。ima1zumiです。 私はRubyKaigi Takeout 2021 で Dive into Encoding というタイトルでオレオレ文字コードを作って文字コードを学ぶ話をしました。 その中で、C拡張のgemとして自作文字コードEncoding::IROHARubyで使えるようにしました。

それがこちらです。

https://github.com/ima1zumi/encoding_iroha/

このgemを使うことで、みなさんのお手元でもEncoding::IROHAという文字コードが使えるようになります。 どう作るかとかそういった話はRubyKaigi Takeout 2021のアーカイブをご覧ください。

ですが思ったのです。C拡張のgemってビルド要るからめんどくさいですよね。

ということで、pure Ruby文字コード変換を(雑に)実装してみました。それがこちらです。

https://github.com/ima1zumi/ruby_encoding_iroha/

今日はこのコードについて解説します。これを読み終わるころには、みなさんもRuby文字コード変換が実装できるようになっているはずです。*1

文字コード変換を実装するとは

RubyKaigi で語ったので割愛しますが、Rubyの場合はEncodingクラスの定数として使えるようにすることと変換器が必要です。

Encodingクラスの定数

Encoding には、 replicate というメソッドがあります。これを使うと元となった encoding と同じバイト構造を持つ Encoding クラスの定数を作ることができます。何をやっているか知りたい場合は CRuby の rb_enc_replicate を見るとよいです。

Encoding::IROHA は1バイト固定長の文字コードなので、同じく1バイト固定長の ASCII_8BIT を元に IROHA を作りましょう。

Encoding::ASCII_8BIT.replicate("IROHA")

これで Encoding::IROHA という定数を参照できるようになります。変換器はまだ実装していないので、いろは歌への変換はできません。

replicate の用途に興味があるので、ご存知の方がいればTwitter等で教えてもらえると嬉しいです。

変換器

Encoding::IROHAいろは歌+ASCIIをつかえるようにした文字コードです。RubyCSI方式で多言語対応されているので、何に変換できるようにしてあげるか決めてあげないといけません。とりあえずUnicodeに変換できるようにしましょう。UTF-8を基本としつつ、せっかくなのでUnicode系全般に対応させてみました。

    UNICODE =
    [
      Encoding::UTF_16,
      Encoding::UTF_16BE,
      Encoding::UTF_16LE,
      Encoding::UTF_32,
      Encoding::UTF_32BE,
      Encoding::UTF_32LE,
      Encoding::UTF_7,
      Encoding::UTF_8,
      Encoding::UTF8_DOCOMO,
      Encoding::UTF8_KDDI,
      Encoding::UTF8_MAC,
      Encoding::UTF8_SOFTBANK,
    ]

るりまを見てUTFと入っているものからチョイスしたので漏れや、もはや使わなさそうな文字コードもあるかもしれませんが、大体良さそうです。

さて変換テーブルを実装しましょう。いろは歌部分は50文字もないので、変換テーブルはhashでちゃちゃっと書いてしまいまします。

    UTF8_TO_IROHA_TABLE = {
      "" => "\x80",
      "" => "\x81",
      "" => "\x82",
      "" => "\x83",
      "" => "\x84",
      "" => "\x85",
      "" => "\x86",
      "" => "\x87",
      "" => "\x88",
      "" => "\x89",
      "" => "\x8A",
      "" => "\x8B",
      "" => "\x8C",
      "" => "\x8D",
      "" => "\x8E",
      "" => "\x8F",
      "" => "\x90",
      "" => "\x91",
      "" => "\x92",
      "" => "\x93",
      "" => "\x94",
      "" => "\x95",
      "" => "\x96",
      "" => "\x97",
      "" => "\x98",
      "" => "\x99",
      "" => "\x9A",
      "" => "\x9B",
      "" => "\x9C",
      "" => "\x9D",
      "" => "\x9E",
      "" => "\x9F",
      "" => "\xA0",
      "" => "\xA1",
      "" => "\xA2",
      "" => "\xA3",
      "" => "\xA4",
      "" => "\xA5",
      "" => "\xA6",
      "" => "\xA7",
      "" => "\xA8",
      "" => "\xA9",
      "" => "\xAA",
      "" => "\xAB",
      "" => "\xAC",
      "" => "\xAD",
      "" => "\xAE",
    }

なんで\x80なのかとかはRubyKaigiのアーカイブを見てください。

変換テーブルができたので、UnicodeからIROHAへの変換を実装していきましょう。

UTF8_TO_IROHA_TABLEいろは歌部分とのマッチングをします。次にASCIIを変換しますが、ASCIIの場合はバイト列はUTF-8と同じなので ascii_only? メソッドでASCIIであるかどうかだけ確認してあげます。いろは歌でもASCIIでもない文字…例えばひらがなの "が" は変換不能な文字です。ここでは Encoding::UndefinedConversionError を上げて止めるようにしました。

    def utf8_to_iroha(char)
      iroha = UTF8_TO_IROHA_TABLE[char]

      if iroha
        iroha
      else iroha.nil?
        if char.ascii_only?
          char
        else
          raise Encoding::UndefinedConversionError
        end
      end
    end

変換不能文字の処理にバグがあってうまくいかないパターンがありますが、とりあえずこのままいきましょう。*2

文字を1文字ずつ変換して、最後に連結します。join すると encoding が IROHA ではないので、 force_encoding で Encoding::IROHA に置き換えます。

ちなみに force_encoding は、その Encoding で正しいバイト列かどうかチェックしないので注意してください。Ruby では encoding は String についているラベルのようなものなのですが、ラベルだけ張り替えて変換処理を行わないのが force_encoding です。encode はラベルの張替えだけでなく実際の変換処理を行いバイト列を書き換えます。 ここでは変換処理は utf8_to_iroha で実行しているため、最後に encoding 情報を正しくするという目的で force_encoding しています。

    def to_iroha(encoding)
      raise Encoding::ConverterNotFoundError unless UNICODE.include?(encoding)

      self.each_char.map { |char| utf8_to_iroha(char.encode(Encoding::UTF_8)) }.join.force_encoding(Encoding::IROHA)
    end

同様にIROHAからUnicodeへの変換処理を実装します。

    IROHA_TO_UTF8_TABLE = UTF8_TO_IROHA_TABLE.to_h { |utf8, iroha|
      [iroha.b, utf8]
    }


    def iroha_to_utf8(char)
      utf8 = IROHA_TO_UTF8_TABLE[char.b]

      if utf8
        utf8
      else utf8.nil?
        if char.ascii_only?
          char
        else
          raise Encoding::UndefinedConversionError
        end
      end
    end

.b しているのは encoding が同じでないとうまく比較処理が動かなかったためです。なんでだろう…

後はおおむね IROHA への変換と同じです。違うのは最後の encode(encoding) で、ここでは Unicode 系への変換処理を行うため Ruby 本体の変換器を使えるので、force_encoding ではなく encode しています。

    def from_iroha(encoding)
      raise Encoding::ConverterNotFoundError unless UNICODE.include?(encoding)

      self.each_char.map { |char| iroha_to_utf8(char) }.join.encode(encoding)
    end

String#encode に IROHA 用の変換処理を挟み込みます。 from_encoding の扱いがこれでいいのかはよくわかってないです。また、**options には対応していません。

    def encode(encoding, from_encoding = self.encoding, **options)

      to_enc = convert_encoding_constant(encoding)
      from_enc = convert_encoding_constant(from_encoding)

      if to_enc == Encoding::IROHA
        return to_iroha(from_enc)
      elsif from_encoding == Encoding::IROHA
        return from_iroha(to_enc)
      end

      super
    end

これでできました。 雑にStringに追加しているのでお行儀は悪いのですが、とりあえず動くようになったのでヨシとしましょう。

感想

C拡張でしか実現出来ないと思っていたRubyへの文字コードの実装が、Rubyだけで出来て気持ちが良かったです

*1:本当に文字コードの追加が必要な場合は、自作せずに https://bugs.ruby-lang.org/ で相談しましょう

*2: 'a'.encode(Encoding::UTF_16).encode(Encoding::IROHA)すると空文字列が返ってくる。多分BOMの扱いが間違っていてバグっている。

フィヨルドブートキャンプを(11ヶ月前に)卒業したこと、楽しいことをすること

フィヨルドブートキャンプ Part 2 Advent Calendar 2021 - Adventar」4日目の記事です。

2021年1月にフィヨルドブートキャンプというプログラミングスクールを卒業しました。2021年1月から永和システムマネジメントという会社で働いており、スクールを卒業して就職してから11ヶ月経ちました。卒業エントリにしては時間が経っているのですが、時間が経ったから見えてくることもあるかなと思うのでこれまでのことと、これからのことをつらつらと書いていきます。

フィヨルドブートキャンプとは

フィヨルドブートキャンプとは、

プログラマーとして就職を目指せるだけのスキルを身につけることを目標としたオンラインプログラミングスクールです。就職を目指せるスキルを弊社では「現場の人間にとって、戦力になるプログラマー」としています。

というプログラミングスクールです。主にRailsエンジニアとなれるような学習サポートを行っています。

私は以前SIerCOBOLアセンブラで書かれたプログラムの保守をしていました。その会社は技術的な知識より業務知識のほうが重視される環境でした。仕事をしているうちに技術的なことを知るのが楽しくなってきたので転職したくなり、転職できるだけのスキルを身につけるためにフィヨルドブートキャンプの門を叩きました。

フィヨルドブートキャンプの卒業

フィヨルドブートキャンプでは、基本的にカリキュラムの最後にある「自作Webサービスを作る」を終えたときに卒業になります。*1 私は少し例外で、自作Webサービスを作らないまま卒業してしまったのですが…それは2022年の目標にしようと思っています。

カリキュラムは 学習内容 | FJORD BOOT CAMP(フィヨルドブートキャンプ) に載っています。この課題1つ1つをプラクティスと呼ぶのですが、プラクティスを一通りやることで最終課題である「自作Webサービスを作る」ができるような順番になっています。

ということで卒業すると自作Webサービスを自分で作れるだけの技術力が身につくようになっていますが、その過程をどう進めるかは個人の自由です。プラクティスの終了条件を満たせば良しとしてどんどん進むこともできますし、自分の理解度に合わせてじっくりと進めることもできます。私は後者の方で、分からない・疑問に思ったところは時間がかかっても脇道に逸れてもなるべく理解しながら進めるようにしました。

フィヨルドブートキャンプを卒業して、当初の目標だった「転職できるだけのスキルを身につける」「技術力を重視する会社に転職する」は達成できたと思っています。加えてOSSにコントリビューションするとか、フィヨルドブートキャンプ在籍中から取り組んでいたことが繋がって卒業後にRubyKaigiに登壇するなど、入る前に思っていたよりいろいろなことを経験できました。

卒業したらどうなりたい?

フィヨルドブートキャンプを卒業と言っても、卒業して出来るようになっていることや、どんなプログラマーになりたいと思うかは人それぞれみんな違います。「自作Webサービスを作れるくらいの技術力が身につく」はほとんどの人に共通していますが、それ以外は同じ人はいません。

私はフィヨルドブートキャンプでプラクティスを取り組むうちに、自分は好きなことや気になることをつきつめるのが一番楽しいんだなと気づきました。また得意・不得意な分野も分かってきました。タスクを素早く仕上げるのは苦手です。また、なぜこう動くか分からず分からないことが気になっている状態でコードを書いていると具合が悪くなってきます。バグ探し、なぜこのコードはこう動くのかを調べること、コードの品質に気を配ることは得意な方です。また、私はOSSにコントリビューションできるとうれしいです。自分が使っているソフトウェアが誰かが作ったものであること、好きなソフトウェアがよりよくなるお手伝いができると喜びがあります。

就職に向けて自分を振り返るときに、自分は何がきっかけでフィヨルドブートキャンプに入って、これからどんなことがしたいだろうということを考えました。それはここに書きなぐってあるのですが、なぜエンジニアになろうと思ったのか? - :wq その中でやっぱり技術好きだなーと思って、そういった気持ちを持っている人が多そうな永和システムマネジメントに入りたいと思ったのでした。その印象は入社しても変わらず、よかったなぁとしみじみ感じているところです。

出会いを大事にする

今では文字コードが好きで RubyKaigi で文字コードの話を延々とするような私ですが、1年ほど前まで別に好きでもなんでもなく興味がある分野の1つでしかありませんでした。きっかけは、たまたまフィヨルドブートキャンプ内で文字コードの話を見かけて、自分の知っている範囲での文字コードまとめを日報に書いたことでした。書いた勢いでその日のフィヨルドブートキャンプ内の雑談タイムに参加して、たまたま igaiga, udzura がいたので「こんな認識で合ってますか?」というのを見てもらってその流れで家族の絵文字という面白い特徴を持った絵文字があることを教えてもらい、へぇ〜と思って家族の絵文字をirbに入力したらクラッシュしました。これがすべての始まりでした。

クラッシュする理由は全然分からなかったものの、クラッシュするのはよくないよなと思って osyo に教えてもらいつつ頑張って英語で Reline に issue を立てました。せっかく自分で遭遇したバグだから自分で直したいな〜と思いコードを眺めていましたが、Reline のコードは難しくて全然わかりませんでした。うーんと思っていたら Toyama.rb で Reline の作者の aycabta に Reline の基本的な構造を教えてもらう機会があり、自分でチャレンジすることにしました。文字コードの基礎がわからんとどうしようもないなと思って「プログラマのための文字コード技術入門」を読んでみたり必死で print デバッグしたりしてました。最終的には「1文字前の情報があれば修正できそうだが、1文字前の情報がどこにあるのかわからん」までは自力でたどり着いたのですが、修正までは行けず結局修正方法は aycabta に教えてもらいました。それでも自分の PR がマージされたときは感無量でした。それがきっかけで、 Reline と irb にはとても思い入れがあり、これからも手伝っていきたいと思っています。

OSS にコントリビュートできたといっても特別ななにかをしていたわけではなく、普段のプログラミング学習中にたまたま見つけた不具合にエイッと勇気を出して issue を立てたことと、Ruby が好きな人たちとのつながりのおかげできっかけや後押しをもらって、その勢いに乗ったら自分ひとりでもいろいろできるようになってきたと思っています。不具合も人間も出会いを大事にしてやっていくと、面白いことが起きるものだなぁと思います。

これからどうしたい?

自分の楽しいと感じること、自分の内なる声が「こっちが面白そう!」という方に向かっていきたいなと思っています。そうやっていると日々の人生がイキイキしてきますし、自分自身を信用している感じがして気持ちがいいです。

もう少し具体的な話でいうと、アジャイルな開発をいい感じにすすめていくことや、端末プログラミング(つまりReline)、Unicodeに興味があります。それ以外にも、お絵かきとか、フランス語とか、英語とか、焚き火に興味があって趣味でじわじわと取り組んでいます。来年は Rust も書いてみたいし、お仕事で使う JavaScriptCSSAWS とももっと仲良くなりたいです。OSS 活動も継続的にやっていきたい。やりたいことがたくさんあってとっ散らかっているのですが、ある程度継続できたら、楽しくないことはそのうちやらなくなってくるので自然にまかせておけばいいかなぁと思っています。楽しいことをしていると人生楽しいのでおすすめです。楽しくは感じられないがやらなければならないことは、そもそもなんで楽しくないのかを考えたほうがいいんだろうなと思います。

終わりに

シン・ゴジラという映画である人が書き置きを残しているのですが、その言葉が好きなので引用して終わりにしたいと思います。

私は好きにした、君らも好きにしろ

*1:正確には review ready な状態になると卒業扱いになる

RubyKaigi Takeout 2021 に登壇します

RubyKaigi Takeout 2021 に『Dive into Encoding』というタイトルで登壇します。

私の登壇は3日目である 2021-09-11 (土) の 11:00 - 11:25 です。

rubykaigi.org

自作文字コードを作ってローカルのRubyにビルドして遊んだ話をします。文字コードの基礎からRuby文字コードの取り扱い・実装まで潜っていきます。

RubyのStringやEncodingが好きな方、文字コードの実装が気になる方はぜひ遊びにきてください。