トップ 追記

2020-06-04 [長年日記]

_ GitHub Package Registry使ってみたけど見送った

GitHub Packages: Your packages, at home with their code

分かったこと

少なくとも npm package の registry 追加、変更はあんまりカジュアルじゃない

  • rubygems なら source 書き足すだけでいいけど、package.json にそういう記述がない
  • .npmrc で registry の設定を変更することはできる。これを npm.pkg.github.com にしておくと、存在しない package を自動で npmjs.org から取得するように fallback できる。が、yarn には影響しない

GitHub 側の問題じゃなくて npm の仕様の課題かなー。rubygems は昔からカジュアルにミラーサーバ用意できたんだけど、npm とか yarn とかめんどいね。


2020-06-03 [長年日記]

_ Bundler v2の動作の変更にやっと追いついた

Bundler 2はGemfile.lockに書かれているBUNDLED_WITHを尊重する

Bundler: How to Upgrade to Bundler 2

Version Autoswitch

Now that you have Bundler 2 installed, you should know that Bundler will automatically switch between version 1 and version 2 based on your application’s Gemfile.lock. If your lockfile was created by Bundler 1, your commands will be run by Bundler 1. If your lockfile was created by Bundler 2, your commands will be run by Bundler 2.

これが分かっていないと以下のような現象にビックリする。

  • Ruby 2.6 は bundler gem も default gem になっていて、そのバージョンは1.7
  • 2.5.x までの感覚で何も考えずに gem install bundler で 2020-06 時点の最新の 2系 を入れる
  • BUNDLED_WITH 1.x な Gemfile.lock を持つプロジェクトで bundle コマンドを使うといきなり 1.7 が動く

これで何に驚くかと言うと、「せっかく bundler 2 を入れたんだから bundle update して BUNDLED_WITH を更新したいのにできない!」です。

言い方を変えると Bundler 2 以降の世界では .ruby-version と同じように Gemfile.lock が機能するようになるんだけど、direnv や rvm のようには「bundler の動作バージョン変わったで」とは教えてくれないし、Gemfile.lock 内の BUNDLED_WITH だけ書き換えるようなコマンド(例えば rbenv local みたいな)はないので各位覚えておくように、ということでした。

フツーは Gemfile.lock を手で編集しようと思わないもんなぁ…。(昔は CI でゴリっと書き換えるみたいなアクロバットをやってたけど cf. WindowsでRails x Herokuと仲良くする - あーありがち(2016-09-26)

どの程度今さらなのか確認

ちなみに Bundler 2 が出たのは1年以上前の2019年1月でした。あらま。

Bundler: Announcing Bundler 2.0

以前のバージョンの Bundler では Gemfile.lock に書かれている BUNDLED WITH と異なるバージョンを入れていると bundle コマンド実行後にこの部分だけ diff が出てしまうことがよくあったし、一時期は CI が Bundler 2 に対応してないとかイロイロあったけど、今は安定しているし、Bundler 2 には auto-switch があることを覚えて頑張っていきましょう、ということっぽい。

Tags: RubyGems Ruby
本日のツッコミ(全2件) [ツッコミを入れる]

_ えりむ [> Gemfile.lock 内の BUNDLED_WITH だけ書き換える それが記事中リンクにもある `$..]

_ wtnabe [あーサブコマンドではなくオプションとしてはあるんですね。ありがとうございます。]


2020-05-31 [長年日記]

_ GFMのコードブロック対応のmarkdown変換コマンドとしてmarkedを使ってみることにした

Marked.js Documentation

別にハイライトされる必要はなくて、単に GitHub 用に言語名を埋め込んでいるとか、そういう部分に対応していればヨシ!

blockquote class="twitter-tweet">

https://t.co/K2SFka28zN これkramdownよりマシっぽい。

— wtnabe, yet another yak shaver (@wtnabe) May 31, 2020

とりあえずkramdownよりはパッとコマンド叩いた時の結果は良好。

Tags: Node Markdown

2020-05-24 [長年日記]

_ RailsのApplicationController::RoutingErrorがたまらなくうざい

いやまぁ書いた通りなんだけど、ApplicationController::RoutingError の backtrace って全然役に立たないし、邪魔じゃないですか。できればこのエラーだけ backtrace をオフにできたらステキだなと思ったのでその辺の対処方法をまとめてみた。

この「RoutingErrorのログが邪魔問題」の解決方法は主に以下のような3つくらいのパターンがあるっぽい。

  1. routing で丸ごとキャッチしてしまってそもそも RoutingError が起きないようにして手動で 404 を返す
  2. Logger を差し替えてなかったことにする、DebugExceptions そのものを使わないようにする
  3. DebugExceptions の中でゴニョゴニョする

RoutingErrorが起きないようにroutes.rbで全部拾う

1 の方法については Stack Overflow や Qiita なんかにたくさん記事や回答がある。あるんだけど、ちょっとイマイチっぽい、みたいなニュアンス。

個人的にも想定外のリクエストがあってエラーが起きたという事実について情報量をコントロールしたいとは思うものの、すべて正常な処理で 404 が返っただけになってしまうのはちょっと意図と違うなという気がする。

Loggerやrack middlewareを差し替えてもみ消す

2 の方法はなかなか見つからないんだけど、例えば

stve/silencer: Easily suppress the Rails logger

みたいなやつ。

もっと大胆に DebugExceptions middleware を無効にしちゃうとか、 3 と組み合わせて自分で動的に Logger を差し替えちゃうという方法も Stack Overflow で見かけたが、middleware や Logger を全部差し替えたりするのは差し替え処理と差し替えた Logger ( middleware ) そのものが正しく動作するか検証しなくちゃいけないので重たいなーという印象。

そもそもエラーは起きているがそれが記録されないのは 1 よりもさらにイマイチな気がする。

DebugExceptions middleware + interceptorで好きなようにする

3 の方法については 2 の方法が見つかってあれこれコードを読んでいて自分で気がついたんだけど、実は DebugExceptions には interceptor という仕組みがあるのでそれが使える。

この方法を採用している事例は探した限り見つからなかったんだけど、結構使えるテクだと思うので紹介しておく。対象バージョンは

  • Rails 6.0.0

で、DebugExceptions は ActionDispatch の中の middleware で、rake middleware すると真ん中辺りに出てくるんじゃないかと思う。

この middleware のコードを追うと以下のように ActionDispatch::DebugExceptions.call の中で、事前に register された interceptor が次々に呼ばれることが分かる。interceptor には request と exception が渡ってくる。

module ActionDispatch
  # This middleware is responsible for logging exceptions and
  # showing a debugging page in case the request is local.
  class DebugExceptions
    cattr_reader :interceptors, instance_accessor: false, default: []

    def self.register_interceptor(object = nil, &block)
      interceptor = object || block
      interceptors << interceptor
    end

...

    def call(env)
      ...
    rescue Exception => exception
      invoke_interceptors(request, exception)
      raise exception unless request.show_exceptions?
      render_exception(request, exception)
    end

...

     def invoke_interceptors(request, exception)
       backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
       wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)

       @interceptors.each do |interceptor|
         interceptor.call(request, exception)
       rescue Exception
         log_error(request, wrapper)
       end
     end

ということで独自の interceptor を作ってその中で ActionController::RoutingError かどうか判別して何らかの加工を加えるなり処理を行うなどするとよさそう。

具体的には request オブジェクトを書き換えたり exception オブジェクトを書き換えると backtrace は無視するといったことが可能で、そのうえで必要な情報は独自にログに落とすとかどこかエラー収集の仕組みに投げるようなコードを書けばよいと思う。

Tags: Rails Ruby Rack