くりにっき

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

compact_blankというgemを作った

なんやかんやで久しぶりにgem作りました

どんなgem?

Array#compactHash#compact *1だとnilを除外したArrayやHashを作ることができますが、空文字も除外したいことがちょいちょいあるので作りました。 *2

使い方

refinementsを使ってるので using CompactBlank を書いた場所のみ compact_blankcompact_blank! が生えます

Array#compact_blank, Array#compact_blank!

compact_blank!(ビックリマークがついてるメソッド)は自分自身を破壊的に変更します。(変更時は self が返って、変更されなかった時は nil が返るのも #compact! 準拠です)

using CompactBlank

array = ["a", nil, "b", ""]

array.compact
#=> ["a", "b", ""]

array.compact_blank
#=> ["a", "b"]

array.compact_blank!
#=> ["a", "b"]
array
#=> ["a", "b"]

Hash#compact_blank, Hash#compact_blank!

using CompactBlank

hash = { a: "1", b: nil, c: "3", d: "" }

# NOTE: Hash#compact is feature of activesupport
hash.compact
#=> {:a=>"1", :c=>"3", :d=>""}

hash.compact_blank
#=> {:a=>"1", :c=>"3"}

hash.compact_blank!
#=> {:a=>"1", :c=>"3"}
hash
#=> {:a=>"1", :c=>"3"}

やってること

20行ちょいの雑なモンキーパッチです https://github.com/sue445/compact_blank/blob/v0.1.0/lib/compact_blank.rb

*1:Array#compact はRuby本体のメソッドだけど Hash#compactはactivesupportのメソッド

*2:まぁ真面目に array.reject(&:blank?) や hash.reject{|_, v| v.blank? } を書いてもよかったんですが、同じ記述を3個以上書くことになってつらくなったのでgem化した

ドリコムで使ってるgem一覧 #railsdm

先日 【増枠】Rails Developers Meetup #2 でLTした時の資料です。ご査収ください

rails-developers-meetup.connpass.com

資料

スライド版

sue445.github.io

markdown

github.com

当日の質問

覚えてる範囲で

社内gemにするかOSSするかどう切り分けてる?

  • 基本的には外に出すこと前提で作ってる
    • 理由:みんなに使ってもらえた方がフィードバックが得られやすいし、Travis CIなどのエコシステムも利用できる
  • ビジネスロジックを抽出していたり、社内コンテキスト*1に依存してるような場合は社内gemにしてる
  • OSSにするとどうしても汎用化しちゃいがちでEasyから外れてしまうので、社内利用用途に絞ることでEasyを維持*2しているケースもある

詳しくは以前エントリに書きました

sue445.hatenablog.com

どうでもいい情報

*1:capistrano系の社内gemは社内インフラ構成前提になってる

*2:イージーをいじ

TwittodonというTwitterからMastodonに流すボットを作った

ここ最近作ってた便利ツールの共有です

Twittodonとは?

Twitterからの任意のツイートをMastodonに流すためのボットです

github.com

ちなみにTwittodon(ついっとどん)とはTwitter + Mastodonの造語です

サンプル

f:id:sue445:20170601004222p:plain

https://precure.ml/@sue445/85064

  • Twitterの検索クエリにマッチしたツイートをMastodonにトゥートする
  • ツイートに画像が含まれていればMastodonにもアップロードして画像付きのトゥートにする
  • トゥートに元ツイートへのリンクを付与
  • ツイートに短縮URL(t.co)が含まれていた場合、短縮前の元URLの状態でトゥートに含める

といったことをやっています

使い方

TwitterMastodonAPIを使うためのトークンを取得する部分は手動ですが*1Heroku のアカウントがあればその後のサーバへのデプロイはDeploy to Herokuボタンを使ってワンクリックでデプロイできます。

f:id:sue445:20170601005523p:plain

Twitterの検索条件はHeroku Schedulerのジョブに渡せます。

f:id:sue445:20170601005947p:plain

詳しくは https://github.com/sue445/twittodon/blob/master/GETTING_STARTED.md を読んで下さい

Twitter -> Mastodon トゥート同期アプリ」との違い

似たようなサービスで Twitter -> Mastodon トゥート同期アプリ というのがあります。

sync.twi2mstdn.space

Twitter -> Mastodon トゥート同期アプリ」だと連携したTwitterアカウントのツイートを全てMastodonに送るようですが、TwittodonだとMastodonに送るツイートを検索条件で指定することができます。

検索APIを使っているので、自分以外のツイートもMastodonに送れます。

イメージ的にはIFTTTの「Post to Slack when a tweet matches your search term(Twitterの検索条件にマッチしたツイートをSlackに送るアプレット)」のMastodon版を目指して作っています。

ifttt.com

最後に

最初のトークンの取得が手動なのが面倒かもしれませんが*2、ワンクリックでデプロイできるようにしたりTwitterの画像をMastodonに再アップロードなどいろいろ作り込んでいて便利なので是非ご利用ください。

また、インスタンスによってはボット利用が禁止されたり制限されてる場合もあるので節度をもって使うようにしてください。

*1:GETTING_STARTEDに手順は全部書いてる

*2:その手順を簡略化するためのアプリの作成もなくはなかったんですが、これ以上簡単にしすぎるとボットが作られ放題でそれはそれで治安が悪くなりそうな予感があったので、最低限トークンの取得くらい手順書見ながら自力でどうにかできる人だけに使ってほしいという思いでふるいにかけるために現状の仕様にしています

Travis CIで定期的にビルドを実行する

tl;dr;

Travis CIを使っているのならCron Jobsを使うのが便利

前置き

Meguro.rb#2OSSパッチ会 で発表した資料で「1年以上ビルドしてないリポジトリだと久しぶりにPRが飛んできたらactivesupport系でだいたいテストが落ちる」といったことをしゃべったのですが、それに対してリポジトリ管理者はどうすべきかというアンサーソングです

解決方法

リポジトリを定期的にビルドをすることで解決することができます。

大半のOSSだとTravis CIを使ってることが多いと思いますが、Travis CIだと「Cron Jobs」でブランチの定期ビルドができます

Cron Jobs - Travis CI

設定方法

Travis CIの Settings -> Cron Jobsで設定するだけです。(詳しくは 公式ドキュメント 参照)

f:id:sue445:20170528151200p:plain

monthly(1ヶ月に1回ビルド)、weekly(1週間に1回ビルド)、daily(1日1回ビルド)のいずれかのタイミングで定期ビルドが実行できます。

f:id:sue445:20170528151441p:plain

活用例

自分はweeklyを使って週1の定期ビルドしています。

登録した日時を起点にして定期ビルドが実行されるのですが、金曜日の18:30過ぎ(だいたい定時)に設定したので、20個くらいのリポジトリで一斉にビルドが実行されてSlackに通知が流れると非常に花金感があります。

f:id:sue445:20170528151524p:plain

プリキュアが始まる前にトゥートするmastodonボットなどを作った

前置き

最近 Mastodon が流行っていますが、僕はプリキュア好きなのでプリキュアインスタンスきゅあったー に参加しています。

precure.ml

中の人曰く

f:id:sue445:20170507212951p:plain

とのことだったので*1、サーバの負荷にならないレベルで雑にボットを作ってみました

プリキュアこのあとすぐボット

プリキュアは日曜朝(通称ニチアサ)の本放送以外にも、過去作品がほぼ毎日どこかの放送局で再放送されています。それが始まる前にトゥートするボットが「プリキュアこのあとすぐボット」です

https://precure.ml/@precure_onair_bot

f:id:sue445:20170507213554p:plain

実際にトゥートした結果

こんな感じ。

f:id:sue445:20170507212206p:plain

https://precure.ml/@precure_onair_bot/20677

f:id:sue445:20170508174846p:plain

https://precure.ml/@precure_onair_bot/23663

技術的なこと

番組情報を しょぼいカレンダーAPI から取得して、プリキュア開始10分前くらいになったらトゥートするようにしてます。*2

気持ち的には開始5分前くらいにしたかったんだけど、Heroku Schedulerで指定できる時間が10分刻みなため10分前にしています。

f:id:sue445:20170507214528p:plain

これくらいのボットなら個人サーバに置いてcrontabで動かすというのもあったけど、git pushで (楽に|雑に) デプロイできるのが魅力だったのでHerokuを採用。

プリキュア誕生日ボット

プリキュアの誕生日にトゥートするだけのボットです

https://precure.ml/@precure_birthday_bot

f:id:sue445:20170507215038p:plain

開発時期の関係でまだ1トゥートもしてないですが、バグってなければ5/28のキュアロゼッタの誕生日にトゥートされるはず

【2017/5/28追記】 ちゃんと投稿されたのでスクショ追加

f:id:sue445:20170528145844p:plain

https://precure.ml/@precure_birthday_bot/79359

技術的なこと

プリキュアの誕生日情報は rubicure で管理されているので、今日が誕生日のプリキュアを取得したい場合はこういう風にワンライナーでシュッと書けます。rubicure便利(熱い自画自賛

birthday_girls = Precure.all.select { |girl| girl.birthday?(today) }

https://github.com/sue445/cure-mastodon-bots/blob/2f8beb07fcd5e980cf8dd926329804a44d665e40/lib/birthday_bot.rb

ソースコード

いずれもこちらになります

github.com

参考リンク

*1: https://precure.ml/@precure/20379

*2:厳密には毎時50分(20分)になったら10〜39分後(つまり毎時0〜29分 or 毎時30〜59分)に開始する番組の中にプリキュアが含まれてる場合にトゥート

chrome-gitlab-notifier v2.0.0をリリースした

今年初のビッグバンリリースです

chrome.google.com

tl;dr

既存のコードを全て捨てて全部書き直しました

書き直した経緯

  • GitLab API v4に対応するにあたって、既存のコードベースでv3とv4両方対応するのはいろいろつらそうだったため
    • 特にjQueryでDOMをゴリゴリ操作してるところとか
  • テストを書いてないことはなかったけど、jQueryでDOM操作してるviewや定期的にGitLab APIをたたいてポーリングしてるバッググラウンド処理のテストが全然なくて、かつ今までの経験上一番不具合起こってた場所だったので手厚くテストを書きたかった

主な変更点

https://github.com/sue445/chrome-gitlab-notifier/blob/master/CHANGELOG.md#200-20170504 からの抜粋です

  • 全てのjsをES6で書き直した
    • Chromeはトランスパイル不要でES6がそのまま動かせるので、あえてBabel系のツールは使っていません
    • Chrome拡張はChrome以外のブラウザを考慮不要なのが非常によい
    • classとアロー演算子便利
  • jQueryに依存してた処理を mithril.js に移植
    • Twitter BootstrapがjQueryに依存してるためjQuery自体は捨てていませんが、プロダクトコードでのjQuery依存は全部なくしました
    • mithril v1を使ってたのですが、日本語サイト がv0系のままで苦労した記憶(mithril移植終わったくらいで日本語サイトもv1対応してた)
  • Jasmineでやってたユニットテストmocha に変更
    • 最初 ospec っていうmithril付属のテスティングフレームワーク使ってたのですが、あまりにも機能が少なすぎたので断念
    • 一番最初にテスト書いてた当時(4年前くらい)はJasmineとmochaほぼ同じくらいのシェア(主観)だったのですが、今はmochaが優勢な気がした(主観)のでmochaを採用
  • ESLint 導入
    • 仕事でrubocopをよく使ってるのでjsでも使いたいと思って探していたらESLintに行き着いた
  • yarn 導入
    • Travis CIでnpm installしたパッケージのキャッシュを効かせるにはyarnが必要っぽかったので導入
  • せっかくなので使ってるライブラリも諸々アップデート
  • その他細かいバグ修正など

差分

プルリクエストだと差分しかなくてワケワカメなので細かいdiff読むならマイルストーンがおすすめ

f:id:sue445:20170504024921p:plain

プルリクエスト上だとライブラリのアップデート内容も含まれてるので無駄に差分が大きいですが、書き直したソースの差分だけならこんな感じ

$ git diff --stat 1.4.3...2.0.0 -- src/
 src/avatar_cache.js       |  69 +++++++--------
 src/background.js         | 356 +++++++++++++++++++++++++++++++++++------------------------------------------
 src/background_init.js    |  42 ++++++++++
 src/base_cache.js         |  19 +++++
 src/config.js             | 348 ++++++++++++++++++++++++++++++++++-----------------------------------------
 src/gitlab.js             | 313 ++++++++++++++++++++++++++++++++++++++------------------------------
 src/notification.js       | 130 +++++++++++++++-------------
 src/notification_cache.js |  71 ++++++++--------
 src/options.js            | 489 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
 src/options_init.js       |  42 ++++++++++
 src/popup.js              | 235 +++++++++++++++++++++++++++------------------------
 src/popup_init.js         |  36 ++++++++
 src/util.js               |  61 --------------
 13 files changed, 1237 insertions(+), 974 deletions(-)

$ git diff --stat 1.4.3...2.0.0 -- test/
 test/avatar_cache_test.js       |  56 +++++++++++++++++++++
 test/background_test.js         | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/base_cache_test.js         |  38 ++++++++++++++
 test/notification_cache_test.js |  65 ++++++++++++++++++++++++
 test/notification_test.js       | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/options_test.js            |  31 ++++++++++++
 test/popup_test.js              |  63 +++++++++++++++++++++++
 test/stub/projects.json         | 112 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 786 insertions(+)

$ git diff --stat 1.4.3...2.0.0 -- spec/
 spec/SpecRunner.html                   |   63 ---
 spec/gitlab_spec.js                    |   98 ----
 spec/lib/jasmine-1.3.1/MIT.LICENSE     |   20 -
 spec/lib/jasmine-1.3.1/jasmine-html.js |  681 ------------------------
 spec/lib/jasmine-1.3.1/jasmine.css     |   82 ---
 spec/lib/jasmine-1.3.1/jasmine.js      | 2600 --------------------------------------------------------------------------------------------
 spec/lib/jquery.mockjax.js             |  587 ---------------------
 spec/lib/run-jasmine.js                |   86 ----
 spec/notification_spec.js              |   94 ----
 spec/spec_helper.js                    |    4 -
 spec/stub.js                           |   89 ----
 11 files changed, 4404 deletions(-)

spec/ 全消しなのはJasmineを捨ててmochaに乗り換えたためです

mithril.jsを採用した経緯

実は最初Vue.jsを使って書き直してたのですが、Vue.jsの中で使ってるevalがChrome拡張だとサンドボックスモードを有効にしないと使えなくて、サンドボックスを有効にすると今度はChromeのlocalStorageにアクセスできなくてVue.jsは断念しました。

が、後日Twitterでのやりとりで事前に全部コンパイルしているとChrome拡張でもVue.jsが使えるということが判明。

jp.vuejs.org

次にChrome拡張作る時はVue.jsワンチャンありそう

開発期間とか

前述のVue.js時代から含めるとかれこれ2ヶ月くらいかかって全部のコードを書き直しています

あとビッグバンリリースと銘打ってますが、TDDのこころ に従って1ファイルずつ地道にES6化&テスト追加しています

1ヶ月くらい自分のローカルで動かしてたので致命的なバグはないはずです。

今日から使える!OSSプルリク集 #megurorb

昨日 Meguro.rb#2 2017/04/20(Thu) でLTをしたのでその時の資料を公開したいと想います

megurorb.connpass.com

スライド版

sue445.github.io

リポジトリhttps://github.com/sue445/megurorb-02

ブログ版(内容はスライドとほぼ同じです)

OSSにプルリク出す時のあるあるネタを実用例を交えて紹介


1. ドキュメントのtypoなどを修正

  • これが一番プルリクの難易度は低い

https://github.com/gitlabhq/gitlabhq/pull/7534

  • GitLabのwebhookで実装はされているが、リファレンスから漏れているパラメータがいくつかあったので追加
  • 「◯◯(プルリク番号)で追加されているけどその時にリファレンスに更新されていないよ!」って言えればベスト
  • GitLabはAPIの実装とリファレンスの差異が結構多いので狙い目

2. .travis.yml に新しいRubyのバージョンを追加

rvm:
  - 2.1
  - 2.2.2
  - 2.3.1
  # ここに2.4を追加したい

CI against ruby 2.4

https://github.com/sue445/index_shotgun/pull/28/files

f:id:sue445:20170420010405p:plain


英文の元ネタ

https://github.com/amatsuda/database_rewinder/commit/6a1f87c3a0729391bd24c68f38d28622d385479b

f:id:sue445:20170420010438p:plain

「CI against 〜」は使いやすいので定型句として覚えていていい


3. gemの新しいバージョンが出たので依存を緩めたい

f:id:sue445:20170420010449p:plain


https://github.com/activeadmin/activeadmin/pull/4722

  • kaminari v1系が出た直後に、activeadminでkaminari 1系使うために依存を緩めたかった

f:id:sue445:20170420010458p:plain


英文の元ネタ

https://github.com/activeadmin/activeadmin/commit/7a861b723bd65ea174541cf2f23048143575cba8

f:id:sue445:20170420010506p:plain

「Relax ◯◯ dependency for △△△」も使いやすいので定型句として覚えていていい


4. activesupportactiverecordに依存してるgemでRuby 2.2未満系でコケるので5系未満使うようにする

  • 1年以上ビルドしてないようなリポジトリだと久しぶりのPRでビルドがコケる原因第1位

f:id:sue445:20170420010518p:plain

https://travis-ci.org/railsware/global/jobs/198722120


Gemfileにとりあえずこれ書いとけば bundle install できるのでPR送る

if Gem::Version.create(RUBY_VERSION) < Gem::Version.create("2.2.2")
  # activesupport 5+ requires MRI 2.2.2+
  gem "activesupport", "< 5.0.0"
end
  • Ruby 2.2.2未満で動かんからとりあえずサポート切ったわ!」っていきなりPR送るのは穏やかじゃないので、Ruby 2.2.2未満だったらCIでactivesupport 5系使わないようにしてCIを正常な状態に戻すのが平和
  • 実際にRuby 2.2.2未満のサポート切るかどうかはリポジトリオーナーの判断に委ねる

Tips:バージョンは文字列比較ではなく Gem::Version で比較した方がいい

"2.1.10" > "2.1.2"
#=> false

Gem::Version.create("2.1.10") > Gem::Version.create("2.1.2")
#=> true

"5.1.0" > "5.1.0.rc1"
#=> false

Gem::Version.create("5.1.0") > Gem::Version.create("5.1.0.rc1")
#=> true

5. Railsのrc出たからとりあえずビルドしようぜー!

https://github.com/mitaku/komachi_heartbeat/pull/22

f:id:sue445:20170420010531p:plain


.travis.ymlで複数gemfile対応してるのであればgemfile作って1行追加するだけ

gemfiles/rails5_1.gemfile

source "https://rubygems.org"

gem 'rails', "~> 5.1.0.rc1"

gemspec path: '../'

.travis.yml

gemfile:
  - gemfiles/rails4_1.gemfile
  - gemfiles/rails4_2.gemfile
  - gemfiles/rails5_0.gemfile
  - gemfiles/rails5_1.gemfile # <- 1行追加

正式版じゃないのでallow_failuresにしておいて、ビルドコケるのは許容する

matrix:
  allow_failures:
    # NOTE: There are unstable versions
    - rvm: ruby-head
    - gemfile: gemfiles/rails5_1.gemfile # TODO: Remove this after rails5.1 is released!

6. Travis CI対応してないリポジトリに .travis.yml 投げつける

f:id:sue445:20170420010539p:plain


Let’s contribute! :innocent:

備考

今回スライド作成に reveak-ck を使っていますが、reveal-ckはOGP対応していなかったのでOGP対応してプルリク投げています

github.com

発表に使ったスライドもプルリク投げたブランチでビルドしています

# frozen_string_literal: true
source "https://rubygems.org"

gem "rake"
# gem "reveal-ck"
gem "reveal-ck", github: "sue445/reveal-ck", branch: "meta_contents"

https://github.com/sue445/megurorb-02/blob/68f69bcd4de980969e9b0fa42fed9e6c262b8b69/Gemfile

OGP対応の結果はこちらになります sue445.github.io

2017/4/24追記

reveal-ckに僕のプルリクが取り込まれたやつが v3.6.0 としてリリースされています! https://github.com/jedcn/reveal-ck/blob/master/CHANGELOG.md#360–2017-04-23