のえら

技術備忘とかメモとか.間違いはつっこんでいただきたい所存.アフィリエイトはやっていません.

1ヶ月をミリ秒に換算して使いたい(Java編)

*最大31日としたいので日数は31日固定

1日 = 24時間
1時間 = 60分
1分 = 60秒
1秒 = 1000ミリ秒

31 * 24 * 60 * 60 * 1000

期待している結果は 2678400000 だったがユニットテストを実行してみると -1616567296 になっていた。

よくみると IntelliJ で警告が表示されていることに気がつく。

Numeric overflow expression This inspection checks for expressions which overflow during computation, i.e.: a = 1.0/0.0;

Integer は 2147483647 が最大値なので、オーバーフローを起こしていた。

最大値が収まる Long 型にするため、乗算する際にミリ秒を L で Long 型にして、計算結果を暗黙的にキャストする。

31 * 24 * 60 * 60 * 1000L

rails new でバージョン指定したのに上のバージョンになって困った話

初歩的なミスなのですが。

バージョンを指定して新規プロジェクトするのに、以下のコマンドを実行。

rails _5.0.2_ new sample

(中略)

-> Installing rails 5.0.6

>>5.0.6<<

!?

rails new 実行すると続けて bundle install が走るため Gemfile にデフォルトで記述される 5.0.2「以上」が反映されてしまう。

bundle install をスキップして、バージョンを指定後 bundle install すればOK

rails _5.0.2_ new sample --skip-bundle
cd sample
vi Gemfile

gem 'rails', '~> 5.0.2'

gem 'rails', '= 5.0.2'

にする

bundle install --path=vendor/bundle

macOS Sierra(10.12.6) に rails をインストールした

開発用に MacBook Air を購入したので rails をインストールしたときのメモを残す。
今回は以下のツール・環境で構築した。

homebrew のインストール

homebrew をインストールするのに XCode(Command Line Tools for Xcode) をインストールしなきゃいけないなー、と思っていたら、以下のコマンドを叩いて homebrew をインストールすると、実行途中で Xcode ないやで?インストールする?と聞かれるんですね。

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
# 確認
brew doctor
rbenv のインストール
brew update
brew install rbenv ruby-build 
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
ruby のインストール
# ruby のバージョン確認
rbenv install -l
# 2.4.2をインストール
rbenv install 2.4.2
# 環境全体で使用するバージョンを設定
rbenv global 2.4.2
# インストールの確認
ruby -v
rails のインストール
gem install rails

デフォルトでインストールされたもの

Done installing documentation for i18n, thread_safe, tzinfo, concurrent-ruby, activesupport, rack, rack-test, mini_portile2, nokogiri, crass, loofah, rails-html-sanitizer, rails-dom-testing, builder, erubi, actionview, actionpack, activemodel, arel, activerecord, globalid, activejob, mime-types-data, mime-types, mail, actionmailer, nio4r, websocket-extensions, websocket-driver, actioncable, thor, method_source, railties, bundler, sprockets, sprockets-rails, rails after 70 seconds

bundler のインストール
gem install bundler
設定の反映
rbenv rehash
source ~/.bash_profile

# インストールの確認
rails -v
> Rails 5.1.4

Groovyc: unexpected token: } と whereブロック

Spock(Groovy)のテストケースを書いていて、後からwhereブロックを追加したら以下のエラーが出たけど始めなんで怒られているのかわからなかった。

Groovyc: unexpected token: }

書いていたテストはこんな感じ。
API叩いて結果を確認するだけ。

def 'GET: /hoge/list Hogeの一覧を返す'() {
  when:
  // APIリクエスト クロージャ
  def request = {
    // Rest execute
  }
  
  then:
  with(request.call()) {
    it.status == xxx
    it.body == xxx
  }
}

と、シンプルなフィーチャーメソッドを作成して、後から色々なパラメータ与えたくなってwhereを追加した。
パラメータ自体は1種だけ。

def 'GET: /hoge/list Hogeの一覧を返す'() {
  when:
  def request = {
    // Rest execute(params) <-ここにwhereブロックの変数paramsが入る
  }
  
  then:
  with(request.call()) {
    it.status == xxx
    it.body == xxx
  }

  where:
  params || -
  1           || -
  2           || -
  null       || -
}

こんな感じで、データテーブルは1行では認識されないため、最低2列用意しないといけないのはわかっていたので、規約に沿って空白列を追加。
で、追加したところで、前述のエラーメッセージ。
閉じ位置は変えていないのになんでだろ?と思ってよく見直したら、空白列でアンダーバーを記述しなければならない箇所でハイフンを記述していたのでワイルドカードが認識されずにエラーになっていただけという。

正しくはwhereブロックはこうなる。

where:
param || _
1          || _
2          || _
null      || _

ハイフンは変数ではないので当たり前のことなんだけども、ぼーっとしながら書いちゃダメだなと思った。

テーブルデータが1つなら、空白列足すよりパイプ使った方がスッキリするやも。

where:
param << [1, 2, null]


ちなみに、whereブロックを1つだけしか定義しないと以下のエラーメッセージが表示される。めっちゃ丁寧。

Groovyc: where-blocks may only contain parameterizations (e.g. 'salary << [1000, 5000, 9000]; salaryk = salary / 1000')

Rspecの呼び出し回数チェックテストで全件通し実行するとコケていた件

rspecでrake task系のユニットテストで、onceなどのメソッド呼び出し回数チェックを使用していた。
それらのユニットテストをそれ単体で実行すると成功するが、テストを通して全件実行すると失敗する。
検証したところ、spec/lib/tasks/xxx_spec.rb で以下のようにrake taskを呼び出すためにロードしているが、 Rake::Task[task_name].invoke がこのコードを読み込んだ回数分、指定のタスクを実行していた。

before(:all) do
  Rails.application.load_tasks
end

このため、同様のrake task系テストをまとめているディレクトリ配下のユニットテストを通しで実行すると、回数を検証するonceなどを使用しているitブロックで複数回rake叩いた挙動になってしまい、テストに失敗する。

例)
spec/aaa_task_spec.rb

before(:all) do
  Rails.application.load_tasks
end

context 'HogeClass#foo' do
  it { expect(HogeClass).to receive(:foo).once.with(kind_of(RuntimeError)) }
end

spec/bbb_task_spec.rb

before(:all) do
  Rails.application.load_tasks
end

context 'FugaClass#foo' do
  it { expect(FugaClass).to receive(:foo).once.with(kind_of(RuntimeError)) }
end

spec/ccc_task_spec.rb

before(:all) do
  Rails.application.load_tasks
end

context 'HogeClass#foo' do
  it { expect(HogeClass).to receive(:foo).once.with(kind_of(RuntimeError)) }
end

rspec spec/

  • > 1) HogeClass#foo

Failure/Error: expect(HogeClass).to receive(:foo).once.with(kind_of(RuntimeError))

(HogeClass (class)).foo(kind of RuntimeError)
expected: 1 time with arguments: (kind of RuntimeError)
received: 2 times
...

※load_tasksを呼び出す回数ずつ増える

解決策の例

1)各ファイルでのタスク読み込みをやめてspec_helperなどで一回だけ呼ぶようにする
2)タスク読み込みをまとめて行うのではなく、都度Rake.application.rake_requireする

rails_helperにて一回だけ呼ぶように変更

IntelliJ の git 操作で Could not execute editor

IntelliJ で git 操作するのに Terminal からコマンド打ってぽちぽちしようとしたらエディタを実行できないというエラーメッセージが表示されてコマンドが実行できない。

起きたこと

IntelliJ, VSC は git を使用。
Terminal で git 操作をしていて、PR のコミットを整理しようと以下のコマンドを実行。

git rebase -i HEAD~4

実行するとテキストエディタが起動して対象のコミットを選択する表示になるはず。
が、以下のメッセージが。

Could not execute editor

git がテキストエディタを起動できないらしい。。
ターミナルで git 操作していた時は vi が起動していたので IntelliJ 経由でも起動してくれると思っていた。

解決した方法

git が起動するエディタを設定する。
ターミナルを起動して以下実行。

# 使用しているvimのパスを確認
$ which vim
-> /usr/bin/vim

# git が起動するエディタを、上記で確認した vim のパスに設定
$ git config --global core.editor "/usr/bin/vim"

再度 IntelliJ の Termina から git rebase コマンド打ってみるとエディタが起動、解決。

git のデフォルトエディタの設定について

https://git-scm.com/book/ja/v1/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%81%AE%E8%A8%AD%E5%AE%9A

core.editor
コミットやタグのメッセージを編集するときに使うエディタは、ユーザーがデフォルトエディタとして設定したものとなります。デフォルトエディタが設定されていない場合は Vi エディタを使います。このデフォルト設定を別のものに変更するには core.editor を設定します。
$ git config --global core.editor emacs

Groovy の式展開(埋め込み文字列)の型は GStringImpl

ruby の "hello #{str}" のような感じで Groovy でも式展開が使える。

"hello ${str}"
  • 文字列をダブルクォートでくくる
  • 展開したい変数を ${} でくくる

で、この展開された文字列の型は String ではなく org.codehaus.groovy.runtime.GStringImpl クラスとなるため、List<String>のように String で定義しているものに突っ込もうとするとこける。

String として扱うなら #toString() で変換する。