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

週刊Railsウォッチ: Airbrakeで検出されたエラー内訳記事、Rubyで3Dモデリングほか(20220426後編)

こんにちは、hachi8833です。

週刊Railsウォッチについて

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

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

🔗Ruby

🔗 Airbrakeで検出されたエラー内訳レポート記事(Ruby Weeklyより)

airbrake/airbrake - GitHub

airbrake/airbrake-ruby - GitHub


つっつきボイス:「Airbrakeはエラー監視サービスですね」「言語別で見るとRubyが多い↓のは、AirbrakeがRuby方面で普及しているからだと思いますが、もちろんAirbrakeはRuby以外の言語でも使えます」「そのつもりで読むべきということですね」「Airbrakeの顧客が使っている言語の内訳ぐらいに思うのがいいでしょうね」


同記事より

「通知されたエラーの内37.5%が90日以上放置されているんですって↓」「緊急性の低いエラーだとそうなりそう」「逆にエラーの2/3は2週間以内に修正されていますね」


同記事より

🔗 WAF

「ところで最近は、脆弱性を突こうとしてWAFをくぐり抜けてやってくるヘッダー加工されたリクエストに起因するエラーが増えていますね: LDAPの脆弱性とか」「気づいてなかったけど、もしかすると見落としてるのかな」「同じエラーが繰り返されるときは学習してエラーを減らしたりしているかもしれませんけどね」

参考: Web Application Firewall(WAF) – Wikipedia
参考: CA3005:LDAP インジェクションの脆弱性のコード レビュー (コード分析) – .NET | Microsoft Docs

「ヘッダー加工されたリクエストなんかはWAFがかなり防いでくれますけど、それでもたまにくぐり抜けてくるものが検出されたりする」「攻撃側は手口をいろいろ変えて攻略できる分、有利になりやすい面はありますね」「たしかに」

🔗 Rubyで3Dモデリング


つっつきボイス:「お、Rubyで3Dモデリングか」「DragonRubyを使っている↓」「Rubyだけで書けるゲームツールキット、そういえばありますね」「macOS上で動かしているみたい」「Wasm使ってるかな?」

DragonRuby is a zero dependency, cross platform, Ruby runtime built on top of mRuby, libSDL, and LLVM.
Write Ruby on any OS and deploy to PC, Mac, Linux, iOS, Android, Raspberry Pi, WASM, Nintendo Switch, Sony Playstation, and Microsoft Xbox.
https://dragonruby.org/より

「なおDrogonRubyをやっている人たちは、RubyMotion↓も手掛けてます」「あ、ネイティブアプリをRubyで書いてビルドできるSDKですね」「RubyMotionはRubyKaigiにも何度か登場していますね」「そういえば見たかも」

参考: RubyKaigi 2014 | Inside RubyMotion for Android

🔗 erb2builder(Ruby Weeklyより)


つっつきボイス:「なるほど、erb2builderでERBを解析してビルダー形式のコードに変換できるんですね↓」「記事はERBに含まれるRubyコードを解析してRuboCopなどにかけられるようにしたかったみたいです」

<!-- 同記事より -->
<h1>
  <% if @user %>
    Hello, <%= @user.name %>
  <% else %>
    Not logged in
  <% end %>
</h1>
# 同記事より
> input = File.read("user.html.erb")
> output = Unparser.unparse(Erb2Builder.parse(input))
> puts output

xml << "      "
xml.h1 do
  xml << "\n        "
  xml << ""
  if @user
    xml << "\n          Hello, "
    xml << ""
    xml << @user.name
    xml << "\n        "
    xml << ""
  else
    xml << "\n          Not logged in\n        "
    xml << ""
  end
  xml << "\n      "
end
xml << "\n"

「ERBはそのままだとRubyのASTとして処理できないけど、上の結果を取れればparser gemなどでASTを得られますね↓」

# 同記事より
s(:if,
  s(:ivar, :@user),
  s(:send,
    s(:ivar, :@user), :name), nil)

参考: 抽象構文木(AST) – Wikipedia

whitequark/parser - GitHub

「そういえばRuboCopでERBをチェックできましたっけ?」「原理的にはもちろん可能ですが、構文レベルのチェックまでやりたいなら、何らかのERBパーサーを自分で用意するなどしてAST的に扱えるようにする必要があるでしょうね: 単語レベルのチェックどまりなら正規表現で抽出するぐらいでよさそうですが」「それもそうですね」「ASTの読み方わからない😅」「こういうのは機械で処理するものですから」


後で、以前ウォッチ20201026でShopifyのerb-lintを取り上げていたのを思い出しました↓。

Shopify/erb-lint - GitHub

🔗 その他Ruby

つっつきボイス:「Matzのリツイートで知りました」「自作キーボード勢すごい」「PRKはたしかPicoRubyベースのキーボードファームウェアだったはず↓」「PicoRuby知らなかった〜」

picoruby/prk_firmware - GitHub

picoruby/picoruby - GitHub


後で調べると、prk_firmwareはRuby Prize 2021でも最終ノミネートされていたんですね↓。

参考: Ruby Prize 2021 FINAL NOMINEES Hitoshi Hasumi Interview | RubyPrize


「自作キーボード好きな人って多いのかな?」「自作するとみんなに見せたくなるから目に止まりやすいだけかもしれませんけどね」「まあたしかに」「趣味としてはとっても楽しい😋」

「自分は昔衝動買いして以来KINESIS派」「自分はHappy Hacking Keybord派です」「私もHHK」(以下延々)

参考: Kinesis Advantage2
参考: Happy Hacking Keyboard|PFUダイレクト


HHKといえば、製造・販売元であるPFUについてこんなニュースが今日出ました↓。

参考: 富士通 PFUをリコーに売却へ | MRO北陸放送

🔗DB

🔗 あまり知られていないPostgreSQLの機能


つっつきボイス:「はてブでバズっていた記事でした」「一見タイトル優先のPV狙い記事に見えるけど、知らなかった知見も結構あってとてもいい記事でした👍」「お〜、たくさん載ってますね」

🔗 UPSERTで更新・挿入の行数を取得

「UPSERTで更新・挿入の行数が取れる↓: これはPostgreSQLに前からありますね」「MySQLだと変更しましたということしか教えてくれなかったような覚えがありますけど、行数も取れるんですか」「RETURNING *, (xmax = 0) AS inserted;のようにxmaxを使うことで、更新と挿入の行数をそれぞれ取れるのがいいですね」

--同記事より
db=# WITH new_employees AS (
    SELECT * FROM (VALUES
        ('George', 'Sales',    'Manager',   1000),
        ('Jane',   'R&D',      'Developer', 1200)
    ) AS t(
         name,      department, role,       salary
    )
)
INSERT INTO employees (name, department, role, salary)
SELECT name, department, role, salary
FROM new_employees
ON CONFLICT (name) DO UPDATE SET
    department = EXCLUDED.department,
    role = EXCLUDED.role,
    salary = EXCLUDED.salary
RETURNING *, (xmax = 0) AS inserted;

  name  │ department │   role    │ salary │ inserted
────────┼────────────┼───────────┼────────┼──────────
 Jane   │ R&D        │ Developer │   1200 │ t
 George │ Sales      │ Manager   │   1000 │ f
INSERT 0 2

参考: PostgreSQL 13.1文書 6.4. 更新された行のデータを返すRETURNING

🔗 特定カラムの権限制御

「特定の列の権限付与は?」「カラムに対してGRANTやREVOKEできる機能ですね: これは使ったことなかった」「お〜なるほど!」「特定のカラムだけSELECTを許したい・禁止したいみたいなときに使う感じ」

--同記事より
db=# \connect db postgres
You are now connected to database "db" as user "postgres".

db=# REVOKE SELECT ON users FROM analyst;
REVOKE

db=# GRANT SELECT (id, username) ON users TO analyst;
GRANT

「ただ、こういうことはVIEWでやりたい気もするので↓、自分はあまり使わないかも」「Railsみたいにアプリケーションロジックでもやれますしね」「それにSELECT *したときにpermission deniedみたいなメッセージが出るのはちょっと違和感ある」「RailsだとSELECT *が多用されるからつらそう」

RDBMSのVIEWを使ってRailsのデータアクセスをいい感じにする【銀座Rails#10】

🔗 SIMILAR TO

「SIMILAR TOと|で複数パターンのORマッチングができる: これは使うことがありますね」「これ初めて見ました」

--同記事より
SELECT *
FROM users
WHERE email SIMILAR TO '%@gmail.com|%@yahoo.com'

~で正規表現も使えるし、ANYも使える↓」「何だか凄い」

--同記事より
SELECT *
FROM users
WHERE email ~ '@gmail\.com$|@yahoo\.com$'
--同記事より
SELECT *
FROM users
WHERE email ~ ANY(ARRAY['@gmail\.com$', '@yahoo\.com$'])

参考: PostgreSQL 13.1文書 9.7. パターンマッチ

🔗 シーケンスの取得

「あまり使わないかもしれないけど、シーケンスを進めずにpg_sequencesビューで値を確認できる↓: MySQLだと統計テーブルから取得するヤツですね」「この辺の情報よくググります」

--同記事より
db=# SELECT * FROM pg_sequences WHERE sequencename = 'sale_id_seq';
─[ RECORD 1 ]─┬────────────
schemaname    │ public
sequencename  │ sale_id_seq
sequenceowner │ db
data_type     │ integer
start_value   │ 1
min_value     │ 1
max_value     │ 2147483647
increment_by  │ 1
cycle         │ f
cache_size    │ 1
last_value    │ 155

参考:【MySQL】テーブルの統計情報を取得するSQL | MySQL日記

🔗 PostgreSQLの\COPY

「SQLのCOPYではない、バックスラッシュ付きの\COPYコマンドはとても高速なのでよく使う↓」「お〜」「\COPYはたしかホストのコンテキストで動いたと思います: 実際にやってみるのが早いですね」「後でやってみます」

--同記事より
db=# \COPY (
\copy: parse error at end of line

\COPYはあくまでPostgreSQL CLIのコマンドなので1行でしか書けない、つまり複数行にできない」「\COPYはシェルコマンド的なんですね」「記事では別の方法で回避しています」

🔗 TEMPORARY VIEW

「このTEMPORARY VIEWも知っておくと便利↓: 記事にもあるように、セッションが終了すると自動的に削除される」「へ〜!」

--同記事より
db=# CREATE TEMPORARY VIEW v_department_dbas AS # ...
CREATE VIEW

db=# \COPY (SELECT * FROM v_department_dbas) TO department_dbas.csv WITH CSV HEADER;
COPY 5

参考: PostgreSQL 13.1文書 CREATE VIEW

「TEMPORARY VIEWは、たとえば生SQLでデータを調べるときに便利なんですよ: 問題調査のためにENUM値をCASE-WHENで人間が読めるようにした長大なSELECT文を組み立てて、少しずつ条件やJOIN条件を調整しながらSQLコンソールで実行していると、毎回長大なSQLを実行することになって履歴がぐちゃぐちゃになりがちなんですが、使い捨ての参照用ビューをTEMPORARY VIEWとして作ってSELECTすることで、毎回長大なSQLを書かなくても良くなる」「なるほど!」

「ただし、TEMPORARY VIEWを使うにはCREATEの権限が必要なのが欠点なんですよ」「おぉ?」「データ操作は普通slaveに接続して行うものですけど、slaveでCREATE TEMPORARY VIEWすると通らないということが起きがち」「あ〜、たしかにslaveは普通リードオンリーだけど、CREATE TEMPORARY VIEWはスキーマを編集できる権限が必要なのか!」「TEMPORARY VIEWは便利なのでとても使いたいんですが、権限が足りなくてがっかりすることがたまにありました」


「PostgreSQLは柔軟な書き方がいろいろできるのが強いですね👍」

🔗言語/ツール/OS/CPU

🔗 OneLang: 複数言語間をトランスパイルする言語


つっつきボイス:「サイトを開いて上のDemoのプルダウンを選んでみてください」「同じコードがRubyやPerlやいろんな言語で表示されてますね」


ide.onelang.ioより

「Generic featuresを選んで左上のTypeScriptのコードを書き換えると他のコードもリアルタイムで書き換えられるのか!」「TypeScriptを元にして他の言語に変換しているのかな?」「Cross-language editingにするとTypeScript以外を書き換えても相互に反映されました」

「お〜、TypeScriptのlet mapObj = { x: 5, y: 1 };1を文字列に書き換えてみると、ちゃんとJavaのコードでIntegerObjectに変わりますね」「賢い!」「凄い」「さすがに型がある言語をソース側にしないとできないでしょうけど」

// Java
    public Integer mapTest() throws Exception
    {
        HashMap<String, Integer> mapObj = new HashMap<String, Integer>();
        mapObj.put("x", 5);
        mapObj.put("y", 1);

        //let containsX = "x" in mapObj;
        mapObj.put("z", 9);
        mapObj.remove("x");

        List<String> keysVar = new ArrayList(mapObj.keySet());
        List<Integer> valuesVar = new ArrayList(mapObj.values());
        return mapObj.get("z");
    }
// ↓
    public Integer mapTest() throws Exception
    {
        HashMap<String, Object> mapObj = new HashMap<String, Object>();
        mapObj.put("x", 5);
        mapObj.put("y", "hoge");

        //let containsX = "x" in mapObj;
        mapObj.put("z", 9);
        mapObj.remove("x");

        List<String> keysVar = new ArrayList(mapObj.keySet());
        List<Object> valuesVar = new ArrayList(mapObj.values());
        return mapObj.get("z");
    }

「同じコードをいろんな言語で同時に書きたい人向けなのかな?」「やってみたいから作ったんでしょうね」「リポジトリの説明が面白いですね↓」

onelang/OneLang - GitHub

OneLang.ioとは何か
OneLang自身を定義するのは難しい。
これをトランスパイラ(入力言語から別の入力言語へソースコードをコンパイルできる特別なコンパイラ)と呼ぶ人もいるかもしれない。しかしOneLangは独自の規則を備えていて、入力言語の規則を(下手をすると構文すら)尊重しないので、そういう人にとっては使うのが難しいだろう。
そこでこんな疑問が生じる。OneLangは新しいプログラミング言語なのか?オブジェクト指向や、ジェネリックや、強い型付けといった言葉で語ることもできるが、OneLangは独自の型システムとASTを備えている。
そういうわけで、当面はOneLangをこう定義しておくことにする。OneLangは、複数の言語で同時にコードを書くことを支援するツールであると。
何か問題を解決するわけではなく、少しばかり助けになるに過ぎない。実用的なものを作るには、ターゲット言語とOneLangの両方をマスターする必要がある。
同リポジトリより


後編は以上です。

バックナンバー(2022年度第2四半期)

週刊Railsウォッチ: Active Recordのattribute更新系メソッド比較リスト、Railsリファクタリングガイドほか(20220425前編)

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

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

Ruby Weekly


CONTACT

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