JavaScript,Ruby

こんにちは、しきゆらです。
今回は、flatMapの処理の中で不要な要素が出てきた場合にそれを排除する方法を知ったのでメモしておきます。

結論: 空配列([])を返すと削除できる

こちらのページにある通り、
処理の中で空配列([])を返すと、その要素の処理を削除することができるようです。

let array = [1,2,3,4,5,6,7,8];
array.flatMap( (item) => {
    if (item % 2 === 0) {
        return item * 2;
    } else {
        return [];
    }
})
// => [4, 8, 12, 16]

Ruby

こんにちは、しきゆらです。
今回は、Ruby2.7から3.1.2に更新したらいろいろ変わっていたのでメモしておきます。

変わったことに気づいたのは、タイトルにあるrubocopを回したら怒られたからでした。
ということで、怒られたrubocopの項目とRubyの更新点を今更ながら記載しておきます。

Linux,Ruby,Rust,環境構築

こんにちは、しきゆらです。
今回は、だいぶ旬に乗り遅れた感がありますが、言語等のバージョン管理をasdfに乗り換えたので導入方法や使い方をメモしておきます。

導入の経緯

導入に経緯を一応書いておくと、私はPCの組み換えやOS不調等で、結構な頻度でクリーンインストールをします。
そのたびにRubyをインストールするためにrbenvを導入し、Nodeを使うためにnを導入し、ということを毎度行っていました。
この作業をあまり意識せずにやっていたのですが、先日ふと面倒だなと思うようになりました。
というのも、それぞれ年に数回程度の頻度でしかやらないので、毎度インストールするタイミングで調べて手順をなぞる、というのが知識にもならず無駄に時間がかかるだけなのでは、という風に思ってしまいました。
この辺を解決するツールはないのか、調べてみると、今回使った「asdf」というのがあるということを知ったので触ってみた、という感じです。

Ruby

こんにちは、しきゆらです。
前回から2か月ほどたっていて驚いている今日この頃、いかがお過ごしでしょうか。

今回は、ちょっと前に書いた「【Ruby】YAMLに環境変数を埋め込む」で任意の文字列を環境変数に置換する方法をメモしましたが、そのちょっと発展した話です。
タイトル通り、YAMLにローカル変数を埋め込むにはどうすればよいかなぁ、と思って調べてみたら何とかなったのでちょっとメモしておきます。

Ruby

こんにちは、しきゆらです。
毎年12~2月は気分が落ち気味で何も手がつかない時期なんですが、今年は何もできてませんでした。
気が付いたら、前回の更新が11月ということに驚いています。

さて、今回はタイトルの通りYAMLに環境変数を埋め込みたいなぁと思って何とかしたのでメモしておきます。
YAMLは設定ファイルなどでよく作りますが、Gitで管理したいが重要項目は共有したくないことはよくあるかと思います。
こんな時、YAMLファイルを知っていそうな人経由で回していく運用とかをしているところもあるかもしれませんが、ずっとうまく回るわけはありません。
ということで、YAMLに必要項目を記載しておき、チーム内だけで見れるところに必要な情報を置いておけばよいだろう、という考えです。

方針としては、ファイルにそれっぽいマーカーをつけて置き、ファイル読み込み時に環境変数と置換してYAMLオブジェクトを作る感じです。
例としてはこんな感じ。

# YAMLファイルを文字列として読み込み
yaml_str = File.read("path/to/yaml.yml")
# ${ENV_VARIABLE}形式で埋め込んだ環境変数を置換する
yaml_str.gsub!(/\${\w*}/) do |matched|
  ENV[matched.gsub(/\W*/, "")]
end
 
# YAML文字列をオブジェクトに変換
YAML.safe_load(yaml_str, symbolize_names: true)

実際に挙動を見てみます。
上記のスクリプトを適当なメソッドにして動かしてみます。

 irb(main):001:1* def test(yaml_str)
 irb(main):002:2*   yaml_str.gsub!(/\${\w*}/) do |matched|
 irb(main):003:2*    ENV[matched.gsub(/\W*/, "")]
 irb(main):004:1*  end
 irb(main):005:1*
 irb(main):006:1*  YAML.safe_load(yaml_str, symbolize_names: true)
 irb(main):007:0> end
 => :test
 irb(main):008:0> test("token: ${SERVICE_TOKEN}")
 => {:token=>nil}
 irb(main):009:0> ENV["SERVICE_TOKEN"]
 => nil
 irb(main):010:0> ENV["SERVICE_TOKEN"] = "hogehoge"
 => "hogehoge"
 irb(main):011:0> ENV["SERVICE_TOKEN"]
 => "hogehoge"
 irb(main):012:0> test("token: ${SERVICE_TOKEN}")
 => {:token=>"hogehoge"}

${SERVICE_TOKEN}という文字列を環境変数の置換して、hogehogeという値を埋め込むことができています。
マーカーは自分で定義しているので、正規表現が書ければ好きな形式で表現できます。
本来はerbとかを使って埋め込んだほうがいらないバグが起きないかと思いますが、中でやっていることはこんな感じなので知っておくと便利かと思います。

今回は、ここまで。
おわり

RSpec,Ruby

こんにちは、しきゆらです。
少し前、レンタルサーバの支払いを忘れていて一瞬サイトが消えていました。
自分でもびっくりしました・・・。

さて今回は、というか今回もRSpecのお話。
ここ最近、お仕事で自分の書いている小さなスクリプトにテストがなくて怖いなーという思いが強くなりRSpecを書くことが多いので、その時のメモです。

最近書いているのは、Seleniumでとあるサイトで行っている操作を自動化するというもの。
どうしても外部サイトをあれこれするスクリプトを書いているとテストを書きにくいです。
ということで、直接サイトにあれこれする部分は最低限ログインできるかくらいしかかけていません。
どうするのがいいんでしょうか。

さて、Seleniumでブラウザを制御するときに困るのは、キャッシュやCookieなどの影響で挙動が変わること。
ログインしようとしても前回の残骸が残っていると何度も確かめることができない、なんていうこともあります。
そこで、タイトルの通りテストの時はプライベートモードで動いてほしいなーと思っていい感じに書く方法をあれこれ考えてできたものをメモしておきます。

RSpec,Ruby

こんにちは、しきゆらです。
今回はRSpecで特定の場合だけ動く・動かないようなテストを書く方法を知ったのでメモしておきます。

やりたいこと

ログイン周りのテストをCIで実行したくない

書いていたコードとしては、Seleniumを使ってWebサービスのテストを書いていました。
諸々のテストはいいんですが、ログイン周りのテストは2段階認証などがあるため、Waitをかけて人の手で操作していました。

このRSpecをCI上で動かそうとしたとき、ログイン周りだけは止めたい!
というのが一番初めにあったやりたいことでした。

特定のクラスを継承している場合は実行したくない

合わせて、コードの中で特定のクラスを継承している場合のみこのテストを実行したい、ということもありました。
RSpecはテストを共通化する仕組みがあるので、それを使ってテストコードを共通化していたのですが
一部共通化していたテストの中で、ちょっとまずい事態が出てきました。
上記に関連してSelenium周りなんですが、Seleniumを使うクラスとSeleniumを使わないクラスが出てきたことで共通化していたテストの一部がSeleniumを使わないクラスでは必要なくなるということが起きました。
共通化していた部分を分けてSelenium用の共通コードとSelenium使わないクラスの共通コードに分ければいいんでしょうが、両方とも分類的には同じくくりなので名前を分けるだけだと、名前が似てしまってごちゃっとしてしまいそうでした。

これを回避するために、共通化しているSpec側で実行されているクラスを判定して、必要ない場合は実行しないような世界を作りたかったんです。
こちらも併せて方法が分かったのでメモしておきます。

Ruby

こんにちは、しきゆらです。
今回は、Rubocopの更新を追っていたときに初めて知ったことをメモしておきます。

Rubocopさんは、Rubyを書く方は大半使っているのではないか、と思われる静的コード解析ツールです。
設定により、メソッドの長さやネストの深さなどを制限することで読みやすいコードを書く手伝いをしてくれる頼もしいツールですね。

そんなRubocopさんですが、先日0.90.0がリリースされました。
使っているGemの更新履歴をある程度追っているため、更新内容を確認していたところ今回の更新でも新しい項目が追加されていました。
それが、Lint/UselessMethodDefinitionです。

There are at least 2 cases:
・empty constructors – this may be just overriding parent’s constructor, but this is bad anyway
・methods just calling super

https://github.com/rubocop-hq/rubocop/issues/8472

ということで、空のinitializeメソッドやsuperしか呼び出していないメソッドを怒ってくれるというものです。
内容的には妥当なcopではないかと思います。
必要ないものは書くべきではないですね。

Ruby

こんにちは、しきゆらです。
今回は、タイトル通り`URI.join`の挙動で詰まったのでメモしておきます。

URI.joinとは

join(uri_str, *path) -> object
文字列 uri_str と path … を URI として連結して得られる URI オブジェクトを返します。

https://docs.ruby-lang.org/ja/latest/method/URI/s/parse.html

ということで、URIの文字列にpathを良しなに結合してくれるメソッドです。
しかし、単に`/`を付けるだけの挙動をしているわけではありませんでした。

Ruby

Rakeといえは、RubyでかけるMakefileのようなもの。
しかし、私はMakefileを書いたことがないので、単にRubyでちょっとしたタスクをコマンドとして呼び出せる便利ツールくらいに思っている。

このRakeだが、タスクの追加方法や設定等について調べて出てくるのはどうしてもRails環境が多い。
railsは内部的にはRakeを呼んでいる(?)っぽいので、しょうがないといえばしょうがないが、素のRubyでRakeタスクを作って実行する方法をメモしておく。

準備

Rakeといっても、Gemとして配布されている。
default gemとしてすでに入っているとは思うが、必要であればGemfileに入れてあげるとよい。

gem "rake"

そしてbundle install
ほかのGemと同じなので困ることはないはず。

Rakefile

基本的にはRakefileにタスクを追加してあげればよい。
Railsと同じようにlib/tasks/*.rakeという感じでタスクを個別のファイルで定義したい場合はRakefileに以下のように書いてあげればよい。

Dir["./lib/tasks/*.rake"].sort.each {|file| load file}

注意としては、requireではなくloadということ。
Railsさんも、内部でload使っているし、そういうことです。
(#TODO: 理由は後ほど調べる)

個別のタスク

個別は、普通にタスクを定義してあげればよい。

 namespace :task do
   # シンプルなタスク
   desc "test"
   task :test do
     puts "test task!"
   end
   
   desc "引数ありの場合"
   task :arg_task, [:hoge] do |_, args|
     puts args[:hoge]
   end
 end

ファイル名ごとにnamespaceを切ってあげると、タスク名に困ることはなくなると思います。

そして、rakeタスクを実行するときに引数を渡して実行することができます。
例えば、bundle exec rake task:arg_task[hogehoge]とするとコマンドラインから値を渡すことができます。

二つ目のタスクの通り、タスク名の後に配列で引数の名前を付けてあげる。
そしてブロックに2つの変数を作ってあげて、二つ目の変数に引数が入ってくるので指定した名前でアクセスすると取得できます。

まとめ

今回は、非Rails環境でRakeタスクを追加する方法をメモしておきました。
覚えておくと、ちょっとしたコマンドをRuby/Rakeで作れるので便利です。

RakeタスクはRails環境でしか使ったことがなかったので、素のRubyでも使えることが分かったのと、
ついでに実行時に引数を渡す方法もわかったので、簡単なコマンドをRakeで実装できるようになりました。
Rubyで良しなにスクリプトを書いた後、コマンドっぽく実行したいときに使えそうですね。

今回はここまで。
おわり。