babel + remap-istanbul を使って、ES2015 のコードのカバレッジを計測する

表参道.rb #12【一周年】 で話したネタ。

全然アップデートできていない clairvoyance をちゃんと更新しようと、やる気を高める為に ES2015 で書けるように直した。

資料

やったこと

gulp + babel の環境構築

これは Web 上に資料がいくらでも転がっているので、楽。

clairvoyance
├ lib/
└ test/
  • gulp + babel の構築後
clairvoyance
  ├ lib/   # gulp build で src/lib から生成
  ├ test/  # gulp build で src/test から生成
  └ src/   # ES2015 のソースコード
    ├ lib/
    └ test/

こんな感じになるように環境作った。

ESLint (airbnb) の導入

ES2015 初心者なので、 ESLint を導入して、 airbnb の style に準拠して書くように設定した。
これも苦労せず、 web 上に資料がいくらでも転がっているので、普通に環境作れた。

あとは、 ESLint に指摘された箇所を 頑張って直す だけです。

カバレッジ計測

今まで使っていた istanbul だとカバレッジが計測できなくなったので、 remap-istanbul を使って直した。
これが一番苦労した。

# gulpfile.babel.js
gulp.task('build', ['clean'], () =>
  gulp.src('src/lib/**/*.js')
    .pipe(sourcemaps.init())
    .pipe(babel())
    .pipe(sourcemaps.write('../maps', {
        includeContent: false, sourceRoot: '../src/lib'
      }))
    .pipe(gulp.dest('lib'))
);

gulp.task('remap-istanbul', ['test'], () =>
  gulp.src('coverage/coverage-final.json')
    .pipe(remapIstanbul({
      basePath: 'maps/',
      reports: {
        json: 'coverage/coverage.json',
        html: 'coverage/lcov-report',
        lcovonly: 'coverage/lcov.info',
      },
    }))
);

こんな感じで設定したら動いた。 Current Directory がよく分からんけど、色んなパターンで設定を試したところ、これで動いた。

備考

ブログ書いていたときに見つけたけど、 babel 向けのカバレッジツールもあるみたい。

github.com

codecov とか使えるか検証してないけど、もしかしたら remap-istanbul を使うより楽かも。

最後に

あまり参考になりそうにないブログだけど、 babel + remap-istanbul を使う人の参考に何かなれば幸いです。
詳しく設定内容などを知りたい人は GitHubリポジトリを見てください。

github.com

Gemfile を指定して RSpec を実行する方法

毎回、忘れて困るのでメモ。

bundle install

$ bundle install --gemfile=gemfiles/rails_5.gemspec

BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle install でも動くっぽい。

bundle exec

$ BUNDLE_GEMFILE=gemfiles/rails_5.gemfile bundle exec rspec

参考

Bundler: The best way to manage a Ruby application's gems http://bundler.io/v1.3/bundle_config.html

try! Swift に参加しました

遅くなったけど、 3/2(水)〜4(金) で try! Swift という Swift のカンファレンスに参加していたので、感想とか書いてみました。

セッション

Swift 初心者から上級者まで参考になる話がいくつも発表されていました。*1

Swift 界隈のツールの話、 Swift コミュニティの話、iOS アプリ開発で使えそうなコード例などが紹介されていました。 また、「Sketchでアイコンを作る方法」や「デザイナーを巻き込む方法」など実践的な Tips の発表もありました。

同時通訳

英語のプレゼンには同時通訳があり、発表内容を日本語で聞くことができました。
また、登壇者に質問できるQ&Aルームでも同時通訳をして頂け、日本語の質問を英語に、英語の回答を日本語で聞くことができました。

無料コーヒー、軽食、ランチ

スタバのコーヒー、ジュースが継続的デプロイされていました。 あと、サラダラップなどの軽食、お弁当などもあり、飲食関連がかなり充実していました。

プロトコル指向

個人的に新しいパラダイムだと思って期待していたけど、try! Swift で話を聞いても結局よく分かりませんでした・・・ 誰かの発表で「具象型ではなく、プロトコルに依存させて・・・」みたいな例があったけど、すごいデジャヴを感じた。

あと、「プロトコル拡張で実装をプロトコルに持たせて Mixin する」とか Ruby で何年も前からあるし、いまいち良さが分からん。
ただ、さすがにそれだけで プロトコル指向 !!! とか名乗らないと思うので、他にもメリットあって自分が気付いてないだけだとは思うけど・・・

Swift らしさ

プロトコル指向はよく分からないけど、 try! Swift の話を聞いていると、下記要素を使うと Swift らしさが出そう。

  • struct を使う
  • 具象型じゃなくて protocol に依存させる
  • ジェネリクスを使う
  • enum を使う
  • パターンマッチを使う
  • Optional を使う

一通り基本的な使い方は覚えているけど、まだ慣れていないので、もっとコードを書いて自然に扱えるようになりたい。

英語

RubyKaigi のときも感じたけど、カンファレンスで英語できないエンジニアのコミュ力はゼロになりますね。
ただでさえコミュ力が少ないので、これ以上下がらないように英語は覚えておきたいと思いました。


今回は Swift 初心者だったので、次回の try! Swift 2017 までにレベル上げてから参加したいですね。
あと、英語力もあげたい。

*1:私は Swift 初心者なので、上級者の気持ちは推測です

プロトコル拡張で条件をつけたり、特定のプロトコル拡張のメソッドを呼ぶ方法

Swiftプロトコル拡張の動きが気になったので調べた結果を備忘録として残しておく。

プロトコル拡張で条件を定義

特定プロトコルの場合だけ挙動を変える。

protocol A {}
protocol B {}

extension A {
    func say() {
        print("A")
    }
}
extension A where Self : B {
    func say() {
        print("B")
    }
}

class User: A, B {}
class Author: A {}

User().say() // B
Author().say() // A

プロトコル、クラスのどちらが優先されるか?

クラスが優先された。

protocol A {}
protocol B {}

extension A {
    func say() {
        print("A")
    }
}
extension A where Self : B {
    func say() {
        print("B")
    }
}

extension A where Self : User {
    func say() {
        print("User")
    }
}

class User: A, B {}
class Author: A {}

User().say() // User
Author().say() // A

プロトコル拡張のメソッドを呼ぶ

プロトコルにキャストすれば呼べる。

protocol A {}
protocol B {}

extension A {
    func say() {
        print("A")
    }
}
extension A where Self : B {
    func say() {
        print("B")
    }
}

extension A where Self : User {
    func say() {
        print("User")
    }
}

class User: A, B {
    func say() {
        (self as A).say()
    }
}
class Author: A {}

User().say() // A
Author().say() // A

tachikoma の PR にバージョン比較URLを追加する TachikomaAI という gem を作った

アップデートされた gem の内容を確認するの面倒だったので、作った。

リポジトリ

sinsoku/tachikoma_ai

これは何?

定期的に bundle update してくれる sanemat/tachikoma にバージョン比較のコメントを追加する gem です。

インストール方法

  1. Gemfile に gem を追加する。
gem 'tachikoma_ai'
  1. bundle install する。
  2. Rakefile で読み込む。
require 'tachikoma_ai'

使い方

普通に tachikoma を使うと Pull Request のコメントが画像のように変わります。

f:id:sinsoku:20160229024048p:plain

時間があればやりたいこと

  • タグの最初に v がない場合(例: 1.0.0)の対応
  • リポジトリあるのに gemspec に書いていない場合の対応

Rails でパラメータを別モデルにして、バリデーションできるようにする

ブログをサボりすぎているので、備忘録でも書くようにしておく。

やったこと

ちょっと詳細書くのが難しいんだけど、処理自体を抽象化して扱おうとしたら、こうなった。

module Task
  class Base
    attr_reader :args

    def self.arguments(&block)
      klass = Class.new.include(ActiveModel::Model)
      klass.class_eval(&block)
      const_set :Arguments, klass
    end

    def initialize(attrs = {})
      @args = self.class.const_get(:Arguments).new(attrs)
    end

    def name
      self.class.name.demodulize.underscore
    end
  end
  
  class SlackPosting < Base
    arguments do
      attr_accessor :channel, :text
      validates :channel, presence: true
      validates :text, presence: true
    end

    def run
      return false unless args.valid?

      # Slack に投稿する処理
      # args.channel, args.text が使える
    end
  end
end

このクラスを使うのはこんな感じ。

task = Task::SlackPosting.new(channel: 'general', text: 'Hello')
task.run