2018年07月30日

勤怠時刻を Slack 投稿から出すやつ作った作業ログ

はじめに

作業ログなので無駄に長い。 その割に途中で飽きて雑になってる。

本文

勤怠管理で、開始時刻と終了時刻を正確に申告しろという指令が下った。 もちろん、不真面目な我々は毎日律儀にそんなものを記録しないし 月末にまとめて申請するので当然正確な時間なんてわからん。

だが我々は Slack を使っている。 つまり Slack の投稿時刻から大体の時間は割り出せるはずである。 というわけで作る。 類似品が世の中にありそうだがそんなのは無視。探しもしない。 何故なら作ることが目的だからだ。

欲しい機能
Required
  • CLI で動いてほしい
  • 日を指定できてほしい
  • 無指定の時は実行日を指定日として使ってほしい
  • 指定日の Slack 初投稿時刻を拾って来てほしい
  • 同様に最終投稿時刻も拾って来てほしい
  • 出力は、タブ区切りで 日付, 始業時刻, 終業時刻 を出力
Optional
  • 指定日って書いてるけど、0時区切りでなく、午前5時を区切りにしてほしい
今回はやらない
  • 区切り時刻を設定ファイルで指定できるようにする。正直個人用だと午前5時固定で十分
何で作るか

Go言語でやってみる。

  • ろくに使ったことないからたまには使ってみる。流行り言語だし
  • CLI 強そう

あたりが理由

作る前にちょっと環境構築
まずは実行環境
% which go
/Users/mugijiru/.anyenv/envs/goenv/shims/go

% go --version
goenv: go: command not found

The `go' command exists in these Go versions:
  1.9.2

なんということだ goenv で 1.9.2 は入ってるが PATH が通ってない。

% goenv global 1.9.2
% go --version
flag provided but not defined: -version
Go is a tool for managing Go source code.

Usage:

        go command [arguments]
(以下略)

怒られた。次が正しいみたい。 お前らは –version だったり -v だったり -version だったり忙しいな。

% go version
go version go1.9.2 darwin/amd64

よし動いている。 が、最新版じゃないはずだ。

というわけで公式サイトを見る https://golang.org/doc/devel/release.html

現時点では 1.10 が最新の模様

% goenv install -l
Available versions:
(略)
  1.9.0
  1.9.1
  1.9.2

なんてこった。やっぱり goenv が古いぞ。

% cd ~/.anyenv/envs/goenv
% git pull
remote: Counting objects: 93, done.
remote: Total 93 (delta 32), reused 32 (delta 32), pack-reused 61
Unpacking objects: 100% (93/93), done.
From https://github.com/syndbg/goenv
(略)
% goenv install -l
Available versions:
(略)
  1.10.0
  1.10beta2
  1.10rc1
  1.10rc2
  1.10.1
  1.10.2
  1.10.3

よし、1.10.3 がある。きっとこれが最新だろう。 というわけで入れる

% goenv install 1.10.3
Downloading go1.10.3.darwin-amd64.tar.gz...
-> https://dl.google.com/go/go1.10.3.darwin-amd64.tar.gz
Installing Go Darwin 64bit 1.10.3...
Installed Go Darwin 64bit 1.10.3 to /Users/mugijiru/.anyenv/envs/goenv/versions/1.10.3

% go version
go version go1.9.2 darwin/amd64

よし。完璧。

次に編集環境

実行環境を入れたので次は編集環境。 もちろん使うのは Emacs。 というわけで https://qiita.com/bussorenre/items/3e80e59d517db8aebf46 とかを参考にちょっと環境を整えてみる。

まずは何も考えずに便利そうな Go のツールを入れる

go get github.com/rogpeppe/godef
go get -u github.com/nsf/gocode
go get github.com/golang/lint/golint
go get github.com/kisielk/errcheck

そしてさっきのページに従いいくつか設定。

go/third-party/bin

PATH 通したりしているファイルでとりあえず PATH 通す

; goenv の Go を使うように
(setq exec-path (cons (expand-file-name "~/.anyenv/envs/goenv/shims") exec-path))

; go tools を使えるように
(setq exec-path (cons (expand-file-name "~/go/third-party/bin") exec-path))

ってそんなところにツールは入るのか。 バージョン変わった時つらそうだな。

el-get install go-mode
el-get install go-autocomplete

で、適当に設定

(with-eval-after-load 'go-mode
  (require 'go-autocomplete))

(defun my-go-mode-hook ()
  (auto-complete-mode)
  (flycheck-mode)
  (add-hook 'before-save-hook 'gofmt-before-save nil 'make-it-local)
  (local-set-key (kbd "M-.") 'godef-jump)
  (set (make-local-variable 'indent-tabs-mode) nil)
  (set (make-local-variable 'c-basic-offset) 4)
  (set (make-local-variable 'tab-width) 4))

(add-hook 'go-mode-hook 'my-go-mode-hook)

go-projectile とかも気になったけど 大きいプロジェクトにする気がないので放置。

開発開始

とりあえず適当にディレクトリを掘ってその中で開発する。

% mkdir ~/projects/private/worktime

で、コード書く時は https://qiita.com/tfmzbc/items/e2a3d7ce7ab8868e37f7 を見て なんとなく書いていく。 ダメだったらきっと gofmt とかが怒ってくれる

まずは Hello world 的なところ

とりあえず最終出力が

  • 出力は、タブ区切りで 日付, 始業時刻, 終業時刻 を出力

という感じなので、 まずは hello world 的に 今これを書いている日と定時で出力できるようにするか。

https://gobyexample.com/hello-world

とかによると import しないといけないみたい。 Java か貴様は。 最近の LL に慣れ親しんだ身としては Hello world だけで import が必要なのはだるいぞい。 とかブー垂れててもしょうがないのでとりあえずやる。

package main

import "fmt"

func main() {
  fmt.Println("2018/07/25\t10:00\t19:00")
}

とりあえずできた。 Println がますます Java みを感じさせる。 あと main 関数がある。Cっぽい。 っていうかこいつコンパイル言語だった。今の今まで忘れてた。 それはともかく実行

% go run worktime.go
2018/07/25      10:00   19:00

よし動いた。 (本当は動く版が出来るまで何度か怒られたのは隠しつつ)

次は日付を扱いたい

せめてさ、第一カラムはあれだよね。

  • 無指定の時は実行日を指定日として使ってほしい

のあたりで使うから 今日の日付を拾って来てから表示してほしいよね。

というわけで https://ashitani.jp/golangtips/tips_time.html#time_Format あたりを見て変更してみる

package main

import "fmt"
import "time"

func main() {
  t := time.Now()
  const format = "2006/01/02"
  fmt.Printf("%v\t10:00\t19:00\n", t.Format(format))
}
% go run worktime.go
2018/07/25      10:00   19:00
コマンドライン引数を取りたい

「日を指定できてほしい」

って言ってたよね。引数で指定したいよね。 適当にググると http://matope.hatenablog.com/entry/2014/03/09/115439 こんな記事とかがある というわけで参考に変更してみる

とりあえずヘルプ用の文言を突っ込む

よくわからん flag とかいうやつを import したらいいらしい。 あと、ヘルプ用文言とかを追加できるらしい。 というわけでひとまずそれだけ入れてみる

package main

import (
  "flag"
  "fmt"
  "os"
  "time"
)

func main() {
  // -hオプション用文言
  flag.Usage = func() {
   fmt.Fprintf(os.Stderr, `
Usage of %s:
   %s [date]\n`, os.Args[0], os.Args[0])
   flag.PrintDefaults()
  }

  flag.Parse()
  t := time.Now()
  const format = "2006/01/02"
  fmt.Printf("%v\t10:00\t19:00\n", t.Format(format))
}

実行してみると

% go run worktime.go -h

UUsage of /var/folders/hn/g_7n_91j7_gfglfcjyxd8r1c0000gn/T/go-build393189667/command-line-arguments/_obj/exe/worktime:
   /var/folders/hn/g_7n_91j7_gfglfcjyxd8r1c0000gn/T/go-build393189667/command-line-arguments/_obj/exe/worktime [date]\nexit status 2

なるほど適当にコンパイルされたのが var 以下に作られるのか go run は。

日付を入れたい

help 用の文言なんて正直どうでもいいんですよ。 日付を入れたいんですよ僕は。 というわけで入れられるようにしてみる。

package main

import (
  "flag"
  "fmt"
  "os"
  "time"
)

func main() {
  // -hオプション用文言
  flag.Usage = func() {
   fmt.Fprintf(os.Stderr, `
Usage of %s:
   %s [date]
`, os.Args[0], os.Args[0])
   flag.PrintDefaults()
  }

  flag.Parse()

  const format = "2006/01/02"
  t := time.Now()

  if flag.Arg(0) != "" {
   t, _ = time.Parse(format, flag.Arg(0))
  }

  fmt.Printf("%v\t10:00\t19:00\n", t.Format(format))
}

Go は最初の代入は := でその後は = なのか? よくわからんな。 とりあえずなんとか目的の感じになった。

ただ段々 main が長くなってきたので そのうちどうにかしないとね。そのうち。

Slack の自分投稿を取りたい

さて。そろそろ難しそうな話になってきたぞ。 Slack の投稿を取って来たいぞ。

それには多分 Slack に接続したりできる Go のパッケージか何かがあるはずだ。探そう というわけで雑にググって https://github.com/nlopes/slack を見つけた

というわけで

% go get -u github.com/nlopes/slack

ってあれ。これサンプル見ると TOKEN 必要じゃん いやまあそうだろうけど。

設定ファイルを用意するのだるいし環境変数から取れるようにしよう

https://api.slack.com/custom-integrations/legacy-tokens とりあえずここからレガシートークンを獲得。 自分用だしこれで十分だろ。

ってことで

% export SLACK_TOKEN='......'

みたいにして環境変数に設定完了。

環境変数に設定できたので それを Go から読めるように

slackToken := os.Getenv("SLACK_TOKEN")

とかしておくだけで良さそう。

slackToken := os.Getenv("SLACK_TOKEN")

if slackToken == "" {
 fmt.Fprintf(os.Stderr, "Slack token is empty\n")
 os.Exit(1)
}

とか書いてたら比較的それっぽいだろ。

で、どうも調べた結果、「日付」「投稿者」で検索して それの最初と最後を取るのが良さそう。

というわけで https://github.com/nlopes/slack/blob/master/search.go を眺めたりしていたら大体以下のようなので取れることがわかった。

api := slack.New(slackToken)
params := slack.SearchParameters{}
params.Count = 100
const format = "2006/01/02"
t := time.Now()
response, _ := api.SearchMessages("from:me on:"+t.Format(format), params)

ここまで辿り着くの、params が必須なのわからないで ??? ってなってたりの 初学者的な苦労があったけど、苦悩しすぎてて書き留めてない

とりあえず t には前の方でコマンドライン引数から日付を入れるコード用意したので 任意の日付の自分の発言は取って来れるようになってる

ここから response から最初と最後のデータを取って来て処理するわけだけど 最後のやつは、100件を超えるとページネーションが発生してつらそうなので一旦置いとく。

https://github.com/nlopes/slack/blob/347a74b1ea3055e8adcf17d2e14cbf3939238f6f/search.go#L54-L59 によると response の Matches に SortMessage が配列か何かで入ってるっぽい。

type SearchMessages struct {
  Matches    []SearchMessage `json:"matches"`
  Paging     `json:"paging"`
  Pagination `json:"pagination"`
  Total      int `json:"total"`
}

というわけでこう。

messages := response.Matches
最後の投稿を取る
messages := response.Matches
lastMessage := messages[0]

で、その日の最後の発言が取れる。 と思うじゃん? 今の今まで俺そう思ってたじゃん?

params.SortDirection = "timestamp"

じゃないと score 順になっててダメそう。というわけで追加しておいた。

そこから必要な情報を取得する

さて、ここで lastMessage を処理することを考える。

https://github.com/nlopes/slack/blob/347a74b1ea3055e8adcf17d2e14cbf3939238f6f/search.go#L39-L52

を見ると SearchMessage の構造は以下の感じなので、 lastMessage.Text で発言内容が取れるし、 lastMessage.Timestamp で投稿時刻が取れる。

type SearchMessage struct {
  Type        string       `json:"type"`
  Channel     CtxChannel   `json:"channel"`
  User        string       `json:"user"`
  Username    string       `json:"username"`
  Timestamp   string       `json:"ts"`
  Text        string       `json:"text"`
  Permalink   string       `json:"permalink"`
  Attachments []Attachment `json:"attachments"`
  Previous    CtxMessage   `json:"previous"`
  Previous2   CtxMessage   `json:"previous_2"`
  Next        CtxMessage   `json:"next"`
  Next2       CtxMessage   `json:"next_2"`
}

なんだけど lastMessage.Timestamp が地味にクセモノで `1532665939.000181` こんな感じの String が来る。 説明が見付からないが Unixtime に小数点以下までついてきている感じ。 正直小数点以下は要らないので、とりあえず分離して、 Unixtime を拾って来て Int 型にする

strings と strconv を import しておいて

components := strings.Split(lastMessage.Timestamp, ".")
intVal, _ := strconv.ParseInt(components[0], 10, 64)

なんだけど、正直

Unixtime, _ := strings.Split(lastMessage.Timestamp, ".")

とかできなくてハマってた。つらい。

そんでまあそれを Time 型に変換

lastTime := time.Unix(intVal, 0)

あとは適切なフォーマットを与えてあげて 出力したらとりあえず出て来る。

timeFormat := "15:04:05"
fmt.Println(lastTime.Format(timeFormat))

というわけで試行錯誤して、指定日の最後の投稿テキストと日時を取れるようにした。 途中途中色々ハマってて段々つらくなってきた。 Go が流行ってる理由がわからなくなってきた

途中経過
package main

import (
  "flag"
  "fmt"
  "github.com/nlopes/slack"
  "os"
  "strconv"
  "strings"
  "time"
)

func main() {
  slackToken := os.Getenv("SLACK_TOKEN")

  if slackToken == "" {
   fmt.Fprintf(os.Stderr, "Slack token is empty\n")
   os.Exit(1)
  }

  api := slack.New(slackToken)
  params := slack.SearchParameters{}
  params.Count = 100
  params.SortDirection = "timestamp"

  // -hオプション用文言
  flag.Usage = func() {
   fmt.Fprintf(os.Stderr, `
Usage of %s:
   %s [date]
`, os.Args[0], os.Args[0])
   flag.PrintDefaults()
  }

  flag.Parse()

  const format = "2006/01/02"
  t := time.Now()

  if flag.Arg(0) != "" {
   t, _ = time.Parse(format, flag.Arg(0))
  }

  response, _ := api.SearchMessages("from:me on:"+t.Format(format), params)
  messages := response.Matches

  lastMessage := messages[0]
  // lastMessage := messages[len(messages)-1]

  fmt.Println(lastMessage.Text)
  components := strings.Split(lastMessage.Timestamp, ".")
  intVal, _ := strconv.ParseInt(components[0], 10, 64)
  lastTime := time.Unix(intVal, 0)

  timeFormat := "15:04:05"
  fmt.Println(lastTime.Format(timeFormat))

  // for _, message := range messages.Matches {
  //    fmt.Println(message.Text)
  // }

  // fmt.Printf("%v\t%v\t%v\n", t.Format(format), firstTime.Format(timeFormat), lastTime.format(timeFormat))
}

あとなんだこのクッソ長い main 関数は。 ちょっと流石にどうにかしてくる。

関数分割の巻

とりあえず時間周りの変換はもう1回使うはずなので関数化。

func getTimeFromMessage(message slack.SearchMessage) time.Time {
  components := strings.Split(message.Timestamp, ".")
  Unixtime, _ := strconv.ParseInt(components[0], 10, 64)
  return time.Unix(Unixtime, 0)
}

これで

lastTime := getTimeFromMessage(lastMessage)

として取れる。

あとは検索部分もなんか邪魔だな。

func searchMessagesOnDate(api *slack.Client, date time.Time) *slack.SearchMessages {
  params := slack.SearchParameters{}
  params.Count = 100
  params.SortDirection = "timestamp"

  response, _ := api.SearchMessages("from:me on:"+date.Format(dateFormat), params)
  return response
}

ところで初期化部分もうざったくなってきたな。分離していこう

func initSlack() *slack.Client {
  slackToken := os.Getenv("SLACK_TOKEN")

  if slackToken == "" {
   fmt.Fprintf(os.Stderr, "Slack token is empty\n")
   os.Exit(1)
  }

  return slack.New(slackToken)
}

usage 用の文言部分も メインの処理からは切り離したいから

// -hオプション用文言
func usage() {
  fmt.Fprintf(os.Stderr, `
Usage of %s:
   %s [date]
`, os.Args[0], os.Args[0])
  flag.PrintDefaults()
}

それと引数から日付をパースしたりする処理も分離したい

func getTargetDate() time.Time {
  targetDate := time.Now()

  if flag.Arg(0) != "" {
   targetDate, _ = time.Parse(dateFormat, flag.Arg(0))
  }

  return targetDate
}

とかやってた。

あとはメインの部分をいじったりしている間に色々変わったけど忘れた。

とりあえず Slack のレスポンスは SortDirection が asc であろうと Matches の中身が降順で返って来るっぽい。

本当は time とかで sort するべきなんだろうけど とりあえず動くし飽きたからもうこれでいいやってなった。

まとめ

というわけで https://github.com/mugijiru/worktimer が出来た。

という、普段は Rails を書いているGo初学者処女作の作成ログでした。 普段使わない言語やるのしんど。

posted by 麦汁 at 00:28 | Comment(0) | Go言語 | このブログの読者になる | 更新情報をチェックする

2018年07月16日

PR 番号または URL から git checkout できるようにした

数日前に出した PR の作業に復帰する時とか 一通りコードレビューは済んだから動作確認したい時とかってありますよね。

そういう時、 PR のページを開いて そこから一番上にあるブランチ名をトリプルクリックで選択してコピーして〜とかよくやりますよね。 僕はよくやる。

よくやるから結構だるくなってきた。 なので git-pr-checkout を作った。

適当に PATH を通して、 対象のリポジトリの workspace 内で

$ git pr-checkout 123

とか

$ git pr-checkout https://github.com/${organization}/${repository}/pull/123

とかやると 該当する PR のブランチを checkout してくれる。 多分便利。(まだギョームで使ってないからわからんけど)


と思ったら hub コマンドで普通にできるじゃんね。 http://shoma2da.hatenablog.com/entry/2014/03/26/222802
タグ:git github Bash
posted by 麦汁 at 02:42 | Comment(0) | git | このブログの読者になる | 更新情報をチェックする

2018年07月15日

僕の最強 Emacs の Rails 開発環境が壊れてきたのでなんとかしてみた

3連休だし2年ぶりに Blog 記事書いてみる。 目的は単にやったことの記録を残すこと。

最近はエディタの設定を弄り倒す気力とかがなくて、 少々環境がブチ壊れても、基本的にそのままにしていた。 その結果、段々と Emacs での Rails 周りの環境がブチ壊れて来ている。

作業効率が低下しているはずなのでなんとかしようと思う

何が壊れてるか

  • flycheck でエラー吐かれる
  • projectile-rails が動いてない
  • auto-complete もぶっ壊れる

壊れてるのをひとまず直す

ruby-lint で怒られてるのをなんとかするの巻

とりあえず Ruby のファイルをいじって何かをしようとすると以下のように怒られが発生する。

Location: /Users/mugijiru/projects/dev/hoge/app/models/fuga.rb on line 16, column 18
Expected: 1
Received: 0
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:125:in `execute_callback'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:95:in `iterate'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/virtual_machine.rb:798:in `evaluate_node'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/virtual_machine.rb:486:in `on_class'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:125:in `execute_callback'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:86:in `block in iterate'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:85:in `catch'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:85:in `iterate'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:91:in `block in iterate'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:90:in `each'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/iterator.rb:90:in `iterate'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/virtual_machine.rb:195:in `block in run'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/virtual_machine.rb:195:in `each'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/virtual_machine.rb:195:in `run'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/runner.rb:125:in `run_vm'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/runner.rb:58:in `analyze_file'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/runner.rb:36:in `block in analyze'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/runner.rb:35:in `each'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/runner.rb:35:in `analyze'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/lib/ruby-lint/command.rb:51:in `run'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/bin/ruby-lint:88:in `block (2 levels) in <top (required)>'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/slop-3.6.0/lib/slop.rb:260:in `parse!'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/slop-3.6.0/lib/slop.rb:211:in `parse'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/ruby-lint-2.3.1/bin/ruby-lint:95:in `<top (required)>'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/bin/ruby-lint:23:in `load'
	from /Users/mugijiru/.anyenv/envs/rbenv/versions/2.5.1/bin/ruby-lint:23:in `<main>'

Try installing a more recent version of ruby-rubylint, and please open a bug report if the issue persists in the latest release.  Thanks!

最新版入れろよなって怒られてるけど、今入ってるのが最新版で その後は特にメンテされてないっぽい。つらい。 悲しいけど無効にする。

まずは Emacs の中で

(setq flycheck-disabled-checkers '(ruby-rubylint))

を突っ込んでおいて

$ gem uninstall ruby-lint

多分 uninstall だけでいいけど。 こいつの役割は rubocop か何かに任せよう。

projectile-rails が動いてない件

次は projectile-rails が動いてないのでファイル間移動がちょっとつらい問題。

M-x projectile-rails-mode

したら動くので、Rails プロジェクト内のファイルを開いた時には自動的に enable になってほしい。

と思って自分の設定を調べてたら単に

(projectile-rails-global-mode)

をコメントアウトしてた。というわけで有効にして解決。

auto-complete が動かなくなった
Making tags completion table for /Users/mugijiru/projects/dev/hoge/app/models/piyo.rb...
Error running timer ‘ac-update-greedy’: (user-error "File /Users/mugijiru/.rbenv/versions/2.1.5/lib/ruby/2.1.0/TAGS does not exist")

う……。いつの時代の設定だ……。 とりあえず .rbenv 内にある TAGS を見る設定を削除。 (っていうかそんなの生成してたんかな俺)

これでとりあえず auto-complete が動くようになった。あくまでとりあえずだけど。

動くようになったのでちょっと欲を出す

helm-for-files した時に helm-projectile の結果を優先的に出したい

helm-for-files 便利ですよね。C-; にキーバインドを当ててるので 基本的にファイルを開く時はそれで開いている。 で、それで projectile で拾えるリストが使えたら便利そうですよね。 というわけで

(setq helm-for-files-preferred-list
      '(helm-source-buffers-list
        helm-source-bookmarks
        helm-source-projectile-files-list
        helm-source-recentf
        helm-source-file-cache
        ))
helm で画像ファイルとかは無視したい問題

helm-for-files で Rails のファイルを検索できるようにしたものの 画像とか基本的に開かないので検索結果に出るとうざい。 あとついでに色々無視したい。

というわけで https://github.com/bbatsov/projectile/blob/master/doc/usage.md#ignoring-files に従い プロジェクト直下に .projectile というファイルを置いて

-/app/assets/images
-/tmp
-/log
-/public/uploads
~/node_modules

とか書いて解決。

最後に

もっと色々やりたかったけど Yak Shaving してしまったのでここまで……

タグ:Emacs ruby Rails
posted by 麦汁 at 23:57 | Comment(0) | emacs | このブログの読者になる | 更新情報をチェックする