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

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

CSS のカバレッジを計測する Clairvoyance というツールを作りました

タイトルの通り、CSSカバレッジを計測するツールを作りました。

github.com

これは何?

css に書かれたスタイルが html の中でどのくらい使われているのか計測できるツールです。

  • 使用頻度の多いスタイルを調べる(影響範囲が大きいので気をつける)
  • 未使用のスタイルを調べる(消したい)

ってのを調べるために作りました。

なんて読むの?

Clairvoyance は「クレアボヤンス」と読みます。 千里眼 という意味です。

PhantomJS を使っているので、超常現象っぽい名前にしてみました。厨二病乙。

インストール方法

npm でインストールできます。

$ npm install clairvoyance

phantomjs を使っているので、もしかしたら phantomjs のインストールが別途必要かも。

使い方

インストールすると clairvoyance というコマンドが使えるようになるので、 css と html のパスを渡します。

$ clairvoyance --css path/app.css --html path/index.html

これで coverage/css-coverage.json が生成されます。

HTML レポート

Clairvoyance はカバレッジデータを JSON で出力しかできないので、HTMLで見るためには clairvoyance-html を使います。

まず、 npm でインストールします。

$ npm install clairvoyance-html

あとはオプションで HTML レポートを指定します。

$ clairvoyance --css path/app.css --html path/index.html --reporter clairvoyance-html

すると、こんな感じでレポートが生成されます。

f:id:sinsoku:20160131172955p:plain

ファイル名をクリックすると、ソースコードを表示できます。

f:id:sinsoku:20160131173013p:plain


まだ直したいところは色々とあるけど、ひとまず自分が欲しい機能はできたのでブログに書きました。

Ruby で SSH 鍵を生成する方法

Rails で Web 上から SSH 鍵を生成したくなったけど、方法がなかなか見つからなかったから書いておく。備忘録。

コード

Gemfile に gem 'net-ssh' を追加して、↓みたいなモデルを作ればうまくできた。

class SslKey < ActiveRecord::Base
  belongs_to :user

  validates :user_id, presence: true
  validates :title, presence: true, uniqueness: { scope: :user }
  validates :private_key, presence: true
  validates :public_key, presence: true

  before_validation :generate_keys

  private

  def generate_keys
    key = OpenSSL::PKey::RSA.new 4096
    self.private_key = key.to_pem
    data = [key.to_blob].pack('m0')
    self.public_key = "#{key.ssh_type} #{data}"
  end
end

参考ページ

stackoverflow.com

Swift 2.2 の機能: 0011_付属型を許容するため、 typealias キーワードを associatedtype に置き換える

2日前にマージされていたので、紹介します。

github.com

概要

typealias キーワードは今のところ2種類の型の宣言に使われています:

  1. タイプエイリアス (既存の型の別名)
  2. 付属型 (プロトコルの一部として使われる型のプレースホルダー)

これらの2つの宣言は異なり、個別のキーワードを使うべきです。これにより違いが明確になり、付属型の使用に関するいくつかの混乱を軽減するだろう。

提案された新しいキーワードは associatedtype です。

protocol Prot {
    associatedtype Container : SequenceType
}
extension Prot {
    typealias Element = Container.Generator.Element
}

付属型を使うのが分かりやすくなりそう。
Swift 初心者なので、詳しく分からないけど(汗

Swift 2.2 の機能: 0001_外部引数名として(大部分の)キーワードを許容する

Swift と英語の勉強の一環として、 apple/swift-evolution の 2.2 を少し読んでみた。

英語苦手なんで、時間がとてもかかるよ・・・。

翻訳したファイル(途中)

the "omit needless words" heuristics のあたりの訳がよく分からなかった。


これからもコツコツと読んで、Swift と英語力を上げていきたい。
あと、変な訳があったら GitHub で Issue や Pull Request を頂けると嬉しいです。