モモンガ本でマークエディタを作ってみた
会社でVue.jsを勉強していて、「firebaseとかと連携してSSRみたいなサービスも作ってみたいんですよね〜」って話したら、モモンガ本っていうのがあると聞いて、休みの日を利用して作ってみた。vue.jsでドキュメントとか見ながら学習するのも、ちょっとずつ飽きてきてたのでちょうどよかった。
↓ こんな感じでスタイルとか雑で、色々できてないところもあるけど、googleログインによる認証機能とか、firebase raletime databaseを使ってメモの保存とかも最低限はできた。
#モモンガ本 1周読み切って見た目が整えてないけどマークダウンエディタを作れた!!あとはVueドキュメントとか見ながら、ちょっとずつ良くしてVueの知識を増やしていきたい所存。 pic.twitter.com/NqjVnH7EN1
— kamelo151515 (@kamelo151515) 2018年7月15日
ドキュメントの復習にもなったし、ちょうど課題問題みたいなのも入って勉強になりそう。仕事終わりはコイツを育てつつVue.jsの勉強を進めて行きたい。
Rubyのsuperキーワード
よく親クラスを継承したサブクラス内のメソッドで、superを使っている。用途としては親クラスにある同名のメソッドを呼び出すためのキーワードなのだけど、Rubyを触り始めて間もない自分にはなんだか見た時に「なんだっけ」ってなるので、備忘録して用途など残しておいた。
superキーワードは親クラスの同名メソッドを呼び出す(オーバーライドされてる)
class Dog attr_reader :name def initialize(name) @name = name end end class Bulldog < Dog attr_reader :sex def initialize(name, sex) super(name, sex) @sex = sex end end instance = Bulldog.new('ブルちゃん', 'オス') instance.name #=> "ブルちゃん" instance.sex #=> "オス"
こんな感じで同名のメソッド(ここではinitialize)の親クラスを呼び出す事が可能(もうちょいい言うと、オーバーライドしているメソッドで親クラスのメソッドを呼ぶって言ったほうが正しいのかも)。もちろん、メソッド名が違ったら、superが親クラスから同盟メソッドを探し出せなくてエラーになる。
結構このsuper
というキーワードに親クラスの処理が入っているので、最初見た時に「何だこれ?なにをしてるんだ??」って面食らう時が個人的に多かった。最近は慣れてきて、「あー親クラスの処理をcallしてるんだな。詳しくは親クラスを見ろってことか」となり、親クラスの調査をしだすようになれた。
今回の場合、親クラス(Dog)のinitializeメソッド
と子クラス(BullDog)のinitializeメソッド
が引数が異なるので、super(name, sex)
とキーワードに引数を渡す必要あった。
しかし、親と子の引数が同じ個数なら、super
と引数無しで書けば、親のinitializeが呼び出される。つまり、super
とだけ書いてあったら、メソッド名と引数の個数が同じ親クラスのメソッドが呼ばれとんのやなと覚えておく。これも慣れるまで個人的にちょっと時間がかかった。
...省略... class Bulldog < Dog attr_reader :sex # これでclass Dogのinitializeが呼ばれる。 def initialize(name) super end end instance = Bulldog.new('ブルちゃん') instance.name #=> "ブルちゃん"
※ あと、子クラスにattr_reader :name, :sex
って書かなくていいのか?と思うかもしれないが、親クラスで定義しているので不要。これは継承が関連してると思う。
super()は引数無しで親クラスを呼ぶ
super()
と呼ぶと、親クラスの同名メソッドを引数なしで呼び出すことになる。
多分、これはほとんど使う機会がない気がするのだけど一応メモ。
追記 こちらの記事の「super vs super()」に、親クラスの引数は引き継ぎたくない時に使えるかも。 (話逸れるけど、この記事の翻訳元の最初の章のコード、あまり良くない気がした。親クラスと子クラスの処理が変わらなければ、そもそも子クラスにsuperとかメソッドの再定義をする必要がない。チェリー本 p.243を参照すればわかる)
追記2
最近知ったイディオム何だけど、Rspecでletやsubjectオブジェクトの中身を「ちょっとこのexampleでは変えたい」って時に、super()
を便利そうだった
# 引用元:http://rspec.info/blog/2013/02/rspec-2-13-is-released/ describe Array do let(:numbers) { [1, 2, 3, 4] } context "when evens are filtered out" do let(:numbers) { super().reject(&:even?) } end end
super.tap{}
のイディオムが便利そう
superというよりtapメソッドを利用したイディオムだと思うので、少し表題とは逸れる気がするけれど、gemのコードを読んでる時によく見るイディオムがあった。便利そう。
さっき言った方にsuperはスーパークラスの同名のメソッドを呼び出す際に使うが、それを呼び出した返り値を色々いじりたいという時に、tapを使うと「あ、superで返ってきた値をいじってるんだな。。。」とわかりやすいコードになるかも。
class Hoge def hoge 1 + 1 end end class Fuga < Hoge def hoge super.tap do |result| @result = result + 1 end puts @result end end fuga = Fuga.new fuga.hoge # => 3
(あんまりいい例じゃないけど).tap
を使わないときはsuperで返した値をなにか変数にいれるかして、色々処理を書かないといけないけど、このtapを使えば、superを入れておくローカル変数を減らすこともできるし、tap内にsuperの返り値を変更する処理をまとめることができて少しコードの見通しが良くなる効果もありそう。「あーsuperで返ってきた値変更したいな〜」って時に便利。
参考文献
- チェリー本 p.242
- Ruby:
super
キーワードの4つの側面(翻訳) - 参考URL1
- 参考URL2
- 参考URL3
開発中にいろいろ思い込みが激しいのをどうにかしたい
開発してるときに、とある機能やライブラリなどを調査して、「なるほど!〜〜になってるから、〜〜みたいに実装すれば良さそう!」とかなって、いざ開発してみると「あれ??動かない。。。なんで。。。〜〜の通りにやってるのに!」とか、「〜〜してるんだから間違いないはず」って結構思い込むことがある。 これで時間食って、改めてよく見てみると単純な間違いに気づく。疑問を常に持って、よく見れば回避できそうなのに。。。
で、最近この類の問題から脱却しようと思って以下を実践している。
「本当か??」と自問自答を3回〜5回唱える
とある実装をして満足せずに、一旦やり終えたら自分のやったことが間違ってないか?おかしな勘違いをしていないか自問自答するのだ。「ほんまか?」と口にだすのも良さそう。
勝手な印象だけど、いままで会ってきた出来る先輩エンジニアの方々の行動に目を向けてみると、「ほんとか?」っと口に出したりして、自分の行いを再確認しているパターンが多い。実装や頭の中の再整理にもなるし、個人的に開発の良い習慣になっている気がするので続けていきたい。
Vueチュートリアル 3日目
https://jp.vuejs.org/v2/guide/components-registration.html
- コンポネントの登録
- 復習:コンポネントは名前付きで再利用可能なvueインスタンス
- そのまま
Vue.component({...})
とかするとグローバルなインスタンスの登録になる。しかし、グローバルだとwebpackなどのバンドラーみたいな機能を使っている時に使わない場面で余計にインスタンスを読み込んじゃうみたいなことが起きるのでよろしくない。 - グローバルではなくローカル登録を心掛ける。こんな感じ
- ちなみにcomponentの命名はキャメルケースでも、パスカルケースでもどちらでもいいけど、パスカルケースで書くと、実際にcomponentを使うときキャメルとパスカルどちらでも使えるようになる。まあ迷うから基本的にキャメルケースに統一したほうが良いと思うけど。
- ローカル登録されたコンポーネントは、他のサブコンポーネント内で使用できない。。。らしい。
var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA }, // ... }
- モジュールシステムもある(小並感)。
https://jp.vuejs.org/v2/guide/components-props.html
- propsはキャメルケースで書いて、実際に使用するときはケバブケース。
Vue.component('blog-post', { // camelCase in JavaScript props: ['postTitle'], template: '<h3>{{ postTitle }}</h3>' }) <!-- kebab-case in HTML --> <blog-post post-title="hello!"></blog-post>
- prop validation 超便利そう。defaultとかrequiredとか型バリデーションとかカスタムバリデーターみたいなのとか。
- passing static
<sample title='hoge'></sample>
- dynamic props
<sample v-bind:title='post.title'></sample>
もしくは<sample v-bind:title="post.title + 'by' + post.author.name"></sample>
。こんな感じで文字列連結みたいにもかける。 - one-way data flowの英語がよくわからない、、、??
- prop validationは、componentインスタンスを作る前にバリデーションをする。そのため、dataとかcomputedみたいなインスタンスオプション内では
default
とvalidator
関数は使えないことを覚えておこう。 - Non-Prop Attributesの節はメリットが良くわからなかった。和訳も上手くできなかった。また読み返す。
https://jp.vuejs.org/v2/guide/components-custom-events.html
- イベント名はケバブケース
やっとcomponentとかが使い方わかってきた気がする。 簡単なTODOアプリを作成しながら学んでいる最中。これをfirebaseとか連携すればちょっとしたTODOアプリは実使用できそうだけど、いかんせんfirebaseがまだわかってないのでそっちも勉強してみる所存。 PracticeVue/test/todo at master · kayawari/PracticeVue · GitHub
Vueチュートリアル 2日目
今日はイベントハンドリング〜コンポネントの基本まで行きました。
https://jp.vuejs.org/v2/guide/events.html
- イベントハンドリングは
v-on
ディレクティブ v-on:click='hoge'
みたいにかける。hogeの部分はメソッドでもいい。ちょっとした実行分も書けるけど冗長になるので基本的にメソッドに切り出すのが無難だと思う。$event
でDOMイベントを取れる。- イベント修飾子なるものが、非常に便利そうな匂いを醸し出しているけれど、まだよくわかっていない。あとイベント修飾子
passive
がまだよくわかっていない。 - キー修飾子もある。
- HTMLにこういうリスナを書くことはHTMLのテンプレートを眺めていれば「どういったイベントが発生するのか」わかりやすくなるという主張はなんとなく納得できた。
https://jp.vuejs.org/v2/guide/forms.html
- inputやtextareaみたいな入力内容のバインディングは
v-model
でできる。(勝手にv-input
とかが良いじゃないのか?なんでもmodelなんだ?と思ったけど、もっと勉強すればわかってくるのかな?) - textarea以外に、checkbox, selectboxなどにも使えて、valueをバインディングすることもできる。
- 修飾子
.lazy
は使えそう。 - あと地味に修飾子
number
とtrim
は、入力内容の余計な情報のトリミングに非常に役立ちそうな予感がした。
https://jp.vuejs.org/v2/guide/components.html
- componentの基本として、componentは名前付きの再利用可能なvueのインスタンスだということ。なので、hogeってcomponentを作って、一つのHTMLにhogeタグを3つ作ってもそれぞれ独立したインスタンスだということ。これは重要なことだと思う。そのhogeがなにかミュータブルな値を保持するコンポーネントだとして、インスタンスが別なので値を共有することはないということになる。
- dataには関数でなければいけない
Vue.componet('hoge', { data: function () { return { count: 0 } } })
dataオプションの中は関数でないといけない。
- componentは利用に当たりグローバルで登録するのと、ローカルで登録するの2種類がある。いままでの書き方はすべてグローバルな登録。
- componentはツリー構造になっている。
- 子のコンポネントに値を受け渡したいときはpropオプションを利用する。
- 単一ルート要素???
- イベントとメッセージは親のコンポネントに送ることができる。使いみちがぱっと思い浮かばなかったけど、リストをいっぺんに変更するとかそういう場面で使えそう。
- 親コンポネントにイベントを送出する場合は
$emit
メソッドがいいらしい。 - componentで
v-model
の使い方 - 動的コンポネント
- tableの中で使うtrみたいな特殊なケースで使われるタグ内でcomponentを使う場合は
is
を使う。
<table> <tr is="blog-post-row"></tr> </table>
こういったケースが関連しているのが、文字列テンプレート、単一ファイルコンポーネント、scriptタグ。。。。らしい。よくわかってない。
ここまでできたので、Todoアプリでも作りたい所存。
Vueチュートリアル 1日目
今日からVue.jsのチュートリアルを始めた。 一通り読んでいき、初見で思ったことや覚えておいたほうが良さそうなことをメモ書きとして書いておく。
進捗度合い
インストール〜リストレンダリングまで読み進めた。 最初のビルドが結構ごちゃごちゃしてて、頭の中で整理できてない感はあるけれど、とりあえず進めてみることにする。
メモ
https://jp.vuejs.org/v2/guide/index.html
- ユーザーインターフェイスを構築するプログレッシブフレームワーク
- 開発用ビルドと本番用ビルドなどビルド方法も幾つか存在するみたい
- 補足:CSPとか知っておくと良さそう。https://oxynotes.com/?p=8895
- reactive: 受身的な、待ちの姿勢。反応を示す、反応が早い、反応を起こしやすい。つまり、変更などにすぐに反応して反映しやすいってことらしい。
- 要素の属性の束縛(バインディング)
- directive:ディレクティブ、指令、命令
- テキストをデータに束縛できるだけではなく、DOMの構造にデータを束縛できる。
- interaction: 交流、ふれあい、やりとり、相互作用
- なるほど。データや捜査対象のDOMを束縛できるから、jsで設定も楽だし、ロジックの開発に集中できるメリットがありそう。
- 双方向バインディング
Vue Componentを上手く使えば、大規模アプリケーションにおいてコンポーネントを小さく分割でき、開発が行いやすくなる。 component使うと例えばこんな感じになりそう
<div id="app"> <app-nav></app-nav> <app-view> <app-sidebar></app-sidebar> <app-content></app-content> </app-view> </div>
一見、わけのわからないタグを使ってhtmlを書いているように見えるけど、各タグはvue componentで小さく分割されている。分割されたcomponentはこのようにコード量を大幅に削ったものになるらしい。 最初はウッとなりそうだけど、慣れればかなり見やすくなりそう。
https://jp.vuejs.org/v2/guide/instance.html
- 慣例として、 vm (ViewModel の略) を Vue インスタンスの変数名としてよく使っている。インスタンス名に迷ったら
vm
とかで良いかも。 - root vue instance
- とりあえず、「全ての Vue コンポーネントは Vue インスタンスで、同じオプションオブジェクトを受け入れる(いくつかのルート特有のオプションを除く)と理解しておけば十分」らしい
- vmインスタンスのdataプロパティは、インスタンスが作成したときにリアクティブになる。あとからインスタンス作成後にdataプロパティに、新規の値を追加しても、それはリアクティブな状態ではない。あとから追加するのがわかっているのなら、初期値を追加しておくべき。とのこと。
- Object.freeze()
- ユーザー定義のプロパティと区別するために、定義済みのプロパティやメソッドは、
$
が着いている。apiリファレンス - instance life cycle hook
- インスタンスプロパティとかコールバックでアロー関数を使うとエラーになるみたい。
created: () => console.log('hoge
)`みたいなのはだめみたい。
https://jp.vuejs.org/v2/guide/syntax.html
- render関数を利用してjsだけでHTMLを描画する方法もある。ただ基本的にはtemplateを使うのが推奨されているらしい。
- mustaches(2重中括弧)。ちなみに和訳は口ひげ
v-html
は生のHTMLを出力するためにあるが、XSS脆弱性に起因するので、基本的に使わないほうが良さそう。{{ 単一式 }}
はOKだけど、{{ 文 or 単一文 }}
は実行できない。OKなのは{{ 1+1 }}
とか。NGは{{ var a = 1 }}
みたいな式になるケース。ちょっとした単一式ならmustachesを使えそう。- ディレクティブ
https://jp.vuejs.org/v2/guide/computed.html
- テンプレート内にロジックを書くと複雑になるので、算出プロパティというのがある。インスタンス内の設定したdataに依存したロジック結果を出してくれて、
vm.hogeFuga
みたいにあプロパティとして呼び出せる。ドキュメントではgetter関数として利用すると書いている。 - 算出プロパティ。。。なんか和訳イケてない気が。computed property
- 算出プロパティは、普通のメソッド定義と違い、依存関係に基づいて結果をキャッシュしてくれる。
message が変わらない限りは、reversedMessage に何度アクセスしても、関数を再び実行することなく以前計算された結果を即時に返すということです。
- 算出プロパティじゃなくて、computed propertyと呼ぶ。。。
- computed propertyはキャッシュを意識したほうが良さそう。
- computed propertyはsetterもある!
- 多くの場合はcomputed propertyで事足りるけど、データの変更に合わせて非同期通信やコストの高い処理を使うときは
watchオプション
が良さそう。https://jp.vuejs.org/v2/api/#vm-watch
https://jp.vuejs.org/v2/guide/class-and-style.html
- クラスとスタイルも属性になるので、
v-bind
でバインディングすることができる。 v-bind:class
はハッシュみたいに渡せたり、computed propertyも渡せるし、配列で複数のプロパティを渡すことも可能- componetを利用するときは注意が必要で、例えば、componentのtemplateに
<p class="hoge"></p>
とかあったとして、そのcomponentを呼び出す先で<my-component class="{active: isActive}"></my-componet>
とかしたら、rootのhogeクラスも引き継いでくる。その要素上に存在するクラスを上書きするということはない。知っておいておいたほうがハマりが少ないかも。 - インラインスタイルのバインディングでやるときは
fontSize
みたいにキャメルケース。ハイフンで区切る宣言でもいいみたい。 - あと、自動プリフィックス機能もあるみたい。便利。まあ、もうベンダープリフィックスはオワコンではあるけど。
https://jp.vuejs.org/v2/guide/conditional.html
v-if
,v-else
,v-else-if
だけど、HTMLタグも間に入っているから、実際に使ったらすごい見づらそう。if内のHTMLとかが長かったら、「どこにelse句あるんだ??」ってなりそうと思った。- なんで、条件付きレンダリングの章で、説明されてるのかよくわからなかったけど、keyによる再利用可能な要素の制御ができるみたい。
- ??? => v-show はtemplate要素をサポートせず、v-else とも連動しないということに注意してください。
- v-ifは遅延描画 lazy renderingらしい。
- ディレクティブは優先度があるらしく、
v-for
はv-if
よりも優先度が高いみたい。CSSみたいだな
v-showとv-ifの使い分け
とても頻繁に何かを切り替える必要があれば v-show を選び、条件が実行時に変更することがほとんどない場合は、v-if を選びます。
うーん。日本語が理解しにくい。何となく分かるけど。
https://jp.vuejs.org/v2/guide/list.html
v-for
はindexもとれる
<li v-for="(item, index) in items"> {{ index }} - {{ item.message }} </li>
第2引数にindex値がくるみたい。これはrubyのeach_with_index
と同じじゃ。
* ハッシュだったら、keyとindex両方渡せるのか。
<div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div>
地味に便利じゃね?と思った。 * in-place patch戦略???
- インデックスでアイテムを直接設定しても、リアクティブにその要素の値を設定できない。でも
set
を使えばいける。 - 配列の長さを設定し直しても、リアクティブに長さを変更できない。でも
splice
を使えばいける。
var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // これをやっても、bがリアクティブにbにはならない vm.items.length = 2 // これをやっても、要素数がリアクティブに2個ならない vm.$set(vm.items, indexOfItem, newValue) // これなら行ける vm.items.splice(newLength) // これなら行ける
- 2.2.0 以降でcomponentでv-forを使う場合はkeyは必須みたいです。
- このリストレンダリングの章の最後に簡単なTODOアプリの基本が載っていて参考になりそう。
2018/06/20
雑多なアウトプット
- よくメソッド名や変数名を命名する時に迷うときがあるのだけど、先輩エンジニアが「命名に迷ったときは有名なサービスがどういった命名にしているのかgithubでみると参考になるよ」って言ってて、あ、確かに、、、。って思った。githubで雑に検索とかはしたりするときはあったけど、有名なサービスがどういった命名にしてるのか?ってのはなかったかも。railsだったら何のサービスが有名かな〜。。。
- ghqをローカルマシンに入れてみたけど、結構便利そう。。。という感じはしてるけど、まだ恩恵を理解してない。。。リポジトリ多くなったら管理しやすいのはいいけど、それくらい??他のgem-srcとかpecoとかと組み合わせると良さそうなので時間ある時に調べてみよう。
今日の反省点
- いまいちomniauthのstrategiesがよくわからず、見よう見まねで「これで動くんじゃね?」「これならどうだ??」ってエイヤでことを運んでいた感があり、もっと事前に調査とか考えをまとめてから手を動かすべきだった。結果、時間使いすぎで進捗だめです状態に陥っていたので、明日はもう少し時間を有効に使いたい。一旦手を動かさずに、ドキュメントや調査、相談の時間に当てて、明日を乗り切りたいところ。
今日の参考リンク
- 積み重ねをしていったブイブイ言わせるオッサんになりてぇ〜。面白い記事でした
- ghqを使ったローカルリポジトリの統一的・効率的な管理について - Kentaro Kuribayashi's blog
- マイ単語帳
どうでもいい日記
最近ライブラリのドキュメント読んだりするので、英語に触れる機会が多いのだけど、英語力。特に英単語力が乏しい気がしてならない。え、これなに?って英単語が出てくると毎回調べることが多いので、最近知らない単語に出会ったらweblio英単語帳に打ち込むようにしてる。英単語を入れたら自動で和訳も出てくるし、独自に和訳編集もできる。 DMM英会話とかでも英語力身につくかなとも考えたけれど、喋れるというより、まずは今より少しでもスムーズに英語ドキュメントが読めるようになりたいというのが目的なので、まずは喋る力・書く力よりも、読む力を鍛えるべきかなと思い、こんな対策をとっている。次は英語でstackoverflowとかOSSに質問とかかけたら良いと思っているので書く力を伸ばしたいな〜。それでその2つを土台に喋る力を鍛え始めるという感じ。もうちょい良いプラクティスがあるか調べておくのも良いかもな〜。