RuboCop 入門 #omotesandorb

表参道.rb #19
https://omotesandorb.connpass.com/event/48967/

の発表資料。

---

## 自己紹介

名前: sinsoku
会社: 株式会社grooves
言語: Ruby
github: [sinsoku](https://github.com/sinsoku)
twitter: [@sinsoku_listy](https://twitter.com/sinsoku_listy)

---

https://jobs.forkwell.com/

![jobs.png](https://qiita-image-store.s3.amazonaws.com/0/30459/256462b2-6e92-721d-5dcb-f6deca2499cc.png)

---

https://github.com/grooves/forkwell_cop

<img width="897" alt="forkwell_cop.png" src="https://qiita-image-store.s3.amazonaws.com/0/30459/72843b73-d03b-c14b-7cbc-20c88f7ad8f1.png">

---

https://jobs.forkwell.com/about/scout

![Forkwell_Scout_001.jpg](https://qiita-image-store.s3.amazonaws.com/0/30459/63c6eff2-8dc9-5f43-5f0c-d660fc100d28.jpeg)

---

## 宣伝おわり

---

## RuboCop 入門

---

## RuboCop 入門

### :beginner: RuboCop のコードを読む
### :bug: 誤検知、エラーを直す
### :cop: 新しい Cop を提案する

---

# :beginner: RuboCop のコードを読む

---

## たった 2 コマンド！簡単！

```sh
$ git clone https://github.com/bbatsov/rubocop.git
$ cd rubocop
```

---

## ディレクトリ構成


```
lib/rubocop/
├  ast/
│  ├  node.rb
│  ├  traversal.rb
│  ├  ...
│
└  cop/
  ├  rails/
  │  ├  action_filter.rb
  │  ├  ...
  │
  ├  style/
  │  ├  access_modifier_indentation.rb
  │  ├  ...
```

---

## イベント

lib/rubocop/ast/traversal.rb に `on_xxx` が書かれている

- `on_const`
- `on_casgn`
- `on_class`
- `on_def`
- `on_send`
- ... etc

---

# :bug: 誤検知、エラーを直す

---

## 誤検知、エラー

- 新しい Cop はわりと :bug: がある
  - v0.44.0 Rails/HttpPositionalArguments
  - v0.46.0 Rails/EnumUniqueness
- ~~誤検知は英語だと **false positive** っぽい~~
  - 偽陽性 (検知してはいけないのに検知してしまう) 
  - 偽陰性 (検知しなければいけないのに検知していない) 

[onk](https://twitter.com/onk) さんにコメントで教えていただきました。ありがとうございます！

[![onk.png](https://qiita-image-store.s3.amazonaws.com/0/30459/2edf4872-4f6e-f0b2-787e-98dc3481ed17.png)](https://twitter.com/onk/status/827111026415931393)

---

## Enum はすぐ直されていた :-)

<img width="773" alt="enum.png" src="https://qiita-image-store.s3.amazonaws.com/0/30459/a2cf69de-4260-df0d-b0e0-14ec3192d61a.png">

---

## 既存 Cop の直し方

1. Issue/PullRequest を見る
1. 再現するテストを書く
1. 直して PullRequest 投げる

---

## 先日直した Rails/Date

**a** string without timezone

```rb
'2017-02-02 19:30:00'.to_time(:utc) # bad
'2017-02-02 19:30:00 +09:00'.to_time(:utc) # good
```

---

## テストコード

```rb
context 'when a string literal with timezone' do
  it 'does not register an offense' do
    inspect_source(cop, '"2016-07-12 14:36:31 +0100".to_time(:utc)')
    expect(cop.offenses).to be_empty
  end
end

context 'when a string literal without timezone' do
  it 'registers an offense' do
    inspect_source(cop, '"2016-07-12 14:36:31".to_time(:utc)')
    expect(cop.offenses.size).to eq(1)
  end
end
```

---

## 実装

```rb
def on_send(node)
  receiver, method_name = *node
  return unless receiver && bad_methods.include?(method_name)

  chain = extract_method_chain(node)
  return if safe_chain?(chain)

  return if method_name == :to_time && safe_to_time?(node)

  add_offense(node, :selector,
              format(MSG_SEND,
                     method_name))
end
```

---

## 実装

```rb
def safe_to_time?(node)
  receiver, _method_name, *args = *node
  if receiver.str_type?
    zone_regexp = /[+-][\d:]+\z/
    receiver.str_content.match(zone_regexp)
  else
    args.length == 1
  end
end
```

---

## 後はプルリクを **英語** で投げるだけ

---

## 英語力...(´・ω・)

<img width="685" alt="comment.png" src="https://qiita-image-store.s3.amazonaws.com/0/30459/e10b1aa7-d9f9-11fb-b8c9-9f94e24bc8e2.png">

---

## マージされた :tada:

<img width="783" alt="pullreq.png" src="https://qiita-image-store.s3.amazonaws.com/0/30459/826a761f-ccdb-432c-94be-21e8882463f4.png">

---

# :cop: 新しい Cop を提案する

---

## 経緯

<img width="768" alt="pr.png" src="https://qiita-image-store.s3.amazonaws.com/0/30459/292de364-00fb-f4d1-212e-54ed2a03ce8d.png">

---

## 気づけなかった...orz

---

## 自動化しよう(｀・ω・´)

---

## 新規 Cop の直し方

1. Issue/PullRequest を見る
1. テストを書く
1. 実装して PullRequest 投げる

---

## デモ

https://github.com/bbatsov/rubocop/pull/4003

---

# まとめ

---

## もっとレビューを楽にしよう！

[![matome.png](https://qiita-image-store.s3.amazonaws.com/0/30459/1f511646-1322-79fb-8a7c-fcfd2b3c5377.png)](https://twitter.com/sinsoku_listy/status/825719133857673216)

---

# ご清聴ありがとうございました！！