初めての人がなんとなく Go で CLI を作ってみた時のまとめ
イントロ
ちょっと昔に 「みんなのGo言語」が良かったので、自分のためだけのCLIツールを作ってみた - えいのうにっき を読んで、なんとなく何か作りたい気分になっていた。
Go 言語の知識が皆無の状態から 自作 CLI 作ったので、その時のメモをまとめてみました。
効率が良いとは思いませんが、こういう学習パスを通ればものは作れるぞ、という一例として参考になれば。
まず最初に読む
Go 言語で CLI 作るときの知見
「Go」 で「CLI」というと、過去に良い記事があったような記憶があったので、
探し出して、読み直してみた。
どちらもすごい良い記事で、更に気分が高まる。
package を探す
Go で CLI 支援パッケージ絶対あるやろ、と思ったらやっぱりあった。
めんどくさがりな自分でもできそうな気がしてきて、更に気分が高まる。
- mitchellh/cli: A Go library for implementing command-line interfaces.
- spf13/cobra: A Commander for modern Go CLI interactions
- urfave/cli: A simple, fast, and fun package for building command line apps in Go
- tcnksm/gcli: The easy way to build Golang command-line application.
- 旧名:
cli-init
- 旧名:
開発環境
作業ディレクトリ(Workspace って言うらしい)
Goコードの書き方 - The Go Programming Language GO:Workspace と GOPATH - Web系開発メモ
多くの Go言語プログラマは、1つの GOPATH(1つの Workspace)で、複数(or 全て)の ソース・パッケージ・リポジトリ・依存性を管理しているようです。
好きなディレクトリで作業できないのはちょっと意外。
回避方法はあると思うが、深くは追わず Go ってそういうものなんだ、で一旦飲み込んだ。
経験者の意見を伺いたいところ。
GitHub で公開することを想定すると、$GOPATH/src/github.com/{repo}
みたいなところで作業をすることになる。
Emacs
go-mode
+ go-autocomplete
を導入。
先人の知恵は素晴らしい。
学習
A Tour of Go
一通り流した。なんとなくイメージが見えてきた。
CLI 支援パッケージまわり
早速調べてあったパッケージを使い始める。
私が触ったのは以下の 2 つ。
spf13/cobra
urfave/cli
spf13/cobra
spf13/cobra: A Commander for modern Go CLI interactions
有名コマンドも採用実績があり、サブコマンドを作りやすいのが嬉しいところ。 gif 見ればなんとなく使い方がわかる、というところも良いと思った。
が、作っていくうちに「今回のやりたい内容を考えると、サブコマンド要らないのでは」と思い直し、方向転換した。 残念ながら軽く触る程度で終わってしまったが、次のチャンスがあればまた触ってみたい。
urfave/cli
urfave/cli: A simple, fast, and fun package for building command line apps in Go
cobra
を止めた後に選んだのはこちら。
star 数と README
のわかりやすさが決め手。
他のパッケージも眺めてみたが、大体これと似ていたので、どれでもいいなら star 数で選ぶというミーハーっぷりを発揮。
依存関係の解決
自分の GOPATH
には既に別のパッケージが散乱していて、汚れまくっていたので、ruby の bundler
的なやつが欲しかった。
そこで Big Sky :: golang オフィシャル謹製のパッケージ依存解決ツール「dep」 を発見。
なんとなくの気分で使ってみるが、まだ使いこなせていない。
まだ Go 言語に慣れてなくて、dep
の全体を把握するのが難しいのもある。
それと、この時に Go の依存関係解決についてよく理解していないことに気づき、以下の資料を見て学んだ。
それ以外の学習
後は思いついた疑問を赴くままにググりまった。効率が悪いがしょうがない。
以下はまだ読んでないけど、時間がある時にまとめて読みたい。
感想
- 恥ずかしながら型言語を触って何かを作ったのは初めての経験。
- 戻り値の型がわかるとコードが読みやすい。
- 書き方がオブジェクト指向っぽくはならず、右往左往している。
- すぐ panic になってしまう Go は、ちょっとかわいい。
- 配列やマップの扱いが難しかった。もっとこう… 何かあるだろ、と思う場面が多い。
- 慣れてないだけかも。
- こういう時、型が無い方がいいなーと思う。
- わかっていないことは非常に多い
- 結局は A Tour of Go を一通りやって、後は勢いで押し切っただけ
- そういう意味では「何でもいいから作りたいものがあるかどうか」が一番大事で、難しいのだよなーと思った
- 日頃の仕事を不便だと感じる気付きが重要となる
できあがったもの
完全に自分用ですが、terminal からコードレビューを依頼する CLI を作った。
仕事環境が変わり、レビュアーが曜日ごとに変わるようになってしまったので、レビュアーを自動特定できるようにした。
「今日は誰にレビュー依頼するのだっけ」「その管理シートどこにあるのだっけ」みたいなことをコードレビューのたびにやっていて、スーパー非効率だったのを改善できて良かった。
(レビュー体制をなんとかしたほうがよいのでは、という論点はあるのだが…)
mgi166/review-request: Request code review in terminal.
とはいえ、毎回固定のメッセージで依頼を投げてしまって bot っぽい。
バレないようにするためにも、ランダムでメッセージを変えるとか、人間っぽさを出していきたい。
terraform quick start 的なメモ
イントロ
terraform の初期化を行うのはプライベートでは二回目。
以前まとめていた自分用メモを、少し整形して公開してみる。
terraform はなんぞや、というところはすっ飛ばし、もう一度手元で terraform を使う環境を構築する人向けです。
内容は今更感がありまくりで、目新しいことは何もなし。
(なお、個人的な趣味により、provider は aws で、backend は s3 にしていますし、その前提で記事を書いています。)
terraform を始める
まず terraform init
コマンドを実行する。
実行するとカレントディレクトリに .terraform
というディレクトリが掘られていて、ここに terraform.tfstate
というファイルが作成される。
この terraform.tfstate
は terraform
が管理するリソースを json 形式で書いたもの。
commit するのは注意が必要。
Command: init - Terraform by HashiCorp
terraform init -backend=s3 \ -backend-config="bucket=terraform-bucket" \ -backend-config="region=ap-northeast-1" \ -backend-config="key=terraform.tfstate" \ -backend-config="profile=profile_name" .
terraform init コマンドの補足
backend とは
tfstate
置き場の事。
-backend=s3
は terraform.tfstate
の置き場所を s3 にする、という設定。
tfstate の管理について
terraform
はローカルにある terraform.tfstate
を元にコマンドが実行される。
したがって、複数人で開発する時、各個人のローカルで持っている terraform.tfstate
の状態に差があると、terraform
の実行結果に差が出てしまう。
ファイルの状態によっては、A さんは EC2 が作られていて、B さんは EC2 が作られていない、という矛盾した状況にもなり得る。こうなると、どちらが正しいかわからなくて困ってしまう。
現在実際に構成されている AWS のリソースが常に正であり、その状態は常に tfstate
は反映されてなければならない。
なので、複数人で開発する場合は、全員が最新の terraform.tfstate
を参照する必要がある。
State - Terraform by HashiCorp
tfstate を s3 で管理する意味
全員が最新の tfstate
を参照する方法の一つとして、s3 に terraform.tfstate
を置く、というやり方がある。
A さんが AWS の状態が更新したら terraform.tfstate
をローカルで上書きして、s3 に保存する。
B さんは s3 の terraform.tfstate
をローカルに反映させて、terraform.terraform
を実行する、というみたいな仕組み。(多分)
なお、terraform init
以外でも、terraform remote config
コマンドを実行することで
terraform.tfstate
を s3 で管理する指定ができる。
Remote State Backend: s3 - Terraform by HashiCorp
terraform remote config \ -backend=s3 \ -backend-config="bucket=terraform-bucket" \ -backend-config="key=terraform.tfstate" \ -backend-config="region=ap-northeast-1"
provider の設定
Provider: AWS - Terraform by HashiCorp
どちらかを選択する
access_key
,secret_key
セットする。profile
をセットする
access_key をセットする
provider "aws" { access_key = "${var.aws_access_key}" secret_key = "${var.aws_secret_key}" region = "us-east-1" }
access_key
or 環境変数AWS_ACCESS_KEY_ID
をセットするsecret_key
orAWS_SECRET_ACCESS_KEY
をセットするregion
orAWS_DEFAULT_REGION
をセットする
profile
をセットする
provider "aws" { region = "ap-northeast-1" profile = "profile名" }
最小限の構成
環境変数を適切にセットしている前提であれば
provider "aws" {}
に落ち着く。
これからどうするの?
後は普通にドキュメント見ながら resource を定義していくだけで OK。
aws の resource はこちらにまとめられている。
Provider: AWS - Terraform by HashiCorp
terraform import 手順
terraform には、現在 AWS に構築されている環境を terraform.tfstate
に落とし込む機能がある。
それを terraform import
と呼ぶらしい。
Import: Usage - Terraform by HashiCorp
terraform import resource名.名前 {id}
というコマンドを叩く。
resource 名は import 対象の resource。名前は terraform で管理したい名前。{id}
は resource によって異なる。
{id}
は勘でなんとかなる気がします。
例えば aws_route53_zone
という resource の場合は、以下のコマンドで import できた。
terraform import -backup=backup aws_route53_zone.mgi166 {zone_id}
このコマンドで何が起こるかというと、ローカルの terraform.tfstate
に、aws_route53 の設定内容が反映される。
後は、自前で resource を定義しながら、terraform plan
との差分が無くなるまで、 tf
ファイルを試行錯誤すれば良い。
というのも、差分が無くなるということは、import コマンドを叩いた後の terraform.tfstate
と、tf
ファイルに書いたコードの内容が同じであることを意味するからです。
しかし、terraform import
は完全ではないようで、差分をなくすのは難しい場合がある。
具体的には一部の属性が変わったりしてしまう。
私はどうしようもないと諦めてしまったけど、このあたりの良い解決方法があれば教えていただきたいです。
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_route53_zone.mgi166: Refreshing state... (ID: xxxx) aws_route53_record.www: Refreshing state... (ID: xxxxx CNAME) The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read. Note: You didn't specify an "-out" parameter to save this plan, so when "apply" is called, Terraform can't guarantee this is what will execute. # force_destroy が `""` だったのが、"false" になっている ~ aws_route53_zone.mgi166 comment: "HostedZone created by Route53 Registrar" => "Managed by Terraform" force_destroy: "" => "false"
まとめ
terraform init
orterraform remote config
で backend の設定を作る- 必要に応じて
terraform import
で既存のリソースを import する - 後は document を読んで頑張る
参考
- Amazon S3 で Terraform の状態管理ファイル terraform.tfstate を管理 / 共有する - Qiita
- Terraformを割と安全に使う方法 - tehepero note(・ω<)
- terraform 独りハンズオン(3)〜 tfstate ファイルを S3 で管理する 〜 - ようへいの日々精進XP
- dtan4/terraforming: Export existing AWS resources to Terraform style (tf, tfstate)
- 使ったことはないけど、
terraform import
以外にも似たようなことができる gem があるっぽい。
- 使ったことはないけど、
ローカル環境構築を MItamae で自動化した話
イントロ
お仕事用 Mac が Mac book pro に変わってしまった。
環境構築をやるのも久々だったのだけれども、dotfiles のボリュームが増えたのと、実はコード化出来ていない部分が多かったりして、かなり面倒だった。
ちゃんともう一度やり直そう、と思って選んだのが MItamae
ansible
は活用例が多いっぽいけど、yaml
だと表現力が気になる(食わず嫌い)Itamae
は良さそうだけど、gem をインストールすることで、環境汚すのはちょっと嫌だ。ruby に依存するし。- となると
chef
も同様 puppet
は思った以上にデカかったboxen
はへんじをしない。ただのしかばねのようだgo
で環境構築したら、Mac 以外の環境構築も楽になるのでは説を思いつくitamae-go
を発見- そういえば
mruby
のItamae
ってなかったっけ - Itamaeのmruby実装「MItamae」が大体いい感じになった話 - k0kubun’s blog を発見
MItamae
にしてみるか
みたいな流れで行き着きました。
今まではどうしていたか
rake
で色々やってた。
自前で rake task を定義していて、rake コマンド叩くことで各種 dotfile
の配置が完了する。
shell よりは書きやすいと思ったのと、ruby の勉強のために rake を使っていた、という経緯がある。
実際にやってみてどうだったか
mruby がほんの僅かに理解できた
結論から言うと MItamae
を使うだけなら、mruby の学習自体は殆ど要らなかった。
ただし mruby
でいう gem の取扱いは、CRuby と全然違うので、ここを知らないと大分混乱する。
mruby と mgem と rbenv と - Qiita
MItamae の install は簡単
Mitamae のバイナリが github で配布されているので、curl でダウンロードでおk。
ここが mruby のすごいところで、CRuby とは違う点。
今までは gem を install する時には、ruby を入れて、gem install
コマンドを実行していたけど、mruby の gem は、gem 自体それぞれ binary になっているようだ。
(正しい表現かはわからない)
ディレクトリ構成は chef っぽく落ち着く
シンプルな Chef なので、書き方は自由。
だが、試行錯誤していくうちに、結局 Chef みたいな構成に落ち着いていった。
Itamae
のwiki にも(Chef みたいな構成とは書いてないが)ベストプラクティスが載っている。
Best Practice · itamae-kitchen/itamae Wiki
レシピの実行順序は ruby で担保する
chef で言う run_list
的なやつは MItamae
には存在しないっぽい。
どうやるのが良いかわかってないが、今のところ mitamae local xxx.rb
コマンドで渡す ruby のコードの中で、include_recipe
を順番に並べて管理している。
MItamae で使っている gem を見る
mitamae の DSL の中で、どの程度自由にやれるのかというと、以下のファイルを見れば良いっぽい。
mitamae/mrbgem.rake at master · k0kubun/mitamae
add_dependency
に追加されている gem は使える。
DSL の中からやりたいこと、という意味では大体揃っている。
結果
dotfile
がすごいすっきりした。嬉しい。
.emacs.d
とか .bundle
等の実体は cookbooks
の中に押し込んでいる。
おわり
k0kubun/dotfiles: Configuration management of development environment がよく出来すぎていて、大体まねっこになってしまった。
MItamae
も mruby
もすごい便利です。
参考
esa.io クライアントを kotori から Quail に乗り換えた
イントロ
職業柄、自分のフィーリングとマッチしているというのもあるのだと思うけど、esa.io を一年運用していて全く困らないし、本当に助かってる。
しかし一点だけ、esa.io
というより、OSX の esa.io
クライアントに不満があった。
それは kotori というクライアントを使っていたのだけど、「リンクをクリックするとクライアント内で画面遷移し、二度と戻れない」という凶悪な仕様だ。
kotori
で書いた記事の中でリンクをクリックするの図はこちらです。
これが超辛い。
esa.io
では Qiita みたいなリアルタイムプレビュー機能がついていて、右側で markdown の変換結果が見れる。
ところが記事書いている途中にうっかりリンクをクリックしたらもうゲームオーバーで、編集画面には二度と戻れない。
じゃあどうするかというと kotori
を強制終了してやり直すしかない。
長文を途中保存していないと全て消えてしまう。これで何回か枕を濡らした。
今までの暫定策
とはいえ、それ以外の kotori
に不満は一切なくて、運用でカバーしてた。
⌘ + S
をなるべく頻繁にタイプする- このショートカットで一次保存できる(素晴らしい)
- スクロールする時、リンクのそばにカーソルを動かさない
とか。
kotori
先輩に鍛えられたおかげで、「これは危ない」という操作が直感でわかるようになってきて、かなり誤操作は少なくなったきた。
半分あきらめてたけど、最近知ったこと
help/サードパーティーesaツール - docs.esa.io を今更見つけて読んだ。
そこで 1000ch/quail というアプリがあるようなので、試してみたのがきっかけ。
インストール方法
1000ch/quail に書いてあるとおり。 zip 落として Applications にコピーするだけ。
electron
製ですね。
使ってみた感想
リンクをクリックすると、ブラウザで開いてくれる。
涙が出るほど嬉しい。初めて触った時嬉しくて声が出ました。
正直 kotori
のほうが軽い気がするし、画面遷移も早い。
それに Quail
でボタンを押した時に一瞬白くなるのは気になる。
けど、この機能には代え難い。
終わりに
私しかこの件で枕を濡らしてないのかもしれないけど、長年辛かったことが解決した事が本当に嬉しいので、記録しておく。
昔は kotori
しか存在しなかった気がしたけど、今は iOS 版もあるみたいだし、みんな徐々に esa.io
の良さに気づき始めているのでしょうか。
インターネットのすみっこから応援しています。
しかし、Quail
になった今でも、リンクをクリックするのはドキドキするという。。
serverless + webpack + babel で AWS Lambda をナウく書く
イントロ
最近 AWS Lamdba を仕事で触っています。
serverless やら Apex なり色々あるわけですが、沢山ありすぎてよくわかりません。
今までは Apex
の手軽さに甘えていましたが、そろそろ serverless
が本気を出してきたという噂を聞き、serverless
を使い始めています。
どうせ serverless
を使うなら、もう全部使い倒してやろうということで、babel
も意識高く使っていきたいわけです。
この記事では serverless
+ babel
を使うところまでをまとめました。
環境
serverless@1.1.0
serverless-webpack@1.0.0-rc.2
webpack@1.13.3
serverless
まずは雛形作成
# template 指定は必須 # `sls` は `serverless` コマンドの alias $ sls create -t aws-nodejs
serverless.yml
というファイルが設定ファイル。
これを早速いじっていく。コメントや公式のドキュメントがわかりやすい。
# serverless.yml を編集していく $ emacs serverless.yml $ git diff serverless.yml provider: name: aws runtime: nodejs4.3 + region: ${env:AWS_REGION} functions: - hello: - handler: handler.hello + imageResizer: + handler: index.handle
# service の deploy $ sls deploy # AWS Lambda 関数の deploy $ sls deploy function -f imageResizer # AWS Lambda 関数の実行 $ sls invoke -f imageResizer # Log の tail $ sls logs -f imageResizer -t
まず最初に sls deploy
で Service の deploy を行う。
この Service というのは serverless
用語の一つで、AWS Lambda を実行するための AWS インフラ全体を指す名称。
この Service を管理するために serverless
は CloudFormation を暗黙的に使用している。
うっかり region 指定を忘れると、sls deploy
を実行した時、serverless デフォルトの region である us-east-1
に、 CloudFormation の Stack が出来上がってしまうので要注意。
region はコマンドラインの option で渡すか serverless.yml
の provider
で指定する。
serverless-webpack
serverless を使って deploy はできるようになった。後は書いたコードを babel を使っていく。
serverless-webpack
プラグインがあって、これを使えば OK。
elastic-coders/serverless-webpack: Serverless plugin to bundle your lambdas with Webpack
外部の npm パッケージを使う場合
serverless-webpack
を使用している場合、任意の package を handler の中で require しようとすると、 webpack コマンドで失敗してしまう。
$ git diff --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ 'use strict'; +import gm from 'gm'; # sls コマンドは serverless コマンドの alias $ sls webpack —out .webpack ... ERROR in ./~/thread-sleep/~/node-pre-gyp/package.json Module parse failed: /Users/argerich/dev/serverless-image-resizer/node_modules/thread-sleep/node_modules/node-pre-gyp/package.json Unexpected token (2:8) You may need an appropriate loader to handle this file type. SyntaxError: Unexpected token (2:8) at Parser.pp$4.raise (/Users/argerich/dev/serverless-image-resizer/node_modules/acorn/dist/acorn.js:2221:15) …
この場合、webpack-node-externals
を使って、設定ファイルを調整する必要がある。
具体的には以下のような修正をする。
# webpack.config.js +const nodeExternals = require('webpack-node-externals'); + module.exports = { entry: './index.js', target: 'node', @@ -5,5 +7,6 @@ module.exports = { libraryTarget: 'commonjs', path: '.webpack', filename: 'index.js' - } + }, + externals: [nodeExternals()] };
# serverless.yml custom: webpack: webpack.config.js + webpackIncludeModules: true
webpack
を通した deploy は serverless deploy function -f
では行われない。
serverless deploy
で行う。
$ sls deploy Serverless: Deprecation Notice: Starting with the next update, we will drop support for Lambda to implicitly create LogGroups. Please remove your log groups and set "provider.cfLogs: true", for CloudFormation to explicitly create them for you. Serverless: Bundling with Webpack... Time: 578ms Asset Size Chunks Chunk Names index.js 2.17 kB 0 [emitted] main Serverless: Packing external modules: babel-polyfill@^6.16.0, gm@^1.23.0 Serverless: Packaging service… Serverless: Uploading CloudFormation file to S3… Serverless: Uploading service .zip file to S3… Serverless: Updating Stack… Serverless: Checking Stack update progress… ..... Serverless: Stack update finished… Serverless: Removing old service versions… Service Information service: serverless-image-resizer stage: dev region: ap-northeast-1 api keys: None endpoints: None functions: serverless-image-resizer-dev-imageResizer: arn:aws:lambda:ap-northeast-1:xxxxxx:function:serverless-image-resizer-dev-imageResizer ✨ Done in 27.52s.
まとめ
region
のデフォルトはus-east-1
なので、指定を忘れないこと。serverless.yml
に region を書いておく(ドキュメントの隅っこ にサラッと書いてある)
serverless-webpack
で外部 package 使う場合は、webpack-node-externals
を使う- deploy は
serverless deploy function
ではなく、serverless deploy
を使う
という話でした。
Apex と Serverless 両方使ってみての感想
個人的には Apex
のほうが学習コスト少なくて、機能もシンプルなので好き。
Serverless
はもれなく CloudFormation が付いてきて、管理運用の面で色々思うところがある。AWS Lamda だけ触りたいんや! と思ってる人にとって、いきなり CloudFormation が出てくるとびっくりする。
けどその分 serverless
は設定ファイルを柔軟に書けるし、プラグインは充実している。Apex
で微妙だと思った環境変数周りを、うまくカバーしているところは好印象。
一方で Apex
でしか出来ないことは Terraform
との連携だけ。この機能にどれだけ期待するかが、一つの採用基準でもあると思う。
しかし、ただ単に AWS Lambda を使いたい、というだけであれば Apex
で十分だし、落とし穴は少ない。
Apex
で不満に思うことが増えてきたら serverless
を検討する、で良いのかな。
と、当たり前の結論に至りました。
参考になる
- pierresaux/serverless-boilerplate: Serverless boilerplate with webpack
- serverless-webpack/examples at master · elastic-coders/serverless-webpack
おまけ
$ sls webpack —out .
とやると、現在のディレクトリが全て消されて途方にくれるので、 良い子のみんなは絶対に真似をしないでください
ファイル名で使えない文字
イントロ
web アプリケーションで、ユーザーにファイルをダウンロードさせる機能を追加したいとする。
例えばダウンロードさせるファイルの名前をアプリ側で自動決定する場合、その名前にはどのような制限があるのだろうか。
何回か調べてる気がするので、まとめてみる。
前提
そもそも、ファイル名の制限は、OS ではなく、基本的にはファイルシステムで決まる。
ファイルシステム上の限界
ファイルシステムの限界はどこまでなのかというと Comparison of file systems - Wikipedia, the free encyclopedia にまとめられている。
古いファイルシステムでは、ファイル名は 8 文字、拡張子が 3 文字、ドットも含めて合計 12 文字までしかダメ、という時代もあったらしい。8.3形式
と呼ばれているのがそれだ。
有名どころのファイルシステム(NTFS
, FAT系
, ext4
, xfs
)では
という仕様が多いようだ。
Windows で禁止されている予約語
ただし Windows は例外がある。
ファイルシステムだけでなく、OS レベルで予約されている文字があり、これらはファイル名として使えない。
Naming Files, Paths, and Namespaces (Windows) によると、以下の文字が予約されている。
< (less than) > (greater than) : (colon) " (double quote) / (forward slash) \ (backslash) | (vertical bar or pipe) ? (question mark) * (asterisk)
手元に win 機が無かったので、残念ながら検証はしていない。
本当にダメなのか試してみたい。
結論
対応するファイルシステムのカバー範囲により、ファイル名に使える文字は異なる。
だが、現実的な落とし所として
- windows を視野にいれるのであれば、windows で禁止されている予約語は使わないほうが良いと思う。
- 予約語 is
< > : " / \ | ? *
- 予約語 is
- NULL文字も使えないファイルシステムが多いため、止めたほうが無難。
- 長過ぎるファイル名は NG なので、そのあたりも調整する。
- マルチバイト文字のときが面倒くさいが、より小さい方に合わせ
255 byte まで
のほうががいいのかな。
- マルチバイト文字のときが面倒くさいが、より小さい方に合わせ
ぐらいを考えておけば良さそうだろうか。
おまけ
https://en.wikipedia.org/wiki/Comparison_of_file_systems によると、制限は以下の通り
File system | Maximum filename length | Allowable characters in directory entries | Maximum pathname length | Maximum file size | Maximum volume size |
---|---|---|---|---|---|
HFS Plus | 255 UTF-16 characters | Any valid Unicode | Unlimited | slightly less than 8 EiB | slightly less than 8 EiB |
# 制御文字のファイル名は作れる `touch "\a"` => "" # null 文字はダメだった `touch "\x0"` # ArgumentError: string contains null byte # from (irb):1:in ``' # from (irb):1 # from /Users/argerich/.rbenv/versions/2.3.0/bin/irb:11:in `<main>' # 256 byte は長すぎる `touch #{"a" * 256}` touch: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: File name too long # 255 byte なら OK `touch #{"a" * 255}` => "" # 日本語で 255 文字はアウト `touch #{"あ" * 255}` touch: あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ: File name too long >> "あ".bytesize => 3 # 3 * 85 = 255 なので、85 文字まで OK >> `touch #{"あ" * 85}` => "" # 86 文字目からアウト >> `touch #{"あ" * 85 + "a"}` touch: あああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああa: File name too long # UTF-16 が OK ならば、絵文字でもいけるはず。 `touch #{"\u{26C4}" * 85}` => ""
絵文字ファイル名で作れているっぽい。ls
すると ?
になるけど。
それにしてもWikipedia 先生。ファイル名の長さ、255 byte までなのでは?
Any valid Unicode
の中に null 文字は入ってないのかな?
一部の文字は互換性維持のため、OS の API で制御しているとの噂もあるけど… うーむ。
情報が少なすぎて、これ以上調べるのは難しそうだった。一次情報どこにあるの。
試してみたものの、Wikipedia を引用してまとめたので、すごい微妙になってきた…
この記事は用法用量を守って、正しくお使いください。
参考
AppStore でアプリのアップデートができなくなった件
イントロ
「この製品のディストリビューションファイルを検証できませんでした。
破損しているか、署名されていない可能性があります」
と出て、update できない。
状況
- 上記のようなメッセージが出て、更新通知があるアプリを更新できない
- 何故か更新できるアプリもある
- キャッシュを消しても出る
- 試したのは
% sudo rm -rf ~/Library/Caches/* /Library/Caches/*
- 乱暴なので、良い子は真似しないように。
- 試したのは
/var/log/system.log
に以下のようなメッセージが出力される-
Assertion failure in -[CheckPreflightOperation verifyDistributionAtURL:allowsDevSign:allowsUnsigned:osVersionToBeInstalled:error:distributionController
-
# /var/log/system.log Sep 2 11:54:11 --- last message repeated 1 time --- Sep 2 11:54:11 argerich-no-Mac-mini iTerm2[348]: Time to encode state for window <PseudoTerminal: 0x7f8544b54630 tabs=1 window=<PTYWindow: 0x7f8542d2b920 frame=NSRect: {{0, 74}, {1918, 972}} title=1. Horowitz (tmux) alpha=1.000000 isMain=0 isKey=0 isVisible=1 delegate=0x7f8544b54630>>: 0.003149032592773438 Sep 2 11:54:15 argerich-no-Mac-mini storedownloadd[583]: *** Assertion failure in -[CheckPreflightOperation verifyDistributionAtURL:allowsDevSign:allowsUnsigned:osVersionToBeInstalled:error:distributionController:], /Library/Caches/com.apple.xbs/Sources/Commerce/Commerce-463.9/CommerceKit/CheckPreflightOperation.m:291 Sep 2 11:54:23 argerich-no-Mac-mini iTerm2[348]: Time to encode state for window <PseudoTerminal: 0x7f8544b54630 tabs=1 window=<PTYWindow: 0x7f8542d2b920 frame=NSRect: {{0, 74}, {1918, 972}} title=1. Horowitz (tmux) alpha=1.000000 isMain=0 isKey=0 isVisible=1 delegate=0x7f8544b54630>>: 0.004208028316497803 Sep 2 11:54:27 argerich-no-Mac-mini iTerm2[348]: Time to encode state for window <PseudoTerminal: 0x7f8544b54630 tabs=1 window=<PTYWindow: 0x7f8542d2b920 frame=NSRect: {{0, 74}, {1918, 972}} title=1. Horowitz (tmux) alpha=1.000000 isMain=0 isKey=0 isVisible=1 delegate=0x7f8544b54630>>: 0.004567980766296387
解消法
ゲストユーザーでログインし、アップデートしたら成功。
恒久対応ではない気がする。
Java 歴 23 分の Ruby エンジニアが Effective Java を読んで感動した話
イントロ
例外処理を書くことはよくやっているのだけれど、その時の主軸となる考え方について、今までなんとなくで行っていた部分が多かった。
毎回考えるポイントは例えば以下のような疑問。
- どこのレイヤーで、どこまで例外処理を行えばよいのだろうか?
- どの例外をキャッチし、どの例外を伝搬させればよいだろうか?
- 前提条件をチェックし、失敗した場合、例外を出したほうがよいか、
nil
,false
を返すほうがよいか? - 例外をどういう単位でラップさせるのが良いだろうか?
- 例外をチェインし過ぎると却って煩雑になる気がする。どうすれば良いのだろうか。
しかし、この辺りの話って、API の設計だったり、仕様の影響もあるので、都度対応が異なってしまうもの。
したがって抽象化して理解することが難しく感じた。
とてもよく使ってるし、とても大事な事なことなのに。
そんな今更な事で悩んでいた時に、Effective Java
という良い本を紹介してもらったので、例外処理の章を読んでまとめてみました。
(5 章まで読んで力尽きていたが、勇気を振り絞り、また読み進めてみた)
EFFECTIVE JAVA 第2版 (The Java Series)
- 作者: Joshua Bloch,柴田芳樹
- 出版社/メーカー: 丸善出版
- 発売日: 2014/03/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (10件) を見る
- イントロ
- 読書メモ
- 感想
- 2017/11/22 追記
読書メモ
項目.57 例外状態の時だけ例外にする
// 行ってはならない try { int i = 0; while(true) range[i++].climb(); } catch(ArrayIndexOutOfBoundsException e) { }
- 例外に基づくイディオムはパフォーマンスが悪い
- そのため、例外の目的がわからない場合は使ってはいけない
- 例外は例外的条件の時のみに使用する。通常の制御フローに対しては使ってはいけない
- コードの保守性を落とすだけでなく、パフォーマンスも悪くなるので
- 通常の制御に例外を使用することをクライアントに強制してはならない
- 例えば、予測不能な状態でのみ呼び出されるメソッドは「状態依存 」である
- e.g)
Iterator#next()
- e.g)
- 一般には状態を判別する状態検査メソッドを持つべき
- e.g)
Itereator#hasNext()
- e.g)
- 状態検査メソッドが呼ばれること無く、状態依存のメソッドが呼ばれた場合は、そうとわかるような特別な値を返す
- 例えば、予測不能な状態でのみ呼び出されるメソッドは「状態依存 」である
状態検査メソッドを使うか、区別できる戻り値を使うか
区別できる戻り値を使う場合
以下の条件を満たすとき。
- 並行してアクセスされる場合
- 外部要因で状態遷移する場合
状態検査メソッドと、その変更メソッドを呼び出す間に、状態が変更になる場合があるから。
状態検査メソッドを使う場合
上記以外のとき。
- 若干読みやすい
- 状態検査メソッドを呼び出すことを忘れると、例外が投げられるため、バグに気づきやすい。
から。
項目.58 回復可能な状態にはチェックされる例外を、プログラミングエラーには実行時例外を使用する
チェックされる例外(checked exception)
- 回復可能な状態であるときに発生する例外
- 回復に役立つ情報を提供するメソッドを持つと良い
実行時例外(runtime exception)
- 回復可能でない状態である場合に発生する例外 = チェックされない例外
- 実行を続けても役にたたない、むしろ害になるような場合に発生する例外
RuntimeException
をサブクラス化する
- 「回復可能かそうでないか」を判別できない場合も「実行時例外」として扱うべき
エラー(error)
- 基本的には使わない
- API のユーザーの混乱を招くだけだから
- 得られるものは殆ど無いから
項目.59 チェックされる例外を不必要に使用するのを避ける
チェックされる例外は、API の使用者に例外処理を強制させ、信頼性を上げる
しかし、チェックされる例外を過剰に増やすと逆に API を使いにくくする。 API を使う側は、以下の2つのどれかを強いられるため、多少の負荷がかかるから。
- 少なくとも1つ以上の catch が必要
- 例外を外側に伝搬させる
チェックされる例外を使う場合
この2つの条件をみたす場合に、上記の負荷が正当化される。(ただし CloneNotSupportedException
は例外)
それ以外の場合はチェックされない例外のほうが適切。
チェックされる例外を、チェックされない例外に変更する方法
上記で述べたように、チェックされる例外を使用し過ぎると、負荷が高くなる。 その方法が「例外を投げるメソッドを分割して、状態検査メソッドと、それ以外の処理に分割する」というもの
ただし、以下の場合は NG。
- 外部同期なしに平行してアクセスされる場合
- 外部要因により、状態遷移する場合
actionPermitted
メソッドが action メソッドの処理を行う必要がある場合- (パフォーマンス上の関係で、この分割を行う必要がないので不要となる)
// チェックされる例外を使用する場合の呼び出し try { obj.action(args); } catch(TheCheckedException e) { // 例外処理 }
// 状態検査メソッドとチェックされない例外を使用する場合の呼び出し if (obj.actionPermitted(args)) { obj.action(args); } else { // 例外処理 }
項目.60 標準例外を使用する
既存の例外を再利用する
- プログラマが熟知している確立された慣例と一致するため、使用が容易になるから
- 見慣れない例外でごちゃごちゃしないので、API を使用するプログラムが読みやすい
- 例外クラスが少ないことは、クラスのロードに費やされる時間が少ないことを意味する
よくある具体例
IllegalArgumentException
- 不適切な引数を渡した時に発生する例外
IllegalStateException
- レシーバーのオブジェクトが不正な状態ならば発生する例外
NullPointerException
- null が禁止されているパラメータに対して、null を渡した場合など
IndexOutOfBoundsException
- index を表すパラメータで、範囲外の値を呼び出した場合など
ConcurrentModificationException
- 並行して変更されようとしている
UnsupportedOperationException
- 行おうとした操作をオブジェクトがサポートしていない場合
また、エラーに関連する情報を付与したい場合は、自由に例外をサブクラス化すること。 再利用する時の例外をどう選択するか、は必ずしも厳密でない場合がある
項目.61 抽象概念に適した例外をスローする
例外翻訳とは
「上位レイヤは下位レベルの例外をキャッチし、上位レベルの抽象概念の観点から説明可能な例外をスローする」こと。例えば以下の様な例を指す。
// イディオム try { } catch (LowerLevelException e) { throw new HighLevelException(...) }
// AbstractSequentialList からの一例 public E get(int index) { ListIterator<E> i = listIterator(index); try { return i.next(); } catch(NoSuchElementException e) { throw new IndexOutOfBoundsException("Index: " + index); } }
上位レベルの例外から、下位レベルの問題をデバッグするためには、例外連鎖を用いる
- 上位レベルから下位レベルの例外を取り出すためのアクセサを用いる
- 具体的には、スーパークラスの連鎖可能なコンストラクタに引き渡す
- 殆どの標準例外は連鎖可能なコンストラクタを持っている
try { // Do something } catch (LowerLevelException cause) { throw new HighLevelException(cause); } class HighLevelException extends Exception { HighLevelException(Throwable cause) { super(cause); } }
例外翻訳は何も考えないで例外を伝搬させるよりは優れてるが、乱用すべきではない
- 可能であれば、下位レベルのメソッドを呼び出す前に、それが成功することを保証する
- (状態検査メソッドのこと?)
- 引数を引き渡す前に、正当性を検査する
- 不可能であれば、上位レイヤに黙って処理させる
- 下位レベルの問題から、上位レベルのメソッド呼び出し元を隔離する事が次善策
- 呼び出し元を隔離出来ない場合は、例外連鎖を使う
項目.62 各メソッドがスローする全ての例外を文章化する
例外がスローされる条件を Javadoc の @throw
タグで正確に文章化する
チェックされない例外についても、注意深く文章化するほうが懸命
- ただし、強制はしない
- 書くことで、メソッドが首尾よく実行されるための事前条件を記述できる
- これは必ずしも達成可能であるとは限らない
-
throw
タグを使わない- チェックされない例外と、チェックされる例外を視覚的に区別するため
項目.63 詳細メッセージにエラー記録情報を含める
例外の toString
メソッドが例外の文字列表現である
- 文字列表現 = クラス名 + 詳細メッセージ
- エラーの原因を表す文字列で、できるだけ多くの情報をかえす事が重要
例外の原因となった全てのパラメータとフィールドの値を含んでいるべき
- 例)
IndexOutOfBoundsException
は下限範囲、上限範囲、範囲内の収まらなかった実際の index を返す。これは診断にとても役立つ情報
例外の文字列表現と、エンドユーザーに対してわかりやすいメッセージを混同すべきではない
- プログラマにとっては、エラーを解析する情報の内容のほうがはるかに重要
- 以下の様にコンストラクタを作成することを推奨
- プログラマがエラーを記録することが容易になるし、逆に記録しないことが困難になるから
- 高品質な文字列表現を生成するコードを一箇所にまとめる事ができるから
- アクセサを提供することで、エラーからの回復に役立てることができるかもしれないから
/* IndexOutOfBoundsException を生成する @params lowerBound 最も小さな正当なインデックス値 @params upperBound 最も大きな正当なインデックス値に 1 を足した値 @params index 実際のインデックス値 */ public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) { super("Lower bound: " + lowerbound + ", Upper bound: " + upperBound + ", Index: " + index); this.lowerbound = lowerBound; this.upperBound = upperBound; this.index = index; }
項目. 64 エラーアトミック性に努める
エラーアトミックとは
- 「失敗したメソッド呼び出しは、オブジェクトをそのメソッド呼び出しの前の状態にしておく」という状態
- なるべくエラーアトミックに保つことを意識する
エラーアトミックを保つための方法
- 不変オブジェクトを設計する
- 変更できないので、エラーが出ても同じ状態であるから
- パラメータの正当性を検査する
- オブジェクトの変更を行う前に例外をスローすることができるから
- 失敗するかもしれない部分を、オブジェクトを変更する部分よりも前に行う
- 操作の途中で発生する例外を捉えて、状態を戻す「回復コード」を書く
- 一般的ではない
- 主に永続的なデータ構造に対して使用される
ただし、エラーアトミック性は必ずしも達成できるとは限らない。例えば複数スレッドが同期なしに、同一オブジェクトを同時に変更する場合など。
メソッドがエラーをスローする場合は、一般的には回復不可能であり、エラーアトミック性を保持しなくてよい
- たとえ回復可能でも、必ずしも望ましいとは限らない
- 例外は回復可能である場合がある。対比に注意
- メソッドの仕様の一部である例外は、エラーアトミック性を保持するべき
// 最初のサイズ検査が無くても例外を投げる // しかし、それだと size フィールドを不正号な状態にしてしまい // オブジェクトに対するその後の呼び出しを失敗させてしまう public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[—size]; elements[size] = null; // 廃れた参照を取り除く return result; }
項目.65 例外を無視しない
例外を無視してはいけない理由
- 例外の目的が達成されないから
- 例外の目的とは、例外的状態を処理させることを強制する、こと
- 火災報知機を無視して、警報を切ってしまうのと同じ
- 無視する場合はコメントに含んでいるべき
- エラーをも無視してしまうから
- 原因とは何も関係のないところでエラーになる可能性がある
- 例外は、外に伝搬させるだけでも有益な情報を残してくれる
// ダメ、ぜったい try { } catch (SomeException e) { }
感想
普段は ruby を書いているが、早速活かせそうな話ばかりだったので、試してみたい。
例外処理を書く時の指針が揃っていたし、その理由も納得できるものだった。特に「チェックされる例外」と「チェックされない例外」という考え方は自分が特に迷っていた部分だったので、参考になった。 例外連鎖を使うときにも指針ができた。
Java は型あるので、擬似コードが理解し易くていいですね。
こういうプログラミング全般?の話というか、プログラミングテクニックというか、そういう本って他にもあるのかな。
基礎力が無いのでもっと読んだほうが良い気がする。Effective Java
も更に読み込んでいきたい。
2017/11/22 追記
かなりスペースを取ってしまってますが、冒頭に目次を追加しました。
忙しい人でも目次だけ読んで、気になったところだけ読めるようにする意図を込めてます。
rails 5 を今更触ってみた話
イントロ
rails5 の主要機能は色々と知られている通りだけど、業務に投入するとなると、やっぱり互換性だったり、細かいコードの違いが気になるもの。
今回 authlogic を使ったログイン機能を雑に作ったので、その限られた狭い範囲であるものの、ハマったところや違いをまとめてみた。
なんで authlogic ?
- 昔業務で使ってたから。そしてまた使うかもしれない。
- なお
devise
は初心者の頃使って見事に爆死し、それ以降使ってない。
- なお
- そこそこ古く、歴史ある gem
rails5
でも使えるかどうか確かめたかった- binarylogic/authlogic_example は 7 年前の化石となっている。
- シンプルな機能だけを提供してくれている
- だから好き。
- (ただし、中身はかなり癖のある実装)
- 昔のおさらい。復習を兼ねて。
環境
rails (5.0.0.rc2)
authlogic (3.4.6)
rspec-core (3.1.7)
気づいたこと
authlogic
は rails5 対応中
結論から言うと、今は使えなかった。
しかし対応 PR や issue も立っているので、しばらく傍観モード。
全くメンテナンスされていないわけではなさそうなので、少し安心した。
- Rails 5 callback by jealt · Pull Request #488 · binarylogic/authlogic
- Fix deprecation warning: prepend_before_filter in Rails 5 by bparanj · Pull Request #491 · binarylogic/authlogic
- Impossible to authenticate using Rails 5 (beta 3) and Authlogic 3.46 · Issue #487 · binarylogic/authlogic
サンプルを作成する時には、vendor/bundle
以下に install されている authlogic を直接修正して、無理やり動かすことになってしまった。
トップページが….
初めて rails s
して localhost:3000
にアクセスするとこんな感じ。かっこいい。
ログを見ると以下のようになっている。
Started GET "/" for 127.0.0.1 at 2016-06-25 22:55:12 +0900 ActiveRecord::SchemaMigration Load (0.6ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by Rails::WelcomeController#index as HTML Parameters: {"internal"=>true} Rendering vendor/bundle/gems/railties-5.0.0.rc2/lib/rails/templates/rails/welcome/index.html.erb Rendered vendor/bundle/gems/railties-5.0.0.rc2/lib/rails/templates/rails/welcome/index.html.erb (4.5ms) Completed 200 OK in 24ms (Views: 11.3ms | ActiveRecord: 0.0ms)
Rails::WelcomeController#index
というのが呼ばれている。
書き換えたいときは今までどおり、root
を設定すればいいっぽい。
controller のテストが rails-controller-testing
に切り出されている
assigns
が使えなくて、scaffold
で作ったテストが NoMethodError
で落ちる。
assigns
を使いたければ rails/rails-controller-testing を各自で install して使う仕組みになったようだ。(対応したのはもっと昔なのだろうけど、知らなかった)
rspec
は minitest
とは違って、全部まるごと入ってるのが嬉しいから、個人的にはちょっと残念。今後の方針がどうなるかは知らないけど、テストのために色々な gem を探したり install するのは大変だし、面倒だと思う。その面倒さが無いのが一番の利点だと思ってたので。*1
prepend_before_filter
が deprecated
authlogic
の内部で書かれている。
なので bundler
で環境を読み込むたび出てくるので鬱陶しい。
$ rails c DEPRECATION WARNING: prepend_before_filter is deprecated and will be removed in Rails 5.1. Use prepend_before_action instead. (called from require at /Users/argerich/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/bundler-1.11.2/lib/bundler/runtime.rb:77) Loading development environment (Rails 5.0.0.rc2) >>
メッセージにも書いてあるとおり、prepend_before_action
を使えば警告を解消できそう。
use_transactional_fixtures
が deprecated
rspec-rails
の use_transactional_fixtures
が deprecated になっている模様。
代わりに use_transactional_tests=
を使えとあるけど、rspec-3.1.7
では対応されておらず、NoMethodError
で弾き返される。
$ rspec … DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/top_controller_spec.rb:3) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/user_sessions_controller_spec.rb:3) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/users_controller_spec.rb:21) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/models/user_spec.rb:3) DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/requests/users_spec.rb:3) …
Deprecation warning: use_transactional_fixtures= is deprecated · Issue #1549 · rspec/rspec-rails を見ると、master branch では対応しているっぽい。
ActionController::TestCase
get url, parameter, session
でお馴染みの、リクエストを送るメソッドの引数が、HTTP method だけになる模様。
get :show, params: { id: 1 }, session: { user_id: 1 } process :update, method: :post, params: { id: 1 } (called from block (3 levels) in <top (required)> at /Users/argerich/dev/authlogic-rails5-example/spec/controllers/users_controller_spec.rb:57) DEPRECATION WARNING: ActionController::TestCase HTTP request methods will accept only keyword arguments in future Rails versions.
具体的には、以下の様な修正を行えばおk。
引数に名前がついて、わかりやすくなった。地味に嬉しい。
しかし、これは多分運用しているテストを直さないといけなくなるのかなー。
--- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -60,7 +60,7 @@ RSpec.describe UsersController, :type => :controller do describe "GET new" do it "assigns a new user as @user" do - get :new, {}, valid_session + get :new, params: {}, session: valid_session expect(assigns(:user)).to be_a_new(User) end end
ログが綺麗になってる
前はもっと asset 周りのログが沢山流れていたが、今は出ない。
すっきり。
Started GET "/" for 127.0.0.1 at 2016-06-26 00:09:06 +0900 Processing by TopController#index as HTML Rendering top/index.html.erb within layouts/application Rendered top/index.html.erb within layouts/application (11.4ms) Completed 200 OK in 40ms (Views: 34.7ms | ActiveRecord: 3.1ms) Started GET "/login" for 127.0.0.1 at 2016-06-26 00:09:12 +0900 Processing by UserSessionsController#new as HTML Rendering user_sessions/new.html.erb within layouts/application Rendered user_sessions/new.html.erb within layouts/application (3.9ms) Completed 200 OK in 66ms (Views: 64.3ms | ActiveRecord: 0.0ms)
last_comment
が deprecated
Rake.application.last_comment
が deprecated らしい。
rspec-core
の 3.1.7
では、ここ に Rake.application.last_comment
が使われていて、警告が出る。
% rake DEPRECATION WARNING: prepend_before_filter is deprecated and will be removed in Rails 5.1. Use prepend_before_action instead. (called from require at /Users/argerich/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/bundler-1.11.2/lib/bundler/runtime.rb:77) [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead. [DEPRECATION] `last_comment` is deprecated. Please use `last_description` instead.
last_description
に書き換えると警告が止まる。
確認はしてないが、master なら治ってそう。
まとめ
休日の空いてる時間で、雑に作ったものですが、できあがったものはこちらです。
mgi166/authlogic-rails5-example: authlogic meets rails 5
*1:もっとも、最近では controller のテストではなく request のテストを書く事が多いだろうと思われるが
webpack-dev-server を使う
イントロ
見ればだいたい書いてある。
webpack
は少し触らないと忘れてしまうので、メモしておく。
それと何故か webpack の公式 Document は読みづらい(私だけ?)というのも理由の一つ。
webpack-dev-server って?
開発用の web サーバー。Express
で作られてる。
おおまかに2つのことができる
Hot Module Replacement
- module を変更したら変更を検知して読み込み直す
Automatic Refresh
- react とかで、component を変更したら、自動で reload する
これだけできれば、わざわざ変更のたびにサーバーを再起動しなおさなくて済むので、とりあえずの開発には困らなくなる。
導入
まずは npm install
$ npm i --save-dev webpack-dev-server
webpack.config.js を編集。
module.exports = { context: path.join(process.env.PWD, 'frontend'), - entry: "./index.js", + entry: [ + "webpack-dev-server/client?http://localhost:8080", + "webpack/hot/dev-server", + "./index.js" + ], output: { path: path.join(__dirname, 'dist'), - filename: 'webpack.bundle.js' + filename: 'webpack.bundle.js', + publicPath: "/assets/" }, @@ -14,7 +18,8 @@ module.exports = { plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV) } - }) + }),[f:id:mgi:20160416232151g:plain] + new webpack.HotModuleReplacementPlugin() ],
やってることは 3 つ
- entry を増やす
webpack-dev-server/client?http://localhost:8080
,webpack/hot/dev-server
の2つ
- plugins に
webpack.HotModuleReplacementPlugin
を足す - output.publicPath: を設定
publicPath
の説明はこちら
後は option つけてコマンドラインで起動すれば良い
$ webpack-dev-server —hot —inline
まとめ
簡単に導入できて、凝ったことしない限りは十分なので非常に助かる。