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
まとめ
簡単に導入できて、凝ったことしない限りは十分なので非常に助かる。
magit と elscreen を使いやすく
イントロ
magit
と elscreen
は結構相性悪いと感じることが多く、今まで以下の様な点で困っていた。
- magit-mode を終了しても magit 用の buffer が消えない
- なんとなく気持ち悪い
- 1 つならまだしも、2 ~ 3個残る。
- elscreen 上で magit buffer を閉じた時、どの buffer が開かれるか、学習できなかった
- 本当は最後に作業していた buffer を開きたい。
- 条件によっては、何故か magit 用 buffer がスクリーンに残ったり 、わけがわからない
- 複数の elscreen 上で magit 動かすと、最後の buffer を全く覚えておらず、不思議な挙動をしているように感じてしまう。
- 本当は最後に作業していた buffer を開きたい。
何言っているかわからないと思うが、俺も何が起こってるかわからなかった。
magit
+ elscreen
で運用している人が少ないのか、あまりインターネッツに情報がない。
これはなんとなく magit 使いづらいと感じていた部分を少しだけ直した話になります。
やったこと
以下のような関数作って、フックに追加する。
これで二週間くらい運用して見た限りでは、だいぶストレスがなくなりました。
しかし、magit-status
毎に buffer を新しく生成しているので、PC リソース(というかメモリ)を上手に使えていないはず。
(defun elscreen-kill-all-scratch-screen () "Delete all scratch screen" (interactive) (dolist (screen-and-buffer (elscreen-get-screen-to-name-alist)) (when (and (string-match "*scratch*" (cdr screen-and-buffer)) (> (length (elscreen-get-screen-list)) 1)) (elscreen-kill (car screen-and-buffer))))) (defun delete-all-magit-buffers () "Delete all *magit-xxx* buffer" (interactive) (dolist (buffer (buffer-list)) (when (string-match "*magit" (buffer-name buffer)) (kill-buffer buffer)))) (defun magit-mode-quit-window () "Restores the previous window configuration and kills the magit buffer" (interactive) (delete-all-magit-buffers) (elscreen-kill-all-scratch-screen) (jump-to-register :magit-fullscreen)) (define-key magit-status-mode-map (kbd "q") 'magit-mode-quit-window) (defun with-editor-post-finish-hook-1 () (delete-all-magit-buffers) (elscreen-kill-all-scratch-screen)) (defun with-editor-post-cancel-hook-1 () (delete-all-magit-buffers) (elscreen-kill-all-scratch-screen))
VPC についてまとめ
イントロ
VPC 周りの知識が曖昧なままここまで来てしまったので、整理する。
なんとなく知っていた用語や単語について、一般的な概要、及び AWS ではどういう特徴をもっているか、を大雑把にまとめたもの。
VPC
概要
Virtual Private Cloud の略。Vrtial Private Cloud とは、クラウド環境に構築された仮想的なプライベートネットワークのこと。
VPC 自体が 1 つの IP アドレスを持っていて、VPC は沢山の private ip を持っている。
そんなインターネット上のでっかい領域を指す。
AWSでは
- VPC は CIDR =
x.x.x.x/16
~x.x.x.x/28
の間で作成可能 - デフォルトの VPC というものが存在する
- CIDR は一度作成したら変更不可
- 後からレンジを変えられないので注意
- VPC 削除のタイミングで、関連のAWS リソースは削除されてしまう
- subnet とか Internet Gateway とか色々。
- 削除して作りなおすと、全て作り直しになってしまうので、CIDR は余裕を持たせるのが基本
VPC の作成方法
VPC とサブネット - Amazon Virtual Private Cloud
インターネットゲートウェイ
インターネットゲートウェイ - Amazon Virtual Private Cloud
- VPC のルーティングを各サブネットのルーティングテーブルに追加できる
- NAT 変換を行い、public IP を持つ instance がインターネットに接続する
という機能を持つ。
AWS では
- デフォルトの VPC というものが存在する。
- インターネットゲートウェイがデフォルトの VPC にアタッチされている
- デフォルトのサブネットの中で起動したインスタンスは、public IP が付与される
- public の IP が付与されると、インターネットゲートウェイが NAT 変換を行える。
- つまりインターネットに接続できる
というわけで、何も考えずに EC2 インスタンスをポチると、外部と通信することができるようになるのは、AWS の素晴らしい挙動によるもの。
インターネットゲートウェイの作成
インターネットゲートウェイ - Amazon Virtual Private Cloud
ルートテーブル
ルートテーブル - Amazon Virtual Private Cloud
インターネットトラフィックがどこからどう流れていくか、を記した経路のこと。
どこからどこにトラフィックを流す、という対応表で表現される。
AWS では
ルートテーブル - Amazon Virtual Private Cloud
にまとめられてる。全部重要だけど最低限の機能としては次の通り。
- VPC を作成すると、ルートテーブルが自動で割り振られて、インターネットゲートウェイへのルートが追加されている。これを メインルートテーブル と呼ぶ
- サブネットを特定のルートテーブルに紐付けないと、メインルートテーブルに紐付けられる。
- つまり作成したサブネットはデフォルトでインターネットに通信できる。
- 新たに追加する場合、ルートは CIDR で指定する
ルートテーブルを操作する
ルートテーブル - Amazon Virtual Private Cloud
サブネット
VPC の中で作成するグループのこと。 VPC が持つ IP address の範囲を超えない程度に、自由にグループ化可能。
VPC が都道府県とするなら、サブネットは市区町村みたいな立ち位置。
サブネットの性質上、ルートテーブルに関連付けることにより、初めてサブネット内にトラフィックを流すことができる。
{public,private} サブネット
public サブネット
インターネットゲートウェイにルーティングされているサブネットのこと。 public サブネット内に作成された EC2 インスタンスが public ip もしくは elastic ip を持っている場合、インターネットに接続することができる。
private サブネット
インターネットゲートウェイに routing されていないサブネットのこと。 このサブネット内に EC2 インスタンスを作成しても、通常はインターネットに接続できない。 インターネットに接続するためには、NAT gateway を構築したり、インターネットゲートウェイをルートテーブルに追加する必要がある。
予約された ip address
- 10.0.0.0
- ネットワークアドレス。ネットワーク自身を表すアドレス
- 10.0.0.255
- ネットワークブロードキャストアドレス。ローカルネットワークのホスト全てに通信するためのアドレス
これ以外にも AWS が独自に予約しているアドレスが存在する。
AWS では
- AZ(Availability zone) にまたがってサブネットを構築することはできない
AWS が予約している ip address
参考
まとめ
AWS のドキュメントは入門書として優秀。 勿論周辺情報を理解するためには、別の文献や本で知識を補わないとダメだけど、AWS なら実際に手を動かしながら試せる環境があるし、概要の把握という意味では理解が進みやすい。
本当はもっと書きたかったのだけど、一旦ここまで。
ActiveRecord::Base.connection#table_exists? と ActiveRecord::Base#table_exists? の違い
イントロ
似ているメソッドで、微妙に挙動が異なり、ちょっとハマったのでメモ
違い
引数、結果をキャッシュするかどうかが違う
引数
ActiveRecord::Base.connection#table_exists?
- 引数を一つ取る
ActiveRecord::Base.connection.table_exists?("users") #=> 引数で受け取ったテーブルが存在していれば true, なかったら false
ActiveRecord::Base.table_exists?
- 引数を取らない
class User < ActiveRecord::Base end user = User.first user.class.table_exists? #=> モデルに対応したテーブルが存在していれば true, なかったら false
キャッシュするかどうか
ActiveRecord::Base.connection#table_exists?
- キャッシュしない
- 毎回 database とやり取りして、テーブルが存在するかどうかを確認するメソッド
ActiveRecord::Base.connection.table_exists?('users') #=> true ActiveRecord::Base.connection.drop_table('users') ActiveRecord::Base.connection.table_exists?('users') #=> false
ActiveRecord::Base.table_exists?
- 一度呼びだされたらキャッシュされる
- キャッシュ先は
ActiveRecord::Base.connection
- キャッシュ先は
- 一度呼びだされたらキャッシュされる
user = User.first user.class.table_exists? #=> true ActiveRecord::Base.connection.drop_table('users') user.class.table_exists? # => true # DROP TABLE `users` したのに true が返る! ActiveRecord::Base.connection.schema_cache.table_exists?('users') # => true # # * `ActiveRecord::ConnectionAdapters::SchemaCache` によってメソッド呼び出し結果が保存されている。 # * `ActiveRecord::ConnectionAdapters::SchemaCache` インスタンスは `ActiveRecord::Base.connection` のインスタンスが保持している
結論
上にも書いたとおり、引数と、メソッド呼び出しの結果をキャッシュするかどうかが違う。
ActiveRecord::Base.table_exists?
は通常ActiveRecord::Base
継承したモデル(例だとUser
)が対象となるので、引数を取らない- また、table の存在判定は、一般的には変更されにくい値であるので、一度
table_exits?
を呼び出したらキャッシュされる
と覚えれば良い。
私は動的テーブルを作ったり消したりしていてハマってしまいました。
ActiveRecord を使って、頻繁にテーブルを作成したり削除したりする場合は注意が必要。かも。
Mac で apery を compile する
イントロ
最近、職場の後輩に将棋で負けたことをきっかけに、将棋がマイブーム。
apery って?
将棋プログラムの一種。2014 年の世界大会で優勝したとかなんとか。
一部界隈では、あの ponanza 先生をも凌ぐとかなんとか言われている?らしく、とにかくすごく強いソフト。
で、そんな世界大会で優勝した将棋エンジンが github 公開されているのを知ったので、compile してみました。
そのままやると...
すさまじい警告が出て、失敗する
$ make 24 warnings generated. g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native -o ../obj/common.o -c common.cpp g++ -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native -o ../obj/pieceScore.o -c pieceScore.cpp g++ -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../obj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/hand.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/thread.o ../obj/common.o ../obj/pieceScore.o -lpthread -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native ld: library not found for -lgomp clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [apery] Error 1
gomp
というライブラリが無いと言われているようだ。
gomp とは
GOMP — An OpenMP implementation for GCC - GNU Project - Free Software Foundation (FSF)
openMP で実装している GNU project らしい。
openMP とは
複数CPU を効率的に計算するライブラリのこと。所謂スレッド。
http://www.cc.u-tokyo.ac.jp/support/kosyu/03/kosyu-openmp_c.pdf
計算を早く行うためにマルチスレッドで処理しているのだろう、と想像。
それと URI protocol の仕様として、計算中でも入力を受け取れるようにしなければならないので、そういうところでもスレッドの出番はありそう。
Mac でどう compile するか
g++-4.9 で compile する
環境
OSX 10.11.2
$ brew install gcc49
$ g++-4.9 --version g++-4.9 (Homebrew gcc49 4.9.3) 4.9.3 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
--- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -COMPILER = g++ +COMPILER = g++-4.9 #COMPILER = mpicxx CFLAGS = -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp CFLAGS += -march=native
結果
$ cd src $ make g++-4.9 -o apery ../obj/main.o ../obj/bitboard.o ../obj/init.o ../obj/mt64bit.o ../obj/position.o ../obj/evalList.o ../obj/move.o ../obj/movePicker.o ../obj/square.o ../obj/usi.o ../obj/generateMoves.o ../obj/evaluate.o ../obj/search.o ../obj/hand.o ../obj/tt.o ../obj/timeManager.o ../obj/book.o ../obj/benchmark.o ../obj/thread.o ../obj/common.o ../obj/pieceScore.o -lpthread -std=c++11 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fopenmp -march=native
というわけでうまくいった。
うまくいったけど、どういうことなのか
HiraokaTakuya/apery の README.md より。
Linux のディストリビューションによっては、Makefile に記述されている '-lpthread' を '-pthread' にしなければ、 実行時にエラーになってしまう場合があります。 Linux, Windows で G++ 4.8 以上のバージョンで動作確認をしています。 Clang では正しくビルド出来ているか確認出来ていません。 Visual Studio でビルドすることは現状では出来ません。 Windows でビルドする場合は、MinGW64 をお使い下さい
というわけで、g++4.9
を使うとうまくいく、と。
mac のデフォルトでは、gcc コマンドが clang コマンドの alias になるという罠があり、明示的に 4.9 以上の gcc を指定する必要があった、というオチ。
普段の生活では gcc
に馴染みがないので、少しハマった。
起動を早くする
初回起動時は評価関数生成のため、起動が非常に遅い。
ので、以下を行って評価関数のみ生成しておく。
linux,macでのコンパイルと使い方 · HiraokaTakuya/apery Wiki
$ git submodule init $ git submodule update --depth=1 # コンパイル済みの apery を bin 以下に移動させる $ cp ../src/apery . $ ls bin 20151105 Readme.txt apery book make_synthesized_eval.bat make_synthesized_eval.sh # bin の directory 上で `make_synthesized_eval.sh` を実行する。 $ cd bin ./make_synthesized_eval.sh info string start setting eval table info string end setting eval table
で成功。
make_synthesized_eval.sh
が、bin
以下で実行されること前提の実装になっていたのが難しかった。
動かしてみる
# 入力待ちになる $ ./apery # 標準入力で通信開始の合図を入れる usi # apery が標準出力でレスポンスを返してくれる id name Apery Debug Build id author Hiraoka Takuya option name Best_Book_Move type check default false option name Book_File type string default book/20150503/book.bin option name Byoyomi_Margin type spin default 500 min 0 max 2147483647 option name Clear_Hash type button option name Emergency_Base_Time type spin default 200 min 0 max 30000 option name Emergency_Move_Horizon type spin default 40 min 0 max 50 option name Emergency_Move_Time type spin default 70 min 0 max 5000 option name Eval_Dir type string default 20151105 option name Max_Book_Ply type spin default 32767 min 0 max 32767 option name Max_Random_Score_Diff type spin default 0 min 0 max 32600 option name Max_Random_Score_Diff_Ply type spin default 40 min 0 max 32767 option name Max_Threads_per_Split_Point type spin default 5 min 4 max 8 option name Min_Book_Ply type spin default 32767 min 0 max 32767 option name Min_Book_Score type spin default -180 min -32601 max 32601 option name Minimum_Thinking_Time type spin default 1500 min 0 max 2147483647 option name MultiPV type spin default 1 min 1 max 594 option name OwnBook type check default true option name Skill_Level type spin default 20 min 0 max 20 option name Slow_Mover type spin default 100 min 10 max 1000 option name Threads type spin default 4 min 1 max 64 option name Use_Sleeping_Threads type check default false option name USI_Hash type spin default 256 min 1 max 65536 option name USI_Ponder type check default true option name Write_Synthesized_Eval type check default false usiok
というわけで無事動かせた。
これで世界レベルの将棋ソフトが動かせる!!!
参考
homebrew の install path を変更して、install 済みパッケージを入れなおすの巻
イントロ
年末になったので、自宅 PC を EL Captain
にしました。
噂には聞いてたが、/usr/local
周りの権限問題により、普通に install すると躓くところが出てくる。困る。
おまけに解決方法が sudo chown -R $(whoami):admin /usr/local
ってどうことだよ、と。
こんな理不尽な方法があっていいのか。
homebrew/El_Capitan_and_Homebrew.md at master · Homebrew/homebrew
自分以外 mac 使わないし、一度は面倒さに屈して、上記のコマンドをしぶしぶ受け入れましたが もう我慢ならぬ ということで、install path を変更して homebrew を再 install しました。
brew bundle
まずは落ち着いて brew bundle
を入れる。
% brew bundle ==> Tapping homebrew/bundle Cloning into '/Users/argerich/.homebrew/Library/Taps/homebrew/homebrew-bundle'... remote: Counting objects: 49, done. remote: Compressing objects: 100% (46/46), done. remote: Total 49 (delta 2), reused 12 (delta 0), pack-reused 0 Unpacking objects: 100% (49/49), done. Checking connectivity... done. Tapped 0 formulae (111 files, 472K)
とやると、勝手に tap してくれる。 引き続き、今 install している package を dump する。
% brew bundle dump
Brewfile
が作成されていることを確認する。ついでに中身もチェックしておく。
install path を決める
適当に決める。
Homebrew のインストール先を変更する - Qiita を見ると /opt/homebrew
とあるが、私は ~/.homebrew
とした。
理由はルートディレクトリのすぐ近くに、ユーザー固有の権限を持つディレクトリを掘りたくなかったから。/usr/local
の二の舞い感がする。
どうせユーザー固有の権限を持つディレクトリを掘るなら、ホームディレクトリでいいかなと考えた。本当に適当です。
決めたら先に path を通しておく。 一時的にとはいえ、brew を uninstall すると色々使えなくなるので、やっておくのが無難。
export PATH=$HOME/.homebrew/bin:$PATH
uninstall するその前に
zsh
homebrew で install した zsh を使っている場合は、shell が起動できなくて詰みそうになるので、デフォルトの shell を変えておく。
もし変更しないとターミナルが起動しなくなり、コマンドを打たせてもらえない。
(クリーンインストールをマジで考えた)
この場合は冷静に mac 標準のターミナルから起動する shell を指定し対処する。
Terminal - Mavericksにしたらターミナルが - Qiita
こういう状態にならないためにも、予め適当に変えておくと良いと思う
echo $SHELL # => /usr/local/bin/zsh なら homebrew で install した zsh を使っている chsh -s /bin/bash # デフォルトシェルを bash に変更
git
alias git="hub"
とやっているそこの君! 安易の homwebrew を uninstall すると、git clone
すらできないので、気をつけよう。
% cd ~ && git clone https://github.com/Homebrew/homebrew.git .homebrew zsh: command not found: hub _direnv_hook:1: command not found: direnv
uninstall
ようやく homebrew を消し去る。 homebrew/FAQ.md at master · Homebrew/homebrew に方法が書いてある。
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)"
勿論いきなりこれを実行するのではなく、curl 先の ruby スクリプトを念のため読む。 良さそうだと思ったら、勇気を出して実行する。
/usr/local/bin/ /usr/local/etc/ /usr/local/lib/ /usr/local/share/ /usr/local/var/ You may consider to remove them by yourself. You may want to restore /usr/local's original permissions sudo chmod 0755 /usr/local sudo chgrp wheel /usr/local _direnv_hook:1: command not found: direnv # direnv 様がお怒りに….
ゴミが残ってしまった。これは適当に掃除する。
(/usr/local
って 0755 だっけ...?)
再 install
消し去ったら homebrew を 再 install する。
ここで注意するのが、tarball を使った install を行わないこと。
homebrew/Installation.md at master · Homebrew/homebrew
tarball なので、.git
ディレクトリが含まれてないからです。.git
がないと、brew bundle
を install できない。
なので普通に clone する。
% cd ~ % /usr/bin/git clone https://github.com/Homebrew/homebrew.git .homebrew
ちゃんと install 先の path が変わっているか確認する
HOMEBREW_PREFIX
まわりを見れば良さそう。
% brew —config HOMEBREW_VERSION: 0.9.5 ORIGIN: https://github.com/Homebrew/homebrew.git HEAD: 8eda6f6417c09a03486353f1c4565bfd2bdbc84b Last commit: 13 minutes ago HOMEBREW_PREFIX: /Users/argerich/.homebrew HOMEBREW_REPOSITORY: /Users/argerich/.homebrew HOMEBREW_CELLAR: /Users/argerich/.homebrew/Cellar HOMEBREW_BOTTLE_DOMAIN: https://homebrew.bintray.com CPU: quad-core 64-bit haswell OS X: 10.11.2-x86_64 Xcode: 7.2 CLT: 7.2.0.0.1.1447826929 Clang: 7.0 build 700 X11: N/A System Ruby: 2.0.0-p645 Perl: /usr/bin/perl Python: /Users/argerich/.pyenv/shims/python => /Users/argerich Ruby: /usr/bin/ruby => /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby Java: N/A _direnv_hook:1: command not found: direnv
再度 brew bundle
Brewfile
が置かれているディレクトリに移動して以下を実行。
% brew bundle Succeeded in tapping benswift/extempore Succeeded in tapping caskroom/cask Succeeded in tapping homebrew/binary Succeeded in tapping homebrew/boneyard Succeeded in tapping homebrew/bundle ...
後は待つだけ。
まとめ
brew bundle
と組み合わせれば、sudo chown -R $(whoami):admin /usr/local
に屈しないで済む。
package を install すると環境がパワーアップして便利だけど、こういうぬるま湯に浸かってしまうと、イザという時に普段やってることが何もできなくて、とても困ることになる。
そういう時に備えて、せめて vi
は素で使えるように訓練したい(実際している)と常々思う。
幸い普段は emacs
使ってるので、vi
は何もカスタマイズせずとも普段の生活に支障はない。
みんなも emacs
使おう。
babelify7.0.2 で jsx の compile に失敗する件
現象
- babelify 7.0.2
- browserify 12.0.1
- react 0.14.1
var React = require('react'); var Container = React.createClass({ render: function() { <div>test</div> } }); React.render( <Container />, document.getElementById('container') );
% browserify -t babelify src/app.jsx -o build/bundle.js SyntaxError: /Users/horowitz/dev/poochie/src/app.jsx: Unexpected token (9:2) 7 | 8 | React.render( > 9 | <Container />, | ^ 10 | document.getElementById('container') 11 | ); 12 |
SyntaxError
になってしまう。
方法
2つほど。
1. babelify
の version 6.4.0
に戻す
戻すと上手く動いた。
世の中に出回ってる記事のサンプルも動く。
2. presets を指定する
要は追加のオプションを付ける必要があるとのこと。
コマンドラインから実行する場合は、以下のような感じ
npm install --save-dev babel-preset-react echo '{"presets":["react"]}' > .babelrc browserify -t babelify src/app.jsx -o build/bundle.js
gulp の場合は configure
から presets
を渡す
debug: true }) - .transform(babelify) + .transform(babelify.configure({ + presets: ["react"] + })) .bundle() .pipe(source('bundle.js')) .pipe(gulp.dest('build'));
関係ないけど es6
でコードを書いた場合は、babel-preset-es2015
の install と presets: ["es2015"]
の指定が必要になるみたい。
まとめ
js 初学者にはキツイお仕置きでした。
babelify7
から babel6
を内部で使っていて、babel6
から新しく option 付ける必要があるらしい、という雑な理解をしています。