- Ruby / Rails関連
週刊Railsウォッチ: Ruby 3.2のData#initializeの設計、ruby-openai gemほか(20230222後編)
こんにちは、hachi8833です。
Firefox 110がリリースされて、主要ブラウザでコンテナクエリが使えるようになりましたね。
参考: コンテナクエリ @container が全ブラウザ対応。新時代のレスポンシブ対応を完全理解する
🔗Ruby
🔗 Ruby 3.2のData#initialize
にキーワード引数も位置引数も渡せる理由
つっつきボイス:「Ruby 3.2のData
を手がけたコミッターの1人であるzverokさんのこの記事を翻訳していて、Data
で定義したものには値をキーワード引数で渡すことも位置引数で渡すこともできることを今頃知りました↓」「Ruby 3.2のData
はまさに"俺たちが欲しかったもの"だと思います」「RubyのStruct
がこれまで思いの外使いにくかった面はありますね」「Data
はRuby 3.2で一番使いたい機能👍」
# 同記事より
Point = Data.define(:x, :y)
p1 = Point.new(1, 2) #=> #<data Point x=1, y=2>
# or...
p2 = Point.new(x: 1, y: 2) #=> #<data Point x=1, y=2>
参考: class Data
(Ruby 3.2 リファレンスマニュアル)
参考: class Struct
(Ruby 3.2 リファレンスマニュアル)
「記事によると、Ruby 3.2ではStruct
で定義したものにも値をキーワード引数/位置引数で渡せるようになっているんですね↓」「そうそう、この間触れたkeyword_init
オプションはこの変更に関連したものですね(ウォッチ20230201)」
# 同記事より
MutPoint = Struct.new(:x, :y)
MutPoint.new(1, 2) #=> #<struct MutPoint x=1, y=2>
MutPoint.new(x: 1, y: 2) #=> #<struct MutPoint x=1, y=2>
「あとzverokさんの記事の冒頭で、以前も取り上げたRuby Changesサイトの更新情報にRuby 3.2を反映中と書かれていて、今見ると完了したようです↓」「このサイトの更新情報は詳しく記載されていていいですよね👍」「Ruby 2.0からの進化をまとめたRuby Evolutionという項目も凄い」
参考: Introduction - Ruby Changes | rubyreferences.github.io
追記(2023/03/08): その後翻訳記事を公開しました↓
🔗 YAMLドキュメント from hell
つっつきボイス:「この記事でYAML1.1以前に"ノルウェー問題"があったことを初めて知りました: 国名を2文字で表したときにno
がfalse
に解釈される問題です↓(YAML1.2で解決)」「あ〜そういうことですか」
#. 同記事より
geoblock_regions:
- dk
- fi
- is
- no
- se
# 同記事より
{"geoblock_regions": ["dk", "fi", "is", false, "se"]}
「別記事を見ると、YAML1.1以前ではこれらのものがtrue/falseと判定されていたらしい↓」
参考: YAML: The Norway Problem – Bram.us
# https://www.bram.us/2022/01/11/yaml-the-norway-problem/より
y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF
参考: Boolean Language-Independent Type for YAML™ Version 1.1
参考: YAML Ain’t Markup Language (YAML™) revision 1.2.2
「YAMLは元々、ちょっとしたデータを手軽に書けるようにするところから始まったデータフォーマットだと思うんですが、期待されるものやデータがだんだん大きくなってくるに連れてこういう問題が起こることがありますね」「なるほど」「YAMLの中でもヒアドキュメントや値のマージ機能など、環境や処理系のバージョンによって振る舞いが異なることもあったりしますね: おそらくですが最初のうちは厳密さよりも手軽さの方がメインだったのかなと想像しています」
「かといってJSONにもコメントが書けないなどのつらみがあるので、記事でもTOMLやJSON with commentsのような別のフォーマットを検討していますね」「コメント書けないJSONつらい...」
参考: TOML: Tom's Obvious Minimal Language
参考: JSON With Commas and Comments | nigeltao.github.io
「ちなみにGitLabのCI(GitLab Runner)でもTOMLが使われています」
参考: Advanced configuration | GitLab
「その記事には書かれていませんが、ここ数年JSON5というECMAScript 5.1を取り入れたフォーマットも登場しているようです↓」「JSONがあまりにも普及してるので、JSON5が流行るかどうかは既存のJSONライブラリがJSON5をどこまで処理できるようになるか次第かな」「たしかに」「JSON5が普及するためには既存のライブラリが地道に対応していくのが確実でしょうね」
参考: JSON5 – JSON for Humans | JSON5
「考えてみれば、JSONもJavaScript Object Notationの略だけあって、昔はroot要素にオブジェクトしか置けなかったりしましたね: 今はroot要素に配列も使えますが、すごく古いJSONライブラリだと使えないこともありました(さすがに最近はないと思いますが)」
🔗 Rubyの例外処理のパフォーマンス(Ruby Weeklyより)
つっつきボイス:「Rubyの例外処理をベンチマークで調べながら例外処理のパフォーマンスへの悪影響を抑える書き方を解説している記事ですね: 例外処理が遅くなるのは仕組み上仕方ないと思います」
# 同記事より
user system total real
return codes 0.044149 0.000053 0.044202 ( 0.044223)
exceptions 0.508261 0.011618 0.519879 ( 0.520129)
=>
[#<Benchmark::Tms:0x000000014106b598
@cstime=0.0,
@cutime=0.0,
@label="return codes",
@real=0.04422300006262958,
@stime=5.2999999999997494e-05,
@total=0.04420199999999999,
@utime=0.044148999999999994>,
#<Benchmark::Tms:0x000000015486d8f0
@cstime=0.0,
@cutime=0.0,
@label="exceptions",
@real=0.5201290000695735,
@stime=0.011618000000000003,
@total=0.5198790000000001,
@utime=0.5082610000000001>]
「記事の"Use exceptions for exceptional situations"は、例外はあくまで例外的な状況で使えということですね」「例外は文字通り通常の処理では起きないものなので通常のフローに使うのは避けたい: 例外が発生するとrescue
の場所を探索しないといけなくなるし、rescue
で条件が追加されるとさらに遅くなるし、通常のパイプライン処理も効かなくなるし、どうやっても遅くなる」
🔗 by: Rubyライブラリのプリローダー(Ruby Weeklyより)
つっつきボイス:「"Polished Ruby Programming"の著者でもあるJeremy Evansさんのgemです」「プリロードしたい大きなライブラリをby-server
で起動しておいてby
で読み込めるようになるらしい↓: ライブラリの読み込みをどうしても高速化したいときなどにいいかも」
# 同リポジトリより
$ by-server sequel roda capybara
$ by -e 'p [Sequel, Roda, Capybara]'
[Sequel, Roda, Capybara]
🔗 ruby-openai: RubyでOpenAIを使える(Ruby Weeklyより)
つっつきボイス:「RubyでOpenAIを使う解説記事の中でruby-openaiが紹介されていました」「機械学習やAIだとPythonが使われることが多いですが、これはOpenAIのAPIトークンがあれば普通に使えそうな感じ」
# 同記事
require "ruby/openai"
client = OpenAI::Client.new(access_token: 'YOUR_API_TOKEN')
prompt = 'Explain metaprogramming to a 10-year-old?'
response = client.completions(
parameters: {
model: "text-davinci-003",
prompt: prompt,
max_tokens: 2000
})
puts response['choices'][0]['text']
参考: OpenAI
参考: OpenAI - Wikipedia
つっつき後にAPIキー(personal)を取得して渡してみると、あっさり動きました↓。
irb(main):037:0> puts response['choices'][0]['text']
# 結果↓
Ruby metaprogramming is a term used to describe the act of writing code that dynamically alters other code. It involves features in Ruby such as modules, classes, and method calls. Ruby metaprogramming allows developers to write code that works with other code in a more consistent and efficient way. This can be used to reduce coding time and increase code re-usability.
参考: API Reference - OpenAI API
🔗 その他Ruby
つっつきボイス:「Ruby関連ニュースサイトのRubyFlow自身のアナウンスです」「RubyFlowのホスティングがHerokuからfly.ioに移行したのね」「たまたまかもしれないけど、先週もRails 7.1のDockerの話題でfly.ioが登場していましたね(ウォッチ20230214)」「fly.io、もしかして流行りつつある?」「今後を見ないとわからないけどfly.ioは気になっています」
参考: Deploy app servers close to your users · Fly
🔗 設計・セキュリティ
🔗 スライド『30分でわかるデータ指向アプリケーションデザイン』
つっつきボイス:「はてブで見かけて、例のApache Parquetなどにも触れていたのが気になったので取り上げてみました」
参考: Apache Parquet
「このあたりとかは、具体的な方法は違うけどユニケージを思い出す↓」「ユニケージは前職でがっつりやっていたことがありますが、そういう感じはありますね」
「トランザクションの話」「ACIDの中でも分離性が強調されていますね」
参考: ACID (コンピュータ科学) - Wikipedia
「そして分散トランザクションの話: リーダー選出を追求するとサービスディスカバリーも問題になってくる」
「ちなみにスライドに映っているVLDBやSIGMODはデータベース関連では世界トップレベルの国際会議で、前者はVLDB Endowment Inc.という組織が、後者はACMという国際学会が運営しています」
参考: International Conference on Very Large Data Bases - Wikipedia
参考: SIGMOD Website
「テーブルの意味づけが昔とは変化している、たしかにそうですね」
「いいスライド👍: スライド作者が監修した『データ指向アプリケーションデザイン』↓もよさそうなのでポチりました」
「データ指向アプリケーションデザイン ― 信頼性、拡張性、保守性の高い分散システム設計の原理」本日の発売に寄せて、紹介記事を書きました https://t.co/1yx1Kq2soI
— Taro L. Saito (@taroleo) July 18, 2019
🔗クラウド/コンテナ/インフラ/Serverless
🔗 Cネイティブ拡張を使うgemが必要なAWS Ruby Lambdaを構築する(Ruby Weeklyより)
つっつきボイス:「そうそう、Lambdaでpure Rubyだけで書かれたコード(gemもRubyのみ)をリリースするなら、ソースコードをそのままzipにパッケージしてやれば動くんですが、Cネイティブ拡張を含むgemを使う場合、ランタイム側にライブラリがなければ追加してあげる必要があったり、そもそも同等の環境でコンパイルしたものをzipに入れる必要があったりで何かと面倒が増えがち」「たしかに」「AWS LambdaではできるだけRubyだけで書かれたgemを使う方が何かと楽ですね」
参考: Ruby による Lambda 関数の構築 - AWS Lambda
# 同記事より
dir=`pwd`
bundle config set --local deployment 'true'
docker run --platform=linux/amd64 \
-e BUNDLE_SILENCE_ROOT_WARNING=1 \
-v `pwd`:`pwd` \
-w `pwd` \
amazon/aws-sam-cli-build-image-ruby2.7 bundle install
bundle config unset deployment
bundle config unset path
「記事はDockerで解決する方法を解説していますね↑: ビルド済みのものをLambdaにデプロイする方法はAWS公式ドキュメントに記載されていたと思います」
参考: .zip ファイルアーカイブで Ruby Lambda 関数をデプロイする - AWS Lambda
🔗言語/ツール/OS/CPU
🔗 ChatGPTを賢くするコツ
つっつきボイス:「"プロの編集者"といったロールや、何を出力するかなどを明確にして質問することでChatGPTの精度を上げられる、なるほど」「ChatGPTがマークアップも認識できるってすごい」
#命令書: あなたは、プロの編集者です。 以下の制約条件と入力文をもとに、 最高の要約を出力してください。 #制約条件: ・文字数は300文字程度。 ・小学生にもわかりやすく。 ・重要なキーワードを取り残さない。 ・文章を簡潔に。 #入力文: <ここに入力文章> #出力文:
同記事より
特に目から鱗だったのは「あなたはプロの編集者です」と、ChatGPTに役割を与えるという書き出しです。このやり方を実践すると、明らかに回答の精度が上がります。
同記事より
「そういえばChatGPTにLaTeX混じりの文章を与えると、LaTeX表記のまま解釈して回答してくれるので、そのままScrapboxに貼れて便利です↓」
[$ s\lbrack x \mapsto v\rbrack(y)]は、変数[$ x]に値[$ v]を割り当てた新しい割り当て関数を表しています。これは、元の割り当て関数[$ s]から、[$ x]に対する値を[$ v]に変更したものです。特に、[$ y] が[$ x]と等しい場合は、[$ y]に対する値は[$ v]になります。それ以外の場合は、[$ y]に対する値は元の割り当て関数[$ s]と同じです。
参考: LaTeX - Wikipedia
参考: Scrapbox - チームのための新しい共有ノート
後編は以上です。
バックナンバー(2023年度第1四半期)
週刊Railsウォッチ: Ruby30周年記念イベント、ActiveRecord APIクイズほか(20230221前編)
- 20230215後編 Bundler 2.4リリース、RubyKaigi 2023参加募集開始ほか
- 20230214前編 AssumeSSLミドルウェア追加、Fly.ioとRails 7.1のDocker対応ほか
- 20230202後編 ShopifyのYJIT記事、RubyGemsのgem execコマンドほか
- 20230201後編 Ruby 3.2のベンチマーク記事、dry-cliで高度なCLIを作るほか
- 20230131前編 Evil Martiansが使っているgem、JavaScriptガイドが更新ほか
- 20230125前編 2022年のRails振り返り記事、RailsにDocker関連ファイルが追加ほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)
お知らせ: 来週は週刊Railsウォッチに代えて通常記事を公開します🙇