平凡なエンジニアの独り言 はてなブログ出張所

ピアノをこよなく愛するエセRubyistが適当に書き綴ります

VMWare PlayerでホストOSとゲストOSのフォルダを共有しようとしたら認識できなかった

Windows使いとしては、rubyのコードを書くにはもはやVMWare Playerは必須となっているわけですが、どうしたわけか、ホストOSとゲストOSのフォルダの共有がうまく動かなかったので、解決策をメモっておきます。

  • ホストOS: Windows7
  • ゲストOS: CentOS6
  • VMWare Toolsは最初にインストール済み

最初に実行したのは以下の手順です。

上記の作業を行うと、ゲストOS上で「/mnt/hgfs」下に共有したフォルダが出てくるはずですが、出てきません。

同じような現象に遭遇した人は他にもいるらしく、あれこれググったところ、以下の記事を見つけました。

解決策:vmware-config-tools.plを再度実行して、VMWare Toolsを再インストールすれば、共有フォルダが出てきます。(vmhgfsを有効にするか聞かれるので、yesと入力するのを忘れないでください。デフォルトはyesだと思いますが。。。)

mrubyにクラスとメソッドを組み込んでみた(Windows 7)

mrubyを使うなら、Cで拡張も書いてみたいですよね。とりあえず、Cでクラスとメソッドを組み込む方法を以下の記事を参考にしながら書いてみました。

概要

上記の記事では、モジュールの登録になっているので、クラスの登録をmrubyのコードを読みながら実施してみることにしました。下記のHelloクラスと同等のクラスをCで書いて、mrubyに登録します。

class Hello
  def hello(num)
    (0...num).each do |i|
      p "Hello mruby World!"
    end
  end
end

Hello.new.hello(3)

ソースコード

ソースコードは以下の通りです。

#include <mruby.h>
#include <mruby/proc.h>
#include <mruby/compile.h>

//登録するメソッドの処理
static mrb_value hello_hellofunc(mrb_state *mrb, mrb_value self) {
	int i;
	mrb_int arg;
	// 引数をmrb_int型(int型)で取得する
	// 第2引数について詳しく知りたい場合は、
	// class.cのmrb_get_args関数のコメントを見ること
	mrb_get_args(mrb, "i", &arg);
	
	for (i = 0; i < arg; i++) {
		puts("Hello mruby World!");
	}
	
	return self;
}

int main() {
	int n;
	mrb_state* mrb;
	struct mrb_parser_state* st;
	struct RClass *helloclass;
	char* code = "require 'hello'; Hello.new.hello(3)";

	mrb = mrb_open();

	//クラスを定義する
	helloclass = mrb_define_class(mrb, "Hello", mrb->object_class);
	//メソッドを定義する
	mrb_define_method(mrb, helloclass, "hello", hello_hellofunc, ARGS_REQ(1));

	st = mrb_parse_string(mrb, code);
	n = mrb_generate_code(mrb, st->tree);
	mrb_pool_close(st->pool);
	mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_nil_value());
}

ビルドは以下の感じです。適宜、環境に合わせて読み替えてください。

gcc -I../mruby/include -I../mruby/src practice_mruby.c ../mruby/lib/libmruby.a -o practice.exe

実行結果は以下の通り。

Hello mruby World!
Hello mruby World!
Hello mruby World!

ポイント

  • mrb_state型重要
  • mrb_get_args関数で引数を取得
  • mrb_define_class関数でクラス宣言
  • mrb_define_method関数でメソッド宣言
  • mruby.hã‚„class.cを読めばかなりのことがわかる

感想

特に難しいことはなさそうです。環境や言語をまたぐと厄介なのは、いろいろな型の受け渡しなので、その辺はもう少し調べてみる必要がありそうです。

mrubyはまだ情報が少ないので、とっつきにくいところもあるかもしれませんが、使う分には簡単そうですね。

mrubyをNaCl(Native Client)でビルドしてみた(Windows 7)

Ruby 2.0ではNaCl対応するらしいですが、もともとNaCl自体が実行ファイルのサイズが肥大化しやすいうえに、Rubyという巨大なコードを載せてしまっては、実用上厳しいのではと感じていました。実際、20MB位になるらしいです。

そこで、組み込み用途として開発されたmrubyなら少しはましになるんじゃないかと思い、ビルドを試してみることにしました。そのまますんなりとはいかないのですが、とりあえずビルドは成功したので手順を掲載します。

前準備

mrubyとNaClのビルド環境を準備してください。

手順の概要

mrubyは、ビルド環境さえ整えればmakeをたたくだけでビルドできるという親切設計です。NaClでビルドする際、障害になるのはCコードを自動生成している部分です。ビルド中にrubyのコードをバイトコード化してcに埋め込む作業を行っているらしく、その際にmrbc.exeというバイトコードを生成する実行ファイルを生成・実行しているのですが、NaClではnexeを生成するので、mrbc.exeの実行に失敗してしまいます。

そこで、mrubyのMinGWでのビルドを行ってCコード(mrblib.c)を生成してから、オブジェクトファイル(*.o)を削除して、NaClでビルドするというトリッキーな手順を踏みました。

libmruby.aというライブラリファイルが生成されるので、これを自分のNaClのC++コードでリンクすればOKです。(mrubyはCなので、ヘッダを読み込むときにはextern "C"するのを忘れないようにしましょう。最新のコードを見たら、ヘッダの中に書かれていたので必要ないことを確認しました。)

具体的な手順

1. mrubyをMinGWでmakeしてください
2. 各フォルダのオブジェクトファイル(*.o)とlib/libmruby.aを削除してください
3. mrubyのMakefileを書き換えてください

mrubyのMakefileを、NaClのものを指定してください。以下はx86-64ですが、x86用にコンパイルするならi686-nacl-gcc.exeを指定してください。NACL_ROOTはNaCl SDKを置いたパスと置き換えてください。(私の環境だと/C/tools/nacl_sdk/)

export CC = /NACL_ROOT/pepper_19/toolchain/win_x86_newlib/bin/x86_64-nacl-gcc
export LL = /NACL_ROOT/pepper_19/toolchain/win_x86_newlib/bin/x86_64-nacl-gcc
export AR = /NACL_ROOT/pepper_19/toolchain/win_x86_newlib/bin/x86_64-nacl-ar.exe

4. srcに移動してmakeしてください
5. mrblibに移動してmakeしてください
6. lib/libmruby.aを使ってNaCl用に書いたC++をコンパイルしましょう

などと書いても不親切すぎるので、NaClのチュートリアルのコードを改変して試してみました。NaClã‚‚mrubyも全然わかっていませんが・・・。

#include <cstdio>
#include <string>
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"

#include "mruby.h"
#include "mruby/proc.h"
#include "mruby/array.h"
#include "mruby/string.h"
#include "mruby/dump.h"
#include "mruby/irep.h"
#include "mruby/compile.h"

class hello_tutorialInstance : public pp::Instance {
public:
	explicit hello_tutorialInstance(PP_Instance instance) : pp::Instance(instance)
	{
	}
	
	virtual ~hello_tutorialInstance() {}
	
	virtual void HandleMessage(const pp::Var& var_message) {
		if (!var_message.is_string())
			return;
		std::string message = var_message.AsString();
		pp::Var var_reply;
		
		int n;
		mrb_state* mrb;
		struct mrb_parser_state* st;
		
		mrb = mrb_open();
		st = mrb_parse_string(mrb, (char*)message.c_str());
		n = mrb_generate_code(mrb, st->tree);
		mrb_pool_close(st->pool);
		mrb_value result = mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_nil_value());
		
		char s[256];
		sprintf(s, "%d", result.value.i);
		
		var_reply = pp::Var(s);
		PostMessage(var_reply);
	}
};

class hello_tutorialModule : public pp::Module {
public:
	hello_tutorialModule() : pp::Module() {}
	virtual ~hello_tutorialModule() {}

	virtual pp::Instance* CreateInstance(PP_Instance instance) {
		return new hello_tutorialInstance(instance);
	}
};

namespace pp {
	Module* CreateModule() {
		return new hello_tutorialModule();
	}
}  // namespace pp

HTMLは以下の通りです。'125+245'という単純な足し算をmrubyに渡しています。

<!DOCTYPE html>
<html>
<head>
  <title>hello_tutorial</title>

  <script type="text/javascript">
    hello_tutorialModule = null;  // Global application object.
    statusText = 'NO-STATUS';

    function moduleDidLoad() {
      hello_tutorialModule = document.getElementById('hello_tutorial');
      updateStatus('SUCCESS');
      
      //ここでRubyのコードとして'125+245'を送信
      hello_tutorialModule.postMessage('125 + 245');
    }

    function handleMessage(message_event) {
      alert(message_event.data);
    }

    function pageDidLoad() {
      if (hello_tutorialModule == null) {
        updateStatus('LOADING...');
      } else {
        // It's possible that the Native Client module onload event fired
        // before the page's onload event.  In this case, the status message
        // will reflect 'SUCCESS', but won't be displayed.  This call will
        // display the current message.
        updateStatus();
      }
    }

    function updateStatus(opt_message) {
      if (opt_message)
        statusText = opt_message;
      var statusField = document.getElementById('status_field');
      if (statusField) {
        statusField.innerHTML = statusText;
      }
    }
  </script>
</head>
<body onload="pageDidLoad()">

<h1>Native Client Module hello_tutorial</h1>
<p>
 
  <div id="listener">
    <script type="text/javascript">
      var listener = document.getElementById('listener');
      listener.addEventListener('load', moduleDidLoad, true);
      listener.addEventListener('message', handleMessage, true);
    </script>

    <embed name="nacl_module"
       id="hello_tutorial"
       width=0 height=0
       src="hello_tutorial.nmf"
       type="application/x-nacl" />
  </div>
</p>

<h2>Status</h2>
<div id="status_field">NO-STATUS</div>
</body>
</html>

感想

x86-64のファイルサイズは4MBでした。Windowsのexeは1MBちょいだった気がするので、もう少し小さくなってほしいところですが、本家のrubyよりはましになるんじゃないかなと思います。昔からNaClの実行ファイルは大きすぎる気がしているので、この辺はGoogleに頑張ってほしいところです。

NaClに詳しくないのですが、NaClが生成したmrbc.exeを実行することはできる(nexeを実行する方法があったはず)と思うので、普通に環境に応じて場合分けしたmakeファイルを書けば、こんなトリッキーなことをしなくてもビルドできるようになると思います。

mrubyは開発が活発みたいなので(この記事を書いている間も、最新版のMakefileの構造が変わったことに気づいて書き直したりしています)、フィードバックをいろいろとかえせたら有用なのかなと考えています。
# 言語をアプリに組み込むことにワクワクするのは私だけではない・・・はず。

それにしても、まともにMakefileを見るのもC++を書くのも7 ~ 8年ぶりなので、内容的に心もとない感じです。突っ込み大歓迎です。

*1:それぞれのbinを環境変数のPATHに追加してください

mrubyをWindows 7(MinGW, msys)でビルドしてみた

最近、mrubyをぽちぽちと触っています。手軽に言語をアプリに組み込めるってワクワクします・・・よね?

さて、備忘録として、Windowsにおけるビルド手順を記録しておきます。私はWindowsでビルドすることがあまりないので、この辺の土地勘がいまいちなかったりするので、やや不安だったのですが・・・。

  • Windows 7
  • MinGWとmsysを入れる(環境変数のPATHにそれぞれのbinを追加します)
  • mrubyのコードを取得して、makeする

binの下にmruby.exe、mrbc.exe、mirb.exeができました。mirb.exeで対話的にRubyの実行を試せます。

お手軽ですね!

はてなブログにお試しで書いてみます

どうも、あかさたです。長年はてなダイアリーとはてなブックマークを愛用しているものとして、はてなブログもそれなりには使わないとなと思い、ためしに書いてみることにしました。

直感的にはtumblrでブログを開設したときのような手軽さを感じました。

tumblrはお手軽なブログサービスとしても有用なので、敷居が高いと思われがちなはてなにとってもお手軽なブログサービスとして定着していく可能性の素質はあるのかなと思います。(とっても回りくどいですね^^;)

 

※ 弊社の話をすれば、Crowsnestの情報発信を行っているCrowsnest 日本語ブログは、tumblrを使っています。独自ドメインも使えますし、運用も楽だし、デザインも選べばなかなかいけているしと、言うことないですね。

 

はてブと書いた時に、はてなブックマークを指すのか、はてなブログを指すのか微妙ですが、たぶん、はてブ、はてブロみたいな感じで住み分けていくのだろう・・・というか住み分けていってほしいというか、名前もドメイン名も微妙すぎるので、何とかならないのかなぁ・・・。

 

RailsDevCon2010に行ってきた

今日(というかもう昨日ですね)はRailsDevCon2010に行ってきました。場所はオラクル青山センターです。Rails系のイベントに行くのは久々だったので、いろいろと参考になる情報を得ることができました。

以下、このイベントに関する所感です。

RailsDevCon2010について

RailsDevCon2010に行ってみて感じたことは、Railsを軸にしたカンファレンスはニーズが相当あったのだなということでした。

RailsDevConは以下の問いに答えるために開催されました。

  • 皆さんRailsを使っていますか?
  • Railsを上手く活用していますか?

(上記いずれもRailsDevCon2010のページより引用)

イベントの目的をまとめてしまえば、事例の紹介とノウハウやベストプラクティスの共有、あとはエンジニア同士の交流と言うことになるでしょう。日本では、rubyistとRails使いは被ってはいますが、近いようで違う存在なので、切り離したイベントが行われたことには大変意味がありました。

講演者の人選ももエンタープライズ、コンシューマ(ソーシャルゲーム)、TDDというかBDD系の方々とバランスが取れていました。いや、TDDに偏ってるけど(笑)。初回と言うことを考えれば、とてもいい人選だったように思います。達人出版会の対面販売とか、面白い試みもありました。

次回以降も期待ですね。以下、個別のセッションの感想など。

渡米して感じたこと(@masuidriveさん)

ひとことで言うと、海外経験をおもしろおかしく紹介したという感じですが、役立つ話がちらほらと。面白そうなところを以下にピックアップしました。待遇や求められているスキルのところは参考になるところも多いと思います。

  • 海外ではスタートアップや新規案件にRubyがよく使われていること
  • Ruby系の求人はJavaã‚„PHPと比べれば少ないものの、新規案件が多く、条件がいいものが多い
    • Ruby/Rails3年、Facebookアプリ開発経験、RSpec、Cucambar、NoSQL経験ありとかだと、10万ドル〜17.5万ドル位の待遇
    • rubyistはスキルが高いという思い込みもある?
  • Ruby/Railsの技術は世界で通用する
  • 働き方など待遇面は交渉する余地がある
  • 仕事が日本に縛られることがないので、海外の仕事経験を持っておくと精神的に楽

Rails情報源の歩き方(仮)(@IT副編集長、西村賢さん)

最新の情報を大量にウォッチしなくてはならない記者が、Rails系をウォッチする際にどのような情報源にあたるのかという点で非常に興味深い発表でした。試しにRailsで記者の業績(各サイトに投稿した記事のはてブ数などの情報が見られる模様)を見られるサービスを作ったりもしているとのこと。

発表名が(仮)のままなんだけど、これでいいのかな・・・?

Railsに関する情報は英語が多いので、英語系の情報源が充実していました。全ては追えませんでしたが、一部を以下に紹介します。

これだけ見ても情報のたぐり方が凄いとしか言えません。近々、@ITでRailsの情報ハブとなるサイトが始まるそうです。期待ですね。

とあるソーシャルアプリの開発運用(ドリコム@onkさん)

おそらく、今回の発表でもっとも面白かった発表でした。ソーシャルアプリの開発における問題点を以下の3つにまとめて、工夫した点などを紹介してくださいました。

  • Social APIを利用したアプリ開発のデバッグ
  • ユーザー数の急激な増加
  • 短納期

以下、個別の内容について。

  • Social APIを利用したアプリ開発のデバッグ
    • net-http-spy gemでロガーを仕込んだり、tcpflowでサーバに来るパケットをチェック
    • 困ったらレスポンスをチェック
    • 困ったらTCPレイヤーまで降りる
  • ユーザー数の急激な増加
    • 負荷の見積もり
      • アクティブユーザー10万として、1人100imp/day = 1000万imp/day
      • 230imp/sec(平均を取って、ピーク時を考慮して2倍)
      • 1秒に1リクエストを返すのなら、unicornインスタンスが230必要
      • memcache、DBともに1000 〜 2000qps必要
      • Webメモリ8GBのマシンが5台、memcacheは1台でOK、DBそれなりのマシンなら1台でOK・・・とはならない
    • DBに関する工夫
      • ゲームは更新系のクエリが多いので、レプリケーションだけではmasterのDiskIOが溢れるため、垂直分割必要。これにより、JOIN不能(has_many等が使えない)
      • データ量の増加(レコードが増えるクリックを1秒1クリックとしても、毎月260万レコードが増加、普通は数千万レコードが増える)に対応するために、パーティショニング
    • 負荷テスト
      • JMeter。スループット、DiskIO、connection数をチェック
      • 50万ユーザーが3ヶ月遊んだデータを作ってテストを実施
      • faker gemなどを使うとテストデータを作りやすい
  • 短納期
    • 2ヶ月でリリース、1ヶ月に2回の更新などあたりまえ
    • Railsらしさを大切にして開発を高速化
    • 無駄なドキュメントを作らない
      • URL設計書、ER図だけで進める
    • ログや現在のサービスの状況を最速で確認できる環境を作って、対応策を素早く

かなり濃かったので、発表資料の公開が待たれます。メモの半分も記事にできませんでした。。。

Railsプロジェクトを成功させるために現場ができること(ukstudioさん)

フリーランスとして活躍されている@ukstudioさんの現場から得た知見を発表とのこと。抽象的な話になってしまっていましたが、概ね頷ける内容だったので、これまでの経験を思い返してあれこれ考える材料になりました。

技術的な負債をため込まないために、開発プロセスに技術的な負債を返す工程を含めようという話。

  • TDD
  • バージョン管理
  • 使わない機能は技術的な負債と同じなので、減らす工夫も必要

思うに、この種の発表はどうしてもふわふわとした内容になりやすいので、技術的な負債の具体的な例、TDDがなぜモジュールの結合度を下げて凝集度を上げるのか、TDDが発生を抑えてくれる負債の例、リファクタリングが解決してくれる負債の例、バージョン管理のポイントなど、どれかに絞った話が聞きたかったかも。

現実の世界で "はじめる!Cucumber"(@moroさん)

Cucumberの導入について、現実的に導入するための手順を丁寧に解説。以下の3つの疑問を軸に、わかりやすく導入方法を紹介していました。

  • 日本語の情報がない
  • 今のプロジェクトへ適用する作戦が思いつかない
  • 日本語のシナリオに使い道がない

実はこの講演が一番実用的だったと思います。

  • 誤解、導入に失敗する考え方
    • 完璧なCuke → 完璧なRSpec → 実装 → RSpecパス → Cukeパス
  • より適した考え方
    • それっぽいCuke → 必要十分なRSpec → 実装 → RSpecパス
    • 動かないCukeを書いて、動くように変更
    • 必要十分なCuke → 必要十分なRSpec → 実装 → RSpecパス → Cukeパス

個人的には、動かないCukeでも、ユースケース記述に近い内容になるので、仕様の共有に有効なドキュメントになり得ると考えています。特にエンタープライズではそうでしょう。それがテストになるなんて素晴らしい世界。一度、実案件で使ってみたいものです。

Rails Add-onsで楽々開発 - youRoomを題材に -(SonicGarden松村さん)

youRoomの開発で使用したプラグイン、ウェブサービスなどの紹介。本業に関係ない独狐炉は外部のサービスなどを活用する姿勢に、共感を感じました。

初めてがRuby

始めてさわる言語がRubyという世代が生まれつつあるようで、@a_matsudaさん、@yuumi3さんの教え子達によるパネルディスカッション。

  • 質問1 Ruby/Railsをどうやって勉強しましたか?
  • 質問2 Ruby/Railsを勉強していて躓いたところは?
  • 質問3 わからなかったことがわかるようになった瞬間は?
  • まとめ Rubyここがいいよね?
  • 質問 最初にこれを教えていてくれたらもっと早くに理解できたのに、というものはありましたか?

若い世代の話で非常に興味深い内容でした。教育を通じてRuby/Rails文化を育てていくということは非常に大切なことです。教育系の人たちの発表は次回以降も聞きたいです。

そういえば、Ruby系の人は優しいという話がありましたが・・・rubyistは恐いというのが定説だったのに!(笑)

まとめ

次回以降のイベントも楽しみです。エンタープライズだと契約上難しいところもあると思いますが、そちらの方面の事例の話が入るともっと興味深いと感じました。私はWeb系なのであまり仕事上は関係ないので、ドリコムさんの事例だけで十分満腹でしたけど。

いずれにせよ素晴らしいイベントでした。運営の皆様、お疲れ様でした。ありがとうございました!

共同購入サービス「group割」が始まりました!

世間ではフラッシュマーケティングとかソーシャルコマースとかいう考え方を採用したいわゆるGroupon系サービスが流行っています。私が手伝っている株式会社spice lifeが運営しているブラウザ上でオリジナルTシャツが作れるウェブサービス「tmix」でも、流行りに合わせて共同購入サービスを開始することになりました。

f:id:akasata:20100913234532p:image

どういうサービス?

group割は、tmixでデザインしたオリジナルTシャツを、複数人(最低10枚以上)で共同購入することで、定価より安く購入することができるサービスです。(枚数が増えれば増えるほどドンドン安くなっていきます。)従来のtmixのボリュームディスカウントでは、1人が複数枚購入しなくては値引きされなかったのですが、group割を利用することによって、別々の人が購入しても、規定枚数に達すれば値引きを行えるようになりました。

f:id:akasata:20100913234534p:image
tmixのエディタ


時間制限や最低数量が決まっているところは、Groupon系サービスと似ています。とはいえ、group割は他のGroupon系サービスとは若干異なる特徴を持っています。

group割は、tmixでデザインしたTシャツを、共同購入によって安く買うことができるサービスです。つまり、比較的不特定多数の買い手を対象とするGroupon系サービスとは異なり、文脈を共有した人同士で文字通り共同購入を行うことになります。

現在のtmixでは、たとえば、オフ会に着ていくネタTシャツを作るとか、スポーツサークルなどに属している人が練習着をメンバーで揃えて作るとか、花屋さんなどで働いている人がスタッフ専用のエプロンを作るとか、そういう用途で使っている人が多いですから、group割でも、同じような使われ方をすると思います。これだけだと通常のボリュームディスカウントと変わらない*1のですが、第三者でも買うことができるため、リアルの強い関係というよりは、ゆるくつながった人が共有する文脈で使うこともできるでしょう。

とはいえ、group割が始まったときに、緩い文脈でつながっている人同士でどれくらい情報を拡散できるのかという問題点もあります。(実際、今のところ、販売が成立したのはリアルサークルのケースばかりです。)twitterのような優れたツールはありますが、何かソーシャルグラフを活用した仕組みが必要なのかもしれません。この辺は今後の検討材料でしょう。

なんにせよ、安くなるのであれこれ考えずに利用していただけたらなと思います。

*1:もっとも、通常のボリュームディスカウントだと、幹事がメンバーのTシャツのサイズを聞き回ったり、集金したり、できあがったTシャツを配ったりする手間がありますが、group割を使うとそういう手間はかからなくなるので、そういうメリットはあるかもしれません。