IRB の補完機能の色を設定してみた
この記事は、所属している永和システムマネジメントのアドベントカレンダー ESM Advent Calendar 2023 の 2 日目の記事です。
はじめに
11月にリリースされた Reline の v0.4.0 から Reline::Face
というクラスが登場しました。
これによって、IRB のメソッド補完ダイアログの色を変えることができるようになりました。
今回はその色を変える設定をしてみたことについて書いていきます。
設定方法
設定方法は Reline::Face のドキュメントに書かれてます。
まず Reline の v4.0.0 以上がインストールされていなければ Reline の最新版をインストールしましょう。
gem install reline
次に .irbrc へ設定を書きます。 Reline::Face.config(:completion_dialog)
にブロックを渡して設定します。
サンプルコードは以下です。
# .irbrc Reline::Face.config(:completion_dialog) do |conf| conf.define :default, foreground: :white, background: :blue # ^^^^^ `:cyan` by default conf.define :enhanced, foreground: :white, background: :magenta conf.define :scrollbar, foreground: :white, background: :blue end
conf.define
の引数に、色を変えたい対象、文字の色( :foreground
)、背景の色( :background
) を渡すことができます。
色を変えたい対象として、補完候補の表示部分(:default
)、選択された補完候補の部分(:enhanced
)、補完候補のスクロールバーの部分(:scrollbar
) の3箇所の色を変えることができるようです。
指定する色は、ドキュメントの表に書いてある :blue
などの用意されたラベルの色を使う他にも、"#FF1020"
のように16進カラーコードで細かく色を表現することもできます。
他にも :style
オプションを渡して :bold
などを指定することで、文字を太字にするなどの装飾をすることもできます。
実際に設定した内容
自分以下のように設定しました。
# .irbrc Reline::Face.config(:completion_dialog) do |conf| conf.define :default, foreground: :white, background: '#2C2B2B' conf.define :enhanced, foreground: '#FFFFFF', background: '#005bbb' conf.define :scrollbar, foreground: :gray, background: '#2C2B2B' end
ターミナルの黒い画面に目立ち過ぎず馴染むような色にしました。
補完候補の表示部分は、文字の色を white にして背景色を blackより少し明るい黒色にしました。選択された補完候補の部分は、白色にして背景色を青色にしました。スクロールバーの部分は、バーの色を gray にしてバーの背景色を black より少し明るい黒色にしました。
どのように変わったか
設定前
自分はターミナルアプリに iTerm2 を使っており、Monokai Soda というテーマを設定しています。
そのテーマと補完のデフォルトの色との相性が悪いようで、補完候補の部分の文字色が白色で背景色が水色になっており、目を凝らさないと見えないくらい見づらい状態でした。
設定後
設定後はくっきり見えるようになり使いやすくなりました 🎉
おまけ:バージョンによっては補完機能を無効にしたい
色を設定する以前は、補完候補が見づらく実用的でなかったため補完機能を無効にしていました。
# .irbrc IRB.conf[:USE_AUTOCOMPLETE] = false
色を設定したことで補完機能を無効にする記述は消すことができると思ったのですが、
Reline::Face
が利用できるのは Reline の v0.4.0 からなので、Bundler の Gemfile.lock などで v0.4.0 より前のバージョンを固定して使われると Reline::Face
が利用できません。
そのため Reline が v0.4.0 以降であれば色の設定をするようにして、前であれば補完機能を無効にする条件分岐を入れてみました。
# .irbrc if Gem::Version.new(Reline::VERSION) >= Gem::Version.new('0.4.0') Reline::Face.config(:completion_dialog) do |conf| conf.define :default, foreground: :white, background: '#2C2B2B' conf.define :enhanced, foreground: '#FFFFFF', background: '#005bbb' conf.define :scrollbar, foreground: :gray, background: '#2C2B2B' end else IRB.conf[:USE_AUTOCOMPLETE] = false end
さいごに
Kaigi on Rails 2023 に参加した
先週 Kaigi on Rails 2023 がありました。
登壇・参加ブログをいろんな方が書いていたので、自分も簡単に書いてみました。
スポンサー
所属する永和システムマネジメントではスポンサーブースで、Rubyメソッドキーホルダーを配布しました。名札に付けていただいていたり楽しんでもらえてよかったです。もらって下さった方ありがとうございました。
セッション
発表資料のまとめはこちら。
発表を聴講した中で、特に普段から気になってた内容に近い発表をピックアップします。
初めてのパフォーマンス改善
ふーがさんの発表。SQLでパフォーマンス改善をするときに、どのような手順で進めたらよいかというのがわかりやすかった。また「コードにしたものとコードにしなかったことがプログラミング」について、PRにはコード以外の調査についての情報も大事なので、しっかり載せるのはやっていきたいと思った。自分もちょうどその時ふーがさんと同じチームだったので、New Relicの使い方を教えていだいたりした。
Simplicity on Rails -- RDB, REST and Ruby
Simplicity on Rails -- RDB, REST and Ruby - Speaker Deck
moroさんの発表。イベントエンティティを見つけてDB設計をするのがシンプルにするために大事。イベントエンティティは"登録すること"といった行為を指し示す。イベントエンティティを見つけると行為が起きた時間をもたせるなどができる。まだDB設計に慣れていないので、イベントエンティティを見つけられるようになりたいと思った。
ペアプロしようぜ 〜3人で登壇!? 楽しくて速いペアプロ/モブプロ開発〜
ペアプロしようぜ 〜3人で登壇!? 楽しくて速いペアプロ/モブプロ開発〜/pair-mob-programming-kaigi-on-rails-2023 - Speaker Deck
トミーさん、masuyama13さん、あんすとさんの発表。発表に勢いがあって一番聞いていて楽しめた発表だった。前半のなぜペアプロをするのかについての根拠のために、データをたくさん載せていたのが大事なことだなと思った。後半は実際にペアプロをライブコーディングしていただいてライブ感がよかった。指示するときにペンツールをよく使われていたので自分も使っていこうと思った。一方通行にならないように、ドライバーとナビゲーターの役割を区別するのも大事だとわかった。この発表を聞いてベテランと新人でペアプロするときにどのようなところに気をつけるとよいかが新たに気になった。
その他
懇親会では、ブログをよく見させていただいていたインターネットでアイコンだけしか知らなかった方々に実際にお会いして、お話もできてどういう方なのかを知れてよかったです。
Kaigi on Rails中に使っていたKaigi on Rails アプリ *1が、ブックマークした発表の時間になったら通知してくれるので便利でした。
運営の皆様ありがとうございました。
TablePlus で日本語の文字列の値が question mark (?) で表示された場合の対処法
実行環境
TablePlus: Version 5.3.1
困りごと
TablePlus を初めて使ってみたとき、Oracle のデータベースと connection してテーブルのデータを見てみました。
すると、ひらがなや漢字が値として入っているカラムの値が、 question mark (?) で表示されてしまいました。
解決方法
そんなときは、
Connection -> View Using Encoding
が最初は Default
になっているので、JAPANESE_JAPAN.UTF8
に変更してください。
TablePlus のアプリを落として再起動すると、正しく日本語が表示されるようになりました!
参考: https://github.com/TablePlus/TablePlus/issues/713#issuecomment-522823057
VSCode を開いた時、「"java"コマンドラインツールを使用するには、JDKをインストールする必要があります。」が表示される問題
はじめに
あるときから、VSCodeを開いた時に、
「"java"コマンドラインツールを使用するには、JDKをインストールする必要があります。」
というポップアップがでるようになりました。
普段の開発で Java は使っていないので、とくに Java をインストールしたくありませんでした。そのため、毎回このポップアップがでるのが煩わしかったです。
インストールしている何かしらの拡張機能で Java を利用しているのが原因と予想しました。拡張機能を一つずつ無効にしていったところ、原因が判明しました。
原因
「PlantUML」という拡張機能が原因でした。
Java : Platform for PlantUML running.
たしかに PlantUML を実行させるために Java が必要と書いていますね。
解決方法
PlantUML は利用していなかったので、PlantUML を無効にするかアンインストールすることでポップアップが出なくなりました!
この記事がどなたかのお役に立てられれば幸いです。
JSON型カラムをActiveRecord::Storeで使いやすくしてみる
今回はRails アプリケーションの開発でJSON型のカラムを扱った際に ActiveRecord::Store
を使うと便利だったのでそのことについて共有します。
実行環境
以下の環境で試しました。 - Ruby 2.7.1 - Rails 6.0.3.2 - Postgres
JSON型について
PostgresqlではJSONデータ型をサポートしています。 https://www.postgresql.jp/document/12/html/datatype-json.html
Railsではcreate_table
でjson型のカラムを作ることができます。同様にjsonb型のカラムも作ることができます。
https://railsguides.jp/active_record_postgresql.html#json%E3%81%A8jsonb
例題をつかって試してみる
例として、profile
という json 型カラムを持つ users
テーブルを定義することにします。
class CreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| t.json :profile t.timestamps end end end
以下のモデルも定義します。ひとまず何もない空のクラスにします。
class User < ApplicationRecord end
この状態で適当なデータを作って、json型カラムの中の値を参照してみます。
user = create(profile: { name: 'Ken', age: 20 }) user.profile #=> {"name"=>"Ken", "age"=>20} user.profile['name'] #=> "Ken" user.name #=> NoMethodError (undefined method `name' for #<User:0x00007f9f8d20f510>)
最後の行で試した user.name
ですが、 name
というカラムは無いため NoMethodError
になってしまいます。
store_accessor
そこで、 store_accessor
を使ってみます。
以下のように User
クラスの中に書きます。第一引数にはjson型のカラム名(今回は :profile
)、第二引数以降にはkey(今回は :name, :age
)を書きます。
class User < ApplicationRecord store_accessor :profile, :name, :age end
すると name
と age
のGetter・Setterメソッドが追加され、通常のカラムと同様に扱えるようになります。
user.reload.profile #=> {"name"=>"Ken", "age"=>20} user.name #=> "Ken" user.age #=> 20 user.age = 30 user.age #=> 30 user.changed? #=> true user.save #=> User Update user.reload.profile #=> {"name"=>"Ken", "age"=>30}
また、設定した属性の一覧は Model.stored_attributes
で確認できます。
User.stored_attributes[:profile] #=> [:name, :age]
バリデーションも行える
通常のカラム同様に使えるようになるので、もちろん バリデーション も設定することができるようになります。
class User < ApplicationRecord store_accessor :profile, :name, :age validates :name, presence: true end
user.name = "" user.save! #=> ActiveRecord::RecordInvalid (Validation failed: Name can't be blank)
accessors を overwrite
Getter・Setter メソッドはsuper
を使うことで overwrite できます。
例えばname
が大文字で返すかつ、age=
で代入するとIntegerに変換されるようにしてみました。
class User < ApplicationRecord store_accessor :profile, :name, :age validates :name, presence: true def name super.downcase end def age=(number) super(number.to_i) end end
user.profile #=> {"name"=>"Ken", "age"=>20} user.name #=> "KEN" user.age = "30" user.profile #=> {"name"=>"Ken", "age"=>30}
参考URL
describeとRSpec.describeはどちらの書き方が良いのか
この記事は「ESM Advent Calendar 2021」の3日目の記事です。
はじめに
Railsアプリケーションをの開発でRSpecを使ってテストを書くことが多いです。私はRSpecを書くときに、トップレベルの階層の describe をdescribe
ではなく RSpec.describe
でいつも書いています。
トップレベルに describe
を書くパターン。
descirbe User, type: :model do descirbe "foo" do # ... end end
トップレベルに RSpec.describe
を書くパターン。
RSpec.descirbe User, type: :model do descirbe "foo" do # ... end end
どちらの書き方でも動作します。
ちなみに、rspec/rspec-core のREADMEでは RSpec.describe
の書き方で統一されています。
どちらの書き方が推奨されているか気になったので、調べてみることにしました。
調べたこと
stack overflowでまさにこれの質問を見つけました。
回答によるとRSpec バージョン3からは describe
の書き方制限するオプションが新たに加えられたそうです。
後方互換性を維持するためconfig.expose_dsl_globally
がデフォルトで true
になっており、 describe
も RSpec.describe
も書くことができるようにはなっています。
ただし、expose_dsl_globally = false
を設定すると describe
だと "undefined method 'describe'"
にすることができます。
この辺りのバーション3系のアップデートを日本語でまとめている記事もありました。
また generator が作るspecファイルも RSpec.describe
の書き方に書き換えられている。
まとめ
調査から分かったこと
- バージョン3から
describe
の書き方を禁止するオプションが追加された。 describe
はmainをモンキーパッチしているためあまりよくない- RSpec側でもREADMEなどが
RSpec.describe
に書き換えられて、主流になっている模様
追記
expose_dsl_globally = false
とする代わりに、
RSpec.configure { |c| c.disable_monkey_patching! }
とすることでも describe
の書き方を禁止することができます。
expose_dsl_globally = false
よりも強力にモンキーパッチを禁止することができるため、私もあまり使ったことがなかった should
や stub
といったメソッドも禁止にできるようです。
RubyからYoutubeAPIを使ってクラロワ動画を概要欄で絞り込んでみた
はじめに
私はクラッシュロワイヤル(通称クラロワ)というスマホゲームでよく遊んでいます。クラロワは8枚のカードでデッキを組んで相手と戦うカードゲームです。
そのクラロワのスキルアップのために、 YouTube で 『Stats Royal』というチャンネルの動画をよく観ています。クラロワの試合の動画がひたすらアップされているチャンネルです。
私はクラロワで『ゴーレム』というカードが好きなので、『Stats Royal』の動画のうちゴーレムが使われている試合の動画だけを観たいなと思いました。
動画のサムネイルには一応デッキの画像が載っていますが、ひとつひとつ『ゴーレム』の動画を探していくのは疲れるため辛いです。 また、YouTubeで「Stats Royale ゴーレム」などと検索しても、他の動画が出てしまったりしてうまく絞り込むことができませんでした。
ただし、動画の概要欄には親切にも、その動画の試合に使われているデッキのカードが載っていました!
概要欄に情報があるなら、YouTube API を使えばうまく絞り込めそうだなと思いました。
YouTube APIを使ってみた
そこで YouTube API を使って『Stats Royal』チャンネルの内、『ゴーレム』が利用されている動画だけ検索してみることにしました。
チャンネルID
まず必要になるのが 『Stats Royale』 のチャンネルIDです。チャンネルIDはチャンネルページのURLのパスの末尾になります。
https://www.youtube.com/channel/UC698QxCg2KVVWh4G6NQLX_w の UC698QxCg2KVVWh4G6NQLX_w
の部分です。
APIキーの作成
YoutubeAPI を利用するには APIキーを作成しないといけません。 API キーの作り方などはこちらの記事を参考にしました。
利用した Gem
RubyからAPIを楽に利用するため google-api-ruby-client というGemを用いました。
Gemfile には以下の様に書きました。
gem 'google-api-client'
実際に書いたスクリプト
YouTube API から取得できるデータはこちらのドキュメントを参考にしました。
処理の手順は以下になります。
YouTubeService
オブジェクトを作る。- チャンネルIDを使って「Channels: list」のAPIを叩いて、チャンネルのアップロード動画のプレイリストIDを取得する。
- 取得したプレイリストIDを使って「PlaylistItems: list」のAPIを叩いて、アップロードリスト内の動画の概要欄と動画IDを取得する。
- 概要欄のテキストから、デッキに『ゴーレム』が入っている動画だけに絞り込む。
- 絞り込んだ動画の動画IDから動画のURLを作成してHTMLに埋め込む。
require 'google/apis/youtube_v3' # `YouTubeService` オブジェクトを作ります youtube = Google::Apis::YoutubeV3::YouTubeService.new youtube.key = "API Key" # 『Stats Royale』のチャンネルIDです channnel_id = "UC698QxCg2KVVWh4G6NQLX_w" # チャンネルIDを使って「Channels: list」のAPIを叩いて、チャンネルのアップロード動画のプレイリストIDを取得します response = youtube.list_channels('contentDetails', id: channnel_id) uploads_playlist_id = response.items.first.content_details.related_playlists.uploads # 取得したプレイリストIDを使って「PlaylistItems: list」のAPIを叩いて、アップロードリスト内の動画の概要欄と動画IDを取得します # 10 * 50件の動画の情報を取得する uploaded_video_items = [] next_page_token = nil 10.times do response = youtube.list_playlist_items('snippet', playlist_id: uploads_playlist_id, max_results: 50, page_token: next_page_token) uploaded_video_items += response.items puts "#{uploaded_video_items.size} 件取得" next_page_token = response.next_page_token break if next_page_token.nil? sleep 0.1 end # 概要欄のテキストから、デッキに『ゴーレム』が入っている動画だけに絞り込みます golem_video_items = uploaded_video_items .select { |item| item.snippet.description.scan(/deck:\n(.+)\n/).flatten.any? { |m| m.split(", ").include?("Golem")} } # 埋め込み式の動画タグをHTMLにして出力します div_tags = golem_video_items.map do |item| published_at = Time.parse(item.snippet.published_at).localtime.strftime('%F %T') id = item.snippet.resource_id.video_id <<~DIV <div style="margin-bottom: 100px"> <p> #{published_at} </p> <iframe width="1120" height="630" src="https://www.youtube.com/embed/#{id}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> </div> DIV end.join("\n") html = <<~HTML <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> #{div_tags} </body> </html> HTML File.write("output.html", html)
出力したHTML
スクリプトで最後に出力されたHTMLです。 『ゴーレム』の試合の動画ばかりが並べることができ、目的を達成することができました。
おわりに
YouTubeAPI は初めて触ったので利用の仕方など勉強になりました。趣味のゲームを対象にしましたが、技術で楽にすることができたのでよかったです。