【Ruby】ある文字列が、リストの中に一致するものがあるか?のやり方が分かって最高
paizaやっててシリーズ
Pythonの"in"を目指して
もともとPythonを勉強してたこともあり、条件式'in'をついついRubyでも使ってエラーを出してしまう。
word = "greate" list = ["happy", "planet", "greate"] # Python print(word in list) => True # Ruby puts w in list => SyntaxError
Pythonのこの書き方は非常に直感的で好きである。そしてRubyにはない(多分)
そこで、Rubyで同様の表現をするにはどうするのが良いかと、色々考えていて、良いのを見つけました。
word = "greate" list = ["happy", "planet", "greate"] puts list.include?(word) => true
これです!
一般化すると<配列/リスト>.include?(<調査文字列>)
配列を前側に持ってきているのがみそです。実は今までは似た方法で
word = "greate" list = ["happy", "planet", "greate"] puts list.any? { |e| e == w } => true
みたいな冗長な方法でやってました。include?メソッドは知ってましたが、アクセプターに配列をもってこれないと思いこんでいた。
【Rails】AWS ECS(EC2)へのseedの流し込み方
王道かはわかりませんが、とりあえずできたので
前提: Mac PC, EC2 on ECS, Rails5, ruby 2.6, EC2 key-pair取得済み, ECS起動済み
① EC2へssh接続 ターミナルです。
$ ssh -i key-pair.pem ec2-user@<パブリックip>
② 起動コンテナ確認
$ docker ps => CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS <コンテナID> <image> "bundle exec puma -C…" 33 seconds ago Up 32 seconds
コンテナIDをここで確認しておく
③ seed流し込み
$ docker exec -it <コンテナID> bundle exec /bin/sh -c 'rails db:seed'
以上です。
CircleCIでのbuild時にDockerfileでseedできないかなぁ
【Ruby】1.hourなどでNoMethodError (undefined method `hours'になる場合の対応
Paizaをやっててシリーズ
'1.hour'はTimeクラスじゃなかった(衝撃)
Paizaで時刻を扱え問題に出会いました。
そうなると、Timeクラスの計算をすることがあります。
例えば、現在の時間から10分後の時間を表示するとします。↓
now = Time.now # => 2020-01-31 00:58:34 +0900 future = now + 10.minites # NoMethodError (undefined method `minites' for 10:Integer)
はい、エラーが出ましたね。minites
など知らんと言われました。
あれ?メソッドがインポートされてないのかな?名著、チェリー本ではTimeクラスは組み込みモジュールと習ったが… っというか、Time.now
はしっかり動いてるしTimeクラスの問題じゃないっぽい
'1.hour'はActiveSupport::Durationクラス
こちら様の記事に答えがありました。
結論から申し上げますと、次のようにすると動きました。
require 'active_support/time' # 追加 now = Time.now # => 2020-01-31 01:08:14 +0900 future = now + 10.minites # => 2020-01-31 01:18:14 +0900
どうも私は勘違いしていたらしく、10.minutesとか1.hourはTimeクラスではありませんでした。(反省)
irb(main):> 1.hour.class => ActiveSupport::Duration
【Ruby】配列の統合(flatten)と分割(each_slice)
paizaやるときに調べたシリーズ
行列(marix)の操作の時に使用した
数学ではおなじみ行列
以下のような3行3列の行列があったとする
1 2 3
4 5 6
7 8 9
私の浅知恵では、これをプログラムで扱うとすると、配列で入れ子にするのがいいんじゃないかと思うわけです。
# こんな感じ matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 2行目の2列目の要素を取り出したい時は matrix_22 = matrix[1][1]
詳しい文脈は割愛しまして、配列の入れ子が邪魔な時もありまして、一旦、1つの配列にしてしまいたいと思いました。それについてはflattenメソッドがあることは知っていましたが、一度flattenしてしまってもとに戻せるの?ってなりましたが、どうやら行けそうです。
flatten <==> each_slice
使い方
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # flatten matrix.flatten # => [1, 2, 3, 4, 5, 6, 7, 8, 9] p matrix # => [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] flattenは非破壊メソッド matrix.flatten! p matrix # => [1, 2, 3, 4, 5, 6, 7, 8, 9] "!"をつけて破壊的に matrix.each_slice(3) # => #<Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9]:each_slice(3)> # イミュータブルなものが帰ってくるので必ずto_aする matrix.each_slice(3).to_a # => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] p matrix # => [1, 2, 3, 4, 5, 6, 7, 8, 9] each_sliceは非破壊
each_sliceは非破壊メソッドですが、each_slice! とか、each_slice(3)!とかeach_slice(3).to_a!とかは総じてエラーになったので破壊的にはできないのかなぁ
【Ruby】配列から要素を抜き出すpop, shift
Paizaをやってて調べたことシリーズ
popはケツから、shiftはアタマから
配列に入っている要素を使いたい場合、インデックスを指定して利用することが多いと思います(例:array[1]とか)
しかし、その場合だと要素を参照しただけで、元の配列自体から要素を抜き出した(取り去った)わけではありません。そして、そういう処理をしたい時はたまに訪れます。
array = [1, 2, 3, 4] number = array[2] p number # 3 p array # [1, 2, 3, 4] そのまま
pythonでは最後尾の要素を取り出すのにpopがありました、rubyにもあるかなと思い探すと、あ、り、ま、し、た。
# popの使い方 array = [1, 2, 3, 4] pop_number = array.pop p pop_number # 4 p array # [1, 2, 3]
popの逆バージョンも見つけました。こっちは知りませんでした
# shiftの使い方 array = [1, 2, 3, 4] pop_number = array.shift p pop_number # 1 p array # [2, 3, 4]
抜き出した値を利用しない場合は他の選択肢もあり
##非破壊的メソッド「Array#reject」 array = [1,2,3] p arry.reject {|item| item == 2} #=> [1, 3] p arry #=> [1, 2, 3] ##破壊的メソッド「Array#delete_if」 array = [1,2,3] p arry.delete_if {|item| item == 2} #=> [1, 3] p arry #=> [1, 3]
【Paiza】Rubyでは文字列のeachはeach_charでまわす等
D問題を解く過程で調べたこと
文字列を1文字ずつeachする時はeach_char
word = "abcdef" #正しい word.each_char { |w| puts w } # 間違い word.each { |w| puts w }
文字列に特定の文字が含まれているかの判定に、'in'が使えない(多分)
これはpythonとの比較でのこと
"abcdef"という文字列に、母音が含まれているか判別したい時
pythonでは"in"が使えた(多分)
word = "abcdef" boin = ['a', 'i', 'u', 'e', 'o'] for w in word: if w in boin: print w
どうやらrubyではそのようなものは無いようだ(多分) しかたないので、any?とinclude?で代用
word.each_char do |w| unless boin.any? { |b| w.include?(b) } puts w end end
【Rails】RSpec(Capybara)で使うvisitはit句の中でしか使えない?(調査中)
調べ中ですが忘れないようにとりあえずメモ
system specでよく使うvisit
system specを書く時、僕なんかはログイン状態のテストをするときは
visit login_path
みたいに書いて、ログインページに移動するんですが。何気なく使っていると以下のようなエラーが出ました。
> docker-compose run web rspec An error occurred while loading ./spec/system/records_spec.rb. Failure/Error: visit login_path NameError: undefined local variable or method `login_path' for RSpec::ExampleGroups::Nested::Nested::Nested:Class 0 examples, 0 failures, 1 error occurred outside of examples
login_pathみたいなものは定義されてないよということですが、要は、visit句が機能してないということ。
ちなみにコードはこうです。(分かりやすくしています)
describe 'レコード', type: :system do context 'ログインしている時' do let(:user) { FactoryBot.create(:user) } # user作成 visit login_path # ログインページへ fill_in "email-form", with: user.eamil it 'hogehoge' do expect(page).to have_css('#record') end end end
そこで試しに、visit句を含めたフィクスチャをit句の中へ
describe 'レコード', type: :system do context 'ログインしている時' do it 'hogehoge' do let(:user) { FactoryBot.create(:user) } # user作成 visit login_path # ログインページへ fill_in "email-form", with: user.eamil expect(page).to have_css('#record') end end end
すると、エラーなくRSpecが動きました。
visit ○○_pathはit句の中でしか使えないのか?
軽くしか調べてないのでなんとも言えませんが 少なくともcontext直下では使えないっぽいですね。
(追記)
とりあえずこんな感じで運用中
describe 'レコード', type: :system do context 'ログインしている時' do let(:user) { FactoryBot.create(:user) } # user作成 before do visit login_path # ログインページへ fill_in "email-form", with: user.eamil end it 'hogehoge' do expect(page).to have_css('#record') end end end
流石にフィクスチャをit句の中に入れるのは抵抗があるので、beforeブロックにしました。ポイントはlet句はbeforeの外に出しています。letはbeforeの中で使えないので