スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[JRuby]MonkeybarsとRawrでGUI

JRubyでJavaのSwingを利用しようと思い、サンプルを書いてみましたが
自力でjarを作ったりするのは結構手間です。
フレームワーク的なものを探してみたところ、
Monkeybarsというのを見つけたので、チュートリアルに従って試してみました。

[参考]
・Monkeybars
 http://monkeybars.rubyforge.org/
 JRubyのGUI用フレームワーク

 チュートリアル
 http://monkeybars.rubyforge.org/tutorials.html

・Rawr
 http://d.hatena.ne.jp/xibbar/mobile?date=20081220
 JRubyからexeやappを作成するツール


まずは、Monkeybarsを使用してプロジェクトの下地を作ります。

#インストール
jruby -S gem install monkeybars
jruby -S gem install rawr

#プロジェクト作成
monkeybars sample
cd sample

#rawrをプロジェクトへインストール
rawr install

Rawr has found an exisiting Rakefile.
Please select one of these options:
1: Keep the current Rakefile, and add the rawr content to the top.
2: Replace the current Rakefile with a new Rakefile. You will lose everything in the current Rakefile!
3: Quit, leave the current Rakefile alone, and add nothing new.
Your choice (1, 2, or 3):

→1で良いようです。

#ソースファイルをジェネレート
jruby -S rake generate ALL="src/hello"

#Swingレイアウト拡張jarをコピー
cp /Applications/NetBeans/NetBeans\ 6.5.app/Contents/Resources/NetBeans/platform9/modules/ext/swing-layout-1.0.3.jar lib/java/


下地ができたところで、NetBeansにプロジェクトとして取り込みます。
「既存のソースを使用するJavaプロジェクト」として作成します。

1_プロジェクトとして取り込み

先ほど作成したプロジェクトフォルダを指定します。

2_プロジェクトフォルダ指定

ソースパッケージフォルダとして、「src」フォルダを指定して、「完了」ボタンを押します。

3_ソースパッケージフォルダ

「lib/java/」のjarへのクラスパスを設定します。

4_Jar追加(右クリック)

5_Jar追加

次にアプリケーションを作成していきますが、まずGUI部分を作成します。

6_JFrame追加(右クリック)

7_JFrame追加

8_JFrame編集

ソースファイルを編集していきます。

#src/hello/hello_model.rb

class HelloModel
 attr_accessor :message

 def initialize
  @message = "Hello!"
 end

end

#src/hello/hello_view.rb

class HelloView < ApplicationView
 set_java_class 'hello.Hello'

 map :model => :message, :view => "jLabel1.text"
end

#src/hello/hello_controller.rb

class HelloController < ApplicationController
 set_model 'HelloModel'
 set_view 'HelloView'
 set_close_action :exit

 def jButton1_action_performed
  model.message = "OK!"
  update_view
 end

end

#src/main.rb(48行目付近)

begin
 # Your application code goes here
 require 'hello_controller'
 HelloController.instance.open

rescue => e
 show_error_dialog_and_exit(e)
end


実行してみます。
(主クラスを聞かれるので「org.rubyforge.rawr.Main」を指定します。)

9_実行1

10_実行2

最後にRawrを使用して、appを作成します。

#rakeタスクを表示
jruby -S rake -T

#コンパイル
jruby -S rake rawr:jar

#app作成
jruby -S rake rawr:bundle:app


pakage/osxに「ChangeMe.app」が作成されました。


チュートリアルなのでもっと深いところは全然わかっていませんが
とても便利だと思いました。

gemのプラグインを使用したい場合は自力でjarにまとめれば良いのでしょうか。
いろいろ触り甲斐がありそうです。
スポンサーサイト

[Merb]アプリケーションのルートパスを取得する

Merbアプリケーションのルートパスなど、
触っている中で知ったものをいくつかメモしておきます。

# Merbアプリケーションのルートパス
Merb.root

# 実行されているモード(developmentやproductionなど)
Merb.env

# config/init.rbで設定されている値
Merb.config[:session_id_key]

# ユーザーエージェント
request.env["HTTP_USER_AGENT"]

[Merb]merb-authを使ってみる

Merbに最初から準備されているmerb-authという認証を
以下のページを参考にやってみました。

認証を用いたHelloWorld

Flash(Actionscript)のFileReference.uploadを使用してファイルを
アップロードしている箇所があるのですがなぜか認証がうまくいかないという
問題が出ました。

どうやらクッキーが渡されていないようです。

じゃあ手動でクッキーを格納したらどうかと以下のような感じでやってみました。

# Javascript
function getCookie(){
 return document.cookie;
}

# Actionscript
var request:URLRequest = new URLRequest(url);
var cookies = flash.external.ExternalInterface.call("getCookie").toString();
request.requestHeaders = new Array(new URLRequestHeader("Cookie", cookies));
fileRef.upload(request);



試してみましたが、サーバー側には値が送られてきませんでした。

もう少し調べてみると、リファレンス

URLRequest パラメータを受け取るメッソドすべてが requestHeaders プロパティをサポートしているわけではありません。呼び出すメソッドのマニュアルを参照してください。例えば、FileReference.upload() メソッドおよび FileReference.download() メソッドは、URLRequest.requestHeaders プロパティをサポートしていません。



という記述がありました。
ファイルアップロードの時にクッキーを設定したりするのは厳しそうです。

ということで、パラメータの一部に含めてサーバーに送ることにします。

# Actionscript
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
variables["cookies"] = ExternalInterface.call("getCookie").toString();
request.data = variables;
fileRef.upload(request);



サーバー側でファイルアップロードを待ち受けているところだけ
認証を行う前に、POSTパラメータからクッキーを取り出して
本来クッキーが格納されるところに手動で入れてやります。

# vi app/helpers/global_helpers.rb
module Merb
 module GlobalHelpers
  # helpers defined here available to all views.
  def provide_cookies_from_params
   cookies = params[:cookies]
   cookies.split(";").each do |cookie|
    temp = cookie.split("=")
    request.cookies[temp[0]] = temp[1]
   end
  end
 end
end

# vi app/controllers/items.rb
class Items < Application
 before :provide_cookies_from_params, :only => :upload
 before :ensure_authenticated

 def index
 end

 def upload
 end
end



とりあえず動いたからOKにしました。

その後調べてみたところ、こんなライブラリもあるみたいです。
http://code.google.com/p/as3httpclientlib/
http://code.google.com/p/as3httpclientlib/wiki/Examples

これは便利そう。

[Merb]DataMapperのvalidation

前回に引き続きDataMapperについてです。
今回はvalidation関係を探ってみようと思います。

Modelを編集します。

vi app/models/entry.rb

class Entry
 include DataMapper::Resource

 validates_present :title, :content

 property :id, Serial

 property :title, String, :unique => true
 property :content, String

 has n, :comments
end



実行してみます。

rake db:automigrate
merb -i
entry = Entry.new
entry.title = "タイトル1"
entry.save



失敗しました。
validates_presentで指定されたフィールドは値を保存しないと怒られるようです。

entry.content = "内容1"
entry.save



次に別レコードで同じtitleを登録しようとします。

entry = Entry.new
entry.title = "タイトル1"
entry.content = "内容2"
entry.save



失敗しました。
unique指定しているため、ちゃんとチェックしてくれるようです。

事前に保存可能かどうかを調べるには・・

entry.valid?



でいけるみたいです。

後は独自のチェックをしたい場合は、Modelにチェックメソッドを定義したり
valid?をオーバーライドするとかでしょうか。

例えばcontentが10バイト未満をエラーにするとして・・

vi app/models/entry.rb

class Entry
 include DataMapper::Resource

 validates_present :title, :content

 property :id, Serial

 property :title, String, :unique => true
 property :content, String

 has n, :comments

 def vaiid?(context = :default)
  if !super(context)
   return false
  end
  if @content.length < 10
   return false
  end
  true
 end
end



試してみます。

merb -i
entry.title = "abcd"
entry.content = "123456789"
entry.valid?
=> false

entry.content = "1234567890"
entry.valid?
=> true



関連づけているModelまでチェックしてくれるのか試してみます。
commentのcontentを必須とします。

vi app/models/comment.rb

class Comment
 include DataMapper::Resource

 validates_present :content

 property :id, Serial

 property :entry_id, Integer
 property :content, String

 belongs_to :entry
end



実行します。

merb -i
entry = Entry.new
entry.title = "abcd"
entry.content = "1234567890"
entry.valid?
=> true

entry.comments.push(Comment.new)
entry.valid?
=> true



entry.valid?は通過しました。
どうやら関連づいたModelのチェックまではしないようです。

entry.comments[0].valid?
=> false



直接comment.valid?を呼ぶとfalseが返されます。
保存しようとするとどうなるのか。

entry.save

~ SELECT "id" FROM "entries" WHERE ("title" = 'abcd') ORDER BY "id" LIMIT 1
~ INSERT INTO "entries" ("content", "title") VALUES ('1234567890', 'abcd')
~ SELECT "id", "entry_id", "content" FROM "comments" WHERE ("entry_id" IN (3)) ORDER BY "id"
=> true



commentテーブルへの追加は行われませんでした。
ちゃんとcomment.contentにデータを入れます。

entry.comments[0].content = "comment"
entry.save

~ SELECT "id" FROM "entries" WHERE ("title" = 'abcd') ORDER BY "id" LIMIT 1
~ INSERT INTO "comments" ("entry_id", "content") VALUES (3, 'comment')
~ SELECT "id", "entry_id", "content" FROM "comments" WHERE ("entry_id" IN (3)) ORDER BY "id"
=> true



今度はcommentテーブルにデータを追加されました。

エラーメッセージは以下の方法で取得できるようです。

entry = Entry.new
entry.title = "abcd"
entry.valid?
=> false
entry.errors.full_messages
=> ["Title is already taken", "Content must not be blank"]



エラーコード的なものも取得できたら良いなと思ったのですが
よくわからなかったです。

[Merb]DataMapperを触ってみる

MerbのDataMapperを触ってみました。
RailsのActiveRecordすらまともに触ったことがないので手探りな感じです。

まずサンプルのModelを作ります。

merb-gen model entry title:string,content:string
merb-gen model comment content:string,entry_id:integer



記事とそれに関連づくコメントというイメージです。
次に2つのモデルを1対Nの関係にするため、Modelを修正します。

vi app/models/entry.rb

class Entry
 include DataMapper::Resource

 property :id, Serial

 property :title, String
 property :content, String

 has n, :comments
end

vi app/models/comment.rb

class Comment
 include DataMapper::Resource

 property :id, Serial

 property :entry_id, Integer
 property :content, String

 belongs_to :entry
end



DBを作成してサーバーを起動します。

rake db:automigrate
merb -i



entryテーブルにレコードを追加します。

entry = Entry.new(:title=>"タイトル1", :content=>"内容1")
entry.save



こんな書き方もできます。

entry = Entry.new
entry.title = "タイトル2"
entry.content = "内容2"



次はcommentテーブルにレコードを追加します。

comment = Comment.new(:content=>"タイトル1のコメント1", :entry_id=>1)
comment.save



entryとcommentを関連づけていますので、一発で保存することもできました。
(内部では2つのSQLが発行されています。)

entry = Entry.new(:title=>"タイトル3", :content=>"内容3")
comment = Comment.new(:content=>"タイトル3のコメント1")
entry.comments.push(comment)
entry.save



entry_idという名前を自動的に関連づけるIDと見なしてくれるようです。

次は検索ということで全件取得します。

entries = Entry.all



IDを指定して取得します。

entry = Entry.get(1)



取得フィールドを限定します。

entry = Entry.all(:fields => [:id, :title])
entry = Entry.get(1, :fields => [:id, :title])



ソートを指定してみます。

entries = Entry.all(:order => [:id.desc])



取得件数を絞ります。

entries = Entry.all(:order => [:id.desc], :offset => 1, :limit => 2)



commentを取得します。

entry = Entry.get(1)
entry.comments.each do |comment|
 puts comment.content
end



entryオブジェクトのメンバとしてアクセスできるわけですね。

今までガリガリSQL文を書いてきた経験しかないので
このオブジェクトを操作する感覚で、データを操作できるところがとても新鮮です。

結合して取得したり、複雑な検索条件をどうさばけばいいのかが気になるところです。
継続して調べていきたいと思います。
プロフィール

jou4

Author:jou4
FC2ブログへようこそ!

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。