プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

小学校では距離の単位は時速らしい

 この時期になると必ずでてくる風物詩の小学校かけ算順序問題。4個ずつ5人に配るというのは

4×5 = 20

であり、

5×4 = 20

は間違いだと言うことだ。これは

4[個]×5[人] = 20[個]
5[人]×4[個] = 20[人]

となるからだそうだ。非常に面白いと思う。
 ここで重要なのは、被乗数では個や人が単位として認められているのに、乗数の単位は認められないという点だ。もしくは、被乗数の単位は自動的に乗数の単位で割られた単位が設定されるとも定義出来る。つまり、

4[個]×5[時間] = 20[個]
4[個]×5[/個] = 20[個]

これが正解だ。それが小学校教育の定義なのだから、それはそれで問題ない。そういう系なのだ。
 すなわち、小学校では時速20kmで2時間走る距離は

20[km/h] × 2[h] = 40[km/h]

だ。時速20kmで2時間かかる距離は時速40kmだ。
 それが、間違いだのどうのこうのではなく、そういう定義の系なのだから、そうなのだ。行列は何故可換ではないのか?そうなる乗算の定義の系だからだ。「1+1=0」は何故なのか?0,1の集合が和に関して群の系だからだ。それに従えと言うだけだ。

 

問題の本質は何なのか?

 この問題を批判する方、擁護する方、ともに大きな勘違いをしている、いや、前提とすべき事を見ようとしていない気がするのだ。

 まず、学校教育は何の為にあるのか?これは紛うことなく、未来の日本人の育成である。では、未来の日本人とはどのような人物が求められているのか?
 誰も口にしようとしないが、日本教育において、「目上(先生)に従順な奴隷」が求められる人物像であろう。個性などはいらないし、極端に優秀な人材もいらない。村八分。日本社会はそういう社会だ。
 最低限の国語と英語が出来れば、後は従順な奴隷であればあるほどよい。何も考えない無能な人間であればある程、素晴らしい。逆に支配層の人間は自分たちで教育を施せるから、学校教育に頼る必要はない。従って、それを問題にする必要がない。残念なことに、それが日本教育だと思う。

 私も小学生の頃、「1-2はどうなるか?」と当てられて「-1」と答えたら、「何言ってんだ?」と返された。答えは計算出来ないであった。記憶力の悪い私が未だに覚えている小学校1年生の頃の記憶だ。非常に不満に思ったのを覚えている。
 だが、大人になった今は、教師が正しかったと分かる。

 数学的に言えば、「1-2」が「-1」になるには、少なくとも対象とする系において、-1が定義されていないといけない。自然数の世界だけの話ならば、「-1」は存在しない。あの時、問題は自然数の範囲だけだという前置きがあったかどうかの記憶は無いが、小学校において、自然数と0ぐらいの世界しか存在しないという前提があるのならば、数学的に私が間違っている。
 そして、何よりも最大の間違いは、「教師がその答えを求めていなかった」点だ。教師が求めていないことを答えれば、当然それは間違いだ。教師が赤を黄色と言えば、その教師の前では赤を黄色と答えるのが正しいのだ。

 

 かけ算順序の問題も、教師がそのように書かなければいけないと思っているのならば、そういう系で教えているのならば、当たり前だが、それに従わなければ間違いだ。
 落ちこぼれる生徒も、浮きこぼれる生徒も、問題は学力ではなく、教師の思惑の外に出るから駄目なのだ。

 さて、問題の本質はかけ算の順序なのだろうか。

初心者がプログラムの設計を出来ない理由を考えてみた

 初心者がプログラムを書く上で、何をすれば良いのか全く分からない、全部分からない。分からないことが分からない。

 幸か不幸か、そういう感覚が私にはさっぱり分かりません。「何をすれば良いのか分からない」というところで詰まった記憶が特にありません。自分は初心者のときに懇切丁寧に教えてもらったことを忘れて、いざ逆の立場になったらそういうのは、記憶力か人格が悪すぎると言われましたが、そもそも私のプログラミングは全て独学で、入門時に誰かに教えてもらったことは一度もありません。(だって、聞く相手がいなかったし。むろん、多くの書籍にはお世話になりました。)

 

 無論、数々分からん事にぶつかり、中には結局全く分からなくて諦めた物も多々あります。「分からないことがある」ということが分からない訳ではありません。

 

 だが、私のぶつかってきた「全く分からない」とどうも違う。彼らの「全部分からない」が分からない。
 彼らが何故躓き、堂々巡りしているのか共感をしてあげられない。寧ろ、全部答えを教えろと、ただ口を開けて待っている様にしか見えなくて、腹が立ってしまいます。
 

 共感することが出来ないなら、解析するしかない。というわけで、色々と考えてみたことを書いてみようかと。

 

初心者とは

 単に初心者といっても幅は広いですね。
 プログラムのプの字も知らない、スマホは知ってるけどPCは触ったことがない、他の言語を知ってるけどこの言語やライブラリは知らない、etc………

 ここでは、最低限の学習は終えたレベルの初心者とします。

  • ifなどの制御構文は使える
  • 変数、配列は分かる
  • 関数は怪しいけど、使える
  • 構造体、ポインタなどは使えない。オブジェクト指向?何それ美味しいの

 

 具体的にはFizzBuzzなどの簡単な物なら自力で作れるし、数百行程度のプログラムなら詳細な実装仕様を与えれば、動く物が作れるが、機能仕様だけでは途端に手足が出ない。

 すなわち、プログラムは書けるが、プログラムの設計が出来ない人を、この記事では初心者と呼びます。

 

分からない5つの理由

 あれこれ考えた結果、私が最終的に辿り着いた「分からない理由」は以下の5つです。

  1. いつでも常に受け身
  2. 考える気が無い 考察が甘い
  3. 「上手く書けない=出来ない」と思っている
  4. 処理を分割し、まとめ、再構築することが出来ない
  5. 教える人間の人格問題

1:いつでも常に受け身


 学習や仕事とは常に「誰かに」「懇切丁寧に」「教えてもらう」ものと思っている可能性があります。誰かに教えてもらっていないものは、「未来永劫知る必要の無いもの」とすら思っているかも知れません。

 常に受け身な人は教えた以上のことは絶対に学びませんから、教えた以上のことは解決出来ません。
 そして、プログラミングは課題を解決する「手段」であって、「解決」そのものではありません。

 従って、受け身である人はいくらプログラミングを最低限覚えようと、何一つ解決が出来ない、という事態になるのではないかと。

 別の言葉で言い換えるなら、具体的思考しか出来ないタイプの人であるともいえるでしょう。

 ただ、これで完結してしまっては何の意味も無いので、正直この結論は無価値な知見でしょう。

2:考える気が無い 考察が甘い

 受け身の話とも被ると思いますが、殆どの場合、考える気が無いんじゃないかと思います。

 プログラムに限らず、詳細な手順書、つまりマニュアルさえあれば、殆どの部分はただの単純作業になります。特に初心者の頃に作る物なんて、完全に単純作業。故に「プログラミング」=「何も考えなくても良い」と思っているんじゃないかと。とにかく、流れで手を動かせば、何とかなる。

 しかし、設計をするには、目的とする物を「理解」し、「分解」し、抽象的にまとめる「再構築」という、思考を経なければいけません。設計とは真に錬金術だ。

 そういう、頭を使う必要性に不快感を感じているかも知れません。

 

理解する気が無い

 最初の行程である「理解」をするには、必ず自分で勉強をする必要があります。理解の為の勉強は、主に以下の4つの行程からなります。

  • 対象の基礎知識を身につける
  • 資料を探す
  • 資料を読む
  • 調べたことを試す

 以上のことをしていない場合、理解する気が無いか、理解する方法を知らないかのどちらかだと思います。特に読むのを嫌がる、試すのを嫌がる、後回しにしようとする場合、理解する気が無いと断定して良いと思います。

 理解を後回しにして分解、再構築など出来ません。にもかかわらず、後回ししているのなら、本人的には考えてるつもりでも、結果的に何も考えていない様にしか見えないでしょう。

 

基礎知識の身につけ方を知らない可能性

 理解における「基礎知識を身につける」が一番重要で、一番疎かにしたくなります。だって面倒くさいからね。基礎とかどうでも良いから、表面だけなぞって何となくできれば一番楽だもんね。

 とやかく言う私も、本日、理解する気が無かったから失敗したばっかですし。アプリケーションのほんの一部だけ使いたいんだけどってノリで何も基礎知識なくやったら、大失敗したぜぇ。
 いやー、危うく環境ぶっ壊すところだったお( ^ω^)

 

 一方で、私の様に明確に悪意があってサボっている訳ではない場合、基礎知識の会得手段を知らない可能性があります。具体的に言うと、全体を把握する前に詳細を把握しようとする。小事に拘って、大事を見ていません。

 日本語の文章を読む書く、英語、歴史の勉強、数学の勉強、何でもそうですが、最初にざっと全体概要を把握するのが一番重要です。それがなければ、ただひたすら荒野の中を進む様な物。全体像が分からないから、一つ分からないと、自分が何処の位置で蹴躓いたのかも分からない。分からないことが分からない。そうなるのではないかと。
 

 ただ、全体をざっと把握するのに、かなりの量の基礎知識が必要である課題を与えていないかどうかには、注意しなければならないでしょう。そもそも、全体をざっと把握する為の良い資料が、どこにもない場合もあります。
 そんな課題を放り投げている場合は、少し時期尚早かも知れません。


 学校の教育論になってしまいますが、日本の教育は全体を把握する教育に非常に弱い気がします。国語とか英語とか、馬鹿みてぇに文章をみんなで一行一行声に出して読ませて、数学は阿呆みてぇに一行一行式を追って。
 そのくせ、昔塾講やってた時の経験ですが、文盲ではないけど日本語がまともに読めない子、式を一行一行展開出来ない子を量産してるんですよねぇ。不思議だ。
  

Google力が足りない

 BingでもYahoo!でも百度でも何でも構いませんが、基礎知識を身につける、調べる際、検索力が低い所為で進捗が遅い可能性があります。

 検索力が低い理由は主に以下の二つがあげられるでしょう。

  • 読解力が低い
  • 検索(Google)力が低い

 

 単に読解力が低いと言っても、文盲でないのに文章が正しく理解出来ないレベルの人(機能的非識字)は、もう、ほっとくしかないです。
 塾講でもこういう子は一番苦労しました。何度言っても、何度声に出して読ませても、自力で問題の文章を読むことが出来ず、トンチンカンなことをし始めます。しかも、本人は読めてるつもりなので、本当にどうしようもないです。
 あなたが教師でもないのなら、放棄するのが一番です。

 

 文章は読めるが、情報を抜き出す力(情報リテラシー)が弱い場合、ページに答えが書いてあっても、彼らが求める状況や答えと100%一致していないなら、求める答えではないと判断するようです。
 100%一致する答えが出てくる可能性は低いことを理解させ、出てきた情報から重要な情報を抜き出す力、抜き出した単語から更に検索をかけていく力などを養う必要があるでしょう。

 また、やたら一つのページに書いてあることに執着する傾向がある場合も注意しましょう。先生(ひとつのページ)が言っていることを絶対と信じ、それを忠実に実行しようとする真面目な良い子、悪く言えばマニュアル人間でしょうか。
 ですが、ネットの情報は高確率で間違っています。このページだって、書いてあることの殆どは真実はないです。殆どの情報は、個人がこう考え、個人がこう試してみて、こうだった、俺はこう思う、という情報達なのです。(無論、IPAなどの高確率で信用出来るサイトもありますが、それだって全てが真実ではありません。)間違っていなくても、情報が古い場合もあります。
 少なくとも二つ以上のページを参照し、実際に自分で確認してみることで初めて、情報は自分にとっての真実となる。このことをしっかり教えておく必要があるでしょう。

 

 検索能力が低い場合は、Googleセンセーの動きを理解させる必要があります。単語じゃなくて、文章で検索してたりしたら、ヤバいですね。他には、

  • 「-」を付加して検索するとどうなるか
  • 「site:」を付加して検索するとどうなるか
  • ここ一年以内の情報を得たい場合はどうするか
  • 絶対に含めたいキーワードがある場合はどうするか

この位を聞いてみて、答えられない様なら、Google力が足りません。まずはGoogleについてGoogleさせるところから始めましょう。

 

3:上手くないことが出来ないことだと思っている

 これは、結構な人が陥るパターンじゃないかなーと思います。私も時々陥ります。

 基本的に何事も上手くこなすというのは、スキルです。スキルはどうやっても一朝一夕には手に入らない。なのに、上手く出来ないことが全部が出来ないことだと思い込んでしまうと、手が止まってしまいます。

 

 例えばテニスなら、上達するには、実際に体を動かし、上手い人を参考にして何度も何度も糞なボールを打ち、何故自分が糞なのか考え、糞な部分を修正しつつ練習するしかありません。ボールが真っ直ぐ打てる様になるまで、ラケットは握らなかった人が居るでしょうか?

 プログラムも同じで、上手い人のコードを参考にして(コピペではない)、何度も糞コードを生産し、何故それが糞コードなのかを考え、リファクタリングをする。ごく一部の天才を除き、そうすることでしか、上達は無いと思います。

 そもそも、世に上手いプログラムを書ける人なんて一握りしか居ません。上手くない事なんて、気にする必要もない事です。常に、上手くあろうとする努力が重要なのです。


 私?便所以下のゲロ臭いコードを量産してますが何か?ヽ( ・∀・)ノ

 

一つ出来ないことがすべてが出来ないことだと思っている

 全体の中で、ほんの僅かな部分だけが出来ないことが、全部が出来ていないことだと思い、強いストレスを感じる人が居ます。おそらくは完璧主義なタイプか、潔癖症なのでしょう。

 しかし、開発とは紆余曲折あるもの。調子の良いところもあれば、悪いところもある。
 というか、すべてが上手くいった開発の方が稀でしょう。

 一つ出来ないことはすべてが出来ないことでは無いし、それで自信を無くすことも、ストレスを感じる必要もないということも教えてあげる必要があるかも知れません。
 それでもどうしても駄目という場合は、先ずは出来るところからでも手を付けさせて、中途半端に放置することを覚えさせるべきかも知れません。

 

知らないことと、できないことの区別が付いていない

 初心者は知識の絶対量が少ないので、出来ないことと、知らないことが全く同じになっている可能性があります。
 小さな事、特に具体的な実装方法を知らないことが、そのまますべてが出来ないことになっている可能性があります。

 しかし、現実問題として、知らないから出来ないとは限りません。

 設計をするのにまず最初に必要なのは、各ステップの詳細な記述ではなく、何となくの青写真です。
 風景画を描くのに、いきなり砂の一粒一粒から描き始めるでしょうか?普通、先ずは空と地面と山や大ざっぱな建物ぐらいのぼんやりした下絵から描き始めますよね。
 下絵を描いている時に、葉っぱの詳細な形や、岩の詳細の形なんて知りもしないでしょう。
 最終的にディティールを上げる際に、必要であればよく観察し、描き込めば良いのです。

 ぶっちゃけ、知らないことは必要になってから詳細に知るのでも遅くはないのです。

 

4:処理を分割し、まとめ、再構築することが出来ない

 設計をするには「理解」「分解」「再構築」が必要ですが、「分解」と「再構築」には、それぞれ異なる能力が必要です。

 プログラムを設計する際、何から手を出せば良いのか分からない場合、分解の段階で躓いている可能性が大きいです。

 

 先にも述べてますが、今回対象とする初心者は最低限のプログラミングを記述する能力があるとしています。FizzBuzz等は書けるのに、ちょっと複雑になったり、規模が大きくなると途端に何して良いか分からなくなります。

 そのままで分からないなら、分かる程度の大きさにまで、処理を分割すればいいだろう、と設計が出来る(と少なくとも思っている)側の人間は思います。しかし、そう言っても、彼らは首を捻るばかりで、それ以上は何もリアクションはありません。


 

 例として、「電話をすると、ピザが来る」システムについて考察するとしましょう。
 このシステムは最低限 「電話を受け取り、注文を受ける」、「ピザを焼く」、「ピザを届ける」という処理ぐらいには分割出来ると思います。しかし、彼らはそれをしない。

 彼らにとっては、「電話をすると、ピザが来る」がアトミックな処理であり、最小の処理単位なのです。従って、「電話をする」という行動から「ピザが来る」という結果までが、一意に、一発で、一つの関数で書けなければならない。
 しかし、現実問題として、電話からピザが来るまでに多くの工程があります。タイミングによっては、細かい条件が異なったり、エラーが起こることだってある訳です。電話をするという場面から、ピザが来るまで、一つ一つの処理を、一つ一つ確実に実装していくなんてあまりに遠すぎます。
 確かに、始めに何をすれば良いかすら、分からないという気持ちも理解出来ます。ゴールも分からないでしょう。

 

 そして、分からない理由を彼らはプログラミング能力に転嫁します。むろん、割込みとか、マルチスレッド、難しいアルゴリズムなど、高いプログラミング能力、経験が要求される問題が存在することは確かです。
 しかし、初心者に任せてもいい程度の課題なんて、FizzBuzzが書けて関数が使えれば、ほぼ十分です。

 

 当初は「応用力」の低さなのかと考えていましたが、以下が足りないという結論に辿り着きました。

  • 観察力
  • 考察力
  • 説明力
  • 「データ」の概念

 

 設計に必要なのはプログラミングに関する深い知識ではなく、対象を観察し、それを考察して説明する能力です。
 日本語と図が書ければそれでいいのです。
 (もちろん、深い知識があればより良い設計が作れるし、場合によっては、言語機能やライブラリに設計が依存することは否定しません)

 

 きちんと分割ができているのか確認するには、処理について、今北産業で聞いてみましょう。
 3行というのはとても良いです。殆どの処理は、入力+処理+出力からなります。ピザの例も、3行に分けてますね。

 

 この段階で、「え~…と…………わかりません。」とか思考を放棄したり、「Aを作る………?」など、目的しか言えない様であれば、観察力、考察力が足りなすぎます。それ以前の基礎知識が全く足りていないのかも知れません。
 相手にとっても、そして、我々聞く側にとっても非常に辛いですが、心を鬼にして、考えさせて下さい。もしくは、考える仕事を与えることを諦めて下さい。

 なお、この分割の程度は個性なので、あまりに極端な分割でなければ、OKを出しましょう。我々の思っている答えが絶対ではありません。

 3行でまとめられず、長々説明しようとしたり、とにかく具体的なことを話す人は、ボトムアップ思考で、説明力が足りていません。簡単にまとめる、わかりやすく伝える力を養って下さい。

 3行になったら、①→②→③と紙に書き(1,2,3は三行の内容)、それぞれの項目を同様に細分化させる様に指示します。

 

 なお、初心者は手書きで考えさせるのが良いと思います。
 私なんかは面倒くさいので、ドキュメントだったり、作図ツール、JavaのInterfaceやC++のヘッダで考えてしまいます。が、ドキュメントを作る点に意識が行くと、脳のリソースが無駄に割かれるので、手書きが一番だと思います。

 どうでも良いけど、PythonとかはJavaのInterfaceとかC++のヘッダみたいに、枠だけ考えるってのが出来ないからすっげー嫌い。

 

データという概念の欠落

 観察、考察、説明をさせる前に注意したい点として、彼らには「データ」という概念がない可能性があります。

 

 ピザの例に戻しましょう。電話をしてからピザが手元に届くには、「注文(音声)」→「受注票(紙)」→「ピザと宅配先住所」→「ピザのみ」という風にデータが変化していく流れがあります。
 こういった、データが変化する場所は処理の大きな区切りになります。

 

 しかし、彼らは「手順」しか観察していません。「手順」しかない為、明確に処理を区切る場所の判断基準が少なくなります。ピザの例の様に具体的な事象ならまだしも、抽象的な処理の手順だけから、区切りを見つけるのは難しいでしょう。

 

 では、何故データを観察しないのか?
 無論、データを観察するという事を知らないから、というのが大部分の理由でしょう。
 しかし、もう一つ、無駄なデータが存在することが悪であると思っている可能性は無視出来ません。

 例えば、「受注票」は最終的な「ピザ」には存在しない、中間的なデータだと言えます。「ピザ」に「受注票」は存在しないのだから、そんなデータは無駄、悪だとなります。
 むろん、ピザの例は非常に具体的なので、彼らもすんなりと受け入れることでしょう。しかし、少し抽象的な内容になったらどうでしょうか?抽象的なデータの中間データを定義してみろというと、おそらく、「それはいらないのでは?」とか、「何の為に?」なんて聞いてくると思います。

 

 そういう場合は、そういう中間的なデータは普通に存在し、無駄ではない、悪ではないと言うことを理解させてあげる必要があると思います。

 

5:教える人間が人間落第

 この可能性は十分あります。てか、これが一番かも。
 世の中、相手が悪いと思った時、常に悪いのは自分です。騙された?騙された自分が悪い。覚えが悪い?教える自分が悪い。基本そうですよね。

 というわけで、クソニートなもんで、すんまそん。
 

終わりに

 あくまで、一切共感出来ない私が、私の経験や違和感、他人の記事を読んだ内容を統合し、解析した物です。
 解析したから、次どうするのよって話は、私も知りません。どうすりゃいいんでしょうね。
 

 てか、理解しようと努めてみましたが、結局本人ではないので、本当に何に躓いているのかなんてぶっちゃけ分かりません。本人も分からないなら、問題は完全に闇の中。
 プログラミングには向き不向きがあるから、能力よりも、根本的な思考パターン依存かもしれないし。

 

 いや、中々難しいね。と言うことで、以上です。(^^)/

JavaScript嫌いのES6入門~環境構築編~

この記事を書いてる人のレベル

 諸君 私はJavaScriptが嫌いだ
 諸君 私はJavaScriptが嫌いだ
 諸君 私はJavaScriptが大嫌いだ

 varが嫌いだ
 オーバーロードが無いのが嫌いだ
 prototypeが嫌いだ
 thisが嫌いだ
 整数型がないのが嫌いだ
 定数がないのが嫌いだ
 ファイルスコープがないのが嫌いだ
 ブロックスコープがないのが嫌いだ

 Chromeで IEで
 Firefoxで Opera最強伝説で
 Vivaldiで Edgeで

 この世界で行われるありとあらゆるJavaScriptが大嫌いだ

 以下略

 

 というわけで、私はかつてはJavaScriptが死ぬ程嫌い、いや、憎い頃もありました。
 しかし、海外勢の美しいソースコードに感化され、今では立派にJavaScriptが大嫌いです。

var value = "value";
var flag = false;
hoge();

function hoge(){
  if(flag){// ← flagはfalseなのでこのif文は無効
    var value = "hoge";
    console.log(value);
  }
  console.log(value);// ← 問題はここ
}

 これを実行して"value"と表示させるつもりが、"undefined"と表示されてファッΣ(゚Д゚;)とかなるレベルの人間です。


 これ、変数の巻き上げとか言うエラソーな名前付いてるらしいけど、ぶっちゃけ一番最初にインタプリタ作った人が、変数保持するハッシュマップをブロックレベルで管理するの面倒くさかっただけだろ。その怠慢な実装が仕様として現代まで残ってしまったと。Verilogのwireやregと同レベルの怠慢と思っています。C88以下だぞ。真実かどうかは知らないけども。

ES6では色々解決されたらしい

 ES2015やらなんやら呼び方が色々あるのか、何がES6なのかワカリマセンが(C++1xとかC++2xみたいなもの?)、letやconstが導入され、モジュールが追加されたことでファイルスコープも出来る様です。classだって作れるらしい。

 今までJavaScriptを使うこともなかったので、JavaScriptの知識はCoffeeScriptが出始めた頃で停止している。そんな人間の屑がちょっと個人的な理由でJavaScriptを触らないといけなくなったので、ついでにES6に入門してみました。


環境構築の段階で心折れそう

 さて、何はともあれ、環境構築からかな。JavaScriptなんて簡単簡単………

f:id:nodamushi:20170924190105p:plain


 あ゛ぁ゛ん゛!?


 え、何これ、今JavaScript界隈ってこんな面倒くさいことになってるの?これが素晴らしい!みたいな雰囲気だけど、みんな本気で言ってるの?JavaScriptってもっと、こう、お手軽で簡単な物じゃなかった?

 環境構築が面倒と言われるC++より酷い。ていうか、C++なんかVisualStudio入れれば動くし、アンチVisualStudioな場合でもMinGWとMakeとCMake入れりゃ十分だというのに。ていうか、MSYS2の上でだいたい全部すむのに。一昔前のTeXの環境構築を彷彿とさせるカオス。しかも、1年単位で言ってることがコロコロ変わってる。

 CoffeeScriptの時代より悪化してる様な気が………

 何かもう頭が痛くなってきましたが、ここで脱落してしまえばいつまで経ってもCoffeeScript良いよねっていう老害に終始してしまいます。一個ずつ紐解き、耐えねば。

 CoffeeScript2が出てたぞ!!私は老害じゃなかった!わはははは!

Node.jsとnpm

 どうも、Node.jsからは逃げることは不可能らしいです。正直、Webと関わりが無い私は、こやつが一体何者かもよく分かっていません。なので、コレがなんなのかもついでに学習してみました。

 JavaScript環境だとかサーバーがとか、IOがとか、あちこちでよーわからん説明がされていますが、個人的には

  • Node.js≒MSYS
  • npm  ≒pacman

という理解で決着しました。
 要するに、JavaScriptで作られ、JavaScriptが動くシェルみたいな環境。Emacsのeshellみたいな。正確には違うのでしょうが、個人的にはコレで納得出来たので良しとします。マサカリ飛んで来そう?ははは。全部避けてやる。

 Windows上でC++開発するならMSYSが必須(異論は認める)な様に、現代のJavaScriptを開発するなら、Node.jsという環境が必要なようです。

 元からCoffeeScriptのために入っていましたが、ついでなので最新版に更新しました。

package.json

 package.jsonがあるディレクトリから下が、プロジェクト管理下に置かれるらしい。つまりは、Eclipseの.projectファイルとか、CMakeLists.txtみたいなものかな。

 とりあえず、以下の様な内容を書いておきゃいいらしい。

{
  "name":"プロジェクト名",
  "version":"1.0.0",
  "scripts": {
     "run":"node main.jsとか、実際に実行させる際のコマンド"
      //ここにビルドコマンドとか、実行コマンドとか書くと、npm run ***でそのコマンドが実行される
  }
}

コンパイラ

 ES6を試したいのですが、現状はES6が完全に動く環境は存在しないらしい。なので、ES6のコードを現在の環境でも動く様に変換してくれるコンパイラが必要となる。それがbabelという物らしい。ただ、babelはexport、importの解析まではしないので、ブラウザでexport,importを使うことが出来ない。
 そこで、browserifyが登場する。これを使うと、export、importの関係を解析し、一つのファイルにまとめてくれるとのこと。

Name Description
babel-cli ES6を今のブラウザで動作する様に変換する
babel-preset-**** ES2015とかES2016とか、言語仕様が違うのか知らないけど、それに対応する為のライブラリっぽい?
.babelrc どのpresetを使用するのかとか、babel-cliの動作を設定するファイルらしい。package.jsonに書いてもいいらしい。
browserify import,exportを解析し、一つのファイルにする。最近はwebpack?
babelify browserifyとbabelの橋渡し機能

 つまり、C++でいうところ、babelがコンパイラで、browserifyがリンカーで、babelifyはパイプという理解でよろしいでしょうか。

 なんか、最近はbrowserifyは死亡してwebpackだとか、何だかもう知らねぇよ。理解したら書き換えるかも。

 調べていると、これらのパッケージはグローバルにインストール(npm install -g)しちゃいけないと書かれている場合もある。バージョンごとによって挙動が違うから、プロジェクトごとに管理した方が良いとのことらしい。Mavenとかのビルドプラグインのバージョン指定みたいな感じかな。

 babel-preset-***をインストールすることで、ES2015やES2016といったバージョンに対応できるようになる。それらが何の違いがあるのかは知らない。C++の-std=c++1xとか、-std=c++2xみたいなものだろう。私は面倒くさいからenvを使うことにした。各ブラウザのバージョンに対応したコードを出力出来るらしい。
 どのpresetを使うのかというのをbabelに知らせる為に、.babelrcに情報を記述するらしい。
 

npm install --save-dev babel-cli babel-preset-env browserify babelify


".babelrc"

{
  "presets": ["env"]
}

 --save-devで、前述のpackage.jsonにインストールしたパッケージの情報が書き込まれる。pomにdependencyとかbuildを自動で書いてくれる様な物と理解した。

 はー、これだけでもおなかいっぱいです。他にも圧縮だとか色々話題があるけど、にわかの私はここまでで良いです。

package.jsonにビルドコマンド追加

 前述した様に、scriptsにビルドコマンドなどを登録しておくと、npm run buildなどで実行できるようになるらしいので、ビルドコマンドを書いておきます。

 とりあえず、srcフォルダにJavaScriptを配置し、binに吐き出すことにします。

{
  "name": "hoge",
  "version": "1.0.0",
  "scripts": {
    "build": "browserify src/main.js -o bin/main.js -t babelify"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.6.0"
    "babelify": "^7.3.0",
    "browserify": "^14.4.0"
  }
}

 (devDependenciesはnpm install --save-devで勝手に追加された物です。)

 main.js以外にもhoge.jsなどが追加されたとしても、main.jsからそのhoge.jsがimportされている限り、browserifyがその関係を解析して勝手にコンパイルしてくれるみたいなので、基準ファイル一つを指定しておけば良いみたいです。


テスト環境

 ブラウザでしか動かない物はブラウザで試す必要があるけど、全部ブラウザで試すのは辛たん。JUnitテストとか、GoogleTestみたいなことがしたいです。
 というわけで、テスト環境について調べてみると、mochaというNode.js上で動くテスト環境がある様だ。mocha単体にはアサーション機能が無いので、chaiとか、別な物を利用するらしい。面倒くさいな。

npm install -g mocha 
npm install -g chai

 これはglobalなインストールで良いのだろうか? さっきまでの話の理解だと、-gを付けちゃ駄目な気がするのだが。………まぁ、いいや。

 で、globalなインストールをした場合は環境変数NODE_PATHにそのパスを通しておかないと、require出来ないらしい。
 というわけで、PowerShellで以下を実行。

$node_module = npm root -g
[Environment]::SetEnvironmentVariable("NODE_PATH", $node_module, [EnvironmentVariableTarget]::User)

 これで、mochaを実行すると、プロジェクトのtestディレクトリにあるJavaScriptファイルが実行されるっぽい。というわけで、pacakge.jsonにtestコマンドを追加した。Node.jsだとexportとimport構文にはまだ対応してないので、browserifyを同じように通している。これだとエラーが起こった時に、何処が原因なのかわかりにくいのが難点。いや、別に、Node.js標準のrequireで書いてもいいんだけどさ………ES6の勉強してるのに何か、負けた気分じゃん………。
 ※mochaでコンパイラが指定出来るらしい。Babel6でMochaとChaiを使ったテストを書く
 babel-coreをインストールしておく。

npm install --save-dev babel-core 
{
  "name": "hoge",
  "version": "1.0.0",
  "scripts": {
    "build": "browserify src/main.js -o bin/main.js -t babelify",
     "test": "mocha --compilers js:babel-register"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.0",
    "babel-preset-env": "^1.6.0"
    "babelify": "^7.3.0",
    "browserify": "^14.4.0"
  }
}

Gulp.js

 どうやらMakeとかCMakeとかの様な物らしい。スクリプト的に書けるから、Gradleが近いかな。

 にわかの私はpackage.jsonのscriptsで十分なので放置

Emacsの環境設定

package-installで以下をインストールして、init.elに設定追加。

  • js2-mode : 神Add-on Keysnailの作者id:mooz様が作ったJavaScriptモード。そろそろ神が死にそう。
  • js-doc : JavaScript用JavaDocを簡単に書く為のid:mooz様が作ったパッケージ
  • tern : company-ternで使う。
  • company-tern : JavaScript用のcompany backend。auto-completeな人は知らない。
(use-package tern)
(use-package company-tern
  :init
  (add-to-list 'company-backends'(company-tern :with company-dabbrev-code :with company-yasnippet)))

(use-package js2-mode
  :init
  (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
  (add-hook 'js2-mode-hook 'tern-mode))

(use-package js-doc
  :init
  (setq js-doc-author "nodamushi")
  (add-hook 'js2-mode-hook
            #'(lambda ()
                (define-key js2-mode-map (kbd "C-x i d") 'js-doc-insert-function-doc)
                (define-key js2-mode-map "@" 'js-doc-insert-tag))))

 ternを動かすには、Node.js上で動くJavaScript解析サーバーを別途インストールする必要がある。

npm install -g tern

テストを動かしてみる

 あぁ、パトラッシュ、僕はもう疲れたよ。もうゴールしてもいいよね?

 というわけで、ひとまず、テストを実行出来るのか試してみる。

"src/main.js"

/**
 * 二乗するだけ。
 * @param {number} x 
 * @returns {number} x*x
 */
export function test(x){
  return x*x;
}

"test/allTest.js"

const chai = require("chai");
const assert = chai.assert;

import {test} from '../src/main';

describe('src/main.js',()=>{
  describe('test',()=>{
    it('(0)',()=>{
      assert.strictEqual(0,test(0));
    });
    it('(10)',()=>{
      assert.strictEqual(100,test(10));
    });
    it('(-10)',()=>{
      assert.strictEqual(100,test(-10));
    });
  });
});

 で、以下を実行。

mkdir test
npm run test

f:id:nodamushi:20170924210857p:plain
npm run testの実行結果

感想

 はー、疲れた。今回はここまでです。………あれ、私まだ何も入門してなくない?

 なんというか、狂った異常な言語から、普通の言語にやっとES6でなったという感じなのに、その普通になる為にこんだけ苦労しないといけないのか………。
 やっぱ、JavaScriptが嫌いです。

直前の英字文字列をIMEで再変換するAIUEO Eclipse Plugin作った

 いよぅ!IME圏でEclipseを使っているみんな!nodamushiからのナイスクリームなプラグインをプレゼントだ!

 ………すいませんでした。現在深夜………というか明朝の5時、妙なテンションになりました。気がついたら徹夜だよ。


 さて、前回の記事でAtokの入力済みのローマ字を再変換する機能について触れました。
 ポップアップも消せるようになりましたし、とてもいい機能なんですが、最悪の欠点が2つあります。

  1. 本当に直前に入力した文字しか変換できない
  2. 変換確定後IMEがONになっている

 最初のはまだしも、2番目がプログラミングをする上でこの上なくウザい。画面割りたくなる。

 プログラミングで日本語(笑 とか言ってる意識高い(笑 人は放っておいて、基本的には日本語って以下の状況で使うと思います。

  1. コメント
  2. JavaDocなどのドキュメント
  3. テストメソッド名

 コメント書いてるときはまだいいんですが、JavaDocを書いてるときは@paramとか{@link ****}とか出てきて英語と日本語のチャンポンなのでIME切り替えが面倒くさい。テストメソッド名も、その後必ず()を書くわけで、IMEの切り替えが面倒くさい。

 というわけで、そんな不満を解消するためにAIUEOという名前のプラグイン作りました。名前が酷い。

 もし、既に似たようなのが存在してたら泣く。
 

インストール

利用可のなのはWindowsだけです。

Eclipseの新規ソフトウェアのインストールで「https://nodamushi.github.io/AIUEO」からインストール。

手動インストールが良い人はReleases · nodamushi/AIUEO · GitHubからzipをダウンロードし、dropinに展開する。


使ってはダメな人

 英数字、日本語の入力切り替えをIMEのON/OFF(半角/全角キー)ではなく、無変換・変換キーで行う人はインストールしないでください。仕組み上、対応できません。

機能と仕組み

あいうえおkakikukeko|sasisuseso

 oとsの間の|はカーソル位置だと思ってください。

1. カーソル位置から前方(もしくは後方)に区切り文字を探し、書き換え範囲を見つける。(設定で区切り文字は変えられます)
  1. oを読み取る。(区切り文字ではない) 
  2. kを読み取る。(区切り文字ではない)
    ………
  3. おを読み取る。区切り文字なので、その一つ前のkまでを 書き換え範囲とする
2. kakikukekoを削除する
3. IMEをオンにする
4. kakikukekoをキーボード入力する
5. スペースを入力する
6. IMEの変換が終了するまでイベント待機
7. IMEの変換終了イベントを受け取ると、IMEをoffにする

 つまり、完全にアナログなやり方を模倣してるだけです。もっといいやり方あるんだろうけど、いんだよ、出来りゃ。

使い方

 キーバインドはデフォルトではCtrl+;に「ローマ字を再変換する(前方)」を割り当てています。


f:id:nodamushi:20170723052222p:plain

 上↑の画像のような状態でCtrl+;を押すと、下↓の様にIMEで変換できます。

f:id:nodamushi:20170723052322p:plain

 変換完了後はIMEがOFFになります。

f:id:nodamushi:20170723052616p:plain

 「そー言えばこれは変換に失敗します」と打ちたかったのですが、初期設定だと、「そー」が変換されません。

f:id:nodamushi:20170723052649p:plain

 これは、-が区切り文字と見なされているからです。-も変換したい場合はこれを消してください。

f:id:nodamushi:20170723052755p:plain

f:id:nodamushi:20170723052908p:plain

JISキー以外のキーボードの方

 何とか根性でJIS以外のキーボード設定を作って下さい。なんとなく読めば分かると思う。
 ただ、一応くっつけたけど、nodamushiは全くテストしてないので(オイ 動くかは知らない。

ATOKの直前の入力を日本語にするをポップアップさせない方法

 ATOKの直前の入力を日本語にするっていう機能あんまり使わないけど、プログラミングで半角入力のまま日本語入力とか微妙に便利だったりします。
(とある理由で、私にはもう必要の無い機能になったのですが)

 でも、この機能を使っていると、ポップアップがこの上なくウザい。
f:id:nodamushi:20170717141603j:plain

 これを非表示にする方法を調べたのだけども、ググっても出てこなかったのだけど、何故かヘルプの方で検索すると出てきたので、ここでもメモ。

 "日本語入力オフのまま入力した文字を読みにする"というヘルプページに"●こんなときには"という項目に書いてあるのだが

読みへの復帰のキー操作を提示するツールチップを表示したくないときは、以下の手順で設定をオフにします。
1. ATOK プロパティを起動します。
2. [入力・変換]シートの[入力補助-特殊]を選択します。
3. [設定一覧]の[日本語入力オンへの切り替えを通知する]をオフにします。
4. [OK]をクリックします。

 とのこと。
f:id:nodamushi:20170717141845j:plain

 これで確かに出なくなりました。は~、ストレス元が一つ減った。

JUnit4でJMockitを使いつつ@Theoryを使う方法

 Javaのテストをするときに、JMockitMockitoなどのモックライブラリを使うことがあると思います。

 Mockitoはちょっとしたことをしたいときに便利なのですが、実デバイスのシミュレータなど、モックにかなり複雑な処理をさせたい場合は、JMockitの方が便利という印象です。


 で、このJMockitなのですが、JUnit4.5以上と共存させるには、@RunWith(JMockit.class)と指定する必要があります。これをしない場合は、ライブラリの読み込み順序の指定しないといけないので、めんどうくちゃい。@RunWith(JMockit.class)を使いたい。

 しかし、@Theoryを使うには@RunWith(Theories.class)とする必要があります。つまり、単純には共存できなくてどーしよ、となりました。

 え、JUnit5を使えと?いや、うん………、そりゃまそうなんだけどさぁ。キゾンコードノイコウメンドウクサイジャンカー.

Theoriesランナーを拡張する


 JMockitランナーって何やってるのさ、と覗いてみたら、なんと、BlockJUnit4ClassRunnerを拡張してstatic { Startup.initializeIfPossible(); }としてるだけだった。

jmockit1/JMockit.java at master · jmockit/jmockit1 · GitHub

 あれ?これってもしかして、Theoriesを拡張して、static { Startup.initializeIfPossible(); }するだけのランナー作ったらいけるんちゃう?とやってみたら、行けてしまった

package my.mockit;

import org.junit.runners.*;
import org.junit.runners.model.*;
import org.junit.experimental.theories.*;

import mockit.internal.startup.*;

public class TheoriesWithJMockit extends Theories
{
   static { Startup.initializeIfPossible(); }

   public TheoriesWithJMockit(Class<?> testClass) throws InitializationError
   {
      super(testClass);
   }
}

 これでクラスパスの順序とか気にせずに、JMockitでモックしまくりながら、Theoriesでクルクル回せるぜ!

 まだまだJUnit4も使えますなぁ。

 私がJUnit5に移行するのはいつになるのですかなぁ。
 とりあえず、Theories相当の拡張機能とかあれば移行するかなぁ。クラスで引数を選択してくれるのが好きなんだよな。
 TestFactoryも慣れれば行けるのか?

Eclipseプラグイン開発: 拡張ポイントの定義

Eclipse プラグイン開発 目次



 Eclipseプラグイン開発でほぼ確実に避けて通れないのが拡張ポイント。拡張ポイントはなんだかよく分からんけど、裏でEclipseが上手いこと処理して、何か素晴らしぃことをしてくれる仕組み………なんてふつくしぃ世界はなく、泥臭い処理がEclipseプラグイン開発者の手によって走らされております。

 拡張ポイントとは何なのか?それを理解するには、まず自分で一回作ってみるのが、何よりも一番手っ取り早くて確実です。他人が用意した拡張ポイントを使う前に、実装してみることをお勧めします。




拡張ポイントとは

 XMLとXML Schemaである。以上。解散。


 一切の冗談抜きにこれだけです。XMLは説明不要でしょう。HTMLによく似た奴です。XML SchemaはXMLに書ける要素(HTMLならdivとかaとかimgとか)を定義するファイルです。

 XMLとXML Schemaを手で書くのは流石にしんどいので、手打ちせずにGUIで設定できるエディタが提供されてるだけです。後は、Eclipse起動時にXMLを勝手に読み込んで、DOM(みたいなもの)にしてくれるぐらいです。

 じゃぁ、どうして拡張ポイントを他のプラグイン開発者が利用しただけで、色々な機能を拡張できるのでしょうか?それは当然、拡張ポイントを定義した人はシコシコXML解析するプログラムを作って、シコシコ解析した情報を自分のプラグインにゴリゴリ統合しているからです。

 決して謎の技術ではなく、裏でそういう血と涙と汗が流れている技術なのです。


 

拡張ポイントを定義する

 拡張ポイントをシコシコ解析する前に、シコシコ解析されるXMLを書くための定義を書かなくてはなりません。

 ここでは、例として「本」を定義する拡張ポイント「sample.core.books」を作ってみましょう。

 拡張ポイント(Extension Point)タブの追加から新規拡張ポイントを定義できます。

日本語化した場合:
f:id:nodamushi:20170414005600p:plain

英語の場合:
f:id:nodamushi:20181007014848p:plain
 

 今回の例では、次のような情報を持たせようと思います。

  1. 本はタイトルを持つ
  2. 本はユニークなISBNを持つ
  3. 本はカテゴリを持つ
  4. 本は一人以上の複数の著者からなる
  5. 本は1P以上のページからなる
  6. 本は複数の他の本への参照を持つ

 

要素の定義をする

 HTMLでは、<body><a><span><table><img>など、多くの要素を利用することが出来ます。HTMLの仕様によってこれらがHTMLの要素と定義されているからです。

 同じように、拡張ポイントで使用することができる要素を定義していきましょう。

 新規に拡張ポイントを定義すると、最初はextension要素しか定義されていません。このextension要素は、HTMLで言えば<html>要素と同じで、拡張ポイントのルート要素です。削除はできません。

 新規要素ボタンを押して、要素bookを作ってみましょう。

f:id:nodamushi:20170414005629p:plain

英語の場合(以下英語は略):
f:id:nodamushi:20181007015015p:plain


f:id:nodamushi:20170414005640p:plain

 同様に、author、page、reference要素を宣言しておきました。

f:id:nodamushi:20170414005651p:plain

 

属性の定義をする

 各要素は属性を持つことが出来ます。HTMLで言えば、<img src="image.png" alt="画像です" id ="myimg">とあった場合、srcやalt、idが属性です。

 属性にはuseとtypeを指定することが出来ます。

 

use

 例えば、imgタグのsrc属性が無かったら画像を表示することが出来ません。HTMLは解釈がゆるいのでなくても構いませんが、出来ることならユーザーに入力を強制したいものです。その指定をuseで決めます。

use 説明
require 必須で、必ず何らかの入力を要求する。
optional 値を書いても書かなくても許される。
default 初期値が最初から入力される。

 

type

 imgタグのsrc属性はファイルの場所を示す「文字列」、alt属性は画像が読めなかったときに表示する「文字列」といった風にそれぞれ入力する内容が決まっています。typeではどういった「文字列」を入力するのかの指定をします。

type 説明
string 文字列を入力させる。制限事項を使うことで、入力値をコンボボックスで選べる
boolean trueかfalseかのどちらかだけを指定できる文字列
java 特定のクラスのサブクラス、または特定のインターフェースの実装クラスだけを指定できる文字列
resource プラグイン内のリソースのパスを入力する支援ボタンがついた文字列
identifier 拡張ポイントの特定の要素の特定の要素と同じ値を入力する支援ボタンがついた文字列

 

 

 では、book、author、page、referenceに属性を定義してみましょう。

 bookには、title属性、isbn属性、category属性を設定しました。category属性は選択制で、デフォルトはとりあえず工口本にしておきました。

f:id:nodamushi:20170414005702p:plain

 拡張ポイントを使う側のエディタでは、bookの属性入力画面がこんな感じになります。

f:id:nodamushi:20170414005709p:plain

 

 authorにはname属性と、顔写真を載せるためにimage属性を追加しました。

f:id:nodamushi:20170414005717p:plain

 同様に、authorの属性入力画面はこんな感じです。imageにリソース選択ボタンが追加されます。

f:id:nodamushi:20170414005723p:plain

 

 pageにはnumber属性と、ページの内容を表すcontents属性を追加しました。contentsはダイナミックなコンテンツかも知れないので、プログラマブルに指定できるように、sample.core.IBookPageを実装したクラスとしました。

f:id:nodamushi:20170414005730p:plain

 入力画面では、contents属性をクリックすると、IBookPageを継承するクラスを作ることが出来たり、既に存在するIBookPageクラスを選択できるボタンが追加されます。

f:id:nodamushi:20170414005742p:plain

 

 referenceには、参照したい本のISBNを指定させることにします。

f:id:nodamushi:20170414005748p:plain

 入力画面では、既に定義されているbook要素のisbmの値を選べるボタンが追加されます。

f:id:nodamushi:20170414005754p:plain



要素の子要素を定義する

<table>
  <tr><td/></tr>
  <tr><td/></tr>
</table>

 上のHTMLのように、table要素の下にはtr要素を、tr要素の下にはtd要素を配置することが出来ます。

 拡張ポイントの要素も同様に子要素を持つように指定することが可能です。

choice (選択)

 正規表現的に書けば(A|B|C)になります。各要素は個数指定できるので、大ざっぱに書くと、(A*|B*|C*)*ですかね。要素A,B,Cが何個出てきても構わない、というときにchoiceを使うとよいです。

 

sequence (シーケンス)

 正規表現的に書けば(ABC)になります。各要素は個数指定できるので、大ざっぱに書けば、(A*B*C*)*ですかね。なお、完全に正規表現ではないので、AB*C*という指定にした場合も、ABCBCという入力を受け付けます。

 例えばtitle要素は必ず一つ、description要素は0または1、その他の要素は何個でもという様な場合はsequenceを使います。



 さぁ、それでは「sample.core.books」拡張ポイントを完成させてしまいましょう。拡張ポイント直下には「book」を1つ以上できるので、choiceを使って(book)+としました。なお、(book+)でも構わないっちゃ構わない。

 次に、bookには一人以上の著者、1P以上のページ、0個以上の他の本への参照を持つので、sequenceを用いて、(author)+(page)+(reference)*としました。(下図の左)

 エディタでは、下図の右のように要素を構成できます。

f:id:nodamushi:20170414005809p:plain



他の拡張ポイント定義を利用する


 よくスキーマを見ると、「スキーマの取り込み」という項目があります。スキーマは他のスキーマをインクルードすることが出来ます。

f:id:nodamushi:20170414005818p:plain

 

 インクルードすることで、他のファイルで定義した要素をそのまま再利用することが可能になります。

 といっても、この項目をそのまま使うことはまず無いでしょう。そんなに再利用したくなるほど、すゥンばらしィ定義ファイルを自分で作るなんて、普通ないでしょうし。でも、この追加ボタンで追加できるのは、自分で定義したファイルだけなのです。


 それではあまり意味がないので、折角なので、知っておくと非常に有用な要素を取り込んでみましょう。
 ある場面では、拡張を有効化したいけど、ある場面では無効化したいという場面は多いですよね。これは「org.eclipse.core.expressions.definitions」を別途定義してもらい、definitionsに指定したIDを受け取ることで実現可能です。しかし、定義を二個に分離するのも面倒ですね。definitionsで書く内容を我々の拡張ポイントに取り込んでみましょう。(取り込んだものを、Javaで実際にどうやって使うのかは次回説明します)

 まずは、必須プラグインに「org.eclipse.core.expressions」を追加します。

 次に、スキーマのエディタで、「ソース」を選択し、XMLの生ソースを表示します。

annotationの後ろあたりで良いので、次のincludeを追加して下さい。

<include schemaLocation=
  "schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>


 全体としてはこんな感じの場所です。schema直下だったらどこでも良いと思うけど。

f:id:nodamushi:20170414005827p:plain


 では、定義の画面に戻ってみましょう。bookのシーケンスを右クリックして、新規を選択すると、book,page,author,reference以外のadaptなど今回定義していない要素がずらっと並びます。

f:id:nodamushi:20170414005835p:plain


 この中からenablememtを選んで追加して下さい。


 さて、これで自分独自の拡張ポイントを定義することに成功しました。しかし、まだ定義しただけです。これを自分で解析する機構を作らなくてはなりません。

 というわけで、次回に続く。