わたしとVue 今すぐダウンロード
小粒なうぇっぶあぷりを作ってて、 Vue.js を使いたいなと思ってる(使ってる)
小さいしドキュメントも充実しているので、ちょっとガイド読めば使えるのであんまり把握せずに使ってるけど、それはよくないよねということでコード読むところから始めようと思う
読むのはこれ。
現時点の Latest release な 1.0.1 を読む
v-cloak
最初は v-cloak.
理由は特になくなんとなく、簡単にわかりそうだから
要素に付けておくと Vue オブジェクトのコンパイルが終わると消える属性で、コンパイルが完了する前にテンプレートが表示されてしまうのを防ぐために CSS と組み合わせて使ったりするやつ。
ファイルを見てみるとそのものずばりな src/directives/public/cloak.js というのがあるのでそこに目を通す。
予想通りわかりやすそう。
compiled というフックに 'v-cloak' という属性を削除する関数を登録しているように見える。
こっから少し掘り下げてみる。
bind
という名前で関数を export しているのはきっとそういう決まりかな。
src/directives/public 以下の他の js を見てみても、 bind
という関数を export していそうに見える
bind
が使われているところとかはもう少し後で見る。
cloak で src 以下を検索してみると該当するのはわずか。
cloak.js 自体と src/directives/public/index.js で cloak.js を require しているところ。
それとあと一箇所 src/directives.js で 'cloak' が使われてる。
https://github.com/vuejs/vue/blob/1.0.1/src/directive.js#L68L75
場所は Directive
というオブジェクトの _bind
関数
属性が 'v-cloak' でないか vm
がコンパイル済みだったら属性を消すという感じの処理。
descriptor.attr
ってのはなんなのかわからないが、'v-' なんとかの属性はどっかのタイミングで消すもののようだ。
その時に 'v-cloak' を先に消さないようにするための分岐っぽい。
そうすると vm
ってのはちゃんと見たほうがよさそうだな〜
Directive
から辿ってくと、 vm
はコンストラクタの第2引数なので、 new
してるところを見る。
src/intance/lifecycle.js で new
してる。
https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L111
_bindDir
の中で new
していて、第2引数は this
ここでの this
は exports
してる module
自体って理解でいいのかな
ということはこの lifecycle のオブジェクトなのか・・?
確かに、 _compile
という関数の中で this._isCompiled
という変数を設定しているようだ。
https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L68
さっき読んだところで this.vm._isCompiled
というのがあったからなんとなくあってそう。
https://github.com/vuejs/vue/blob/1.0.1/src/directive.js#L70
今読んだ範囲だと vm
を使っているところはあとひとつ、 $once
というのがあった。
しかし $once
を export しているのは src/api/events.js だなぁ。
vue/directive.js at 1.0.1 · vuejs/vue · GitHub
これは一体どういうことか。 lifecycle を require
しているところを見れば多分わかりそう。
https://github.com/vuejs/vue/blob/1.0.1/src/vue.js#L85L86
src/vue.js で require
している。
なるほど、 p
というオブジェクトに extend
していってるんだね。
確かに require('./api/events')
もしている。
ということは↑の vm
は p
オブジェクトで、 $once
も持っているんで理解正しそう。
$once
は予想通りな感じで、一回だけ関数が実行されるように登録された関数を実行したら登録を削除する処理を挟み込むようなもの。
さてじゃあ compiled という hook を呼んでるのはどこかな?と考えると、さっき compile っぽい関数あったよね。
はい、lifecycle.js
で、_isCompiled
の直後にあるね、 callHook('compiled')
https://github.com/vuejs/vue/blob/1.0.1/src/instance/lifecycle.js#L69
これだよこれ。
callHook
は src/instance/events.js で定義されている
https://github.com/vuejs/vue/blob/1.0.1/src/instance/events.js#L155L163
handlers
があればひたすら呼び出していて、 handlers
は this.$options
に hook ごとに登録されてる。
でもここまで handlers
というのは特に出てこなかったような気がする。
$emit
のほうが大事かな。
フックで実行する関数の登録処理は $once
あたりでやってるはず。
$once
を見ると、実際登録してるのは $on
っぽい。
https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L10L34
$on
は this._events
に関数を push
してる。
$emit
をみてみると
https://github.com/vuejs/vue/blob/1.0.1/src/api/events.js#L89L105
_event
に登録されているコールバックを apply
で呼び出してる。
ということで、ここで最初に読んだところで登録された 'v-cloak' 属性を削除するコールバックが呼ばれて、コンパイルが完了すると 'v-cloak' 属性が消えてくれるということだ。
多分。
とりあえずこんなところ。
なんとなく構造がわかってきたしその辺もまとめつつまた読む。
いつもこうなんとなく読み始めちゃうけど、最初に全体像を把握したりとか、あとコメントに色々書いてあるんでコメント読んだりとかちゃんとしたほうがいいな〜と反省する
macでターミナルの起動がめちゃくちゃ遅くなってた
最近家のmacのターミナルの起動が超遅くてストレスを感じてた
きっとzshrcにいろいろ書きまくっているからだろうとそろそろ治すか・・と思ってたら、どうもターミナルの起動時とかタブを新しく開いた時によく見てみると遅いのは login だった。
login が遅いで調べると asl を消すとか出てくる。
Speed Up a Slow Terminal by Clearing Log Files | OSXDaily
asl は Apple System Log ということらしい。
login 時に last login を表示するときにここを検索してるんでここが肥大化すると遅くなるとか。
システムログなんかいらない!(わけない)ということで早速 /var/log/asl
以下のログを消して再起動してみるけど改善せず。
他に方法はないものかと探してると俺しか使わないmacだし quiet に login すれば良さそう。
.hushlogin を置いておくとできるようだが touch ~/.hushlogin
しても変化なし
原因わからないのでこの辺は時間あるときにもうちょっと調べたいがとりあえずは iTerm の Profiles から起動時のコマンドをデフォルトの Login Shell (login -fp login -qfp <user>
と入れる
これで速くなったのでとりあえずしばらくこれでしのぐ
ハロー "Hello, World" がおもしろい
まだ3章までしか読んでないけど、『ハロー "Hello, World"』がおもしろい
最近はLinux Kernelのコード読んだりしてみたいな〜と思って読んだりしてたんだけど、やっぱ膨大なのでとっつきにくい。
そこでこんな本を見かけたものだから、"OSと標準ライブラリのシゴトとしくみ" ってのに惹かれて買ってみた。
はじめに、の部分を軽く読んで「手を動かして、調べかたを知る」とか、資料に頼るんじゃなくて手を動かして調べることを重視した本なんだということが書いてあっていいねーと思う
やっぱり自分で動かしながら動きを追ってみないと頭に入ってこないなーと思ってたので色々な角度から解析してる本とかとても魅力的。
というわけで読んでみると、僕のような素人にも優しい感じ。
親切親切
二章から GDB を使ってがんばって題名の Hello, World を解析していく。
GDB はあんまり使ったことがなかったけどまぁ本の通りにやっていけばなんとなく動かせる
disable とか知らなかったけど便利だ
ひたすら追いかけるのはどこでどうやって hello world って文字列が出力されるのかということ
それを知るためにステップ実行してアセンブリ読んでコード読んで、後は確かめるために文字列を出力している部分のバイナリをnopに書き換えてみて出力されなくなることを確認したり。
おもしろい!!
IO はカーネルがやるからシステムコールでカーネルに処理を頼むんだよなーとかそのくらいはわかってたつもりだし、CPUは動くときにレジスタ使ってどうこう、スタック使ってどうこうとかもなんとなーく知ってたけど、hello worldでそれが具体的にどう動いてるかと言われるとまぁよーわからんなーという程度の知識しかなかったんで、それを丹念に追っていくのは大変興味深い
システムコールに引数をどう渡すか、どう値を返すのか、エラーをどうセットするのか。
負の値を返せないのどうしてるのかとか、標準ライブラリの役割とか。
知らんことばかりでした
動かしながら学ぶとなんとなく納得感があっていい。
先が楽しみ
システムコールの定義
を読んでgrepしたり、http://lxr.free-electrons.com/ident?i= で検索してもなかなかシステムコールを定義してる箇所が見つからないなーと思ってたら、
SYSCALL_DEFINEx っていうマクロを使うようになってたのね。
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct fd f = fdget_pos(fd); ssize_t ret = -EBADF; if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_read(f.file, buf, count, &pos); if (ret >= 0) file_pos_write(f.file, pos); fdput_pos(f); } return ret; }
とか。
SYSCALL_DEFINEx 自体は include/linux/syscalls.h で
#define SYSCALL_DEFINE0(sname) \ SYSCALL_METADATA(_##sname, 0); \ asmlinkage long sys_##sname(void) ..(略).. #define SYSCALL_DEFINEx(x, sname, ...) \ SYSCALL_METADATA(sname, x, __VA_ARGS__) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__) #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ __attribute__((alias(__stringify(SyS##name)))); \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ __MAP(x,__SC_TEST,__VA_ARGS__); \ __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ return ret; \ } \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
とかで定義されてる。
rust で数値からenumに変換する
rustのenumを定数を列挙するためだけに使いたいということもありますね?(ないですか?)
そういう時、数値からenumに変換したいということがありますね?(ないですか?)
rustのenumはこんなふうに定義します。 rustのenumはだいぶ高機能なのでいろんなことができますが、今回は定数の列挙に使いたいという想定ですね。
enum TrafficLight{ Blue, Yellow, Red, }
このように定義するとデフォルトで0から数値がふられるので enum から数値に 変換することはできます。
fn main() { println!("{:?} = {}", TrafficLight::Blue, TrafficLight::Blue as i32); println!("{:?} = {}", TrafficLight::Yellow, TrafficLight::Yellow as i32); println!("{:?} = {}", TrafficLight::Red, TrafficLight::Red as i32); }
結果
$ cargo run Blue = 0 Yellow = 1 Red = 2
こうなります。
逆はできません。
$ cargo build src/main.rs:12:32: 12:49 error: non-scalar cast: `i32` as `TrafficLight` src/main.rs:12 let light : TrafficLight = 0 as TrafficLight; ^~~~~~~~~~~~~~~~~ error: aborting due to previous error Could not compile `light`. To learn more, run the command again with --verbose.
こうなります。
調べてみると以下がでてきますね。
書いてある通りに std::num::FromPrimitive
は削除されてしまいましたが、今は http://doc.rust-lang.org/num/num/index.html に同様な機能を持つものが入っています。
crateに頼ることになるのは遺憾ですが公式が提供してる(?)ものなのでまぁいいとしましょう。
これを使って FromPrimitive
という trait を実装すると
from_i64(n: i64) from_u64(n: u64) from_isize(n: isize) from_i8(n: i8) from_i16(n: i16) from_i32(n: i32) from_usize(n: usize) from_u8(n: u8) from_u16(n: u16) from_u32(n: u32) from_f32(n: f32) from_f64(n: f64)
これらが使えるようになるので、基本の数値型ならどれからでも変換できるようになります。
実装する必要があるのは、 from_i64
と from_u64
の2つです。
以下使い方
Cargo.toml に依存を追加しましょう
[dependencies] num = "*"
で実装してきます
extern crate num; use num::traits::FromPrimitive; impl FromPrimitive for TrafficLight { fn from_i64(n: i64) -> Option<TrafficLight> { match n { 0 => Some(TrafficLight::Blue), 1 => Some(TrafficLight::Yellow), 2 => Some(TrafficLight::Red), _ => None, } } fn from_u64(n: u64) -> Option<TrafficLight> { match n { 0 => Some(TrafficLight::Blue), 1 => Some(TrafficLight::Yellow), 2 => Some(TrafficLight::Red), _ => None, } } }
こうです。
このmatchあたりがめんどくさいのでなんとかしたいですね。いい方法があるといいんですが。
ここに数値を書かないといけないとなると網羅してるかもよくわからないし変更や追加に弱いしこれはなんとかしたいです。
(これのいい方法が知りたくてこんな記事をだらだら書いてると言っても過言ではありません。誰か教えてください。)
let blue = TrafficLight::from_i64(0 as i64).unwrap(); let yellow = TrafficLight::from_u8(1 as u8).unwrap(); let red = TrafficLight::from_usize(2 as usize).unwrap(); println!("{:?}", blue); println!("{:?}", yellow); println!("{:?}", red);
結果
$ cargo run Blue Yellow Red
できましたね
mixlib-cliのオプションで複数の値を渡す
mixlib-cli、便利ですよね。
この option
で同じオプションで複数の値を渡したい時はどうすればいいか
例えば --hosts
で複数のホストの情報を渡したいとか。
ぱっと調べた感じ&動作を見た感じでは、 cmd --hosts host1 --hosts host2
とかいう渡し方でうまく処理してくれるということはなさそう
:proc
オプションを使うとそれっぽくできる
:proc
オプションは、 Proc
を渡しておくと渡された値をその関数で前処理しておいてくれる。
options :hosts, :long => "--hosts", :proc => Proc.new { |a| a.split(",") }
↑のようにしておくと cmd --hosts host1,host2
で複数の値をカンマ区切りで渡せば、プログラム内で config[:hosts] = ["host1", "host2"]
として使える。
テーブルのカラムにないデータをEloquentのレスポンスに入れる
なんて言ったらいいかよくわからないけどタイトルみたいなことがしたいときどうするか
テーブルのデータそのものじゃなくてテーブルのデータから計算できるデータがあったとして、それをクライアントに計算させるんじゃなくてレスポンスに入れて返したいとかそんな時
普通にドキュメントに書いてあるけど、そういう時は Accessors と $appends
ってのを使うとできる
Accessors は↓これ。で、 appends については同じページの一番下に書いてある
Eloquent ORM - Laravel - The PHP Framework For Web Artisans
$appends
は Eloquent
を継承してるクラスのメンバ変数として定義しておく
class SomeModel extends Eloquent { protected $table = 'some_table'; protected $appends = array('some_append_data'); // ←これ // Accessors public getSomeAppendDataAttribute() { return "something"; } }
こうすると、 SomeModel::find($id)
とかで返ってくるデータに
"some_append_data" => "something"
も一緒に入ってくる。