npm installで依存関係エラーが出る場合の対処
eslint周りで色々installしていたら依存関係でエラーを吐いてどうにもならなくなりました。
結論としては、npmのversionを最新化したら直りました。
npm installが失敗した時に試したい3つのコマンド - Qiita にもありましたが、以下のコマンドで最新化できます。大抵の場合これでいける気がします。
$ npm update -g npm
ついでですが、以下のようにversion指定してあげることもできます。
$ npm install -g npm@3.10.3
Node.js周りは、nvm, node, npmそれぞれにversionがあってややこしいですね。
パーフェクトJavaScript (PERFECT SERIES 4)
- 作者: 井上誠一郎,土江拓郎,浜辺将太
- 出版社/メーカー: 技術評論社
- 発売日: 2011/09/23
- メディア: 大型本
- 購入: 24人 クリック: 588回
- この商品を含むブログ (12件) を見る
Gemfileとpackage.jsonでみるバージョン指定の読み方
セマンティック・バージョニング(SemVer)によると
バージョンナンバーは、メジャー.マイナー.パッチとし、バージョンを上げるには、
SemVerはバージョニングのルールみたいなものですね。
Gemfile(Ruby)やpackage.json(Node.js)等で依存関係を記述する時、 チルダ(~)やキャレット(^)を使って指定するかと思いますが、自分の中での解釈が曖昧だったのでまとめます。
Gemfile
Rubyの場合は ~>
の記法が使われます。
これはpessimistic operator(悲観的バージョン演算子)というそうです。
解釈は以下のようになります。
- 指定バージョンの一番右の数字を取り除く
- 次に、一番右の数字をインクリメントしたものを上限とする
# e.g. gem 'hoge', '~> 5.1.1' # 次と等価 gem 'hoge', '>= 5.1.1', '< 5.2.0'
参考: Ruby's Pessimistic Operator
package.json
package.jsonではチルダ(~)とキャレット(^)を使います。
参考: semver | npm Documentation
Tilde Ranges
Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not.
とのことで
- 基本的にはマイナーバージョンまで固定
- マイナーバージョンが指定されてない場合はメジャーバージョン固定
です。
e.g. ~1.2.3 := >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0 ~1.2 := >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0 ~1 := >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0
Caret Ranges
Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple. In other words, this allows patch and minor updates for versions 1.0.0 and above, patch updates for versions 0.X >=0.1.0, and no updates for versions 0.0.X.
- 基本的にはメジャーバージョン固定(メジャーバージョンが0でない場合)
- メジャーバージョンが0の場合マイナーバージョン固定
- メジャー・パッチバージョンが0の場合はアップデートしない
^1.2.3 := >=1.2.3 <2.0.0 ^0.2.3 := >=0.2.3 <0.3.0 ^0.0.3 := >=0.0.3 <0.0.4
大抵の場合はメジャーバージョン固定のCaret(^)指定で問題ないかと思います。
- 作者: 大川ぶくぶ
- 出版社/メーカー: 竹書房
- 発売日: 2015/12/07
- メディア: コミック
- この商品を含むブログ (7件) を見る
プログラマのためのDocker教科書を読み始めた
Dockerを使いこなせないと会社で人権がないので プログラマのためのDocker教科書を読み始めました。
プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化
- 作者: WINGSプロジェクト阿佐志保
- 出版社/メーカー: 翔泳社
- 発売日: 2015/11/19
- メディア: Kindle版
- この商品を含むブログ (3件) を見る
プログラマのための、というタイトルから、 "Dockerの使い方だけ紹介" みたいな雰囲気があるんですが、 想定以上に諸々しっかり書いてありました。
序盤にインフラ・仮想化・コンテナ技術の歴史と概要についてしっかり書かれていて、 非常に参考になりました。定期的に読み直したい内容です。
以下、適当にDocker周りの備忘録を適当にまとめていきます。
Docker の Install(Mac)
Docker for Macがリリースされているのでこちらを使います。 (数ヶ月前にちょっと触った時はまだプライベートベータでした)
$ brew update && brew upgrade $ brew cask install docker
あとは適当にDocker.appでsetupします。
いろいろ試す
docker pull
超軽量Linux Distributionの"Alpine Linux"を使います。
とりあえず docker search
してみます。
$ docker search alpine NAME DESCRIPTION STARS OFFICIAL AUTOMATED alpine A minimal Docker image based on Alpine Lin... 1475 [OK] anapsix/alpine-java Oracle Java 8 (and 7) with GLIBC 2.23 over... 151 [OK] ...
docker pull
でイメージを落とします
$ docker pull alpine Using default tag: latest latest: Pulling from library/alpine c0cb142e4345: Pull complete Digest: sha256:ca7b185775966003d38ccbd9bba822fb570766e4bb69292ac23490f36f8a742e Status: Downloaded newer image for alpine:latest
Imageの確認
docker images
で一覧確認します。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE rails latest 9df3ff98cd15 9 days ago 840.6 MB nginx latest ba6bed934df2 2 weeks ago 181.4 MB alpine latest ee4603260daa 2 weeks ago 4.803 MB msaraiva/elixir-dev latest 6287638223f3 3 months ago 52.54 MB
いろいろ試しに入れてたので余計なものも出てきてますが、alpineのdocker imageだけ圧倒的に軽いですね。
個別に中身を見たい場合は inspect
を使います
$ docker inspect alpine ... "Architecture": "amd64", "Os": "linux", "Size": 4802964, "VirtualSize": 4802964, ...
hello world
基本型は
docker run <dockerイメージ名> <コマンド>
です。
$ docker run alpine /bin/echo 'hello world' hello world
dockerイメージがローカルに見つからなければ勝手にpullしてくれます。
tag
イメージにtagを付けて管理することができます。
例
$ docker tag alpine:latest shotat/alpine:foo $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest ee4603260daa 2 weeks ago 4.803 MB shotat/alpine foo ee4603260daa 2 weeks ago 4.803 MB
コンテナのshellを起動する
単体でshellを起動したい場合は以下のようなコマンドを使います。
$ docker run -it --rm alpine /bin/sh
オプションについて
-it --rm
のオプションを見ていきます。
$ docker run --help | grep -E '(?:--tty|--interactive|--rm)' -i, --interactive Keep STDIN open even if not attached --rm Automatically remove the container when it exits -t, --tty Allocate a pseudo-TTY
-i
: 標準入力を開く-t
: 疑似ttyを割り当てる--rm
: exit後にコンテナを破棄する
-it
を付けないと対話shellをうまく扱えないので必ずつけましょう。
/bin/echo 'hoge'
みたいなことしかしない場合は不要です。
マスコットキャラクターの名前
Dockerのクジラのキャラクターの本名は "Moby Dock" というそうです。
白鯨 - Moby-Dick; or The White Whale - を文字ってるみたいですね。( 白鯨 - Wikipedia )
npm scriptsを並列実行する
npm-run-all を使う
使い方
npm i --save-dev npm-run-all
でinstallします。
直列・並列実行コマンドの run-s
, run-p
が使えるようになります。
package.jsonのscripts部を以下のように設定してみます。
"scripts": { "dev": "run-p stub watch", "stub": "stubcell", "build": "webpack", "watch": "run-p watch:*", "watch:js": "watch 'npm run build' ./src/scripts" },
この状態で npm run dev
とすると、stubサーバとjavascriptのwatch & buildが同時に走るようになります。
楽ちんですね。
Node.jsのversionをプロジェクト毎に設定する
Rubyの場合は .ruby-version
にバージョン指定すればプロジェクト毎にversion指定できるのですが、
Node.jsの場合どうすればいいのか分からなかったので備忘録。
大きく分けて2パターンありました。
avn を使う
.node-version
でversion指定すればディレクトリ移動したときに自動でversionが切り替わるみたいです。
nodeのversion指定するために別コマンドいれるの微妙な気がしたので今回は使ってません。
nvm useを使う
.nvmrc
にversionを記述して、nvm use
を実行します。
rbenvみたいに自動で切り替わらないのかな?と思ったのですが、以下のissueを見るに切り替わらないっぽいです。
zshのhook使って自動的にnvm use実行する、みたいなのも見ました。個人的にはavn使うよりこっちの方がスマートな気がします。
- 作者: 掌田津耶乃
- 出版社/メーカー: マイナビ
- 発売日: 2014/03/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
Ruby Style Guide読んだ && 一部抜粋
普段はRubocopのおかげで概ねStyle準拠できているはず、と思ってたのですが、 改めてStyle Guideを読むと知見がたくさんありました。
以下、個人的に把握できてなかった箇所を抜粋しつつ、今後意識していきます。
andとorの使用は禁止
使うべき理由がないです。 常に、代わりに&&と||を使いましょう。
メソッドチェーンでのdo...endは避ける
# 悪い例 names.select do |name| name.start_with?('S') end.map { |name| name.upcase } # 良い例 names.select { |name| name.start_with?('S') }.map(&:upcase)
do...end.map
やりたくなる場面がたまにあるんですが、我慢します。
代入部分を括弧で囲まずに、=の返り値を条件式に用いてはいけない
# 悪い例 (+ 警告が出ます) if v = array.grep(/foo/) do_something(v) ... end # 良い例 (MRIはこれでも文句を言いますが、RuboCopでは問題ありません) if (v = array.grep(/foo/)) do_something(v) ... end # 良い例 v = array.grep(/foo/) if v do_something(v) ... end
変数がまだ初期化されていないときにだけ初期化したいのであれば、||=を使う
# 悪い例 name = name ? name : 'Bozhidar' # 悪い例 name = 'Bozhidar' unless name # 良い例 - nameがnilかfalseの場合のみ、Bozhidarで初期化します name ||= 'Bozhidar'
値が入っているかわからない変数の前処理のは&&=を用いる
# 悪い例 if something something = something.downcase end # 悪い例 something = something ? something.downcase : nil # ok something = something.downcase if something # 良い例 something = something && something.downcase # より良い例 something &&= something.downcase
Proc.newよりprocを使う
# 悪い例 p = Proc.new { |n| puts n } # 良い例 p = proc { |n| puts n }
STDOUT/STDERR/STDINの代わりに$stdout/$stderr/$stdinを用いる
STDOUT/STDERR/STDINは定数であり、 Rubyでの定数は、実際は再代入できます(つまりリダイレクトに使えます)が、 もし実行するとインタープリタからの警告が出ます。
ロジックを使って複雑な比較を行うよりも、 可能な限りRangeやComparable#between?を用いる
# 悪い例 do_something if x >= 1000 && x <= 2000 # 良い例 do_something if (1000..2000).include?(x) # 良い例 do_something if x.between?(1000, 2000)
collectよりmap、detectよりfind、find_allよりselect injectよりreduce、lengthよりsizeを使う
これは絶対のルールではないです。 別名のほうが可読性に優れているなら、 そちらを使っていただいて構いません。 韻を踏んでいるほうのメソッド名はSmalltalkから引き継いできたもので、 他のプログラミング言語でそこまで一般的ではないです。 find_allよりもselectが推奨されるのは、 rejectとの相性がよいことと、 メソッド名から挙動を推察することも容易だからです。
シンボル、メソッド、変数にはsnake_caseを用いましょう。
シンボルはcamelCaseでも怒られない気がしたんですが、こちらもsnake_caseが良いみたいです。
危険 な可能性のあるメソッド (引数やselfを変更するようなメソッドや、 exit!(exitと違ってファイナライザが走らない)のようなもの) は、その安全なバージョンがある場合には、 危険 であることを明示する意味で感嘆符で終わる
# 悪い例 - 対応する「安全」なメソッドが存在しません class Person def update! end end # 良い例 class Person def update end end # 良い例 class Person def update! end def update end end
対応する安全なメソッドが存在しない場合は !
付けない方が正しいみたいですね。副作用が大きいメソッドは !
つけるようにしてたんですが、Style Guilde的には微妙みたいです。
コメント
- パフォーマンスに問題を及ぼすかもしれない遅い、または非効率なコードの注釈にはOPTIMIZEを使いましょう。
- 疑問の残るコードの書き方でコードの臭いを感じた箇所の注釈にはHACKを使いましょう。
- 意図したとおりに動くか確認する必要がある箇所の注釈にはREVIEWを使いましょう。
ハッシュから連続して複数の値が必要になる時は、Hash#values_atを用いる
# 悪い例 email = data['email'] username = data['nickname'] # 良い例 email, username = data.values_at('email', 'nickname')
利用するケースにより特化した速い代替手段がある場合、String#gsubは使わないようにする
url = 'http://example.com' str = 'lisp-case-rules' # 悪い例 url.gsub('http://', 'https://') str.gsub('-', '_') # 良い例 url.sub('http://', 'https://') str.tr('-', '_')
文字列の添字に直接正規表現を渡すことで、文字列の構築をシンプルにできる
match = string[/regexp/] # マッチした内容が得られる first_group = string[/text(grp)/, 1] # キャプチャグループの内容が得られる string[/text (grp)/, 1] = 'replace' # string => 'text replace'
sub/gsubでの複雑な置換は、ブロックやハッシュを用いることで実現できる
words = 'foo bar' words.sub(/f/, 'f' => 'F') # => 'Foo bar' words.gsub(/\w+/) { |word| word.capitalize } # => 'Foo Bar'
Effective Ruby 第六章まとめ テスティング
Effective Ruby 第五章 メタプログラミング まとめ その2 - Memento memo. の続き。
Effective Rubyのテスティング章をまとめていきます。
MiniTestはRuby標準のテスティングライブラリで、 主要なコンポーネントは以下の3つです。
- ユニットテスト
- スペックテスト
- モック
require('minitest/autorun')
でライブラリ全体をロードすると、上記のコンポーネントも含まれます。
テストのファイル名は tests/xxx_test.rb
といった名前で格納するとrailsの作法に乗れて良いみたいです。
ユニットテストとスペックテスト(ビヘイビアスペック)はどっちでもいいらしいですが、 RubyだとRSpecがデファクト感あるのでスペックテストの方が馴染みがありそうです。
- 作者: Peter J.Jones
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/19
- メディア: Kindle版
- この商品を含むブログ (4件) を見る
MiniTestユニットテストに慣れる
- テストクラスを定義し、スーパークラスを
MiniTest::Unit::TestCase
にする - 個々のテストケースはインスタンスメソッドとして記述し、"test_"プレフィクスをつける
- ユニットテスト時はアサーションを使う
- テストメソッドは短くする
- アサーションメソッドは
assert
メソッドだけでなく、assert_equal
等の適切なものを使う assert_xxx
に対応するrefute_xxx
で逆の動作を扱える- テストをまとめて実行するRake taskを使う(または作る)
class HogeTest < MiniTest::Unit::TestCase def test_hoge hoge = Hoge.new assert_equal(0, hoge.xxx) end end
MiniTestスペックテストに慣れる
- 基本的にはユニットテストをラップしてるだけ
- describeメソッド呼び出しでクラスが自動的に定義されるため、自前でクラス定義を書く必要がない
- アサート系メソッドの代わりにオブジェクトに注入されたエクスペクテーションメソッド(
must_equal
,wont_equal
)を使う。
describe(Hoge) do describe('xxx') do before do @hoge = Hoge.new end it('returns initial value') do @hoge.xxx.must_equal(0) end end end
モックオブジェクトで決定論をシミュレートする
- 非決定的な処理(HTTPリクエスト等)からテストを切り離したいときはモックを使う
- モックで交換するメソッドは外部ライブラリが提供している部分にすべき
- テストメソッドを終える前に必ず
verify
を呼んで、モックメソッドが実行されていることを確認する。 - MiniTest::Mockでモックを作成できるが、Mocha等の別ライブラリ使った方が高機能なのでおすすめ
インタフェースをテストする、という原則があるのですが、実装詳細に立ち入ってモックを使わざるを得ないケースもあると思います。その場合 verify
でモックメソッドが確実に実行されていることをテストする必要があります。
すると、実装詳細がしれっと変わった場合でもテストで検知できるようになります。
効果的なテストを追求する
用語等
ハッピーパステスト
テストしているコードのすべての前提条件を丁寧に準備して有効な入力しか与えないテスト。バグ発見の効果が薄い。
例外パステスト
さまざまな入力を送り込んでコードの全ての分岐先を確実に実行するテスト。一般に複雑になりすぎるが、ファズテストとプロパティテストで対処できる。
ファズテスト
プログラムや特定のメソッドにランダムデータを大量に送り込むことで、 クラッシュさせたり予想外の例外を発生させることができるかをチェックするテスト。
FuzzBert gem等で実行可能。基本的にほぼ無限にテストを行うため時間がかかる。
プロパティテスト
ファズテスト同様にランダムなデータを大量に送り込むが、コードが満たすべきプロパティ(性質)を満足するかをチェックするテスト。
MrProper gem等で実行可能。
参考: ソフトウェアの品質を学びまくる:Property-based Testing、そしてExample-based testing、とは
Rubyとは別でテスティングの理論的なところをあまり深く理解できていないので、もうちょっと勉強していきたいです。 あとは実践的なところでRSpecを使いこなせるようになりたいです。(適当にしか使えてないので。。。)
The RSpec Book (Professional Ruby Series)
- 作者: David Chelimsky,Dave Astels,Zach Dennis,角谷 信太郎,豊田 祐司,株式会社クイープ
- 出版社/メーカー: 翔泳社
- 発売日: 2012/02/22
- メディア: 大型本
- 購入: 7人 クリック: 141回
- この商品を含むブログ (19件) を見る
Elixir & Phoenix のLT資料
先日、Elixir & Phoenix布教をすべく、社内でLTをしてきました。社内LT会自体は毎週やっているので、個人的に最低月1回は発表するよう心がけています。
内容は超薄いのですが、とりあえず公開することが大事だと思うので資料upしました。SpeakerDeckデビュー。
- 作者: Dave Thomas,笹田耕一,鳥井雪
- 出版社/メーカー: オーム社
- 発売日: 2016/08/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
GitHubのリポジトリを直接指定してgemをinstallする
自作gemとかOSSのgemのリポジトリとかブランチとかを指定して使いたい場合の解決策です。
リポジトリの .gemspec
ファイル等は設定済み前提で。
Gemfile使う方法とGemfile使わない方法の2通りあります。
Gemfileを使う場合
普通に指定できます。以下のようにGemfileに記述
gem 'hogehoge', git: 'git@github.com:foo/bar.git', branch: 'develop'
Gemfileを使わない場合
specific_install
gemを使います。
specific_installのInstall
$ gem install specific_install
リポジトリからgem install
$ gem specific_install git@github.com:foo/bar.git develop
内部的にはcloneしてbuild & installしてローカルリポジトリ破棄してるっぽいです。
Effective Ruby 第五章 メタプログラミング まとめ その2
Effective Ruby 第五章 メタプログラミング まとめ その1 - Memento memo. の続きです。
モンキーパッチの代わりとなるものを検討する
モンキーパッチとは
- モンキーパッチとは、実行時にコアクラスを拡張したり挙動を書き換える(パッチを当てる)こと。Active Supportが有名。
- 複数パッチが衝突すると大事故になるのでできるだけモンキーパッチは避けたい
方法1 module関数を使う
愚直にmoduleを定義&オブジェクトをextendする方法です。
module OnlySpace ONLY_SPACE_UNICODE_RE = %r/\A[[:space]]*\z/ def self.only_space? (str) if str.ascii_only? !str.bytes.any? do |b| b != 32 && !b.between?(9, 13) end else ONLY_SPACE_UNICODE_RE === str end end def only_space? OnlySpace.only_space?(self) end end str1 = " \r\n" puts OnlySpace.only_space?(str1) # OOPっぽくなくなる str2 = "hello" str2.extend(OnlySpace) puts str2.only_space? # extendしないと使えない
方法2 新しい別のクラスを作成する
Stringクラスの代わりにStringExtraクラスを作成します。 継承ではなく委譲を使ってStringライクなStringExtraを実装します。(実装省略)
方法3 Refinements機能を使う
Ruby 2.1から入ったRefinements機能を使います。
Refinementsでは、パッチの適用範囲がレキシカルスコープの中に限定されます。以下の例で String#loud
は Foo
の外で呼ぶことはできません。
使い方はこんな感じになります。
module Loud refine String do def loud "#{self}!!!" end end end class Foo using(Loud) def initialize(str) puts str.loud end end Foo.new("wei") #=> wei!!!
参考
エイリアスチェイニングで書き換えたメソッドを呼び出す
- 既存のメソッドに新しい名前を与え、元のメソッド名でメソッドを再定義して最終的に元のメソッドを呼び出す。
- エイリアス作成時にメソッド名がユニークになるよう注意
- エイリアスチェイニングを取り消すメソッドも作成する
alias_methodについて
alias_method(new_name, original_name)
でmethodにエイリアスを貼ることができます。
参考: ref.xaio.jp
sample
module LogMethod def log_method(method) orig = "#{method}_without_logging".to_sym if instance_methods.include?(orig) raise(NameError, "#{orig} isn't a unique name") end alias_method(orig, method) define_method(method) do |*args, &block| $stdout.puts("calling method '#{method}'") result = send(orig, *args, &block) $stdout.puts("'#{method}' returned #{result.inspect}") result end end #エイリアスチェイニングを取り消すメソッドも作成する def unlog_method(method) orig = "#{method}_without_logging".to_sym if !instance_methods.include?(orig) raise(NameError, "was #{orig} already removed?") end remove_method(method) alias_method(method, orig) remove_method(orig) end end Array.extend(LogMethod) #=> Array Array.log_method(:first) #=> :first [1,2,3].first # calling method 'first' '# first' returned 1 #=> 1 Array.unlog_method(:first) #=> Array irb(main):008:0> [1,2,3].first #=> 1
Procの引数の個数の違いに対応できるようにする
- Procオブジェクト生成には"強いProc"と"弱いProc"がある。
lambda?
メソッドで識別可能。 - 弱い(Weak)Proc: 引数の扱いが緩く、間違った個数の引数を与えてもエラーにならない。e.g. block
- 強い(Strong)Proc: 通常メソッド呼び出しと同じで、引数の個数が違うとArgumentError例外が発生する。e.g. lambda
- Proc#arityメソッドを使うと、Procオブジェクトが期待する引数の数がわかる。
- Proc#arityメソッドで引数の個数の違いをうまく吸収させる。
モジュールのprependを使うときは慎重に考える
- 継承階層は
ancestors
メソッドで確認可能 - includeは継承階層においてレシーバの後にモジュールを挿入する。
- prependは継承階層においてレシーバの前にモジュールを挿入する。
- prependよりもalias_methodを使った方が柔軟になる
メタプログラミング面白いですね。Refinementsで局所的にクラス拡張するのは結構気に入りました。
まだ メタプログラミングRuby 第2版 も読めていないのですが、健全なメタプロパワーを高めていきたいです。
- 作者: Peter J.Jones
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/19
- メディア: Kindle版
- この商品を含むブログ (4件) を見る