動かざることバグの如し

近づきたいよ 君の理想に

rails credentials:editをVSCode内でやりたい人生だった

動機

Rails5.2以降では秘匿情報はCredentialsで管理することが推奨されている。rails secrets:xxxxなんでなかったんや

で、結構 rails credentials:edit することが多いんだが、正直Vimだとコピペがやりづらいとか色々ある。できればこれもVSCodeで完結させたい

やり方

で、ググったら方法あった 単にEDITOR環境変数指定すればよかったぽい

EDITOR='code --wait' rails credentials:edit

ただ、デフォルトだとcodeコマンドがないのでVSCodeから設定する必要がある。

  • Command + Shift + Pでコマンドパレット開く。
  • 「Shell」と入力して検索
  • エンターでインストール

参考リンク

Pumaより速い「Falcon」を試す

RubyKaigi 2019のスライドでちょっと話に出てたので初めて知った 試してみる

Falconとは

Railsに使うミドルウェアといえば、Unicorn、Pumaあたりが有名だが、falconはわりと新興である。

速さの秘訣は

  • Unicorn マルチプロセスで(Webrickよりかは)速い
  • Puma マルチスレッドでUnicornより速い
  • Falcon マルチファイバー(Fiber)でPumaより速い

公式いわく、、めっちゃパフォーマンスいいらしいが、、

f:id:thr3a:20190420071401p:plain

Fiberについては以下のサイトが詳しい

インストール

早速Railsに使ってみる!すごく簡単で、Gemfileに以下を追記してbundle install するだけ

gem 'falcon'

gem 'puma' は消してよろしい 😊

起動

あとはいつもどおりrails s するだけ 簡単すぎる。。

RACK_HANDLER=falcon rails server

ベンチマーク

あとで

RubyからPythonのMatplotlibグラフを生成する

Rubyでも簡単にグラフ画像を生成したい人生だった

やりたいこと

RubyからMatplotlibのグラフ画像を生成する。

Rubyでグラフ生成ならtopfunky/gruffが有名だが、最近はあまりメンテされてる感じがないし、どうせならMatplotlibの知見を活かしたい

環境

後述するが、Pythonのインストールは若干癖があるので注意

インストール

RubyからPythonを呼び出すにはPycallというライブラリを使う そのまんま

  • [mrkn/pycall.rb: Calling Python functions from the Ruby language]

Gemfileに以下を追加してbundle install

gem "pycall"

Python側でMatplotlibがインストールされている必要があるので、

pip install -U matplotlib

しておく

サンプル

簡単な折れ線グラフを生成してみる

require 'pycall/import'
include PyCall::Import
pyimport 'matplotlib.pyplot', as: 'plt'

plt.title('sample graph')
plt.xlabel('foo')
plt.ylabel('bar')
plt.plot([1,3,2,4])
plt.savefig("graph.png")

すると以下のようなグラフができる!

f:id:thr3a:20190419213115p:plain

エラーになるとき

ImportError

ImportError: No module named site

みたいに怒られる&pyenvでビルドしたPythonを使っていた場合はビルドのオプション「enable-shared」を有効にして再インストールする必要がある。

env PYTHON_CONFIGURE_OPTS='--enable-shared' pyenv install 3.8.0

でおk

Python is not installed as a framework

以下のようなエラー

Traceback (most recent call last):
    3: from index2.rb:19:in `<main>'
    2: from /Users/thr3a/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/pycall-1.2.1/lib/pycall/import.rb:18:in `pyimport'
    1: from /Users/thr3a/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/pycall-1.2.1/lib/pycall.rb:62:in `import_module'
/Users/thr3a/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/pycall-1.2.1/lib/pycall.rb:62:in `import_module': <class 'ImportError'>: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using (Ana)Conda please install python.app and replace the use of 'python' with 'pythonw'. See 'Working with Matplotlib on OSX' in the Matplotlib FAQ for more information. (PyCall::PyError)
  File "/Users/thr3a/.pyenv/versions/3.6.8/lib/python3.6/site-packages/matplotlib/pyplot.py", line 2372, in <module>
    switch_backend(rcParams["backend"])
  File "/Users/thr3a/.pyenv/versions/3.6.8/lib/python3.6/site-packages/matplotlib/pyplot.py", line 207, in switch_backend
    backend_mod = importlib.import_module(backend_name)
  File "/Users/thr3a/.pyenv/versions/3.6.8/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/Users/thr3a/.pyenv/versions/3.6.8/lib/python3.6/site-packages/matplotlib/backends/backend_macosx.py", line 14, in <module>
    from matplotlib.backends import _macosx

これ一見Pycall側のエラーに見えるが実はMatplotlib側のエラーで、Matplotlibの設定を変更する必要がある。

設定ファイルの確認

python -c "import matplotlib;print(matplotlib.matplotlib_fname())"

で表示されたファイル matplotlibrc を開いて、

backend : macosx

backend : Tkagg

に変更して再実行すればおk

余談

red-data-tools/chartyというラッパーがあって、もっとイケてるグラフも簡単に生成できるらしんだが、そもそも動作しなかった。。。。 Chartyの記事書くはずだったんだけど

RubyでFile.read()を使うときは注意が必要だった(過去形)

まとめ

  • Ruby 2.6以前ではFile.read()の引数に|から始める文字列を渡すと、それがそのままコマンドとして実行されてしまう
    • ので、WEBアプリケーションで第三者から受け取ったパラメータをFile.read()に渡すのはセキュリティ的に危険
  • Ruby 2.6.0で修正されたので今後は大丈夫

どういうことか

ちょうどRubyKaigi2019の講演聞いている最中の話。実際に挙動を見てみる

~ $ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]
~ $irb
irb(main):001:0> File.read("|echo 'hello world'")
(irb):1: warning: IO.read called on File to invoke external command
=> "hello world\n"

確かに、コマンドが実行できる。。。!

この挙動は別にバグでもなく仕様で、そもそもFileクラスはIOクラスを継承している。

で、IO.read()の公式ドキュメントを見るとたしかに

Kernel.#open と同様 path の先頭が "|" ならば、"|" に続くコマンドの出力を読み取ります。

となっている。つまり、IO.read()の仕様がそのままFile.read()にも来ているだけである。

IO.read()でコマンド実行できるのセキュリティ的にどうなん?ってIssueが上がって、けどそれはアプリケーションレベルでの問題で、Rubyの問題ではないって話になり、けどFile.read()でまさかコマンドが実行できるのはちょっと(期待される挙動として)おかしくないかって別Issueが上がって、そっちは採択された模様。

なので前述のとおり、Rubyの2.6以降では実行できなくなっている

~ $ruby -v
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin16]
~ $irb
irb(main):001:0> File.read("|echo 'hello world'")
Traceback (most recent call last):
        5: from /Users/thr3a/.rbenv/versions/2.6.1/bin/irb:23:in `<main>'
        4: from /Users/thr3a/.rbenv/versions/2.6.1/bin/irb:23:in `load'
        3: from /Users/thr3a/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):1
        1: from (irb):1:in `read'
Errno::ENOENT (No such file or directory @ rb_sysopen - |echo 'hello world')

こうやってどんどんRubyはよくなっていくんだなぁ(こなみ いやほんとありがとうございます