konashi make-a-thonに参加してきた
6/1と昨日6/22の2日間、konashi make-a-thonに参加してきた。konashiを使ってiOSと連携するハードウェアをmakeするイベントだった。数人のチームに分かれてアイデアのブレーンストーミングから実際の開発まで行った。
一日目はワークショップ形式でたくさんのアイデアを出しまくった。その中から実装するアイデアを決めた。二日目までの3週間、僕はiOSアプリ担当ということで90%くらい完成させた。で、二日目にはハードウェアと筐体とkonashiを結合して、アプリから操作するところまでを確認し、微調整をした。で、できたのがこれ。
なにこの完成度ww
このコースターはグラスのビールが空になるとiOSにバイブで通知する。コースターには感圧センサーが入っていて、重さをkonashiを使ってbluetoothでiOSアプリに送信する。で、アプリ側で重さが一定値を超えるとバイブするようになっている。上司のグラスが空になったらアプリが教えてくれるので、飲み会の席でうまく立ち回れる。アプリのソースコードはGithubで公開しているので、konashiのサンプルコードとして参考にしてもらえるとうれしい。
感想としては、自分では思いもよらない面白いアイデアがどんどん出てきて面白かった。もっとこういう話をいろんな人としてみたいと思った。makeのための環境や技術はどんどん進歩していく一方で、相対的にmakeするもののアイデアが不足しているように感じていたところ、こういう機会に参加できたことはいい刺激になった。
あと、不特定多数が利用するデバイスを利用者それぞれにパーソナライズして利用できるようにするための手段としてスマホを捉えるのは、すごく興味深い応用範囲のひろい考え方だと思った。スマホには利用履歴や設定が保存されており、それを共用デバイスと通信することで共用デバイスをパーソナライズすることが可能、というのは考えたことなかった。コンビニで買い物するときいちいち「TSUTAYAカード持ってません」って言うの誰の得にもなってない気がする。TSUTAYA_CARD = false
みたいな設定をスマホに保存し、なんらかの形でコンビニと通信することでこの問題を解決したい。
ちょっと話が脱線したけど、どのチームも完成度が高くて面白かった。イベント終了後の懇親会では、言い知れぬ充実感とものづくりの喜びと今後のmakerムーブメントへの期待とでいい気分になった。よかった。
slide_template改めglideの今後について
LTのスライドつくるのだるい - naoty.to_sの続き。
"slide_template"という名前はあまりに味気なかったので"glide"という名前をつけた。"slide"に近い単語で、スムーズにスライドを作成できるイメージから名付けてみた。あと、ギタフリで好きな曲の名前でもある。
slide_template改めglideの今後の方向性と課題について考えてみた。glideが目指している方向性を端的に言うと「slide版のtwitter bootstrap」だと思う。すごく凝ったスライドをつくる人には向いてないけど、時間をかけずにそれなりにいい感じのスライドを作りたい人に向けたプロダクトにしていきたい。プログラマーがプログラミング以外のところで時間を奪われるのは社会的な損失だと思う。一方で、プログラマーによる勉強会は増えてる気がする。いちおう僕もEbisu.rbを月1で開催してたりする。勉強会が増えるとスライドを作成する時間も増える。勉強会自体はいいことだと思うけど、スライド作成に時間が奪われるのはよくないことだと思う。そこで、スライドを簡単に作成するフレームワークが必要だと思った。ここらへんがglideをつくるきっかけとなってる。
で、この方向性に沿って今後やっていくことは、以下のように考えてる。
- デフォルトのテーマを豊富にそろえる。今のところほとんどCSSがない状態なので、bootstrapみたいな感じでクラスを指定するだけでかっこいい感じのスライドになるようにしたい。
- スライドをPDF形式で出力できるようにする。htmlをアップするサーバーを持たない人はspeakerdeckとか使うと思うので、PDF化が必要。
- bowerに依存せずにセットアップできるようにする。デザイナーさんなどに協力をお願いするにあたって一番のネックは環境構築だと思う。今のところJSとCSSのセットアップにbowerを使っているけど、bowerはnodeとnpmが必要なので慣れてないときついかもしれない。なので、bower以外のセットアップ方法も用意する必要がある。
とりあえず3.を片付けてデザイナーさんと協力できる体制を整えて1.に取り掛かりたいと思ってる。2.についてはPDF用のCSSが必要っぽくて未知の領域なので、ここもやはりデザイナーさんに教えてもらいたいところ。
一人でできるレベルを超えてきた感じがしてきたので、まずはこうやってブログを書いてみることが大事だと思った。
LTのスライドつくるのだるい
Keynoteの使い方よくわからないし、なんでこんなものに数千円はらったのか意味がわからない。だいたい、マスタという概念はwebでいうCSSなんだからテキストファイルとして定義できるようにすればいいのに。そうすれば、githubとかで共有できるから、かっこいいスライドのマスタを再利用することができる。そういうところでLTのスライドつくるのがだるくなる。明らかな非効率性を目の前にするとまったく手が進まなくなる。
だるいことは自動化するのがプログラマの美徳なので、土日で自動化を試みた。
cloneして、content.md
というファイルにスライドの内容をmarkdownで書いて、rake
すればHTMLのスライドができる。cssでスライドを自由にデザインできる。面倒なGUIの操作をいちいち覚える必要はなくなった。cssということはそれを共有することで、感じのいいスライドを再利用できる。あの人のスライドで使ってるフォントをいちいち調べる必要もない。
こういうフレームワーク的なものは既にいくつかあって、最初はreveal.jsを使おうと思った。ただ、実際に使ってみると確かにかっこいいアニメーションがついていい感じなんだけど、いくつか不満な点があった。まず、海外で作られたデザインなので、日本語を使うと文字サイズや余白のバランスに違和感を感じる。で、カスタマイズしてみようと思ったんだけど、どこをいじっていいのかわからなかった。いや、これは僕のスキルに問題があるだけかもしれない。実際、sassを使ったりmixinを使ったり工夫がこらしてあった。でも、正直、ここまで複雑で凝ったものはいらなかった。なんでもそうだと思うけど、長く使っていくツールに必要なのは"カスタマイズしやすさ"だと思う。違和感を感じたときにすぐに修正できないとストレスがたまっていって、ずっと使っていくことができなくなる。カスタマイズしやすいツールに必要なのは、疎結合な設計だと思う。設定の変更が及ぼす影響をなるべく小さくしないと、恐ろしくてカスタマイズできない。
というわけでreveal.jsもよかったけど、もっと小さいライブラリを自作することにした。
上のテンプレではこのライブラリを使ってHTMLをスライドっぽくしている。これまでJSのライブラリ(というには小さくておこがましいけど)を作ったことがなかったので、yak-shavingをすることになった。まず生JSはイヤだったのでcoffeescriptで書くことにして、coffeescriptをJSにコンパイルするためにgruntを使った。コンパイルされたJSは自動的にminifyするようにした。ここらへんの環境構築については以下のエントリが参考になった。
昨今のWebアプリケーションのひな形その2 - Grunt - naoyaのはてなダイアリー
で、このライブラリをテンプレで使うためにbowerのレポジトリに登録することにした。これが思ったより簡単でbower.json
を決められたフォーマットで記述して
$ bower register haas.js git://github.com/naoty/haas.js.git
を実行するだけだった。
テンプレの話に戻ると、rakeタスク内でRedcarpetとTiltを使ってmarkdownやhamlをHTML化している。で、そのHTMLを上のhaas.jsでスライドっぽくすることで、なんとかスライドの体裁を整えることはできた。あとは、肝心のデザインをなんとかしなくちゃいけない。デザインについてはCSS難しいしできればどなたかにお願いしたいところではある。というか、それがこのテンプレをgithubで公開する目的なんだけど。
以上のような話を今度のebisu.rbで話すので、参加者の方はあんまり見ないようにお願いします(もう遅い
追記
ebisu.rbで話したので、上のテンプレで作ったスライドを公開します。
todoリストをwebに公開した話
自分が開発したいこと、勉強したいことをwebに公開した。
以前に書いた記事の通り、ここ数週間vimでtodoリストを書くようになった。これがなかなかよくて、.vimrcをいじってtodoリストを書きやすいようにvimをカスタマイズした。GUIアプリだと自由にカスタマイズできなくて、痒いところに手が届かずに使わなくなってしまうケースがあったけど、vimだと自由にいじれるからそういうこともなく長続きしているのだと思う。
そうこうしてるうちに、vimで書いたtodoリストはどんどん増えていった。その中には誰かがやってくれればいいものもあったので、公開していいかと思った。あと、todoリストを買い物リストのように使うことがあって、そういうときに外出先でiPhoneからチェックしたいと思ったのでwebで公開した。viewportを設定してモバイル端末からも見やすいようにした。
公開の仕組みは単純で、todo.mdというファイルをguardで監視して保存されたら自動的にあるスクリプト(下記リンク)とscpが実行されるようにした。このスクリプトはtodo.mdをパースし用意しておいたテンプレートとくっつけてHTML化する。そして、そのHTMLがscpでサーバーにアップロードされる。
あとRedcarpetをちょっと拡張して- [ ]
, - [x]
をチェックボックスに変換するようにした。これはGithub Flavored Markdownで実装されているTask Listの形式を参考にした。
余談
最初はこの仕組みをSinatra、Heroku、Dropbox APIで作ろうとしたのだけど、いろいろ問題があって今の仕組みにいたった。結局「markdownの変換」「scpによるアップロード」の2つを自動化しただけのシンプルな形になった。最近これ以外にも、仕組みを選択する段階で失敗する経験があった。単純な仕組みであるほど問題は少ないし、起きたときに解決しやすいと思った。
「todoリストをテキストファイルとして扱う」というアイデアは、vimを十二分にカスタマイズ可能なtodoアプリとして扱えるようになっただけでなく、今回のようにtodoリストをwebに公開するというところまで行き着いた。なんかで読んだけど、データをテキストとして保存した方が扱いやすいというのが身にしみて理解できたのでよかった。
Androidに乗り換えるかも
自分のために作ったアプリを公開したい場合にiOSはとてもハードルが高い。 仕事でやるなら別にいいんだけど、自分で使うのが主のモチベーションで 「他の人もこれ使ったら便利だと思う」程度のモチベで公開しようとするとそのハードルの高さに愕然とする。 審査が入るから、かなり完成度を高めないと落とされる。 完成度を高めていく作業はけっこう根気がいる。
iOSは審査プロセスもビルドプロセスも複雑で、開発以外の部分で時間をとられるのがむかつく。 なぜかよくわからないけど、Androidはantとかmavenでビルドを自動化するノウハウがたくさんあるのに、 iOSはビルドの自動化に関して情報が少ない気がする。 とりあえずrakeでビルドとTestFlightへのアップロードを自動化したけど、けっこう時間がかかった。
Rakefile for building and uploading to testflight
iOSはAndroidとくらべてUIがキレイというのはある。 だけど、Android2.3なんかと比べるとそうだと思うけど、4以降になるとそんなに気にする程でもなくなったと思う。
今のところiPhone5を使っているけど、片手で使えるNexusシリーズが出たらAndroidに乗り換えると思う。 Android端末はデカすぎる。日本のメーカーはあれだけ小型化・薄型化が好きだったのに、 なんでスマホになると大型化するのか意味がわからない。
mrb_valueについて調べてみた
昨日の続き。
mrubyのソースコードを読むと、mrb_value
という構造体がよく出てくるのでソースコードを追いかけて使い方を調べてみた。参照しているコミット番号は昨日と同じく「9663a7」です。
mrb_valueの定義
// include/mruby/value.h:40 typdef struct mrb_value { union { mrb_float f; void *p; mrb_int i; mrb_sym sym; } value; enum mrb_vtype tt; } mrb_value;
mrb_value
構造体は値とその値のデータ型をもつ。enum mrb_vtype
にはMRB_TT_FIXNUM
とかMRB_TT_STRING
などが入る。value
とtt
は適切な組み合わせにする必要があるはず。
mrb_value
はMRB_NAN_BOXING
が定義されているかどうかでその定義が変わるんだけど、MRB_NAN_BOXING
はmrbconf.hでコメントアウトされていたので、mrb_value
のデフォルトの定義は上のようになる。
// include/mrbconf.h:23 /* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT */ //#define MRB_NAN_BOXING
どういうときにこれを使うのかはまだよくわかってない。
mrb_valueとデータ型の変換
int型、char型などとmrb_value
を変換する方法も調べた。まず、変換する関数によく使われているmrb_value
構造体に値をセットするマクロがある。
// include/mruby/value.h:53 #define MRB_SET_VALUE(o, ttt, attr, v) do {\ (o).tt = ttt;\ (o).attr = v;\ } while (0)
これを使って変換する関数が実装されているっぽい。とりあえず見つけたのは以下の通り。
int
-> mrb_value
// include/mruby/value.h:205 static inline mrb_value mrb_fixnum_value(mrb_int i) { mrb_value v; MRB_SET_VALUE(v, MRB_TT_FIXNUM, value.i, i); return v; }
mrb_value
-> int
// include/mruby/value.h:145 #define mrb_fixnum(o) (o).value.i
float
-> mrb_value
// include/mruby/value.h:58 static inline mrb_value mrb_float_value(mrb_float f) { mrb_value v; MRB_SET_VALUE(v, MRB_TT_FLOAT, value.f, f); return v; }
mrb_value
-> float
// include/mruby/value.h:51 #define mrb_float(o) (o).value.f
char[]
-> mrb_value
// src/string.c:670 char * mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) { mrb_value str = mrb_str_to_str(mrb, ptr); return RSTRING_PTR(str); }
char[]
-> mrb_value
// src/string.c:232 mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len) { struct RString *s; s = str_new(mrb, p, len); return mrb_obj_value(s); }
mrubyで定義したクラスとメソッドをCから呼び出す
mrubyで書いた方がいいところはmrubyで書いてそうじゃないところはCで書く、という開発をするには、Cで定義した関数をRubyから実行させたり、逆にRubyで定義したクラスやメソッドをCから呼び出せるようにする必要があると思った。前者のような実装はmrbgemsを読めばたくさんある一方で、後者の実装は調べたけどあんまりなかった。そこで、先日「Head First C」でCの初歩を学んだことだし、mrubyのソースコードを読みながら後者の「mrubyで定義したクラスとメソッドをCから呼び出す」実装を試行錯誤してみた。
試行錯誤してみてとりあえず動いたというだけで、正しいやり方じゃないかもしれないので、コメントか@naoty_k宛にメッセージをいただけるとありがたいです。また、参照しているmrubyのコミット番号は「9663a7」です。
Rubyのクラスとメソッドを用意
適当にPersonクラスとメソッド2つを用意する。あとでこれらをCから呼び出す。
// person.rb class Person attr_accessor :name, :age def initialize(name, age) @name = name @age = age end def greeting "Hello, my name is #{name}, #{age} years old." end end
mrbcでコンパイル
RubyのファイルをCからロードするにはいくつか方法があるようだけど、今回はmrbcで*.mrb形式にコンパイルしてCからロードするようにする。
$ ls person.rb $ mrbc person.rb $ ls person.mrb person.rb
Cから定義したクラスとメソッドを呼び出す
CからRubyで定義したPerson
インスタンスを生成してgreeting
メソッドの結果を標準出力に表示してみる。
// greeting.c #include <stdio.h> #include <mruby.h> #include <mruby/string.h> int main() { mrb_state* mrb = mrb_open(); // mrubyファイルをロードする FILE *fd = fopen("person.mrb", "r"); mrb_load_irep_file(mrb, fd); // クラスオブジェクトを取得する struct RClass *person = mrb_class_obj_get(mrb, "Person"); // 引数をmrb_valueに変換する mrb_value person_value = mrb_obj_value(person); mrb_value name_value = mrb_str_new(mrb, "naoty", 5); mrb_value age_value = mrb_fixnum_value(25); // Person#newを呼び出す mrb_value naoty = mrb_funcall(mrb, person_value, "new", 2, name_value, age_value); // Person#greetingを呼び出す mrb_value greeting_value = mrb_funcall(mrb, naoty, "greeting", 0); // 返り値をchar*に変換して出力する char *greeting = mrb_string_value_ptr(mrb, greeting_value); printf("%s\n", greeting); mrb_close(mrb); return 0; }
- *.mrb形式のファイルをロードするには
mrb_load_irep_file()
を実行する。 - 次にクラスを取得するには
mrb_class_obj_get()
を実行し、メソッドを呼び出すにはmrb_funcall()
を実行する。 mrb_funcall()
には、第2引数にメソッドのレシーバ、第3引数にメソッド名、第4引数にメソッドの引数の数、第5引数以降にはメソッドの引数を渡す。第2引数と第5引数以降はint
やchar*
などをそのまま渡すことはできなくて、mrb_value
という構造体に変換する必要がある。変換するための関数については長くなりそうなので、別の記事にしようと思う。mrb_funcall()
の返り値もmrb_value
構造体なので、標準出力をするためにchar*
に変換する。
Cをコンパイルして実行
Cのソースコードをmrubyのヘッダーファイルやスタティックライブラリと一緒にコンパイルする。僕の環境だと以下のコマンドでコンパイルできた。
$ gcc -I ~/mruby/include greeting.c ~/mruby/build/host/lib/libmruby.a -lm -o greeting $ ./greeting Hello, my name is naoty, 25 years old.
greeting.cはperson.mrbに依存し、person.mrbはperson.rbに依存しているので、一連のビルドはMakefileかRakefileで自動化したほうがいいと思う。
// Rakefile require "rake/clean" CC = "gcc" MRBC = "mrbc" CLEAN.include("person.mrb") CLOBBER.include("greeting") task default: "greeting" file "greeting" => ["greeting.c", "person.mrb"] do |t| sh "#{CC} -I ~/mruby/include #{t.prerequisites[0]} ~/mruby/build/host/lib/libmruby.a -lm -o #{t.name}" end file "person.mrb" => ["person.rb"] do |t| sh "#{MRBC} #{t.prerequisites[0]}" end
$ rake $ ./greeting
参考
@naoty_k クラスの取り出しはmrb_class_obj_get()、メソッドの呼び出しはmrb_funcall()を使ってください。funcallには派生形あり。
— Yukihiro Matsumotoさん (@yukihiro_matz) 2013年4月30日