rake taskで可変長引数を使う

rake taskで可変長引数を使う

約1年間Railsエンジニアやってて初めてrake task書いた。

その時のめも。

to_a メソッドを使う

namespace :test_task do
  desc '可変長引数を受け取るtask'
  task :hoge, ['huga'] => :environment do |_task, args|
    p args.to_a
    p args.huga
  end
end

実行する。

$ bundle exec rake test_task:hoge[1,2,3,4]
["1", "2", "3", "4"]
"1"

argsHashではなくRake::TaskArgumentsであり、Rake::TaskArgumentsインスタンスメソッドである to_aを使うことで引数の値をすべて取得する事ができる

  • リファレンス

http://www.rubydoc.info/gems/rake/12.0.0/Rake/TaskArguments#to_a-instance_method

Ruby勉強し直してみた 3

メソッドの可変長引数

Ruby勉強し直してて普段あんま使ったことないのでめも。

自分で定義するメソッドで可変長引数を使いたければ引数名の手前に*をつける

def メソッド名(引数1, 引数2, *可変長引数)
  # メソッド処理
end

みたいに。

def test(*name)
  name
end

test('tanaka', 'fuzita', 'yamada')
=> ['tanaka', 'fuzita', 'yamada']

可変長引数で渡された引数は配列になる

さっそく使ってみたい…!

Ruby勉強し直してみた 2

inject/reduce

たたみ込み演算なるもの… 例を見たほうが早い

numbers = [1, 2, 3, 4]
sum = numbers.inject(0) { |result, n| result + n }

ブロックの第一引数(result)には初回のみinjectメソッドの引数が入る。

2回目以降は前回のブロックの戻り値が入る。

繰り返し処理が最後まで終わると、ブロックの戻り値がinjectメソッドの戻り値になる。

チェリー本にて復習中だけども、以外と知らなかったことが多い…

Danger 導入した

機械的なレビューを自動で行ってくれるDangerというgemを最近導入したので、その時の

Dangerってそもそも何?

image.png

 

DangerのGithubには以下のことが書かれています

 Stop saying "you forgot to …" in code review

 Formalize your Pull Request etiquette.

  

「あなたは〜をやることを忘れているよ。」ということをやめる。

プルリクエストの礼儀作法を形式化

 

つまり

「プルリクエストの礼儀作法を形式化し、指摘を自動化する」ための便利なgemです

 

導入背景

チーム開発をしていると、そのチームごとにプルリクエストの書き方の決まりやルールなどができてくると思います。例えば

  • テストは必ず書きましょう
  • レビューしてもらいたい時はWIPを外しましょう
  • labelを必ずつけましょう
  • 変更が多い場合はプルリクエストを分けましょう

…などなど

もちろん自分のチームでも上記のようなルールがあったのですが、

  • テストを書いていなかったり
  • WIPつけっぱなしのままレビュー依頼出しちゃったり
  • labelつけ忘れてたり
  • 1つのプルリクエストでの変更が多すぎたり

…などなどが発生しており、そのようなプルリクエストが上がるたびに同じ指摘を繰り返していました。

しかし、上記で上げたような指摘って誰にでもできるものですよね? いちいち同じ指摘する工数工数なので自動化しよう!!というのがきっかけです

 

Danger導入

Circle CiでDangerを実行し、プルリクエストに自動でコメントします

 

Gemfileの設定

source "https://rubygems.org"
gem 'danger'

Gemfile編集後に'bundle install'コマンドを実行します

 

Dangerfile設定

'bundle exec danger init'コマンドを実行します

'danger init'を実行すると初期セットアップ実行され、'Dangerfile'が作成されます。

'Dangerfile'としてはクックパッド開発者ブログを参考に以下のように編集しました。

# ===== PR title =====
warn('PR is classed as Work in Progress') if github.pr_title.include? '[WIP]'

# ===== diff size =====
warn('PRの変更量が多すぎます。PRを分割しましょう!') if git.lines_of_code > 500

# ===== Test =====
raise('テストが書かれていません!') if `grep -r fdescribe specs/ `.length > 1
raise('テストが書かれていません!') if `grep -r fit specs/ `.length > 1
# ===== Label ====
labels = github.pr_labels
warn('labelを選択してください!') if labels.empty?

 

  • WIPがつけっぱなしのとき
  • プルリクエストの変更差分が多すぎるとき
  • テストが書かれていないとき
  • labelをつけていないとき

に自動でレビューを行ってくれる設定です。

 

'Dangerfile'を作成すると長文の説明文が流れてくるので、読みつつ、設定しつつenterで進めていきます

 

  • Step1

'Dangerfile'を作成しましたというメッセージ

 

  • Step2

bot用のGithubアカウントの作成を促されます。

'Danger'からプルリクエストに対してコメントの書き込みが行われるので、そのためのアカウントを作成しておくと良いです。

 

  • Step3

botアカウントでアクセストークンを作るように、と言われます。

リポジトリにアクセス可能なアカウントでAPI トークンを作成します。

個人のアカウントでも問題はないのですが、bot用のアカウントだと機械的に指摘されたコメントというように区別できてわかりやすいです

 

  • Step4

Ciの設定を行います。

詳しい案内はないのでGetting Set Upを参照します

Ciのsettingsで対象のリポジトリAPI permissionsにトークンを登録します。

 

'.circleci/config.yml'に以下のように追記します

- run:
name: Run Danger file
command: bundle exec danger --verbose

 

最後に!

Circle Ciでdangerを使う場合は 'Only Build pull requests'を有効にし、プルリクエスト作成時のスキップを回避してください

 

これで設定は終了です。

プルリクエストをWIPつけっぱなしで作成するとちゃんと指摘してくれてますね! image.png  

まとめ

このような感じで誰でもできるようなレビューはdangerにまかせて、本当にレビューする必要がある箇所に意識が集中できるようにどんどんしていきたいですね!

 

 

 

 

Rails ActiveRecord いろいろ

仕事柄プルリクをレビューすることが多々あるのですが、やっぱりまだまだわかっていないことが多い… 忘れないようにメモメモ…

inverse_of

inverse_of を指定したリレーションのある2つのモデルでは、双方から同一のインスタンスを参照することができる。 つまり、双方ともメモリ上では同じインスタンスとして扱われる。 inverse_of の設定がないと同一のインスタンスとしては扱われず、一方からの変更がもう一方から参照されても変更されていない ふむふむ…

class User < ActiveRecord::Base
  has_many :menus
end

class Menu < ActiveRecord::Base
  belongs_to :user
end
user = User.first
menu = user.menus.first
user.name == menu.user.name # => true
user.name = "change"
user.name == menu.user.name # => false

Userのフィールド name の変更が、Menu からたどった時に変更が参照されていない。メモリ上では別インスタンスとして扱われているからである。

inverse_of を指定してあげる

class User < ActiveRecord::Base
  has_many :menus, inverse_of: :user
end

class Menu < ActiveRecord::Base
  belongs_to :user, inverse_of: :menus
end

メモリ上では同一インスタンスとして扱われるようになるので、user もしくは user.menuから name を変更しても以下の結果になる

user.name == menu.user.name # => true

すげーな!

change_column_null

ActiveRecordでcolumnにNotNull成約をかけてしまったけども、後々になってやっぱり制約を外したい…なんてときに使います。

class ChangeColumnToUser < ActiveRecord::Migration[5.1]
  def change
    change_column_null :users, :name, true
  end
end
change_column_null table名, column名, true/false

Ruby勉強し直してみた 1

Railsエンジニアになってはや1年が経とうとしています。そんな中で最近思うのですが「Railsはわかってきたけれども、Rubyが全くわからない…」 これはやべぇと思い、ここで改めてRubyを勉強し直していきます その備忘録

Ruby演算子

ruby演算子には優先度があります

高い  !
    &&
    ||
    not
低い  and or

優先度があることにより、英語の論理演算子と記号の論理演算子を混在させてしまうと、求めたい結果が変わってしまうことがある

a = true
b = false
!a || b
not a || b

↓このように評価される

(!a) || b
not (a || b)

ふむふむ。 また記号の論理演算子と違い、英語の論理演算子同士の場合は優先順位の違いがない。 ()をつかわなければ左から右に順番に評価されていく

a = true
b = true
c = false

# && の方が || より優先順位が高い
a || (b && c)

# and or は優先順位が同じなので左から評価されていく
(a or b) and c

記号と英語の演算子で優先順位に違いがあるため and or を && || の代わりに使おうとすると期待と違う形になるやも

and や or は条件分岐で使うのではなく、制御フローを扱うのに向いている 例えば 「正常なuserであればメールを送信する」という制御フローを実行したければ

user.valid? and send_mail_to user

というように書くことができる

or も「Aが真か? 真でなければBせよ」という制御フローを実現することに向いている

# userが不正だったらエラーメッセージを返す
user.valid? or return 'userが不正です'

三項演算子

n = 11
if n > 10
  '10より大きい'
else
  '10以下'
end
=> "10より大きい"

こんな風にかける

n = 11
n > 10 ? '10より大きい' : '10以下'
=> "10より大きい"

シンプルなif/else文であればこの書き方のほうがスッキリと書くことができる

改めてRuby勉強するとおもしろい…!

Go langでFizzBuzz

田舎育ちのエンジニアです Go lang気になってたのでちょっと勉強始めてみました 備忘録です。

Go langとは

Go言語は2009年にGoogleによって作られたオープンソースの静的言語です。 特徴としては ・ シンプル

・ コンパイル・実行速度が早い。

・ 安全性が高い。

・ 同期処理が容易に行える。

などなど…

ちなみに調べる時は「Go」だけでなく「Go lang」、「Go言語」と検索したほうが良いです

FizzBuzz

プログラマーの人ならだいたい書いたことのあるFizzBuzzをGo langで書いていきます。

package main

import "fmt"

func main() {
    n := 0
    for {
        n++
        if n > 15 {
            break
        }
        switch n {
        case 15:
            fmt.Println("FizzBuzz")
        case 5, 10:
            fmt.Println("Buzz")
        case 3, 6, 9, 12:
            fmt.Println("Fizz")
        default:
            fmt.Println(n)
        }
    }
}

こんな感じで書くことができるのですが、Go langのcase文では値だけでなく式を指定することもできます 少し変更を加えると

package main

import "fmt"

func main() {
    n := 0
    for {
        n++
        if n > 15 {
            break
        }
        switch {
        case n%15 == 0:
            fmt.Println("FizzBuzz")
        case n%5 == 0:
            fmt.Println("Fizz")
        case n%3 == 0:
            fmt.Println("Buzz")
        default:
            fmt.Println(n)
        }
    }
}

うん。こっちの方がなんか良い!

まだGo langをはじめて数日ですが、おもしろいと感じています。

これからも雑でもアウトプットは出していきたい…