IRB の補完機能の色を設定してみた

この記事は、所属している永和システムマネジメントのアドベントカレンダー ESM Advent Calendar 2023 の 2 日目の記事です。

はじめに

11月にリリースされた Reline の v0.4.0 から Reline::Face というクラスが登場しました。

github.com

これによって、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

さいごに

IRB の補完機能をどんどん使っていきたいです。ますます便利になっていく IRB に期待です。

Kaigi on Rails 2023 に参加した

先週 Kaigi on Rails 2023 がありました。

kaigionrails.org

登壇・参加ブログをいろんな方が書いていたので、自分も簡単に書いてみました。

スポンサー

所属する永和システムマネジメントではスポンサーブースで、Rubyメソッドキーホルダーを配布しました。名札に付けていただいていたり楽しんでもらえてよかったです。もらって下さった方ありがとうございました。

blog.agile.esm.co.jp

セッション

発表資料のまとめはこちら。

qiita.com

発表を聴講した中で、特に普段から気になってた内容に近い発表をピックアップします。

初めてのパフォーマンス改善

初めてのパフォーマンス改善 - Speaker Deck

ふーがさんの発表。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」という拡張機能が原因でした。

marketplace.visualstudio.com

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_tablejson型のカラムを作ることができます。同様に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 を使ってみます。

api.rubyonrails.org

以下のように User クラスの中に書きます。第一引数にはjson型のカラム名(今回は :profile)、第二引数以降にはkey(今回は :name, :age)を書きます。

class User < ApplicationRecord
  store_accessor :profile, :name, :age
end

すると nameage の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

https://api.rubyonrails.org/classes/ActiveRecord/Store.html

describeとRSpec.describeはどちらの書き方が良いのか

この記事は「ESM Advent Calendar 2021」の3日目の記事です。

adventar.org

はじめに

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 の書き方で統一されています。

github.com

どちらの書き方が推奨されているか気になったので、調べてみることにしました。

調べたこと

stack overflowでまさにこれの質問を見つけました。

stackoverflow.com

回答によるとRSpec バージョン3からは describe の書き方制限するオプションが新たに加えられたそうです。

relishapp.com

後方互換性を維持するためconfig.expose_dsl_globally がデフォルトで true になっており、 describeRSpec.describe も書くことができるようにはなっています。

ただし、expose_dsl_globally = false を設定すると describe だと "undefined method 'describe'" にすることができます。

この辺りのバーション3系のアップデートを日本語でまとめている記事もありました。

nilp.hatenablog.com

また generator が作るspecファイルも RSpec.describe の書き方に書き換えられている。

github.com

まとめ

調査から分かったこと

  • バージョン3から describe の書き方を禁止するオプションが追加された。
  • describe はmainをモンキーパッチしているためあまりよくない
  • RSpec側でもREADMEなどが RSpec.describe に書き換えられて、主流になっている模様

追記

expose_dsl_globally = false とする代わりに、

RSpec.configure { |c| c.disable_monkey_patching! }

とすることでも describe の書き方を禁止することができます。

expose_dsl_globally = false よりも強力にモンキーパッチを禁止することができるため、私もあまり使ったことがなかった shouldstub といったメソッドも禁止にできるようです。

relishapp.com

RubyからYoutubeAPIを使ってクラロワ動画を概要欄で絞り込んでみた

はじめに

私はクラッシュロワイヤル(通称クラロワ)というスマホゲームでよく遊んでいます。クラロワは8枚のカードでデッキを組んで相手と戦うカードゲームです。

clashroyale.com

そのクラロワのスキルアップのために、 YouTube で 『Stats Royal』というチャンネルの動画をよく観ています。クラロワの試合の動画がひたすらアップされているチャンネルです。

www.youtube.com

私はクラロワで『ゴーレム』というカードが好きなので、『Stats Royal』の動画のうちゴーレムが使われている試合の動画だけを観たいなと思いました。

f:id:wai-doi:20211020000034p:plain
ゴーレム

動画のサムネイルには一応デッキの画像が載っていますが、ひとつひとつ『ゴーレム』の動画を探していくのは疲れるため辛いです。 また、YouTubeで「Stats Royale ゴーレム」などと検索しても、他の動画が出てしまったりしてうまく絞り込むことができませんでした。

ただし、動画の概要欄には親切にも、その動画の試合に使われているデッキのカードが載っていました!

f:id:wai-doi:20211020002600p:plain

概要欄に情報があるなら、YouTube API を使えばうまく絞り込めそうだなと思いました。

YouTube APIを使ってみた

そこで YouTube API を使って『Stats Royal』チャンネルの内、『ゴーレム』が利用されている動画だけ検索してみることにしました。

チャンネルID

まず必要になるのが 『Stats Royale』 のチャンネルIDです。チャンネルIDはチャンネルページのURLのパスの末尾になります。

https://www.youtube.com/channel/UC698QxCg2KVVWh4G6NQLX_wUC698QxCg2KVVWh4G6NQLX_w の部分です。

APIキーの作成

YoutubeAPI を利用するには APIキーを作成しないといけません。 API キーの作り方などはこちらの記事を参考にしました。

qiita.com

利用した Gem

RubyからAPIを楽に利用するため google-api-ruby-client というGemを用いました。

github.com

Gemfile には以下の様に書きました。

gem 'google-api-client'

実際に書いたスクリプト

YouTube API から取得できるデータはこちらのドキュメントを参考にしました。

developers.google.cn

処理の手順は以下になります。

  1. YouTubeService オブジェクトを作る。
  2. チャンネルIDを使って「Channels: list」のAPIを叩いて、チャンネルのアップロード動画のプレイリストIDを取得する。
  3. 取得したプレイリストIDを使って「PlaylistItems: list」のAPIを叩いて、アップロードリスト内の動画の概要欄と動画IDを取得する。
  4. 概要欄のテキストから、デッキに『ゴーレム』が入っている動画だけに絞り込む。
  5. 絞り込んだ動画の動画IDから動画のURLを作成してHTMLに埋め込む。

以下が実際に書いた Ruby スクリプトです。

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です。 『ゴーレム』の試合の動画ばかりが並べることができ、目的を達成することができました。

f:id:wai-doi:20211020011128p:plain
出力したHTML

おわりに

YouTubeAPI は初めて触ったので利用の仕方など勉強になりました。趣味のゲームを対象にしましたが、技術で楽にすることができたのでよかったです。

今回はRubyスクリプトから使ってみましたが、今後はRailsアプリなどにして動画検索をしやすくしてみたいです。