my_back_pages

プログラミング学習の記録 Ruby / Rails / FjordBootCamp

【正規表現】単語の境界を表すメタ文字 \b

正規表現において、\bは「単語の境界」を表すメタ文字です。

「単語の境界」とは?

単語境界とは、次の文字が単語文字で、前の文字が単語文字でない場合、またはその逆の場合です。

developer.mozilla.org

理解のポイントは以下のようなことの模様。

  • \bは「空白」や「スペース」などの、単語の区切りになるような「文字」にマッチしているわけではない。
  • 単語と非単語の境界という「位置」に一致している。

英単語の検知としての使用

Railsには単語の単数/複数形をうまく変換してくれる便利なヘルパーがあります。

このヘルパーで意図通りにビュー上で単語を表示できているかをテストをしたいときに、このメタ文字について調べました。

api.rubyonrails.org

micropostmicropostsで実験

1 microposts(複数形)ではなく、1 micropostになっていることを確かめたい。

↑単純にmicropostで検索してしまうと、複数形のmicropostsもヒットしてしまいます。

\bmicropost\bのように前後に単語境界を含めるようにすれば、sがつかない単数形のmicropostだけをヒットさせることができます。

↑上述のように\bはあくまで単語と非単語の境界を表しているだけなので、空白以外の非単語(ピリオド・ダブルクォーテーション・!マークなど)と単語の境界も検知します。

単語と非単語の境界の可視化

\bだけで検索すると、あらゆる単語と非単語(行頭・行末含む)の間の「位置」そのものにヒットしていることがよくわかりますね。

正規表現は苦手意識を持ってしまっているのですが(非常に良くない)、使わないと慣れようがないので、避けずにインプット・アウトプットしていこうと思います。

参考にさせていただきました🙏

qiita.com

【rbenv】rbenv × RubyMineで、RubyMineのターミナルからRubyのバージョンを変える際の注意【RubyMine】

サマリ

  • RubyMineは、rbenvによるバージョン設定を検知してくれる(ディレクトリ上の.ruby-versionファイルを読み込む)。
  • してくれるけれど、RubyMine上で起動されるシェルでは、ファイルから読み取られたバージョン設定はRBENV_VERSIONという環境変数に保持される模様。
  • rbenvのルール上、RBENV_VERSION.ruby-versionよりもバージョン決定における優先度が高い。
  • ゆえに、RubyMineのターミナルでrbenv local { rubyのバージョン }を叩いたり、.ruby-versionを手動で変更しても、RubyMineのシェルで使われるRubyのバージョンは変わらない。
  • ↑のコンテキストでRubyのバージョンを変えるときは、rbenv shell { rubyのバージョン }を叩くか、RubyMine上のターミナルを再起動すればOK。

RubyMineのターミナルでrbenv versions

使用バージョンは.ruby-versionの記載と一致しているけれど、正確には「同じ値を入れた環境変数」から読み込まれて設定されている。

(参考)Macのターミナルでrbenv versions

.ruby-versionが直接読み込まれているので、↓のような問題は(おそらく)起きない。

RubyMineのターミナルでrbenv local { rubyのバージョン }を叩く

.ruby-versionは変更されたけれど、変わらず環境変数からバージョンが設定されている。 RBENV_VERSION.ruby-versionよりも優先度が高いので、使用バージョンは変わらない。

Sets a local application-specific Ruby version by writing the version name to a .ruby-version file in the current directory. This version overrides the global version, and can be overridden itself by setting the RBENV_VERSION environment variable or with the rbenv shell command.

github.com

RubyMineのターミナルでrbenv shell { rubyのバージョン }を叩く

rbenv shell { rubyのバージョン }RBENV_VERSIONを書き換えるコマンド。 RubyMineが参照する箇所をダイレクトに変更するため、今回は使用バージョンが変わる。

rbenv shell Sets a shell-specific Ruby version by setting the RBENV_VERSION environment variable in your shell. This version overrides application-specific versions and the global version.

github.com

↑を叩かなくても、RubyMineのターミナルを再起動すれば.ruby-versionが再読み込みされて、それをもとに環境変数も更新されるので、それでもOK。

(もしrbenv local { rubyのバージョン }.ruby-versionを変えたら、単純にターミナルを再起動するのがわかりやすくていいかも?)

(参考)VSCodeのターミナル上でrbenv versions

VSCodeで同じことを検証してみたところ、.ruby-versionが直接読み込まれているようでした(Macと同じ)。

RubyMineのちょっとトリッキー?なことで混乱したので調べたことのシェアでした。

参考にさせていただきました🙏

RubyMineでrbenvが反映されない件 - siroemk's project

Cannot change Ruby version within terminal window : RUBY-27599

【Rails】assert_difference の第一引数に、評価したい式の「文字列」を渡している理由

サマリ

  • assert_differenceの第一引数には評価したい式を入れるけれど、なぜ「文字列」にして入れるのがピンとこなかった。
  • このメソッドは第一引数に渡した式の文字列をevalで実行するProcオブジェクトを作り、内部でそれをcallすることで評価していた。

ピンとこなかったこと

assert_difference 'Article.count' do
  post :create, params: { article: {...} }
end

ActiveSupport::Testing::Assertions

'Article.count'の部分について、なぜArticle.countという式の戻り値をそのまま使わないのだろうか、という疑問。

式の評価結果の値ではなく、文字列を引数にしていることが(プログラミング初心者的には)モヤモヤする感じ……。

上のAPIリファレンスでの当該メソッドの第一仮引数の名前はexpression。 expression......式……sikiとは……。

Railsの中身を見てみる

assert_differenceの第一引数の式は文字列で!と覚えて進もうかなと思いましたが、気になったのでRailsの中身を見てみました。

def assert_difference(expression, *args, &block)
  expressions =
    if expression.is_a?(Hash)
      message = args[0]
      expression
    else
      difference = args[0] || 1
      message = args[1]
      Array(expression).index_with(difference)
    end

  exps = expressions.keys.map { |e|
    e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
  }
  before = exps.map(&:call)

  retval = _assert_nothing_raised_or_warn("assert_difference", &block)

  expressions.zip(exps, before) do |(code, diff), exp, before_value|
    error  = "#{code.inspect} didn't change by #{diff}"
    error  = "#{message}.\n#{error}" if message
    assert_equal(before_value + diff, exp.call, error)
  end

  retval
end

ここがポイントだったみたいです。

  exps = expressions.keys.map { |e|
    e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
  }
  • 第一引数に渡した式の文字列はexpressions.keysの結果の配列に入っていて、それをループで回す。
  • 個々の要素がcallメソッドを持っているか -> Procオブジェクトだったら、それをそのまま使う(今回は文字列なので違う)。
  • 違うのであれば、その式をevalRubyプログラムとして評価するProcオブジェクトをlambdaで作って、それを使う。

内部的には、文字列で渡した式をevalに渡すことで処理してるよ、ということでした。

なお、assert_differenceで(内部的に)チェックするのは、あくまで「文字列の式を実行するProc」なので、初めからlambda式を引数に渡してもOK。

A lambda or a list of lambdas can be passed in and evaluated:

assert_difference ->{ Article.count }, 2 do
  post :create, params: { article: {...} }
end

assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
  post :create, params: { article: {...} }
end

(上のAPIガイドより引用)

ちなみに{評価したい式: 期待するdifference}というハッシュでもOK。ここの評価したい式をlambdaにしてもOK。

こんな手法を取っているメソッドはほかにもたくさんありそうな気がするので、なんとなく流れを確認できてよかったような気がしています。

※ここまで書いてから思ったんですが、よく考えてみると単純に(式の評価結果の)値を引数に取ってしまうと、「(ブロック内の処理が実行されたときの)引数に渡した特定の『式』(値ではなく)の結果の違いをチェックする」という、メソッド本来の意味と一致しないですね……。

evalを使うプログラムに触れられてよかった、ということにしたいと思います。

【Render】Web Service(アプリ)とPostgreSQL(DB)のRegionは合わせよう【Railsチュートリアル】

サマリ

  • RenderでWebアプリケーションを作る際に、DBを作成する際に「Region」をアプリ側と合わせないと、デプロイが失敗する。

Railsチュートリアルを進める中でハマったので、念のためのメモです。

Renderとは

Renderは、静的ページやWebアプリケーションを簡単にデプロイ(本番運用のための配備)できるプラットフォームを提供してくれるサービス(PaaS)です。

render.com

GitHub上のリポジトリとRenderを連携させることで、ワンクリックでリポジトリ上のWebアプリケーションをデプロイできます。

(ワンクリックどころか、リモートリポジトリの更新に合わせてオートデプロイする設定も可能。)

本番用のDBの作成や、Webアプリとの連携(アプリ側のサーバにDBを参照するための環境変数を設定する)などもダッシュボード上で簡単に行なえます。

 

Renderについての詳しい説明は、下の記事などを参照されてください。

zenn.dev

 

ハマったこと

私がいま取り組んでいるRailsチュートリアルでは、作ったWebアプリを本番環境にデプロイすることもカリキュラムに含まれており、そのためにRenderを使用します。

railstutorial.jp

  1. 静的なページを表示するアプリを作成した段階で、DBを作らずにデプロイ
  2. モデル(アプリ登録者のモデルであるUserモデル)を実装し、Render上で本番用のDBを作成、Webアプリと連携してデプロイ

  3. 以降は上記をベースにユーザー認証などの機能を追加

上記のような流れのカリキュラムになっています。

 

2.のパートにこぎつけた私は、チュートリアルのガイドの通りにDBを新規作成し、そのDBにアクセスするための内部パス(Internal Database URL)をWebアプリ側の環境変数に設定して、いざデプロイ!

……したかったのですが、ここで何度リトライしてもデプロイが失敗。

 

ログを見ると「(私がパスで指定した)そんな名前のDBはどこにも見つからないよ」的なメッセージを残して、DB接続エラーになっていました。

しかし、作成したDB側を参照するための Internal Database URL を渡すことにあたり、タイポやコピペミスをしていないことは何度も確認したので、「見つからない」と言われる理由がわからない。

ここで結構時間を溶かしてしまいました。

原因

  • Webアプリ側のサーバのRegionと、DB側のRegionが一致していなかった。

RenderではWebアプリやDBを作成する際に、「Region」を設定する必要があります。

 

私が沼っていたとき、このRegionの設定が、

のようになっていたことが原因で、デプロイ時にアプリがDBにうまく接続できなかったようでした。

一度作ったDBのRegionを変更することは(たぶん)できなさそうなので、同様のミスをしていたらDBを再作成すると、無事デプロイ成功。

 

Renderのダッシュボードの管理画面で、Regionが揃っているかを確認できる

その後、Region選択画面に「DBのRegionはアプリとそろえないと駄目ですよ」という注意書きがあることに気づく……。

初回作成時に見逃してさらっとデフォルトで進めていました。このあたり、今後はもっと注意しなければと反省しております。

そのほか

私は現在「フィヨルドブートキャンプ」というスクールでプログラミングを勉強しています。

bootcamp.fjord.jp

来週からチーム開発のカリキュラムに入るにあたり、Railsの復習を兼ねて「Railsチュートリアル」にここ数日取り組んでおり、その過程でハマったことのシェアが本記事になります。

まだまだプログラミング入門者の私ですが、アウトプットの練習も兼ねて気づきやわかったことをシェアしていきたいなと思っております。

プログラミング初心者が「Osaka RubyKaigi 03」に参加してみた感想

表題通り、プログラミング初心者の私が2023年9月9日に開催された「Osaka RubyKaigi 03」(大阪Ruby会議)に参加した感想をシェアしたいと思います。

regional.rubykaigi.org

Osaka RubyKaigi 03 とは?

関西のRubyコミュニティさん達が主催なさる、Rubyの技術カンファレンスです。

「03」とあるように、今回が3回目の開催とのことでした。

"Rubyで笑おう"

2019年の大阪Ruby会議02から早4年。
長かったコロナ禍を乗り越え、大阪Ruby会議が復活します!
心の底から笑い合える日がまた来ることを願って、
今年のテーマは「Rubyで笑おう」としました。

大阪を含めた関西には20近くのRubyコミュニティがあります。
しかし、コロナ禍の影響で活動を縮小したり、休止してしまったり
ここ数年は元気がないように見えているかもしれません。
このイベントが地域のRubyを盛り上げる一助になれれば幸いです。

https://regional.rubykaigi.org/osaka03/ より引用

参加した私について

私は2023年6月から「フィヨルドブートキャンプ」というスクールでプログラミングを学習しています。

bootcamp.fjord.jp

これまでにProgateやUdemyを活用してプログラミングにトライしたことはありましたが、独学に限界を感じてフィヨルドに入学した、という流れです。

現在入学して3ヶ月くらいが経ち、学習の進み具合としてはRuby on Railsのプラクティスが終了する手前くらいです(カリキュラム紹介でいうところの「Ruby on Rails / 日報の言及機能を作る」を提出したくらい)。

ですが、RubyRailsについて深い知識を得ているわけではもちろん全くなく、初めの方のプラクティスで学んだはずの基礎的なRubyメソッドや文法の仕組みを再度検索しなおしまくる程度には、まだまだプログラミング初心者、という感じです。

参加する前の不安

入学して3ヶ月とはいえ、ここ最近はRubyRailsという言語・フレームワークそのものと、Rubyコミュニティへの興味が日に日に強まってきていたところだったので、スクール内でこのカンファレンスの存在を知ったときは「ぜひ参加したい!」という気持ちになりました。

しかし、ちょっと冷静になったあとにこんな不安が。

  • プログラミング初心者が行っても、全く理解できず辛くなるだけかも……
  • すごいプログラマさんたちの中で浮いてしまわないだろうか……
  • 要するに「場違い」なんじゃないか……

参加申し込みボタンをポチっとするのに何日か寝かせてしまったのですが、フィヨルドのメンターでコードレビューでも大変お世話になっている、当日は基調講演もなされたプログラマの伊藤淳一さんが、

Rubyのコミュニティはみんな優しいので、初心者だからといって尻込みする必要はありません。 そもそも隣に座っている人もあなたと同じ初心者で、「自分だけが初心者に違いない」と思い込んでる可能性もあります。

と発信されていたことが決め手となり、参加を決意しました。

blog.jnito.com

参加してみて感じたこと

  • 初心者が肩身の狭い思いをする、ということは 全く なかった。
    • 「技術やコミュニティへの興味や熱意を持って集まっている」という意味では参加者全員が同じ立場にいて、Rubyを通してみんなでいっしょにワイワイしている!感がすごく素敵。
  • とはいえ、全てのお話のテーマが初心者に対しても優しく設計されている、というわけではもちろんなかった。
    • 上述の私のプログラミング勉強歴で、なんとかついていけた(=細かいことはともかく、発表の大筋の流れを把握してレールに乗ることができた)のは、全体の20%にも満たないくらい?
  • だからといって、ついていけないテーマの発表がつまらないわけではない。というか全然楽しい。
    • 明らかに自分のレベルを超えているテーマであっても、0.5割くらいは知っている単語や概念が出てきたりするので、そこから手繰り寄せて自分の頭で考えたり、それを理解できた未来の自分を想像するのもまた楽しい。

という感じでした。

個別のトピックとしては、こちらの発表からRaspberry Pi + Rubyの電子工作に興味を持ちました!Raspberry Pi、買ってしまうかも……。

あと、Rubyで絵を描く「クリエイティブコーディング」もとても興味深かったです。絵心は全くないのですが、プログラミングでランダムに模様を描く、とかであれば私でも絵で表現するスタートに立てるのでは!?というワクワクをもらえました。

総じて、参加することで『Rubyで笑』うことが大いにできました!

まとめ

プログラミング初心者が技術カンファレンスに参加することを考えた時に、とりあえず(交通費以外は)行ってマイナスなことは何もないと感じました。

マイナスどころか、「次はもっと発表を理解できるようになろう」とか「いつかLTに参加できるくらい勉強を頑張ろう」のようなモチベをもらえるので、本当に行ってよかったと思っています。今後もこのようなカンファレンスには積極的に参加できればと思っています。

あと、もう少し小規模の地域Rubyコミュニティのイベントとかにも参加してみたい、的な欲がすごく出てきました〜……。地域Rubyコミュニティの情報もチェックしていきたいと思います。

最後になりますが、発表者の皆様、参加者の皆様、スポンサーの皆様、そして開催スタッフの皆様、この会に携わられたすべての皆様に感謝申し上げます。ありがとうございました!

【Rails】Rinku で localhost:3000 をリンク化できない問題と解決法

表題通りです。

解決したいこと

URLの文字列をリンク化できるgem「Rinku」でlocalhost:3000というURLをオートリンクしようとしたら反映されない。

# app/views/tasks/show.html.slim

.nav.justy-content-end
  = link_to "一覧", tasks_path, class: 'nav-link'
table.table.table-hover
  tbody
# 中略
    tr
      th= Task.human_attribute_name(:description)
      td= raw Rinku.auto_link(simple_format(h(@task.description), {}, sanitize: false, wrapper_tag: "div"), # Rinku.auto_link でURLをリンクに自動変換

@task.description にはURLの文字列が入っている。

反映されない……。

google.comなどの普通のURLはリンク化される。

サニタイズの設定やヘルパーメソッド(h)の問題かと思ったけれど、その辺をなくして素のURL文字列("http://localhost:3000/tasks/id")をRink.auto_linkメソッドの引数に入れても機能しない。

ということはそもそもの「localhostというURLを入れる」というシナリオそのものに問題がありそう。

解決法

オプションを下記のように指定する。

Rinku.auto_link('http://localhost:3000/a', nil, nil, nil, Rinku::AUTOLINK_SHORT_DOMAINS)

参考 : https://github.com/vmg/rinku/issues/7

# app/views/tasks/show.html.slim

    tr
      th= Task.human_attribute_name(:description)
      td= raw Rinku.auto_link(simple_format(h(@task.description), {}, sanitize: false, wrapper_tag: "div"), nil, nil, nil, Rinku::AUTOLINK_SHORT_DOMAINS) # 修正

補足: なんでこんなことにハマったのか

現在Railsの基礎を、 フィヨルドブートキャンプで参考図書として紹介されている『現場で使える Ruby on Rails 5速習実践ガイド』(通称: 現場Rails)で勉強しています。

magazine.rubyist.net

スクショのようなシンプルなタスク管理アプリを作りながら学習を進める中で、サブミットされたタスク本文のうちURL部分をリンク化する、というパートがあります。

その箇所で、リンク化する方法として「auto_link」と「Rinku」という2つのgemが紹介されており、「Rinku」の方は「auto_linkの20倍早い(と製作者が仰っている)」方法として軽く説明されている、という感じです。

パッと「Rinku」でググると、確かに「auto_link」より速い方法として日本語の紹介記事もたくさん出てくるので、軽い気持ちで試してみようと、とりあえずそのときにブラウザで表示されていたlocalhost:3000のURLを使ったところ、上記の沼にハマった次第です。

ちなみに、「auto_link」ではオプションを細かくしていなくてもlocalhost:3000をオートリンク化してくれます。

どのようなシチュエーションでこの知識が役に立つのかは、今の私にはまだ想像がついていませんが、日本語におけるこの事象の紹介がググった結果にパッと見ではなかったので、アウトプットしてみました。

参考にさせていただきました

github.com

qiita.com

「フィヨルドブートキャンプ」に入って、プログラミングを勉強し始めました。

bootcamp.fjord.jp

2023年6月半ばに思い切ってスタート。

2週間半くらい経ちましたが、いまのところとてもいいです。

いましていること

このエントリを書いている時点でRubyのプラクティスを進めており、

『プロを目指す人のためのRuby入門[改訂2版] 言語仕様からテスト駆動開発デバッグ技法まで』(通称:チェリー本)

gihyo.jp

と格闘しています。

このブログについて

  • プログラミング学習の進捗報告
  • 理解できたこと・整理したいこと
  • フィヨルドブートキャンプについて

今後、こんなことをこのブログでシェアできたらいいなと考えています。

とりあえず、今回は投稿テストという感じでここまでです。