のえら

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

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() で変換する。

Spockをちょっと触ったので覚え書き

初めてGroovySpockを触ったので色々と覚え書き。

動作確認は Spock Web Console を使用。
https://meetspock.appspot.com/

基本的な検証の例と出力結果

  • フィーチャーメソッドの名称は自由
  • フィーチャーブロックにはコメントも書ける(出力はされない)
  • setup(given) -> expect or when, then [-> expect or when, then] -> cleanup (whereは後述)
  • when と then はセットで使用する、一つのフィーチャーメソッド内に複数書ける
サンプルコード
import spock.lang.*

class SampleSpec extends Specification {
    def 'given, when, then'() {
        given:
        def amount = 1000
        when: '合計値に0.5をかけた場合'
        def actual = amount * 0.5
        then: '1000が返ること'
        actual == 1000
    }

    def 'only expect'() {
        expect:
        Math.max(10, 3) == 3
    }

    def 'setup, cleanup'() {
        setup:
        def numbers = [1, 3, 4, 0]

        expect:
        numbers.isEmpty()

        cleanup:
        numbers.clear()
    }
}
実行結果

- maximum of two numbers, 0 or 0
- given, when, then FAILED

Condition not satisfied:

actual == 1000
| |
500.0 false

at SampleSpec.given, when, then(Script1.groovy:22)

- only expect FAILED

Condition not satisfied:

Math.max(10, 3) == 3
| |
10 false

at SampleSpec.only expect(Script1.groovy:27)

- setup, cleanup

whereブロックの話

同じ内容のテストをテストする値を変更して実行したい場合に使える。

  • Unrollアノテーションはwhereブロックの実行結果を行ごとで出してくれる(whereブロックの変数が使用できる)
  • フィーチャーメソッドの引数は任意、それぞれの引数の型を明示的に指定することもできる
  • whereブロックはフィーチャーメソッドの中身をまるっと実行する
サンプルコード
import spock.lang.*

class SampleSpec extends Specification {
    @Unroll
    def "maximum of two numbers, #first or #second"(int first, int second, int expected) {
        expect:
        Math.max(first, second) == expected

        where:
        first | second || expected
        1 | 3 || 3
        7 | 4 || 4  // ここは失敗する
        0 | 0 || 0
    }
}
実行結果

SampleSpec
- maximum of two numbers, 1 or 3
- maximum of two numbers, 7 or 4 FAILED

Condition not satisfied:

Math.max(first, second) == expected
| | | | |
7 7 4 | 4
false

at SampleSpec.maximum of two numbers, #first or #second(Script1.groovy:7)

- maximum of two numbers, 0 or 0

whereブロックの話その2

  • 何度目かは #iterationCount で取得できる(フィーチャーメソッド名の中だけで使用可能?)
  • テーブル形式とパイプ形式がある、後者はイテレーションが使えるオブジェクトならなんでも呼び出せる、外部リソースを使うようなテストで使用する?
サンプルコード
import spock.lang.*

class SampleSpec extends Specification {
    @Unroll
    def "like a table(#a, #b)[#iterationCount]"() {
        expect:
        Math.max(a, b) == b
        where:
        a | b
        1 | 7
        2 | 8
        3 | 9
    }

    @Unroll
    def "pipe(#a, #b)[#iterationCount]"() {
        expect:
        Math.max(a, b) == b
        where:
        a << [123]
        b << [789]
    }
}
実行結果

SampleSpec
- like a table(1, 7)[0]
- like a table(2, 8)[1]
- like a table(3, 9)[2]
- pipe(1, 7)[0]
- pipe(2, 8)[1]
- pipe(3, 9)[2]

フィクスチャーメソッド

テスト全体とフィーチャーメソッドの前後に実行される。
RSpec でいう before(:each), before(:all), after(:each), after(:all) のようなもの。

サンプルコード
import spock.lang.*
 
class MyFirstSpec extends Specification {
	def setupSpec() {
		println('call setupSpec')
	}
 
	def setup() {
		println('call setup')
	}

	def cleanup() {
     		println('call cleanup')
   	}
 
   	def cleanupSpec() {
     		println('call cleanupSpec')
   	}
 
   	def 'test1'() {
     		println('call test1')
     		expect:
     		assert true
   	}

   	def 'test2'() {
   		println('call test2')
   		expect:
     		assert true
   	}

	def 'test3'() {
        		println('call test3')
        		expect:
        		assert true
        		where:
        		a | b
        		1 | 2
        		3 | 4
    	}
}
実行結果(外部出力)

call setupSpec
call setup
call test1
call cleanup
call setup
call test2
call cleanup
call setup
call test3
call cleanup
call setup
call test3
call cleanup
call cleanupSpec

rubocop で ruby の数字の桁区切りをアンダースコアでできることを知った話

Use underscores(_) as decimal mark and separate every 3 digits with them.

プロジェクトに導入している rubocop で上記のメッセージが出た。
ruby では10000のような大きな数字を使うとき、人の目で見てパッと何桁かを理解できるよう、任意の箇所に _ (アンダースコア) で区切ることができる、とのこと。
rubocop 的には3桁ごとにアンダースコアを入れなさいよ、と警告しているので 100_00 も 10_000 も許容する。
※桁区切り(カンマ区切り)なので後者の方が見やすいと思われる(よく日本語にはなじまないとか言われてるけど。。)

このアンダースコアはプログラム上無視される。
以下 rails console で検証。

[1] pry(main)> number = 10_000
=> 10000
[2] pry(main)> number == 10_000
=> true
[3] pry(main)> number == 10000
=> true
[4] pry(main)> 10_000 == 10000
=> true
[5] pry(main)> 10_000.class
=> Integer
[6] pry(main)> number.class
=> Integer

rubocop のデフォルトでは5桁以上で適用
https://github.com/bbatsov/rubocop/blob/master/config/default.yml#L1076-L1078

定義は Style/NumericLiterals
https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml#L784-L789

ruby style guide では以下のように記述されている。
https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics

Add underscores to large numeric literals to improve their readability.


# bad - how many 0s are there?
num = 1000000

# good - much easier to parse for the human brain
num = 1_000_000


WebベースのDBクライアント「JackDB」を触ってみたのでメモ

JackDB TOPページ

f:id:noterr0001:20170716014406p:plain


Log in

ログイン画面。
Googleアカウント or githubアカウントでのログインも可能。
アカウントがない場合は「Create a new account.」からアカウント作成画面に遷移して作成する。

f:id:noterr0001:20170716014811p:plain


Sign up

アカウントの作成画面。

  • Email address
  • Full name
  • Company or organization
  • Choose a username
  • Choose a password

全て必須。
企業または組織単位でのアカウント(以下、組織アカウント)作成となり、ユーザ単位でアカウントを作ることはできない。
※この組織アカウントの中にユーザが存在するような感じ

組織アカウントでの無料試用は「14日間」で、ログイン後、組織アカウントを使っていると、画面の左上に「Trial Ends In XX Days」と残りの無料試用可能日数が表示される。
後述の個人アカウントに切り替えることで期限なしで使える。
なお、組織アカウントで14日超えてもプランの切り替え画面に遷移せず、継続できる場合がある(理由は不明)

f:id:noterr0001:20170716014838p:plain


データソース管理画面(組織アカウント)

ログインすると、データソースの管理画面に遷移する。ここがログイン後のトップページ。

組織アカウントでは「JackDB Demo」から、JackDBのデモが操作できる。後述。
DBはPostgreSQLで、サンプルデータに対してSELECTのみ可能。

データソースの追加や切り替えはこの画面から行う。
「Add a data source」をクリックするとデータソースの追加画面に遷移する。

f:id:noterr0001:20170716015057p:plain


データソース追加画面(組織アカウント)

データベースの種類を選んでデータソースを追加する。
組織アカウントでは以下から選択可能。

Herokuの場合は、Herokuにログインしていればデータソースの一覧が出るのでそこから選択。
その他のDBも、接続名称(わかりやすい適当な名前)・ホスト名・ポート・DB名・DBユーザ名・DBパスワードを入力して、登録。
※DBによって若干異なるので適宜変更

追加が完了すると、接続してDBに対してクエリ発行できるようになる。
画面操作については後述のデモ画面参照。

f:id:noterr0001:20170716015116p:plain


JackDBデモ初回(組織アカウント)

データソース管理画面からデモに遷移した画面。
初回のみ、ちょっとした説明が表示される。

f:id:noterr0001:20170716015134p:plain


JackDBデモ(組織アカウント)

サンプルクエリが実行された状態。
ざっと機能概要。

  • 画面左の「OPEN EDITORS」でクエリの管理ができる(最大8つ)
  • 新規エディタを追加するときは「NEW TAB」を押下。
  • タブごとに名前が付けられる(Executeボタン左のテキストボックス押下)
  • Executeボタン押下でクエリ実行、下に結果表示(カラムをクリップボードへコピーする、などの操作は不可)
  • 実行結果はExportボタン押下でファイル保存可能
  • 右上の雲の中に上矢印のボタンでインポートも可能(フォーマットはcsv, psv, tsvから選択)

f:id:noterr0001:20170716015150p:plain


データソース管理画面(個人アカウント)

組織アカウントでログインした後、画面右上の「地球アイコン+組織名」を押下すると、アカウントの切り替えポップアップが表示される。
Personalを選択すると、個人アカウントに切り替わる。
(不満っぽい顔してる)
切り替わると左上の残り試用日数の表示がなくなる。
Demoも使用不可。
組織アカウントとデータソースは共有しない。

f:id:noterr0001:20170716015204p:plain


データソース追加画面

選択できるデータソースが制限されている。

f:id:noterr0001:20170716015220p:plain

Google Cloud Bigquery で非同期処理

require 'google/cloud/bigquery'

bigquery_project = Google::Cloud::Bigquery.new(
  # Bigqueryの接続情報を指定
  project: 'test_project_id',
  keyfile: './service_account.json'
)

sample_query = <<-QUERY
  SELECT
    repository.*
  FROM
    `bigquery-public-data.samples.github_nested`
  ORDER BY repository.forks desc
  LIMIT 1000
QUERY

puts '###QUERY###'
puts sample_query

puts 'Running query'
query_job = bigquery_project.query_job(sample_query) # (1)

puts 'Waiting for query to complete'
query_job.wait_until_done! # (2)

puts 'Query results'
if !query_job.failed? # (3)
  puts query_job.query_results.first
else
  puts query_job.error
end


(1) 指定の project に対してクエリを投げてジョブを作成する

  • クエリを実行するジョブを Bigquery で作ってその情報を返す

ここで戻るのは Google::Cloud::Bigquery::QueryJob クラス

  • Bigquery 側では、ジョブの作成と実行・ジョブ処理に使用する一時テーブル(約24時間後に消える)の作成が行われる
  • レスポンスにクエリの問い合わせ結果は含まれない

(2) Bigquery 内で実行しているジョブに対してリクエストを投げて、状態を確認する

  • 2秒待機→リクエストを、クエリ実行ステータスが「完了(停止)」になるまで繰り返す(5回)
  • 終わるまで後続の処理は実行されない

(3) ジョブの実行結果にエラーが含まれるかチェックする

  • #done? は対象のジョブが停止していたら true を返すだけなので、成功/失敗は判断できない

エラーチェックしたい場合は #failed? を使う

  • エラーがある場合ジョブの error にエラー理由とメッセージが入っている


実行結果


$ bundle exec ruby async_query_sample.rb

###QUERY###
SELECT
repository.*
FROM
`bigquery-public-data.samples.github_nested`
ORDER BY repository.forks desc
LIMIT 1000
Running query
Waiting for query to complete
Query results:
{:url=>"https://github.com/octocat/Spoon-Knife", :has_downloads=>true, :created_at=>"2011/01/27 11:30:43 -0800", :has_issues=>true, :description=>"This repo is for demonstration purposes only. Comments and issues may or may not be responded to.", :forks=>6718, :fork=>false, :has_wiki=>false, :homepage=>"", :integrate_branch=>nil, :master_branch=>nil, :size=>284, :private=>false, :name=>"Spoon-Knife", :organization=>nil, :owner=>"octocat", :open_issues=>139, :watchers=>8025, :pushed_at=>"2011/10/31 07:34:52 -0700", :language=>nil}


(1)でクエリをぶん投げたあとは Bigquery 側で処理を進めているので、重いクエリを実行するときや集計をしている間にプログラム側で何かしたいとき、複数のクエリを投げて並列で集計させたいときなどに使える。

【vim】NeoCompleteを使いたくてlua付きvimをインストールしてviコマンドで使うのに色々ハマった

NeoCompleteを使いたかったのでlua付きの最新vimをインストールするのに色々ハマった。
察しのよい人はもうタイトルからお気づきかと思われますが、vimのインストールはできていたのにviコマンドで呼び出すように設定していなかったというオチです。
まあ他にもインストール時にpython周りでエラーになったのでまた同じことを繰り返さないためにもメモ。
前提として、NeoCompleteはインストール済み。

Homebrewを使って最新のlua付きvimをインストールする。
vim にオプション --with-lua を指定するとluaが有効になっている状態でインストールできるとのことだったので実行。

$ brew install vim --with-lua
==> Using the sandbox
==> Downloading https://github.com/vim/vim/archive/v8.0.0596.tar.gz
Already downloaded: /Users/user_name/Library/Caches/Homebrew/vim-8.0.0596.tar.gz
==> ./configure --prefix=/usr/local --mandir=/usr/local/Cellar/vim/8.0.0596/share/man --enable-multibyte --with-tlib=ncurses --enable-cscope --with-
==> make
Last 15 lines from /Users/user_name/Library/Logs/Homebrew/vim/02.make:
clang -c -I. -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/undo.o undo.c
ang -c -I. -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/userfunc.o userfunc.c
clang -c -I. -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/window.o window.c
clang -c -I. -I/usr/local/include -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/if_lua.o if_lua.c
clang -c -I. -g -DPERL_DARWIN -fno-strict-aliasing -fstack-protector -I/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/if_perl.o auto/if_perl.c
clang -c -I. -g -DPERL_DARWIN -fno-strict-aliasing -fstack-protector -I/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/if_perlsfio.o if_perlsfio.c
clang -c -I. -I/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/include/python2.7 -DPYTHON_HOME='"/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7"' -fPIE -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/if_python.o if_python.c
clang -c -I. -I/Users/user_name/.rbenv/versions/2.4.0/include/ruby-2.4.0 -I/Users/user_name/.rbenv/versions/2.4.0/include/ruby-2.4.0/x86_64-darwin16 -DRUBY_VERSION=24 -Iproto -DHAVE_CONFIG_H -DMACOS_X_UNIX -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -o objects/if_ruby.o if_ruby.c
if_python.c:67:10: fatal error: 'Python.h' file not found
#include
^
1 error generated.
make[1]: *** [objects/if_python.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [first] Error 2

READ THIS: http://docs.brew.sh/Troubleshooting.html

These open issues may also help:
vim package installation error - configure: error: cannot run C compiled programs. https://github.com/Homebrew/homebrew-core/issues/12323

コンパイルエラー・・・。
pythonは入っていたはず、と思い確認してみる。

$ python --version
Python 3.5.0

うむ、入ってますな。
と、エラーメッセージで指定しているpythonのバージョンが違うことに気がつく。
色々確認。

$ which python3
/Users/user_name/.pyenv/shims/python3

$ which python
/Users/user_name/.pyenv/shims/python

コンパイルで指定しているpathと異なる。。

$ pyenv versions
system
* 3.5.0 (set by /Users/user_name/.pyenv/version)

途中で、.bash_profileでpythonのhome_pathをしていたことを思い出す。
プロジェクトで使うのに書いた気がするのでアンインストールは怖い。
コンパイルには2.7系を使っているようなのでとりあえず切り替える。

$ pyenv global system
$ pyenv versions
* system (set by /Users/user_name/.pyenv/version)
3.5.0

$ pyenv rehash
$ python --version
Python 2.7.13

再度インストール。

$ brew install vim --with-lua
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> Updated Formulae
caddy

==> Using the sandbox
==> Downloading https://github.com/vim/vim/archive/v8.0.0596.tar.gz
Already downloaded: /Users/user_name/Library/Caches/Homebrew/vim-8.0.0596.tar.gz
==> ./configure --prefix=/usr/local --mandir=/usr/local/Cellar/vim/8.0.0596/share/man --enable-multibyte --with-tlib=ncurses --enable-cscope --with-
==> make
==> make install prefix=/usr/local/Cellar/vim/8.0.0596 STRIP=/usr/bin/true

できた!

$vi --version

  1. lua と表示されることを確認したので、vi hoge.rbを開いて確認してみるものの、動作しない。。

vi上でコマンド打ってみる。

:NeoCompleteEnable
=> does not work with this version of vim

最新のvim入ったのになんで・・・?
使用しているvimがどこにあるのか確認してみる

$ which vim
=> /usr/local/bin/vim

$ which vi
=> /usr/bin/vi

あっ・・・(察し)

切り替える。

$ cd /usr/local/bin; ln -s vim vi

できた!

他のプラグインもなんか挙動がおかしいと思っていたら、ずっと vi と vim 気にせずに古いバージョン使ってたからか。。