ruby-buildでRubyをインストールしようとしたらoptparseが無いって言われる

なにごと?

ruby-buildrbenv install 3.0.2 したら optparse が無いって言われてエラーになるんですよ。

$ rbenv install 3.0.2
Downloading ruby-3.0.2.tar.gz...
-> https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.2.tar.gz
Installing ruby-3.0.2...

BUILD FAILED (Ubuntu 20.04 using ruby-build 20210526-11-gebdcf0c)

# (略)

./tool/file2lastrev.rb:6:in `require': cannot load such file -- optparse (LoadError)
        from ./tool/file2lastrev.rb:6:in `<main>'

環境

  • Ubuntu 20.04
  • rbenv 1.1.2-61-g585ed84
  • ruby-build 20210526-11-gebdcf0c

なんとかする

今までも ruby-build は普通に使ってたし、これまでのバージョンは入ってるのだけど。

$ rbenv versions
  2.7.2
* 3.0.0 (set by /home/*****/.rbenv/version)

ってよく見ると systemRubyが無いなって思っておもむろにインストール& rbenv で使うように切り替え。

$ sudo apt-get install ruby
$ rbenv global system
$ rbenv rehash

この状態で ruby install するとちゃんとインストールできた。

$ rbenv install 3.0.2
Downloading ruby-3.0.2.tar.gz...
-> https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.2.tar.gz
Installing ruby-3.0.2...
Installed ruby-3.0.2 to /home/*****/.rbenv/versions/3.0.2

KarateでのAPIテストと同時にAssertJ-DBでデータの確認もやりたい

はじめに

Karateを使うとWeb APIのリクエスト&レスポンスのテストがとてもいい感じにできるが、そうすると今度は「POSTされたデータがちゃんとDBに入っているかどうか」とかも確認したくなってきてしまうもの。 そこでKarateでのテストシナリオ実行の際、AssertJ-DBでのデータのアサーションが行われるようにしてみる*1

環境

ポイント

Karateのfeatureファイルでは、Java.type('パッケージ+クラス名')Javaのクラスを参照できる。 これを利用し、あらかじめDBのテスト用メソッドをAssertJ-DBで書いておいて、それをfeatureファイルから呼び出すようにする。

参考: Calling Java | Karate

サンプルコード全体は下記のとおり。

github.com

やり方

JavaでDBのアサーションを行うメソッドを定義する

テストランナーのクラスにDBのアサーションを行うメソッドを定義しておく。下記サンプルの public static void assertTable(String expectedMessage) がそれ。

package demo;

// ...

@SpringBootTest(classes = DemoApplication.class)
public class DemoTestRunner {
    private static DataSource dataSource;

    @Autowired
    private void setDataSource(DataSource dataSource) {
        DemoTestRunner.dataSource = dataSource;
    }

    @Karate.Test
    Karate testAll() {
        return Karate.run().relativeTo(getClass());
    }

    public static void assertTable(String expectedMessage) {
        var table = new Table(dataSource, "messages");
        assertThat(table).hasNumberOfRows(1)
            .row(0)
            .column("message").value().isEqualTo(expectedMessage);
    }
}

Java.type() で使いたいのでメソッドは public static にする必要があり、それに合わせて DataSource をstaticフィールドにしている。 staticなDataSourceをインジェクションできるようにするため、 setDataSource() はだいぶ無理やり感がある…。

DBのアサーション自体は普通にAssertJ-DBで書けばよい。

featureファイルのシナリオでJavaのメソッドを呼び出す

こんな感じ。

Feature: Demo

  Background:
    * url baseUrl
    * def DemoTestRunner = Java.type('demo.DemoTestRunner')

  Scenario: Add a message
    Given path '/'
    And request { "message": "Hello" }
    When method post
    Then status 200
    And DemoTestRunner.assertTable('Hello')

  Scenario: Find messages
    # ...

Backgrounddef DemoTestRunner = Java.type('demo.DemoTestRunner') することで、引数で指定されたJavaのクラス(今回は DemoTestRunner)が使えるようにしておく。 シナリオでは DemoTestRunner.assertTable('Hello') のようにしてメソッドを呼び出す。

実行してみる

いつもどおりテストランナーのクラス(今回は DemoTestRunner)を実行すればよい。

IntelliJ IDEAだとテスト結果は普通にこんな感じで出てくる。

f:id:ser1zw:20210606182242p:plain

HTMLレポートも出てくる。

f:id:ser1zw:20210606182334p:plain

試しにこんな感じでテストをわざと失敗させてみると…

  Scenario: Add a message
    Given path '/'
    And request { "message": "INVALID" }
    When method post
    Then status 200
    And DemoTestRunner.assertTable('Hello')

失敗時の情報もちゃんと出てくる。よさそう。

f:id:ser1zw:20210606182713p:plain

f:id:ser1zw:20210606182812p:plain

*1:今回はAssertJ-DBを使っているが、別にAssertJ-DBである必要は無い。Javaのテスト用ライブラリなら同じように使えるはず。

Spring Bootでプロファイルごとに実装を切り替える

TL; DR

@Profile@ConditionalOnExpression を使う。ちょっとつらいけどがんばる。

サンプルコードは下記のとおり。

github.com

やりたいこと

システム日時を取得するユーティリティがあるが、テストのときに日時が毎回変わると困るので、特定の場合は固定値を返すようにしたい*1

TERASOLUNAの下記機能とほぼ同じ。ただしSpring Bootなので、XMLを使わずアノテーションでなんとかしたい。

terasolunaorg.github.io

環境

  • Spring Boot 2.5.0

解決方法

@Profile アノテーションを使用し、指定されたプロファイルに応じてインジェクションされる実装を切り替える。

例えば、インタフェース DateTimeUtils に対して本物のシステム日時を返す実装クラス SystemDateTimeUtils と、固定日時を返す実装クラス FixedDateTimeUtils を作るとする。

下記のような動作にしたい。

  • プロファイル with-fixeddatetime が指定されている場合は FixedDateTimeUtils を使う
  • そうでない場合は SystemDateTimeUtils を使う

f:id:ser1zw:20210606091828p:plain

固定日時を返す実装クラス FixedDateTimeUtils では、@Profile("with-fixeddatetime") を付与する。

@Component
@Profile("with-fixeddatetime")
public class FixedDateTimeUtils implements DateTimeUtils {
    // ...

本物のシステム日時を返す実装クラス SystemDateTimeUtils では、@Profile("!with-fixeddatetime") を付与する。

@Profile でのプロファイル指定はSpring 式言語 (SpEL)が使える。!with-fixeddatetimeで「with-fixeddatetime以外」となる。

@Component
@Profile("!with-fixeddatetime")
public class SystemDateTimeUtils implements DateTimeUtils {
    // ...

プロファイルの指定には、下記のような方法がある。

  • application.properties で指定
spring.profiles.active=with-fixeddatetime
@SpringBootTest
@ActiveProfiles("with-fixeddatetime")
class DemoApplicationWithFixedDateTimeTests {
    // ...

その他、実行時の引数や環境変数での指定なども可能。

参考:2.6. アクティブ Spring プロファイルを設定する | Spring Boot 「使い方」ガイド - リファレンスドキュメント

@Profile("!with-fixeddatetime") って書かないといけないのはつらい

つらいけどしょうがない。

本当は @Profile("!with-fixeddatetime") って書かなくても with-fixeddatetime じゃなければデフォルトで @Profile 無しのものを使ってほしいところ。 しかし @Profile を付与しない場合は「どのプロファイルでも常に使われる」という動作になるらしい。今回の例で SystemDateTimeUtils から @Profile を外すと、with-fixeddatetime プロファイルを指定した場合に下記エラーとなる。

***************************
APPLICATION FAILED TO START
***************************

Description:

Field dateTimeUtils in com.example.demo.service.impl.DemoServiceImpl required a single bean, but 2 were found:
    - fixedDateTimeUtils: defined in file [/path/to/springboot-profile-switch-demo/target/classes/com/example/demo/util/impl/FixedDateTimeUtils.class]
    - systemDateTimeUtils: defined in file [/path/to/springboot-profile-switch-demo/target/classes/com/example/demo/util/impl/SystemDateTimeUtils.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

@Profile("default") だと、defaultプロファイルでない場合に使われないので、これもNG。

@ComponentScanコンポーネントスキャンの対象を変更することでの対応もできそうだが、ちょっと大掛かりではある。

実装クラスが3つ以上あるんですけど???

f:id:ser1zw:20210606092559p:plain

下記のような動作にする。

  • プロファイルが with-fixeddatetime の場合は FixedDateTimeUtils を使う
  • プロファイルが with-adjusteddatetime の場合は AdjustedDateTimeUtils を使う
  • それ以外の場合は SystemDateTimeUtils を使う

AdjustedDateTimeUtils には @Profile("with-adjusteddatetime") を付与するとして…

@Component
@Profile("with-adjusteddatetime")
public class AdjustedDateTimeUtils implements DateTimeUtils {
    // ...

SystemDateTimeUtils@Profilewith-fixeddatetimewith-adjusteddatetime の両方を除外するために、@Profile("!with-fixeddatetime && !with-adjusteddatetime") みたいになる。つらい。

@Component
@Profile("!with-fixeddatetime && !with-adjusteddatetime")
public class SystemDateTimeUtils implements DateTimeUtils {
    // ...

SpELは正規表現もサポートされているので、@ConditionalOnExpression を使用して「with-〜 にマッチしない」という指定もできる。プロファイル名をルール化できる場合は、この方法がよいかもしれない。

@Component
@ConditionalOnExpression("#{ not ('${spring.profiles.active}' matches '^with-.+') }")
public class SystemDateTimeUtils implements DateTimeUtils {
    // ...

この場合、JUnitテストクラスでは @TestPropertySource でプロファイルを指定する必要がある。あまりちゃんと調べられていないけど、@ActiveProfiles("プロファイル名") だと spring.profiles.active に値が設定されず、@ConditionalOnExpression が意図通りに動かない(Environment#getProperty("spring.profiles.active")null になる)。

@SpringBootTest
@TestPropertySource(properties = "spring.profiles.active=with-fixeddatetime")
class DemoApplicationWithFixedDateTimeTests {
    // ...

SpELについては、下記のドキュメントを見るとよい。

4. Spring 式言語 (SpEL) | Spring Framework コアテクノロジー - リファレンス

演算子については下記の部分を参照。

4.3.7. 演算子 | Spring Framework コアテクノロジー - リファレンス

参考

*1:テストだけであればMockitoを使ったほうが真っ当ではあるが、そうもいかないことが稀によくある。また、テスト以外でも状況に応じて挙動を切り替えたいこともたまにある。実行環境が異なる場合とか、バッチを特定の日付で実行したい場合とか…。

IntelliJ IDEAを使い始めたときに見るとよい情報まとめ

はじめに

最近ようやくIntelliJ IDEAを使い始めたので、役に立った情報をまとめておきます。

想定環境

とりあえずはじめに読むもの

Javaプログラムの作成〜実行

pleiades.io

デバッグ

pleiades.io

便利な機能・ショートカットなど

個人的によく使うのは下記のもの*1。よく使う順。

超使う

かなり使う

その他

他にもいろいろある。下記記事などが参考になる。

blog.jetbrains.com

公式のショートカット一覧は壁に貼って毎日眺めるとよい。

qiita.com

パンくずリスト

現在見ているクラス名やメソッド名がひと目でわかる。クソデカクラス/メソッドを読んでると、自分が今どこにいるのかわからなくなるので、そういうときに便利。 環境によってはデフォルトで表示されているかもしれないが、表示されていなかったら下記記事を参考に設定する。

pleiades.io

いじってたらぶっこわれてまともに動かなくなったときに設定ファイルを消す

下記記事を参考に、ディレクトリごと削除すればよい。

support.samuraism.com

*1:ショートカットは環境によって異なるかもしれないが、リンク先の公式サイトでは上部メニューの「Shortcuts」からOS等が選択できるので、自分の環境に合ったものを確認するとよい。

クリップボード操作コマンドを活用してテキストを手軽に一括編集する

はじめに

macOSpbcopy, pbpasteLinuxxsel を使うと、クリップボードにコピーした値を sed などのコマンドで編集後、別のエディタやスプレッドシートにペースト、といった操作が簡単にできて便利という話です。

スクリプトを書くほどでもないけど手で編集するのは面倒だからシェル芸したい!という場合におすすめ。

環境

どちらの環境ともシェルは zsh です。

よくある使用例

macOSの場合

例えばソースコードに記載されたエラーコードを抜き出してスプレッドシートに貼り付けたいとき。

当該部分を Command-C でコピーして…

f:id:ser1zw:20210531212437p:plain

pbpaste で出力した結果から grepsed で目的の部分を取り出す。

$ pbpaste | grep 'ErrorCode' | sed -E 's/[^"]+"([0-9A-Z]+)",?/\1/g'
E0001
E0002
E9999

そのままパイプで pbcopy につなげれば、目的の値がクリップボードにコピーされる。

$ pbpaste | grep 'ErrorCode' | sed -E 's/[^"]+"([0-9A-Z]+)",?/\1/g' | pbcopy

あとはスプレッドシートにそのまま Command-V とかで貼り付ければOK。

f:id:ser1zw:20210531212513p:plain

Linuxの場合

macOSの例で使用した pbcopy , pbpaste をそれぞれ xsel -bi , xsel -bo に置き換えるだけ。

$ xsel -bo | grep 'ErrorCode' | sed -E 's/[^"]+"([0-9A-Z]+)",?/\1/g' | xsel -bi

ただし xsel は標準では入っていないので、事前にインストールが必要。こんな感じ。

$ sudo apt-get install xsel

コマンド説明

macOSの場合

pbcopy : 標準入力の内容をクリップボードにコピーする

下記の例では HOGEクリップボードに登録される。普通にコピーしたときと同じく、Command-V で結果を貼り付け可能。

$ echo HOGE | pbcopy

pbpaste: クリップボードの内容を標準出力に書き出す

前述の例でクリップボードに登録された HOGE が標準出力に表示される。

$ pbpaste
HOGE

Linuxの場合

xsel: 選択範囲を操作する

xselX Window System上で選択された部分を操作するコマンド。オプション -b または --clipboard をつけることで、クリップボードの操作ができる。 入力と出力の切り替えはオプション -i -o で行う。

xsel -bi: 標準入力の内容をクリップボードにコピーする

入力は -i オプションで行う。クリップボードのオプションとまとめて -bi で指定。

下記の例ではMacでの例と同じく、標準入力から受け取った HOGEクリップボードに登録される。こちらも Ctrl-V で結果を貼り付け可能。

$ echo HOGE | xsel -bi

-i オプションは省略してもOK。

$ echo HOGE | xsel -b

xsel -bo: クリップボードの内容を標準出力に書き出す

出力は -o オプション。 前述の例でクリップボードに登録された HOGE が標準出力に表示される。

$ xsel -bo
HOGE

ちなみにLinuxには xclip というコマンドもある

xsel と同じく、デフォルトでの操作対象は選択部分。-selection cクリップボードの操作になる。

$ echo HOGE | xclip -selection c
$ xclip -selection c -o
HOGE

xclip は画像などのバイナリデータを扱えたり、パイプを経由せず直接ファイルから入力ができたりと、 xsel より便利な機能もある。

$ xclip -selection c -t image/jpeg foo.jpg # 画像ファイルをクリップボードにコピー
$ xclip -selection c -o > bar.jpg # クリップボード内の画像データをファイルに出力

ただ、クリップボードを指定するためのオプションが -selection c と少し長いので、普段はやっぱり xsel を使ってしまう…。

参考

Pleiades (Eclipse)でのSpringアプリ開発時にjarファイルが削除/変更できなくなったので対処した

環境

現象

Springアプリの開発に独自のjarライブラリを使用していたのですが、jarを上書きしたり、jar更新後にGitのブランチ切り替えをしたときにこんなエラーが出ることがありました。

f:id:ser1zw:20190908034141p:plain

リソースの削除中に問題が発生しました。
  'D:\local\pleiades\workspace\***\WebContent\WEB-INF\lib\***.jar' を削除できませんでした。
    ファイルの削除中に問題が発生しました。
      D:\local\pleiades\workspace\***\WebContent\WEB-INF\lib\***.jar を削除できませんでした。
      D:\local\pleiades\workspace\***\WebContent\WEB-INF\lib\***.jar: プロセスはファイルにアクセスできません。別のプロセスが使用中です。

f:id:ser1zw:20190908034201p:plain

Could not rename file D:\local\pleiades\workspace\***\WebContent\WEB-INF\lib\._***.jar9000261316551232106.tmp to D:\local\pleiades\workspace\***\WebContent\WEB-INF\lib\***.jar

ProcessExplorerで調べてみると、EclipseのSpringプラグインらしきものがjarファイルを掴んでいる様子。

対処方法

Springの言語サーバが原因っぽいので、OFFにしてしまいます。おそらく補完などに影響が出るけど、そこは諦める方針。

メニューから「ウィンドウ」→「設定」 をクリック。

f:id:ser1zw:20190908034643p:plain

「言語サーバ」をクリックし、言語サーバのチェックを外して「適用して閉じる」*1

f:id:ser1zw:20190908034943p:plain

*1:勢いで全部OFFにしたけど、Springのやつだけでよかった気がする

2018年に行ったライブ、フェス

今年はいろいろ行きました。

No. 日付 名称 会場 一言
1 2/14 P.T.A.発足10周年!! と5周年!! “Perfumeとあなた”ホールトゥワー 幕張イベントホール 最高。初めての生edge。最高。
2 3/21 Perfume x TECHNOLOGY presents Reframe NHKホール 1曲目のDISPLAYの没入感がやばくて、最初ぜんぶCGかと思った。テクノロジーさん最高。
3 6/2 Amuse Fes in MAKUHARI 2018 -雨男晴女- 幕張メッセ国際展示場 9〜11ホール カタカナTとかサコッシュとか、グッズがPerfumeっぽいと思ったら本当にPerfumeの仕業だった。最高。
4 8/17-8/18 SONICMANIA 2018 幕張メッセ 中田ヤスタカ→MARSHMELLO→FLYING LOTUS(ちょっとだけ)→電気グルーヴ中田ヤスタカ目当てで行ったらMARSHMELLOにハマった。あとTシャツ買うのに2時間かかってCORNELIUS見逃した。
5 8/19 SUMMER SONIC 2018 幕張メッセ レキシ→JORJA SMITH(ちょっとだけ)→m-flo新しい学校のリーダーズ→THUNDERCAT→GEORGE CLINTON & PARLIAMENT FUNKADELIC。レキシでイルカのバルーンをポンポンしたりm-floで爆踊りしたりGEORGE CLINTONと愉快な仲間たちでいえーいってなったりいろいろあったんだけど、最後にやってたオカマのお姉さんたちに全部持ってかれた。
6 10/13 Yasutaka Nakata presents OTONOKO 2018 石川県産業展示館 4号館 やっぱりCAPSULEは最高。そしてまさかの米良美一
7 10/23-10/24 BABYMETAL WORLD TOUR 2018 in JAPAN 幕張メッセイベントホール ゆいちゃんが…。でもライブ自体はすごくよかった。IN THE NAME OFは7人いるからこそできるパフォーマンスだと思う。あとゲストのGalactic Empireも何気に好き。
8 12/11 Perfume 7th Tour 2018 「FUTURE POP」 横浜アリーナ ふゅーーーちゃーーーーーぽーーーーーーーっぷ!!!!
9 12/29 COUNTDOWN JAPAN 18/19 幕張メッセ国際展示場1~11ホール, イベントホール きゃりーぱみゅぱみゅシシド・カフカZAZEN BOYS打首獄門同好会CAPSULE/中田ヤスタカ→DJピエール中野。みんながだいすきな向井秀徳さんがいました。CAPSULE/中田ヤスタカは30分で最初短いなーと思ったけど、盛り上がるやつ全部入りみたいなセトリで終始爆踊りだったので超満足。
10 12/31 Perfume 7th Tour 2018 「FUTURE POP」ファンクラブ限定・カウントダウン公演 横浜アリーナ これから行く。ふゅーーーーーちゃーーーーーーーぽーーーーーーーーーっぷ!!!!!!

来年もいろいろ行きたい。

それでは良いお年を。