のえら

技術備忘とかメモとか.間違いはつっこんでいただきたい所存.

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 気にせずに古いバージョン使ってたからか。。

Google Bigquery の WEB インターフェースのクエリエラー メモ

Bigquery のクエリエラーで(無駄に)ハマったところ

WITH BASE AS (
SELECT
count(id) as total
FROM
 `dataset_name.hoge_*`
WHERE
_TABLE_SUFFIX BETWEEN '20170501' AND '20170510'
)
SELECT
total
FROM
BASE

Bigqueryには実行前にクエリをチェックしてくれる機能があり、WITH句を書いていたら以下のようなエラーが表示された。
※このクエリはWITH句を含みたかっただけなので内容が適当です

エラーメッセージがこちら↓

Error: Encountered " "WITH" "WITH "" at line 1, column 1. Was expecting:

前日まで同様のクエリで問題なかったので、なぜ急に・・・?と色々構文チェックしていたけど、標準SQLを指定するのを忘れていただけだった(ブラウザ再起動後だった)

クエリ実行画面の「show options」を押して「SQL Dialect」の「Use Legacy SQL」のチェックを外せばOK

【rails3】POSTしたらルーティングエラーになったけどSSL設定的なものだった

※rails3での話

ssl_requirement
https://github.com/bartt/ssl_requirement
(railsSSLを使えるようにするgem)

起きたこと

特定の path に対して POST を投げたらルーティングエラーになってしまった。
指定している path のルーティングは routes に記述し、rake routesでも確認済みなので、ブラウザの開発者ツールで network を確認したら、指定の path の直後に同じ path に対して GET をかけていた。
確かに、この path に対してルーティング設定で GET は許可していないので、ルーティングエラーになるのは頷ける。
が、GET は意図して動作させていない。。
どこかでリダイレクトがかかっているみたいだったので確認したところ、ssl 接続の設定が絡んでいた。
今回指定した path は ssl_requirement を使用して HTTP で接続すると HTTPS にリダイレクトがかかるように設定されていて、ここのリダイレクトで GET になるためエラーが発生。
開発環境と本番環境でプロトコル変更するようにしておかないと動作確認に影響が出る。。
が、Rails.env.production? などで条件を指定してプロトコル変更するようにするのは微妙。
と思って gem の README をよく読んだらプロトコル切り替えられるようにできていた!

https://github.com/bartt/ssl_requirement#ssl-url-helper

hoge_path を hoge_path(secure: true) に変更して解決。
secureを指定すると、http と https を実行環境によって切り替えてくれる。
※環境設定で、SslRequirement.disable_ssl_check = true を指定している場合

react というか JSX のコメントアウト

sample.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <script src="http://fb.me/react-0.13.3.js"></script>
    <script src="http://fb.me/JSXTransformer-0.13.3.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script type="text/jsx">
      // コンポーネント宣言
      var Counter = React.createClass({
        // 初期値設定
        getInitialState() {
          return { count: 0 };
        },  
        // クリック時の処理
        onClick() {
          this.setState({count: this.state.count + 1});
        },  
        // コンポーネントを返す
        render() {
          return (
            <div>
              {// state の count を読み込む
              }   
              <div>count:{this.state.count}</div>
              {/* 
                クリック時にクリックイベント呼び出し
              */}                                                                                                                                      
              <button onClick={this.onClick}>click!</button>
            </div>
          );  
        }   
      }); 
      // 描画
      React.render(<Counter />, document.getElementById('app'));
    </script>
  </body>
</html>

こんな感じで、
{// ... }

{/* ... */}
で書ける。

前者は終わりの } を改行しないとエラーになるので注意する。
sample.html をブラウザで開いてデベロッパーツールで確認すると、改行していない場合以下のようなエラーがコンソールに表示されている。

Uncaught Error: Parse Error: Line 18: Unexpected token {
at file:///Users/xxx/work/sample.html

{/*
^
at file:///Users/xxx/work/sample.html

{/*
^