昨日(10/31)、spice lifeの二人の邦明さん(@igaiga555さん、@HolyGrailさん)が主催する勉強会kuniaki.rbに行ってきました。会場は株式会社スマートニュースさん。

まずは、主催のダブル邦明さん、勉強会の運営お疲れさま&ありがとうございました。
また、会場及び飲み物提供の株式会社スマートニュースさん、懇親会の食べ物提供の株式会社spice lifeさん、ありがとうございました。

大変楽しい会でした。会の様子に関しては写真も撮っていたので、後程どなたかがレポートされるかと思います。
私の方はというと、LT枠をいただけたので、以下のお題で発表させていただきました。

mrubyでゲームを書いてみた
http://www.slideshare.net/yousukekuroda/akasata-20131031

久々のLTだったので、デモの真っ最中に銅鑼を喰らう羽目に。次に発表するときはちゃんと練習して行こうと思います。

発表内容の補足


弊社は、ブラウザ上でゲームを作成して共有するサービス「Rmake」(Flash製)を運営しています。マップエディタなど既成のツールと簡易スクリプトエンジンを使って、RPGやノベルを手軽に作って共有することができます。SLGとか作っちゃう猛者もいますが・・・。

ゲームを作成して共有するサイト - Rmake
http://rmake.jp/

ユーザーさんたちには、楽しく使っていただいていますが、既成のツールと簡易スクリプトエンジンでは、作れるゲームにも幅が無いですし、日本のようにスマホや即売会が活発な国では、ブラウザゲームというだけではいまいち広がりがありません。

そこで、PC(即売会向けに)/スマホ/ブラウザに展開可能で、がんばれば市販されているゲームのレベルに近い物が作れるゲームエンジンが欲しいと考えていました。

mrubyを知ったのは去年のことですが、実際に数行のソースコードでアプリに組み込めることを知って、c/c++で大半の処理を書くことで性能と移植性を維持しつつ、ゲームの中核部分をわかりやすいDSLをmrubyで実現することで、楽しく(がんばれば)それなりのレベルのゲーム作成を行うことができるゲームエンジンを実現することができます。

mruby
https://github.com/mruby/mruby

弊社では主に@dycoonが実装していますが、PC(Windows)とAndroidでそれなりに動くようになってきた(iOS/Flash/Macではまだ・・・)ので、ちょろちょろと露出を増やしつつ、先行してさわってくれるユーザーさんを探しつつ、開発に参加してくれる人を探せたらなと考えています。(もちろん、広げていくためにはオープンソースにするとかいろいろ考えられると思うのですが、その辺、まだ何も考えていません。)

開発中のゲームエンジンは以下からダウンロードすることができます。アルファ版ですので、人柱になる勇気のある方はぜひともさわって、アドバイスやらなんやらをいただけるとうれしいです。

Code on Rmake
https://core.rmake.jp/

あと、以下のイベントに参加します。興味のある方は是非いらしてください~。

デジゲー博
http://digigame-expo.org/
日時:2013年11月17日(日) 11:00 ~ 15:00
場所:大田区産業プラザPio 2F小展示ホール

よろしくお願いします。

Posted by あかさた
Wheneverを使ってRubyでcronを設定したときのメモを残しておきます。
春ごろにも仕事で使ったので、備忘録として残しておこうと思ったら忘れてしまって、今頃になってまたcronの設定を仕事でやったので、今度こそはと思い、メモっておきます。

Railsプロジェクトなのでそれを前提に記事を書いています。

Wheneverとは?


Wheneverは、とかく忘れがちなcronの設定をrubyの構文でわかりやすく記述することができます。

いい加減なプロジェクトだと、本番サーバに何となくcronを設定しただけになって、どこを見ればどういうバッチ処理が走っているのか把握しにくいというような場面によく遭遇しました。

Wheneverはただ単にわかりやすいというだけではなく、設定ファイルをバージョン管理システムに登録しておくことで後から読み返すことが容易になり、設定を忘れてしまった場合にも安心です。

設定ファイルを作成する


さっそく使ってみましょう。Gemfileに以下を追記し、bundle updateします。

gem 'whenever', :require => false


プロジェクトのディレクトリに移動して以下のコマンドを実行するとconfig/schedule.rbが生成されます。

wheneverize .


config/schedule.rbをプロジェクトに合わせて書き換えてみましょう。
詳しくはGitHubにあるreadmeを見るとわかりますが、cronの時間設定をrubyの構文で書くことができます。

# 毎分、rails runnerが走ります。
every 1.minutes do
  runner "Hoge.hoge_method()"
end


cron本来の書式や:day、:hourなどを指定することもできます。
Capistranoの特定のロールだけで実行できるタスクを指定するというようなこともできるようです。

実際に設定してみる


以下のコマンドを実行すると、設定内容が出力されます。crontabには書き込まれません。
不都合な点はないか確認すると良いでしょう。

# 設定する内容を出力。crontabには書き込まれません
whenever

# ヘルプでwheneverのオプションを確認する
whenever -h

# 開発環境にする場合は以下のように書く
whenever -s 'environment=development'

# crontabに書き込む場合
whenever -w

# crontabに書き込む(開発環境)
whenever -s 'environment=development' -w


とても楽ですね。

参考




Posted by あかさた
Rails 4.0.0が出ていたので、3.2.12で動かしているウェブアプリ(このブログ)を4.0.0にアップグレードしてみることにしました。

Rails 4.0: Final version released!
http://weblog.rubyonrails.org/2013/6/25/Rails-4-0-final/

(1) GemfileのRailsのバージョンを4.0.0にする

coffee-rails、sass-railsも4.0.0にしました。
古いrailtiesに依存していてbundle updateが動かないことがあるためです。

(2) 以下のコマンドを実施。

bundle update
rake rails:update


以下、rake rails:updateの作業ログです。

  • boot.rbは上書き
  • routes.rbはスキップ
  • application.rb上書き(このアプリに関してはtime_zoneを指定していただけだったので、あとから追記)
  • environment.rb上書き
    • 環境ごとのファイルは適宜マージ
  • initializers/inflections.rb上書き
  • initializers/secret_token.rb上書き
  • initializers/session_store.rb上書き
  • initializers/wrap_parameters.rb上書き
  • locales/en.yml上書き

environment下のマージはいつも面倒・・・。そんなに設定をいじっているわけでもないのですが。

■ ソースコードの修正作業ログ

○ routes.rb

matchがまだ残っていたので、getやpostなどに置き換え。

○ mass-assignment対応

以下のように、controllerでホワイトリスト方式で指定するようになりました。

params.require(:hoge).permit(:attr_1, attr_2)
post_params = params.require(:hoge).permit(:attr_1, attr_2)
hoge = Hoge.new(post_params)


○ ActiveRecordのscopeをlambdaで記述

意外にハマるところなので、注意してください。

○ set_table_nameをself.table_nameに変更

これは3.2でdeprecation warningが出ていたものなのでいまさら感が漂いますが。。。

○ turbolinks

これは有効にしませんでした。。。

■ 雑感

メジャーバージョンアップであることを思えば、割と手軽に上げることができました。
scopeが影響範囲が広いので、テスト書いてないとちょっと怖いですね。


Posted by あかさた
去年末くらいから取り組んでいたのですが、結構いい感じに出来上がったので告知させてください。
スマートフォンのブラウザ上でTシャツをデザインして注文できるウェブサービス「tmix」を開発しました。
サーバーサイドが私でエディタ部分は@dycoonが実装しました。


スマフォ版Tシャツデザインエディタ


■ 経緯

元々tmixは、2009年に始まったPCブラウザ上でTシャツをデザインして注文できるサービス(flash)でした。
このサービスによって、ブラウザ一つで多くの人が手軽にTシャツを作って楽しめるようになりました。
しかし、時代は変わりスマートフォンからのアクセスが4割を占めるようになり、tmixを訪れる多くの方が、tmixを使うことができないという現実に直面していました。

スマフォアプリの全盛期の今、flashのないブラウザで同等のサービスが実現できるか技術的に難しい面もあります。
Eコマースサイトはアプリに移行しにくい問題(決済などの理由)もあり、リッチなブラウザウェブサービスの開発は今後も増え続けるでしょうから、敢えていばらの道に挑んでみることにしました。

PC版とスマフォ版のエディタ


当面はChrome/Firefoxブラウザなどを使えばPCからもさわれるようになっています。ぜひ、さわってみてください。
(そのうちスマフォ/タブレット以外のアクセスはリダイレクトすると思いますが。)

スマートフォン版tmix

■ 仕組み

デザインエディタにはenchant.jsを利用し、サーバーサイドはRuby on Rails 3.2を使っています。
テキストの描画はスマートフォンは回線が弱いことから、フォントをクライアントに転送することはあきらめ、サーバーサイドでImageMagick(freetype)を使って画像を生成して返しています。


サイト上で利用するTシャツデザインのサムネイル画像やTシャツへの印刷画像もサーバーサイドで生成しています。
しかし、大きな画像は即時には生成できない(※)ため、バックエンドジョブキューを独自に開発して、時間のかからない画像生成はオンラインサーバ、時間のかかる画像生成はバックエンドジョブサーバに振り分けています。

※ 印刷に使う画像は3564*5040pixel、数十秒で生成できることもありますが、Amazon EC2のLargeで1 ~ 2分かかる場合もあります。意外にバカにならないのはpngの圧縮にかかる時間です。オプションで結構時間を削れますが、試行錯誤が多少必要でしょう。

インフラはAmazon Web Serviceを使っています。EC2、ELB、S3、Glacier、Route 53、SES、ElastiCache、RDSなどを使っています。
便利すぎてAWSが無いと生きていけない体になりそうです。

■ 課題や今後の計画

リリースしたものの、スマフォ版はいくつかの技術的な課題を抱えています。
当面は問題を解決しつつ、使い勝手を向上していく予定です。

  • Xperiaの標準ブラウザで落ちることがある
  • 機種によってはデザインエディタのタップの反応が鈍い(チューニングすれば改善できることはわかっていますが、まだ手が回ってません)

tmixそのものはPC時代から続く長年の経験によって、SEO、工場生産の仕組み、ユーザーテストを用いた継続的なユーザビリティ向上など、オーダーメイドを伴うEコマース系サービスとしてかなり高いレベルで運用されています。

しかしながら、時代はどんどん進んでおり、ログ解析をベースに統計的アプローチを活用したサービス改善も多くのサービスが取り入れています。

tmixではこうしたアプローチは一部行われていますがまだまだ不十分です。
今のところは、競合でそこまでやっているサービスはないようですが、いずれは当たり前になります。
競合に差をつけ、さらに快適で使いやすいサービスにするためにも、ログ集約基盤としてfluentdを活用しつつ、独自の分析手法を用いたシステムを開発中です。

業務上の機密にかかわる部分は難しいですが、技術的なポイントは共有可能だと思うので、開発が完了したらまたお知らせしたいなと考えています。

■ 参考

ブラウザ上でTシャツをデザイン・注文できるウェブサービス「tmix」の開発に参加した

2009年にPC版をリリースしたときの告知です。この時はFlashでした。
今はスマートフォンですら、HTML+JavaScriptだけでこれだけのことができるのだから、時代は進歩しましたね。

【日本初】tmixが、スマートフォンからオリジナルTシャツを作って購入できるようになりました!!

tmix運営ブログの記事です。日本初!とかって書くとなんか怪しいですね(笑)。

Posted by あかさた
ImageMagick(Ruby 1.9.3/Passenger 4.0.4/Rails 3.2/rmagick 2.3.11/ImageMagick 6.7.9-10)を使って画像処理をしているプロセス(Passenger)が固まってレスポンスを返さない現象が発生していました。

エラーを返すならわかるのですが、プロセスが固まるとなると、フロントにあるHTTPサーバ(Apache/prefork)も応答できずに固まり、リクエストは次々とくるのでプロセスはどんどん増えていくというとても恐ろしいことになります。

■ やったこと

  • ImageMagickをソースからインストール
  • ghostscriptがインストールされていない
    • yumなどのパッケージ管理ツールからImageMagickをインストールすると依存関係でghostscriptがインストールされる(と思う)
  • rmagickでフォントを使ってテキストを描画

■ エラーメッセージ

1回目は、以下のようなエラーが出ます。2回目は無限ループが発生します。

Magick::ImageMagickError (Postscript delegate failed `/tmp/magick-Zb2G2URF': No such file or directory @ error/ps.c/ReadPSImage/833: `(null)')


■ 解決策とまとめ

ググると、ghostscript関連のエラーのようですので、ghostscriptをインストールしたところ、問題は発生しなくなりました。

  • 当たり前のことですが、ソースからインストールする場合は依存関係に注意(他にもfreetypeを入れ忘れたり・・・)
  • 開発サーバでは、本現象は発生せず(開発サーバにはいろいろ入れるので、ghostscriptもすでに入っていた)

ソースからインストールする前に、yum deplistとかで依存関係をチェックすればこういうミスを減らせるかなぁ・・・。

Posted by あかさた
仕事では、Rails 3.2を主に使っているのですが、よく忘れるのでメモっておきます。
# いまだに、fullpathと書くべきところをrequest_uriとか書いてしまうのですが・・・。

# IP/Path関連
puts request.ip
puts request.remote_ip

# http://192.168.1.1/my/project/1
# にアクセスした場合
puts request.url
# => http://192.168.1.1/my/project/1
puts request.fullpath
# => /my/project/1

# HTTP METHOD関連
puts request.request_method
puts request.get?
puts request.post?
puts request.put?
puts request.delete?


# headersやflashも使いますね。。。

■ 参考

ActionDispatch::Request
http://api.rubyonrails.org/classes/ActionDispatch/Request.html

Posted by あかさた
今作っているサービスでRuby 2.0.0を使っているので、開発サーバのRVMをアップデート(1.16.6 → 1.20.5)して、Ruby 2.0.0を入れてみました。

# 安定板を入れるならrvm get stable
rvm get latest

# 呼ばなくても大丈夫そうですが
rvm reload

# Ruby 2.0.0のインストール
rvm install 2.0.0

# 2.0.0に切り替えて、バージョン確認
rvm 2.0.0
ruby -v
 => ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]


いい感じですね!

Posted by あかさた
今更感が途方もなく漂いますが、気付いていなかったので。。。

Ruby 1.8では、レシーバのオブジェクトを取り出すにはブロック引数を使っていましたが、Ruby 1.9ではselfを使って取り出すようです。

class MyClass
  def hello
    puts "Hello World!"
  end
end

MyClass.new.instance_eval do
  hello
end


あまり使わないメソッドですが、最近使う機会があったので。
mrubyでもRuby 1.9と同様の動作でした。

■ 参考


Posted by あかさた
仕事でImageMagickで画像処理をしていたのですが、中間ファイルをいろいろ作る必要があったので、ファイルの掃除も考慮してくれるTempfileを組み合わせて使ってみました。

  • テスト環境
    • Ruby 1.9.3
    • RMagick 2.13.1
    • ImageMagick 6.7.9-10
  • Railsを使っているとアップロードされたファイルはTempfileとして扱われる
    • サイズによってはStringIOとして扱われていた時代もあった気がしますが・・・昔の話のはず
  • 画像処理で中間ファイルを作る場合、ごみを残さないTempfileは便利

require 'RMagick'
require 'tempfile'

# アップロードされたファイル
uploaded_file = params[:file]

# TempfileからImageを作成する
# from_blobはArrayを返すので、shiftして先頭の要素を取得
image = Magick::Image.from_blob(File.read(uploaded_file.path)).shift

# 画像フォーマットの確認
puts image.format

# なんかいろんな処理

# Tempfileの作成
tempfile = Tempfile.open(temp_filename)

# Tempfileへの書き込み
# フォーマットの指定が便利
image.write("png:" + tempfile.path)

# なんかいろんな処理

# Tempfileの削除
tempfile.close!


■ 参考


Posted by あかさた
メソッドのオーバーライドを禁止してみたい(というかjavaでいうところのfinalをやりたい)と思ったので、いろいろ調べてみたところ、クラスの定義に関するフックmethod_addedとinheritedを使うとできそうなので、コードを書いてみました。

  • method_addedでメソッドの定義が行われると、そのメソッドを削除して例外を発生させる
    • 継承してmethod_addedを上書きすると上記チェックを回避できてしまう
  • inheritedで例外を発生させて継承を禁止する
    • inheritedのチェックだけだと、同一クラスの再定義でメソッドを上書きできてしまう

method_addedでremove_methodをすると、上書き前のメソッドも削除されてしまうのが、ちょっと不便ですね。追加前をフックできるといいのですが。。。

module FinalClass
  class << self
    def included(base)
      base.extend ClassMethods
    end
  end
  
  module ClassMethods
    def method_added(name)
      remove_method name
      raise TypeError, "You cannot define a new method!"
    end
    
    def inherited(subklass)
      raise TypeError, "You cannot define a subclass!"
    end
  end
end

class A
  include FinalClass
end


ま、実務で使うかどうかといわれるとわかりませんが・・・。

■ 参考

本記事は上記2記事を足して割った感じです。


freezeの利用も検討しましたが、いろいろと抜け穴ができてしまったので断念しました。

  • クラスをfreezeすると、メソッドの再定義もできなくなる
  • ただし、いくつか抜け道がある
    • 継承するとメソッドのオーバーライドが可能(inheritedでサブクラスをfreezeするアプローチもあるが・・・)
    • クラスをdupするとメソッドのオーバーライドができてしまう(cloneはfreezeを引き継ぐので問題ない)

Posted by あかさた