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

週刊Railsウォッチ: HashieでRubyのハッシュを強化、最近のRubyコア解説記事ほか(20220412後編)

こんにちは、hachi8833です。

週刊Railsウォッチについて

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

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

🔗Ruby

🔗 Hashie: Rubyのハッシュを強化するライブラリ

hashie/hashie - GitHub


つっつきボイス:「BPSのWebチーム内発表で取り上げられていたHashieです」「そうそう、なかなかよさそうなライブラリ」「OpenStructよりいいらしいという評判ですね」

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

「どんなことができるんですか?」「Hashieはハッシュの機能を拡張する複数の便利クラスで構成されていて、たとえばメインと思われるHashie::Mashを使うとハッシュをメソッド呼び出し記法で(JavaScriptのオブジェクトプロパティ風に)キーにアクセスできる↓」「お〜」「Rubyのハッシュと互換性があるので、従来のようにmash[:name]でもアクセスできます」「存在しないキーに代入できるのもJavaScriptのオブジェクトプロパティみたいですね」

# 同リポジトリより
mash = Hashie::Mash.new
mash.name? # => false
mash.name # => nil
mash.name = "My Mash"
mash.name # => "My Mash"
mash.name? # => true
mash.inspect # => <Hashie::Mash name="My Mash">

mash = Hashie::Mash.new
# use bang methods for multi-level assignment
mash.author!.name = "Michael Bleigh"
mash.author # => <Hashie::Mash name="Michael Bleigh">

mash = Hashie::Mash.new
# use under-bang methods for multi-level testing
mash.author_.name? # => false
mash.inspect # => <Hashie::Mash>

参考: JavaScript オブジェクトの基本 - ウェブ開発を学ぶ | MDN

「Hashieは多機能で★の数も多いし、メジャーなライブラリのひとつであるOmniAuthもこのHashieに依存していることを考えると筋はよさそうに見える」「お〜」「こういうハッシュの拡張はつい自作しがちですが、Hashieをうまく使えば車輪の再発明をしなくて済むかも」

omniauth/omniauth - GitHub

Hashie::MashのほかにもHashie::DashHashie::TrashHashie::ClashHashie::Rashといった機能があります: たとえばHashie::DashはRailsのActiveRecord::Attributes的に使える↓」

# 同リポジトリより
class Person < Hashie::Dash
  property :name, required: true
  property :age, required: true, message: 'must be set.'
  property :email
  property :phone, required: -> { email.nil? }, message: 'is required if email is not set.'
  property :pants, required: :weekday?, message: 'are only required on weekdays.'
  property :occupation, default: 'Rubyist'
  property :genome

  def weekday?
    [ Time.now.saturday?, Time.now.sunday? ].none?
  end
end

p = Person.new # => ArgumentError: The property 'name' is required for this Dash.
p = Person.new(name: 'Bob') # => ArgumentError: The property 'age' must be set.

p = Person.new(name: "Bob", age: 18)
p.name         # => 'Bob'
p.name = nil   # => ArgumentError: The property 'name' is required for this Dash.
p.age          # => 18
p.age = nil    # => ArgumentError: The property 'age' must be set.
p.email = 'abc@def.com'
p.occupation   # => 'Rubyist'
p.email        # => 'abc@def.com'
p[:awesome]    # => NoMethodError
p[:occupation] # => 'Rubyist'
p.update_attributes!(name: 'Trudy', occupation: 'Evil')
p.occupation   # => 'Evil'
p.name         # => 'Trudy'
p.update_attributes!(occupation: nil)
p.occupation   # => 'Rubyist'
p.genome = -> { Genome.sequence } # Some expensive operation
p.genome       # => 'GATTACA'

Rails: ActiveRecord標準のattributes APIドキュメント(翻訳)

「Hashieに似ているものとしてdry-rb(旧virtus)のdry-structがありますけど、Hashieはdry-rbのハッシュ周りの機能をもっと強化したような印象」「ふむふむ」「Hashieのコードを少し追ってみるとmethod_missingが使われているのが気になるぐらいかな」

dry-rb/dry-struct - GitHub

solnic/virtus - GitHub

参考: BasicObject#method_missing (Ruby 3.1 リファレンスマニュアル)

「勉強会でも話題になりましたけど、DashのDはdiscrete set(離散集合)とか、TrashのTはキーのtranslate(変換)とか、ClashのCはChainable Lazy Hashとか、RashのRはRegexpsやRangesというふうに、語尾が-ashで韻を踏んでる感じの命名っぽいですね」「この辺の命名はちょっと微妙かな...」

「Hashieを使いたくないという記事もありますね↓(もうディスコンになったVirtusに言及している分古いですが)」「Hashieを使う場所と使わない場所が混在すると見分けづらくなるというのはたしかにそう」「RBSなどの静的型チェックでうまく制約をかけられるといいかも、でもHashie::Mashの実装はmethod_missingを使っているのでRBSによる静的チェックは厳しそうだなあ」

参考: hashie gemを使わない3つの理由 | デロイト トーマツ ウェブサービス株式会社(DWS)公式ブログ

ruby/rbs - GitHub

「数字がキーの場合はメソッドにできないというのはRubyの言語仕様なのでしょうがない」「Rubyの識別子は数字で開始できないんですよね」「う、そうなんですか😅」

参考: 字句構造 (Ruby 3.1 リファレンスマニュアル)

「あれば使いたいと思える機能がいろいろありそうなので、機会があればHashieを試してみたい👍」

🔗 最近のRubyコア解説記事

つっつきボイス:「WasiサポートやFiberなどに言及されているので、Ruby 3.2.0 Preview 1を含む最近のRubyの改修についての解説ですね」「これはリリースノートの単なる写しとかではないですね: 思ったより濃い話題でよさそう👍」「翻訳して欲しい〜」「はい、依頼かけます(後で許可もらえました🎉)」

参考: Ruby 3.2.0 Preview 1 リリース

🔗 Ruby 3.2.0 Preview 1

「そういえばRuby 3.2.0 Preview 1ではWASIベースのWebAssemblyが使えるようになってますね」「お〜すごい」「パターンマッチングのFind Patternもexperimentalが取れた🎉」

参考: Ruby3.0でのパターンマッチ機能の変更点 - メドピア開発者ブログ

「正規表現のタイムアウト機能もよさそう↓」「これは今すぐ使いたい機能」「Regexp.timeoutでグローバルに設定しておくだけで使えるので、ReDoS防止の一環として入れておかない手はない感じですね」

# https://www.ruby-lang.org/ja/news/2022/04/03/ruby-3-2-0-preview1-released/ より
Regexp.timeout = 1.0

/^a*b?a*$/ =~ "a" * 50000 + "x" #=> 1秒後にRegexp::TimeoutError

はじめての正規表現とベストプラクティス10: 危険な「Catastrophic Backtracking」前編

🔗 parallel gem(Ruby Weeklyより)

grosser/parallel - GitHub


つっつきボイス:「parallelは結構有名ですね」「割と使われている印象あります」「プロセスとスレッドとRactorをオプションで使い分けられるのか」「Parallel.mapなどで直感的かつ手軽に書けるのはいいですね: ブロック内で時間のかかる処理がある場合にいい感じにできそう👍」「Ractorを使うにはRuby 3.0以上が必須、たしかに」「ブロック内で例外が発生すると追いかけるのが大変かも」

# 同リポジトリより
# 2 CPUs -> work in 2 processes (a,b + c)
results = Parallel.map(['a','b','c']) do |one_letter|
  SomeClass.expensive_calculation(one_letter)
end

# 3 Processes -> finished after 1 run
results = Parallel.map(['a','b','c'], in_processes: 3) { |one_letter| SomeClass.expensive_calculation(one_letter) }

# 3 Threads -> finished after 1 run
results = Parallel.map(['a','b','c'], in_threads: 3) { |one_letter| SomeClass.expensive_calculation(one_letter) }

# 3 Ractors -> finished after 1 run
results = Parallel.map(['a','b','c'], in_ractors: 3, ractor: [SomeClass, :expensive_calculation])

Ruby 3: FiberやRactorでHTTPサーバーを手作りする(翻訳)


なお、以下は以前のウォッチでも取り上げた姉妹品的なgemです。

grosser/parallel_tests - GitHub

🔗 その他Ruby(Ruby Weeklyより)


* 元記事: SokoAdventure by victords


つっつきボイス:「SokoAdventureはRubyで書かれた倉庫番的なゲームです」「debとexeはあるけどMac版がありませんね😆」「惜しい」「GUIアプリをマルチプラットフォームにするのはいろいろ大変」

参考: 倉庫番 - Wikipedia

🔗DB

🔗 Amplify GraphQL Transformer v2


つっつきボイス:「AWS Amplifyのバージョンが上がって機能が増えているそうです」「GraphQL Transformerがあるのか」「AWS AmplifyはGoogleのFirebaseと似た印象: フロントエンドエンジニアがGraphQLでデータストアにアクセスして、サーバーサイドロジックが少ないアプリを手軽に作りたいときに便利そうかな: AppSyncのGraphQLエンドポイントをAmplifyでサクッと構築できる感じで」

参考: AWS Amplify(アプリケーションの構築とデプロイ)| AWS
参考: Amplify GraphQL Transformer v2 まとめ
参考: Firebase
参考: AWS AppSync とは? - AWS AppSync

🔗クラウド/コンテナ/インフラ/Serverless

🔗 AWS Lambda Function URL


つっつきボイス:「ぼくのツイートだ」「これは待望の機能」「俺たちが欲しかったのはこれ」「そうそう」

参考: [新機能] AWS Lambda Function URLで簡単にLambda関数を実行する - NRIネットコムBlog

「先週話題にした、LambdaからAPIエンドポイントを叩いてバッチ処理を実行する話をちょっと思い出しました(ウォッチ20220406)」「今回のAWS Lambda Function URLは先週のバッチ処理の話とはちょっと違いますね」

「これまでAWS LambdaをWeb APIとして提供しようとするとAPI GatewayやALBも買わないといけなくて、シンプルなWebhookを処理するAPIを作りたいだけの場合だとコスト的にも見合わない感じだったんですが、AWS Lambda Function URLが登場したことでそういうのが不要になった」「やったね」「たとえば一部の機能だけをLambdaで書くみたいなことが、これまでよりも気軽にできるのはありがたい👍」

参考: Amazon API Gateway(規模に応じた API の作成、維持、保護)| AWS
参考: Application Load Balancer とは? - Elastic Load Balancing

「AWS Lambda Function URLの場合はURLを自分で決められないんでしたっけ」「AWSが提供するURLを使うことになるのでそうなりますね」「URLも自分で決められたらAPI Gatewayを使っているユースケースの一部が移行対象にされちゃいそう😆」

「AWS Lambdaが最初に大々的に登場した頃、このFunction URLの機能が使えるのかと思ったらそうじゃなかったのを思い出した」「当然この機能を期待しますよね」「随分待たされたけど、ついにできるようになった🎉」「後はLambdaの最大15分という時間制限も撤廃されて欲しいです」「ちなみに、スロットリングも制御したいならAPI Gatewayを使うことになるでしょうね」

参考: AWS Lambda のタイムアウトが15分になりました。 | Amazon Web Services ブログ
参考: Lambda 関数の同時実行数を超えた呼び出しでスロットリングエラーが発生したことを確認する方法 | DevelopersIO

🔗CSS/HTML/フロントエンド/テスト/デザイン

🔗 Open Props: CSS変数を取り入れたフレームワーク


つっつきボイス:「CSS変数を全面的に取り入れたCSSフレームワークだそうです」「@import "https://unpkg.com/open-props";を書けば--radius-2のような定義済みのCSS変数をvar()の中に書けるということみたい」

// 同サイトより
.card {
  border-radius: var(--radius-2);
  padding: var(--size-fluid-3);
  box-shadow: var(--shadow-2);

  &:hover {
    box-shadow: var(--shadow-3);
  }

  @media (--motionOK) {
    animation: var(--animation-fade-in);
  }
}

参考: CSS カスタムプロパティ (変数) の使用 - CSS: カスケーディングスタイルシート | MDN

参考: これまでとは異なるCSSフレームワークが登場! 一貫性のあるUIコンポーネントを簡単に実装できる -Open Props | コリス

See the Pen
Open Props - Color schemes (auto, light, dark, dim, grape)
by Adam Argyle (@argyleink)
on CodePen.

「手元のRubyMineでopen-propsのCSSを整形してみるとこうなってた↓: この作りなら既存のスタイルとの衝突は起きにくそうに見える」「お〜、こういう書き方するんですね」「でもCSSフレームワークを追加したりすると、複数のスタイルが混在してますますカオスになるので避けたい」「たしかに」

🔗言語/ツール/OS/CPU

🔗 ギャルのための開発環境カスタム


つっつきボイス:「はてブでバズっていた記事です」「キーを打つたびに火花が散るとか、git pushするとロケットを打ち上げるとか」「一度はこういうことに夢中になりますよね」「Windows 2000の頃にこういうのよくやってた: エクスプローラをMac風にするとか」「あったあった😆」「こういうものをカスタマイズしたり壊したりしているうちにいろいろ理解が進むので、学生ならやりたいと思ったときにやってみるのがいいと思います」「そうそう」「社会人は業務に支障が出ないようにしないとですけどね」


後編は以上です。

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

週刊Railsウォッチ: Turbo Railsのチュートリアル、Active Recordの「Leaky Abstraction」を削減ほか(20220411前編)

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

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

Ruby Weekly


CONTACT

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