くりにっき

フルスタックキュアエンジニアです

【今月のgem】activerecord-compatible_legacy_migration というgemを作った

github.com

どんなgemか

同一のmigrationファイルでRails 4.2系とRails 5.0系の両方でいい感じに動くようにするためのgemです

これだけだと分かりづらいので具体例を出します

Rails 4.2系から5.0系へのmigrationファイルの移行について

Rails 4.2系から5.0系に移行する時に、Rails 4.2で作られた既存のmigrationのスーパークラスを下記のように ActiveRecord::Migration から ActiveRecord::Migration[4.2] にします

Rails 4時代のmigration

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.timestamps null: false
    end
  end
end

Rails 5移行後のmigration

class CreateUsers < ActiveRecord::Migration[4.2]
  def change
    create_table :users do |t|
      t.timestamps null: false
    end
  end
end

ActiveRecord::Migration のままでもエラーにはなりませんがログファイルに下記のようなDEPRECATION WARNINGが出ます *1

DEPRECATION WARNING: Directly inheriting from ActiveRecord::Migration is deprecated. Please specify the Rails release the migration was written for:

class CreateUsers < ActiveRecord::Migration[4.2]

ユースケース

アプリであればmigrationファイルを上記のように修正すればいいのですが、moutable engineのようにgemの中に内包されてるmigrationファイルをアプリの db/migrate/ にコピーするgemだとそうはいきません。

  • gem内のmigrationファイルが ActiveRecord::Migration の場合
    • アプリでRails 4.2系を使ってる時は問題なし
    • アプリでRails 5.0系を使ってる時にDEPRECATION WARNINGが出る
      • 動きはするけど、5.1辺りで使えなくなる可能性もあるのでできれば放置はしたくない
      • とはいえgem開発者的にはなるべく多くのバージョンに対応しておきたい
      • アプリでmigrationファイルを修正後にgemのmigration installコマンドをたたいた時にgem側のmigratonファイルとアプリ側のmigratonファイルで差分があると「変更されてるけど上書きしますか?」的な確認が大量にでそう(自信ない)
  • gem内のmigrationファイルが ActiveRecord::Migration[4.2] の場合
    • アプリでRails 5.0系を使ってる時は問題なし
    • アプリでRails 4.2系を使ってる時にはエラーになる

migrationファイルを内包したgemをいくつかメンテしているのですが、Rails 5対応をするために既存のRails 4系のアプリともmigrationファイルの互換性を保つのが割とつらかったのでそれを解決するために作りました

使い方

migrationクラスのスーパークラスActiveRecord::CompatibleLegacyMigration.migration_class にするだけです

class CreateUsers < ActiveRecord::CompatibleLegacyMigration.migration_class
  def change
    create_table :users do |t|
      t.timestamps null: false
    end
  end
end

ActiveRecord::CompatibleLegacyMigration.migration_classRails 5.0以降だと ActiveRecord::Migration[4.2] を、Rails 5未満だと ActiveRecord::Migration を返します

https://github.com/sue445/activerecord-compatible_legacy_migration/blob/v0.1.0/lib/active_record/compatible_legacy_migration.rb

Rails 5.0以降でしか使えないmigrationファイルはgemとして配布する時に ActiveRecord::Migration[5.0] つければいいと思います

おまけ

他のgemはどうやってRails 5対応やってるんだろうなぁと思って試しに devise を見たら [5.0] の部分をerbで埋め込んでた

gemごとに個別対応するの、つらみある。。。

最後に

gemでmigrationファイルを配布していてRails 4.2系とRails 5.0系を両方メンテする必要が出てきたら是非ご利用ください

*1:コンソールには出ないので注意

GitHubでリポジトリにStarつけた人を雑に地図で表示した

だいぶ間が空きましたが社内LT大会ネタで作ったやつ第3弾です

前置き

先日弊社広報ブログで社内LT大会の様子があがりました

www.drecom.co.jp

写真の3枚目が僕なのですが、3本目のLT *1のネタで「GitHubリポジトリにStarつけた人を雑に地図で表示した」というのをやったのでその紹介です

モチベーション

自分が作ったツールが世界中で使われてる様子を可視化したかった(一番Starが多いやつで130)

f:id:sue445:20160727231150p:plain

https://github.com/sue445

作ったスクリプト

github.com

やってること

  1. GitHubAPIでStargazers(リポジトリにStarつけた人)を取得
  2. GitHubのプロフィールから住所を取得
  3. GoogleのGeocoding APIで住所から緯度経度を取得
  4. KMLファイルに出力
  5. GoogleマイマップにKMLファイルをインポート

Googleマイマップとは

Googleドライブの「その他」の中にあるやつです

f:id:sue445:20160727231601p:plain

ファイルをインポートすることでお手軽に地図を表示できます

こんな感じ

https://github.com/sue445/jenkins-backup-script のstargazers map

f:id:sue445:20160727231801p:plain

https://drive.google.com/open?id=148eq4ySxjY5IQO_e29MkjMulfoI

所感

  • ファイルを食わせるだけで雑に地図表示できるのは便利
    • 地図の公開範囲とかもGoogle Driveで制御できる
    • CSVだとアイコンとか設定できなさそうなのでKML使うがよさそうな感じ

この手のサービス無いのでサービス化ワンチャンありそうで気が向いたら作ろうかと思ってたけど、いろいろ忙しくなってきたのでスクリプトのみ公開しました。MITなので煮るなり焼くなりしてください

他のLTネタ

第1弾

sue445.hatenablog.com

第2弾

sue445.hatenablog.com

*1:5分間でLTを3本やったw

index_shotgun v0.3.0をリリースしました

index_shotgunとは?

重複インデックスをいい感じに調べるgemです

github.com

qiita.com

更新内容

https://github.com/sue445/index_shotgun/blob/master/CHANGELOG.md#v030-20160723 をかいつまんで説明すると下記のような感じです

activerecord 5系対応

  • すっかり忘れてたので対応
  • Rails 5から ar_internal_metadata なるテーブルが増えていてテストがこけてたので、ar_internal_metadata や schema_migrations などのテーブルを重複インデックスチェック対象から除外するようにした

rake index_shotgun:fire などで重複インデックスが見つかった時に exit 1 するようにした

  • 個人的には今回のメインの修正
  • CIで実行した時に重複インデックスがあったらビルドがこけてほしかったので exit 1 するようにしました

OracleもCIするようにした

キャンペーンではてなTシャツをもらいました

はてなブックマーク & はてなブログをアプリで使いこなして、はてなTシャツをもらおう! - はてなブックマーク開発ブログ のキャンペーンに参加してはてなのTシャツをもらいました!

はてなさんからTシャツもらいました!

キャンペーン参加した時のエントリはこちら

sue445.hatenablog.com

Tシャツの会社 の関連エントリを書いてはてなTシャツをもらうなんてネタにもほどがあるw

はてなとspicelifeには足を向けて眠れないです

ブコメレス

id:kasumi19732004

キャンペーンではなくキェンペーンに応募したのですね

タイトルtypoしてたので修正 ('A`)

懇親会でピザとビールの発注量を計算するツールを作った

そういうツールを作りました(開発期間2日くらい)

Pizza Beer計算機

https://sue445.github.io/pizza-beer/ hatebu

f:id:sue445:20160708013451p:plain

モチベーション

この手のツールとしては Party が有名で便利なのですが、ピザの単価が安すぎて *1個人的に直したいと思いがありました。

かといって修正してPullRequestを送ろうにもどこに送ればいいか分からない(そもそもOSSなのか?)というのもあって Mithril の勉強も兼ねて自分で作りました

リポジトリ

github.com

masterブランチの代わりにgh-pagesブランチを使うことで、修正したものが即サイトに反映されるようにしています。デプロイいらずで便利

Partyと比べてのPizza Beer計算機のメリット

  • 計算時にサーバにPOSTしない
    • フォーム入力時に自動計算されて表示される(サーバへの通信無し)
  • ピザやビールの単価を調整できる
  • 1人辺りのビールの本数も調整できる(例:1人ビール1.5本とか)
  • スマホ対応

便利だと思うので是非ご利用ください

*1:Lサイズ1枚2500円だと選択肢がほとんどない。。。

golangのバイナリを雑にクロスコンパイルしたかった

zatsu_monitorを作った時の副産物です

sue445.hatenablog.com

やりたかったこと

  • golangのクロスコンパイルを楽にやりたかった
  • ビルドしたバイナリはzipで圧縮しつつ、zipのファイル名にosやarchもつけたかった
    • 例)zatsu_monitor_unix_amd64.zip
    • バージョン名もつくとベスト
    • zipをそのままリポジトリreleases にアップロードしたかった
  • ただしバイナリにはosやarchは つけたくなかった
    • 例)zatsu_monitor
    • 好みの問題だと思うのですが、バイナリにosなどがつくとプロビジョニングツールで削るのが面倒なので
      • プロビジョニングツールではunzipして出てきたファイルをポン置きするだけにしたかった

gox が一番理想に近かったのですが、バイナリにosやarchがつくのが嫌だったので自分でビルドスクリプトを書きました

ビルドスクリプト

https://github.com/sue445/zatsu_monitor/blob/0.2.0/build.sh

できること

  • 各OS, archごとに<バイナリ名>_<バージョン>_<os>_<arch>.zipの形式のzipファイルを作成
  • zipを解凍したらosやarchはつかないバイナリが出てくる
  • バージョンでtagを生成してpushする

使い方

Macの場合は gnu-sed をインストール

Macでデフォルトで入ってるBSD版のsedだと正規表現が使えなくて機能が貧弱なので gru-sedをインストールしてください

brew install gnu-sed

version.go にバージョン情報を記載

package main

const VERSION = "0.1.0"

build.shを適宜変更

readonly DIST_DIR="dist"
readonly BIN_NAME="zatsu_monitor"
  • DIST_DIR : バイナリの出力先
  • BIN_NAME : バイナリ名

実行

distディレクトリに出力するので予め作っておいてください。(あと .gitignore への登録も)

$ ./build.sh
Write: dist/zatsu_monitor_0.1.0_darwin_amd64.zip
Write: dist/zatsu_monitor_0.1.0_linux_amd64.zip
Write: dist/zatsu_monitor_0.1.0_linux_arm.zip

zipの中身

$ unzip -l dist/zatsu_monitor_0.1.0_linux_amd64.zip
Archive:  dist/zatsu_monitor_0.1.0_linux_amd64.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
 11623512  07-06-16 23:23   zatsu_monitor
 --------                   -------
 11623512                   1 file

./build sh release のように実行すると自動的にバージョンのtagを生成してリポジトリにpushまでします

50行くらいのスクリプトなので詳しくはソースを読んでください

ライセンスとか

zatsu_monitor同様MITなので煮るなり焼くなりしてください( ◜◡◝ )

【今月のgem】kiriban_getterというキリ番チェックをするためのgemを作った

社内LT大会ネタで作ったやつ(第2弾)

モチベーション

キリ番には夢がある(断言)

github.com

使い方

refinementsを使っているので

using KiribanGetter

したところでのみ下記のメソッドが使えるようになります

kiriban?

100.kiriban?
#=> true

101.kiriban?
#=> false

111.kiriban?
#=> true

zorome?

111.zorome?
#=> true

2222.zorome?
#=> true

2223.zorome?
#=> false

kuraiban?

100.kuraiban?
#=> true

101.kuraiban?
#=> false

111.kuraiban?
#=> false

余談

  • 「最上位以外の数字が全部0」という数字の名前を調べるのが一番難しかった(いろいろググったら「位番」がしっくり来たので採用)

その他

  • kuraiban? , zorome? ともに何種類か作ってベンチマークとって速いやつを採用
    • Stringや正規表現での判定は整数演算の1.5〜2倍くらい遅いという学び
    • ただしString#lengthはチョッパヤ
  • Rubyでアクセスカウンターを作る時にご利用ください

kiribanとの違い

最初kiribanって名前のgemを作ってpushしようとしたら下記の同名gemがあったので名前を変えてリリースしました(つらい)

secret-garden.hatenablog.com

github.com

  • kiribanはRubyのコアクラス(ObjectやString)をオープンクラスしてメソッドを直接生やしているが、kiriban_getterはrefinementsを使ってるので影響範囲は using KiribanGetter したところのみ
  • kiribanの方が対応してるキリ番は多い
  • kiribanは文字列に変換できるオブジェクトなら AAA のようなやつでもチェックできるが、kirban_getterは Integer のみチェック

ベンチマーク結果

ベンチマークをとったらkiriban_getterの方が速かったです

$ bundle exec ruby benchmark/kiriban_getter.rb
Warming up --------------------------------------
    digit_1 (legacy)    72.272k i/100ms
    digit_2 (v0.1.0)    78.053k i/100ms
Calculating -------------------------------------
    digit_1 (legacy)      1.229M (± 3.0%) i/s -      6.215M in   5.060381s
    digit_2 (v0.1.0)      1.315M (± 4.3%) i/s -      6.635M in   5.057391s

Comparison:
    digit_2 (v0.1.0):  1314506.8 i/s
    digit_1 (legacy):  1229392.4 i/s - same-ish: difference falls within error

Warming up --------------------------------------
kuraiban_1? (legacy)    42.554k i/100ms
kuraiban_2? (v0.1.0)    65.051k i/100ms
zeroban? (kiriban gem)
                         9.175k i/100ms
Calculating -------------------------------------
kuraiban_1? (legacy)    598.862k (± 4.7%) i/s -      3.021M in   5.058023s
kuraiban_2? (v0.1.0)      1.010M (± 2.9%) i/s -      5.074M in   5.027767s
zeroban? (kiriban gem)
                        100.042k (± 5.0%) i/s -    504.625k in   5.057287s

Comparison:
kuraiban_2? (v0.1.0):  1010089.6 i/s
kuraiban_1? (legacy):   598862.0 i/s - 1.69x slower
zeroban? (kiriban gem):   100042.3 i/s - 10.10x slower

Warming up --------------------------------------
  zorome_1? (legacy)    10.264k i/100ms
  zorome_2? (v0.1.0)    25.113k i/100ms
zoroban? (kiriban gem)
                         7.585k i/100ms
Calculating -------------------------------------
  zorome_1? (legacy)    122.994k (± 4.9%) i/s -    615.840k in   5.019815s
  zorome_2? (v0.1.0)    329.715k (± 4.7%) i/s -      1.657M in   5.039460s
zoroban? (kiriban gem)
                         90.235k (± 3.8%) i/s -    455.100k in   5.050971s

Comparison:
  zorome_2? (v0.1.0):   329715.0 i/s
  zorome_1? (legacy):   122994.0 i/s - 2.68x slower
zoroban? (kiriban gem):    90235.3 i/s - 3.65x slower

教訓

  • gemを作る時は https://rubygems.org/ で事前にチェックしよう
  • 空いてたら名前を取られないようにbetaでもいいからリリースすべき