Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ(20210309後編)RubyのIRBに隠れているイースターエッグ、Power Automate Desktop、SQLクエリのありがちなミス6つほか

こんにちは、hachi8833です。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙇

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗Ruby

🔗 RubyのIRBに隠れているgem(Ruby Weeklyより)


つっつきボイス:「gemでないものも含めてIRBにはいろんなものが入っているという記事です」

「Ruby 2.7から入ったと記事に書かれているreline gem↓もIRBで使われている」「relineといえば、@aycabtaさんが心血を注いだgemですね」「他にRipper(パーサー)も使われている」

ruby/reline - GitHub

参考: class Ripper (Ruby 3.0.0 リファレンスマニュアル)

RubyKaigi Takeout 2020の動画を見つけました。

loaderというextensionが入っている: こんなふうにIRBのコンテキストでファイルを読み込んで評価できる↓」「おぉ〜」「-r付けてファイルを読み込む、そういえばやったことあったかも」「irb_loadでIRBの中でもファイルを読み込めるのか」

# 同記事より
$ irb -r ./hi.rb
Hi codenamev!
irb(main):001:0>

参考: ruby/loader.rb at master · ruby/ruby
参考: ruby/loader.rb at master · ruby/ruby · GitHub

use_tracerは自分も使ってます」「最近入ったmeasureはウォッチでも話題にしましたね(ウォッチ2021_02_02)」

参考: ruby/tracer.rb at master · ruby/ruby
参考: ruby/measure.rb at master · ruby/ruby · GitHub

ruby/tracer - GitHub

「以前だとpryを入れないとできないことがありましたけど、今はRuby標準のIRBでできることがとても増えましたよね」「IRBはすごく使いやすくなったと思います」

pry/pry - GitHub

🔗 IRBに隠された「イースターエッグ」

「お、IRBにはイースターエッグが隠されているようですよ」「どれどれ👀」「こんなのが隠れてたなんて!」


同記事より

参考: ruby/easter-egg.rb at master · ruby/ruby

「Ruby 3.0のIRBを立ち上げてIRB.send :easter_eggと入力したら動きました!」「このeaster-egg.rbを明示的に読み込めば他のバージョンのRubyでも動かせそうですね」

「手元のRuby 2.7.1だと以下のような静止画↓で表示されたけど、easter-egg.rbのソースを見るとtypeに:logo:dancingがある: ということは、IRB.send :easter_egg, :dancingと入力すると...動くイースターエッグが出た!🎉」

(注: 微妙に色が付いているのはhachi8833のiTerm設定によるものです)


ちょうどもうすぐイースターなので季節感ありますね。

後で手元のrbenv環境でRubyのバージョンを変えて試したところ、easter-egg.rbはどうやらRuby 2.7.1から入ったようです。Ruby 3.0.0から動くイースターエッグがデフォルトになったんですね。もしやと思って履歴を調べると、動くバージョンを入れたのはやはりmameさんでした。

ついでにeaster-egg.rbをローカルにダウンロードし、easter-egg.rbが入っていないRuby 2.7.0でirb -r ./easter-egg.rbを実行してIRB.send :easter_eggを実行すると、動くイースターエッグが表示されました。

🔗 bundle openでgemを検索・デバッグする(Ruby Weeklyより)


つっつきボイス:「Bundlerにもいろいろ機能が隠れていますね」「bundle open gem名でgemをエディタで開けるらしい」「このopenってもしかしてMacのopenコマンドにしか対応してないのかなと思ったら、Ubuntuでも動いたので大丈夫ですね」「お、なるほど」

「自分も手元でGemfileのあるプロジェクトでやってみたら環境変数でエディタを設定しろと言われたので↓、BUNDLER_EDITOR=vi bundle open nokogiriとしたら動きました」

$ bundle open nokogiri
To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR

🔗 Enumerable#filter_mapRuby Weeklyより)

↑記事の末尾にあります。filter_mapはRuby 2.7で入ったそうです。


つっつきボイス:「小ネタですが、Ruby Weeklyの末尾に載ってるTip of the Weekを拾いました」「filter_mapという名前からして、filtermapを一度にできそう」

参考: Enumerable#filter_map (Ruby 3.0.0 リファレンスマニュアル)

「まさにfilterしたものに対してmapする処理を1個のブロックでまとめて書けるんですね↓」「これは使いたい機能👍」

# Ruby Weekly #541より
[1,2,3,4,5,6].filter_map { |x| x ** 2 if x.even? }
#=> [4,16,36]

「ところでfilter_mapはあるけどselect_mapはないらしい」「言われてみればfilterselectってどちらかがエイリアスでしたっけ?」「ドキュメントを見ると、Rubyのfind_allselectfilterは等価ですね↓」

参考: Enumerable#filter (Ruby 3.0.0 リファレンスマニュアル)

🔗 RubyのnotHacklinesより)


つっつきボイス:「シンタックスハイライトなしでベタに書くと混乱するタイトルをわざと使ってますね☺️」

後でタイトルを手元でハイライトしてみました↓。最後の「(not)」は、「でも実は同じではない」というニュアンスのようです。

Ruby's not keyword is not not but !(not)

「Rubyの否定演算子といえば!ですけど、notってあったかな?」「自分も知らなかったんですが、探すとnotキーワードがありました↓」「not!よりも優先度が低い、なるほど」

参考: 演算子式 (Ruby 3.0.0 リファレンスマニュアル)

# docs.ruby-lang.orgより
高い   ::
       []
       +(単項)  !  ~
       **
       -(単項)
       *  /  %
       +  -
       << >>
       &
       |  ^
       > >=  < <=
       <=> ==  === !=  =~  !~
       &&
       ||
       ..  ...
       ?:(条件演算子)
       =(+=, -= ... )
       not
低い   and or

「Rubyのnotは、andorの次に優先順位が低いんですね」「スペルアウトしたandorがあるならnotがあるのもわかる気がする」「記事では!notを再定義してみてますね↓」「notを実際に使うことはあまりなかったな」

# 同記事より
# ~/code/ruby/rubys_not_is_not_not_but_!_(not).rb

class Banger
  def !
    :bang
  end
end

class Naysayer
  def not
    :nay
  end
end

(Ruby 1.9の)ドキュメントにあるように、Rubyの!はオーバーライドできるので、! message()のようにメッセージの前に置いても値をオーバーライドできます。しかしnotキーワードのオーバーライドは、instance.not()のようにインスタンスの戻り値にしか効きません。
!をオーバーライドするとnotにも効くので、notは何らかの形で!を使っていることがわかります。
ただし!notは機能(つまり優先順位)が異なるので、互いにエイリアスではありません。
同記事より大意

🔗 その他Ruby


つっつきボイス:「よく言われている話ですが一応取り上げてみました」「『macOSに最初から入っているRubyは使わないこと』というのはMacで開発するときの常識になっていますが、初心者がハマる原因でもありますね」

「最近Mac使っていないので昔の話になりますが、macOSに最初から入っているRubyはバージョンが古かったし、記事にもあるようにgemをインストールするのにroot権限を要求されたりとかいろいろ不便でしたね」「あれはつらかったです...😢」

「今のmacOSに入っているRubyのバージョンっていくつなんだろう?」「あ、そういえば今はどうなってるのかな?」


後で調べると、自分のMacBook(OSはCatalina: 10.15.7)の/usr/bin/rubyは2.6.3p62でした。

$ /usr/bin/ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]

今ならウォッチでも取り上げたRails Girlsのインストールレシピ↓を参考にするのがよいでしょうね(ウォッチ20210126)。

参考: Rails Girls インストール・レシピ: Rails Girls - Japanese

🔗DB

🔗 SQLクエリのありがちなミス6つ(DB Weeklyより)

つっつきは6つから抜粋しました。

🔗 NULL値に対してNOT INを使うミス

つっつきボイス:「記事にあるNOT IN (c001, c003, c004, NULL)のように書いたり、なんとか=NULLのように書いたりしても期待どおりには評価されないので、基本的にはカラム定義でNULLを許すときは気をつける必要がありますね」「たしかに」「なお、SQL標準でも多くのRDBでもNULL = NULLはfalseになります」

「RailsのActive Recordではそういう場合にIS NOT NULLをAND条件でつないでくれますが、生SQLを書くときには自分でこうした点に注意する必要があります」

🔗 クエリの句の順序が正しくないミス

SELECTFROMWHEREの次は、『GROUP BYしてHAVINGしてからORDER BYする』という順序で書くのがSQLの構文レベルで決まっているので、順序を間違えるとその時点でシンタックスエラーになります」

-- 同記事より: 間違っている例
SELECT empName 
FROM employees 
WHERE empCategory='DevOps' 
ORDER BY empName 
GROUP BY branchCode 
HAVING count(*) = 1;
-- 同記事より: 正しい例
SELECT empName 
FROM employees 
WHERE empCategory='DevOps' 
GROUP BY branchCode 
HAVING count(*) = 1
ORDER BY empName;

🔗 BETWEENを両端の値を含まない範囲指定として使うミス

「そうそう、SQLのBETWEENは両端の値を含むのが要注意ですね: 4月中の日付で取ろうとして以下のように書いてしまうと、5月1日のものまで取ってしまう↓」

-- 同記事より
SELECT *
FROM products
WHERE manuf_date BETWEEN ‘2020-04-01’  AND ‘2020-05-01’

「そういえば学校で教える英語では常識的にbetweenは両端を含まない(exclusive)なので、英語圏の人がそこで間違えやすそうですね」「そうそう、自分もそこが昔から気になっているんですが、どういうわけかSQLのBETWEENは境界値を含む(inclusive)仕様になっているんですよ」「英語圏では直感に逆らいそう...」

参考: [SQL] 5. データの参照 5 | TECHSCORE(テックスコア)

「少なくとも翻訳の世界では、たとえば"between 2020-01-01 and 2020-02-01"と書かれていたら、1月1日と2月1日は含まないと解釈するんですが、原文が正しくそのつもりで書かれているとも限らないのが要注意だったりします」「へ〜」「ちなみに境界値を含めたい場合はfromとtoで書きます」「たしかにfromとtoで書く方が誤解されなさそう」

「SQLのBETWEENはそうやって面倒になりがちなので、最終的には以下のように書くことが多いかな↓」「なるほど」「これもRailsのActive Recordなら、rangeで指定するとinclusive/exclusiveに応じてBETWEENを使うか使わないかを自動で判断してくれますね」

-- 同記事より
SELECT *
FROM products
WHERE manuf_date => ‘2020-04-01’
AND manuf_date < ‘2020-05-01’

後で調べて思い出しましたが、英語のbetweenは「その期間のどこかの時点」という単発的なニュアンスを含み、fromとtoだと「その期間ずっと」という継続のニュアンスを含むことがよくあります。

参考: 7つの不思議な仕事?(from A to Bの違い?) | 実践で使える英語をマスター!GLJ英語学院/ビズ英アップ!スクール

ついでながら、英語の"between you and me"は「ここだけの話なんだけど」「これは二人だけの秘密だよ」というイディオムです。

🔗 実行時の暗黙のフィールド定義型変換

「これはRDBMSに依存する部分も大きいのでなかなか厄介な問題ですね: 以下のpinがvarcharの場合暗黙で強制変換されて、ランタイムエラーにこそならないけどパフォーマンスが落ちることがある」

-- 同記事より
SELECT *
FROM myAccount acc
WHERE acc.pin = 123654789286
AND acc.isPending IS null;

「MySQLはこういう場合に割といい感じに型変換してくれますが、PostgreSQLはデフォルトだとお固い傾向がありますね」「なるほど」「PostgreSQLもimplicit conversionを指定すればMySQL並に型変換できるようになりますが、それらも含めてこの問題はRDBMSによって変わってきます」

参考: PostgreSQL 12.4文書 CREATE CAST

「これについてもActive Recordはよしなに対応してくれるので、自分でクエリを書くときもActive Recordが出すクエリを参考にすれば、MySQLでは通るのにPostgreSQLでは通らないということを避けたいときにいいでしょうね」「なるほど!」

🔗 kamipo TRADITIONAL

「特にMySQLを使う場合は、通称『kamipo TRADITIONAL』を参考にするといいと思います」「お、何ですかそれ?」「これです↓」

参考: ルーク!MySQLではkamipo TRADITIONALを使え! | おそらくはそれさえも平凡な日々

「記事にもあるようにsql_modeを以下のような感じで設定しておくと、MySQLでも標準SQLに近いクエリしか通らなくなりますので、そうした問題を回避できます」「知らなかった〜」

# https://songmu.jp/riji/entry/2015-07-08-kamipo-traditional.html より
SET SESSION sql_mode='TRADITIONAL,NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY'

「特にONLY_FULL_GROUP_BYは付けることを習慣づけておくといいと思います: ただMySQLの楽な書き方に慣れていると、SELECTするカラムが多い場合にGROUP BYをすべて書くのが面倒に感じられたりもするんですよね...」


「以上、昔からよくあるありがちなSQLのミスでした」

🔗言語/ツール/OS/CPU

🔗 マイクロソフトのRPA「Power Automate Desktop」(Publickeyより)


つっつきボイス:「ちょっと試してみたそうですね」「そうそう、こんな感じでEC2インスタンスを取得したりできます↓」

「Power Automate Desktopは、一度動かすと右のペインで変数の値を参照できたりするのがなかなかよくできていると思いました」「お〜、ExcelのVBA画面みたいですね」「少しずつ動かしながら変数の値を確認して書き足す、といった使い方ができます」

参考: Visual Basic for Applications - Wikipedia

「もちろんまだ成熟していない機能もいろいろありますが、変数の宣言方法以外はドキュメントをほとんど見ないで書けたのはよかった」「へ〜!」「Power Automate Desktopは前から有料版があったのが無料でもダウンロードして利用できるようになったそうです」「記事にも今後はWindows 10に標準搭載されるとありますね」

参考: Power Automate Desktop のよくある質問集 - 吉田の備忘録

「Macに入っているApple ScriptのAutomatorよりはイケてる感じでしょうか?」「Automatorはほとんど使ったことがありませんが、感覚的にはZapierに近いかな」「なるほど」

参考: Automator Actionを実行 – AppleScriptの穴
参考: Zapier | The easiest way to automate your work

「Power Automate Desktopはプログラマーでない人でも作ることができて、この種のツールとしては比較的機能が揃っているのがいいですね: プログラマー向けにはPythonスクリプトの実行やSFTP接続といった項目もあります」「ホントだ」「ちょっとした日々の運用タスクをある程度自動化するのによさそう👍」

🔗 cosmopolitan: 複数環境で実行できるポータブルバイナリを出力(StatusCode Weeklyより)

jart/cosmopolitan - GitHub

cosmopolitan: 国籍や国境にとらわれない国際人


つっつきボイス:「マルチな環境で動くシングルバイナリを出力できるそうです」「リポジトリに貼ってある動物の絵はスカンクかな?」「Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOSで動くって、そんなことが可能なのかしら?」

「リポジトリに謎のタイトルの関連ブログ記事が貼ってある↓」「あ、それはニセのギリシャ語で書かれた英語タイトルです」「ニセギリシャ語😆」「記事を眺めた限りでは、シングルバイナリをマルチな環境で動かす方法があるらしい」「へ〜!」

参考: αcτµαlly pδrταblε εxεcµταblε

「以下のredbeanも同じ人がcosmopolitanをベースに作ったそうです」「実用性はともかく技術的なチャレンジとして面白い」「誰得感ありますね」「スゴい人がいるもんだ...」


後編は以上です。

バックナンバー(2021年度第1四半期)

週刊Railsウォッチ(20210308前編)書籍『Ruby on Rails Performance Apocrypha』、rswag gemほか

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Ruby Weekly

Hacklines

Hacklines

StatusCode Weekly

statuscode_weekly_banner

Publickey

publickey_banner_captured

DB Weekly

db_weekly_banner


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。