<< September/2010
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
>>
前回のネタを書いてから、もうちょっと突き詰めたり、
情報を手に入れたので追記

 ○magic commentについて

冷静に考えれば、「ソースをparseするためのヒントを与えるもの」なのだから、
日本語が混じっていたら無条件と考えて良さそう

コメントに日本語が混じっていた場合が怪しいけども、
「#で始まる部分をparseしない」という保証がない以上、
念のため入れておいたほうがいい気がする

で、問題のrailsについて

railsのデフォコードは当然全部英語で書かれているから、
magic commentはいらないはず
追記した部分に入れておけば問題ない気がする

それでもerbとか、スクリプトでない部分の扱いが気になるので、
結局すぐ移行は難しそう

 ○Ruby1.9におけるファイルオープン

こちらによれば、Ruby1.9でファイルを開く場合、
エンコーディングを指定しないといけないらしい

file = File.open(file_name, "r:utf-8")

システムのエンコーディングと、
読み込むファイルのエンコーディングが一致していればいいですが、
一応きちっと指定しておいた方が問題が少ないのは間違いなさそう

どちらにしても、今作っているシステムは、
UTF-8上でEUC-JPのファイルを読むので、
指定がないと失敗する気が・・・


magic commentは1.8のコードだとただのコメント行だからいいですが、
ファイルのエンコード問題は事前に仕込めないので、
移行後に書き換えるしかないのが面倒です(´・ω・`)

仕事で組んでいるシステムでいろいろ試すのはさすがに抵抗があるので、
自宅で何か適当なシステムを検証するしか・・・

[ Web技術::Ruby ] comments (0) trackback (0)
今Rubyで作っているシステムはどちらかといえばバッチ系なので、
RailsはActiveRecordしか使ってなかったのですが、
DBのメンテナンスUIにRailsを使うことに

なので、先週末から「Rails レシピブック」で本格的に勉強し始めたのですが、
やはりRailsは「フレームワーク」なので、小手先の「作り方」ではなく、
詳細な解説の方が、かえって理解しやすい感じですね(`・ω・´) b

そんなタイミングでRails2.3.2がリリースされたこともあり、
ついでにRuby1.9.1にも移行できないかと、
既存のシステムの環境をいじっていたのですが・・・

「composite_primary_keys」がAR2.3.2に未対応で、
requireした時点で落ちてしまい、システムが動作しなくなりました(´・ω・`)

なので、結果的にはRuby1.8.6 + Rails2.2.2に戻したのですが、
Ruby1.9の導入の段階でもいろいろ問題が

 ○MySQL/Ruby(Windows)がインストールできない

「extconf.rb」がどうしても通らないのです

当然ながら、libmysql.dllはSystem32以下にありますし、
bin以下に置いたり、extconf.rbと同じとこに置いたり、
オプションでフルパス指定したりしたのですが、どうしても動かない(´・ω・`)

Linux環境ならあっさり動きそうな気がしますが、
開発環境がWindowsなので、
やっぱりWindows上で動いてほしいのです

 ○「magic comment」の扱いがよくわからない

$KCODEの代わりに使う、「# -*- coding:utf-8 -*-」ってあれですね

$KCODEの場合、起動するスクリプトで指定しておけば、
他の*.rbで指定する必要がなかったのですが、
magic commentの場合がよくわからないのです

選択肢としては・・・

 ・起動するスクリプトの冒頭にだけ書く
 ・コメント以外で日本語が含まれているファイルに書く
 ・コメントを含めて、日本語が入っていたら書く
 ・とりあえず全部書く

・・・このどれかでしょう
上から順に労力が低いわけですが、
おそらく一番最後が確実な気もします

さらに、Railsで使うerbファイルとか、
*.rbでないファイルの扱いもよくわからないため、
いろいろ危険な香りが・・・(lll゚Д゚)


というわけで、さっさとRuby1.9に移行したいとは思いつつ、
業務レベルではしばらく様子見かなと
個人的にいろいろやってみますか・・・


<追記>
Railsと直接関係ない、コア部分は全部magic commentをつけておくことに
Railsがわからんな・・・

[ Web技術::Ruby ] comments (0) trackback (0)
長いこと悩んでいた問題が解決したのでメモ...φ(・ω・`)


Rubyでは何らかを「追加」するメソッドとして、
たいていは「+」と「<<」が用意されています

# 文字列
str = 'ab'

new_str = str + 'c'
p new_str #=> 'abc'

str << 'c'
p str #=> 'abc'

# 配列
list = ['a', 'b']

new_list = list + 'c'
p new_list # => ['a', 'b', 'c']

list << 'c'
p list # => ['a', 'b', 'c']


これだけ見ると、結果は同じですし、
「<<」の方が明らかに書くのが楽なので、
つい「<<」を多用してしまいそうですが・・・

「<<」は「+」を楽に書くための記法ではありません

さっきのコード、こう書いた途端に結果が変わります

# 文字列
str = 'ab'

str << 'c'
p str #=> 'abc'

new_str = str + 'c'
p new_str #=> 'abcc' not 'abc'


# 配列
list = ['a', 'b']

list << 'c'
p list # => ['a', 'b', 'c']

new_list = list + 'c'
p new_list # => ['a', 'b', 'c', 'c'] not ['a', 'b', 'c']


つまり、「+」は元のオブジェクトに新しい要素を加えて、
新しい情報を返すのに対し、
「<<」は元のオブジェクト自体を書き換えます

この程度なら意識していれば回避できそうですが、
これがメソッドどころかクラスをまたいでいると、
結構忘れてしまうのです

私が詰まったのはこんな感じ

class Resource
  # これをシステム全体で使いまわしたい
  @mydata = ['a', 'b', 'c']

  def self.getResource
    return @mydata
  end
end

class Executor
  def self.execute
    share_data = Resource.getResource
    # これはあくまで参照のコピー

    share_data << 'hoge'
    # ここで書き換えているのは「share_data」の指すオブジェクト、
    # つまり、Resource内の配列そのもの

    # いろいろやる

    p share_data
  end
end

Executor.execute # => ['a', 'b', 'c', 'hoge']
Executor.execute # => ['a', 'b', 'c', 'hoge', 'hoge']
p Resource. getResource # => ['a', 'b', 'c', 'hoge', 'hoge']
# あーあ(´・ω・`)


効率化のために共有リソースとして保持していた配列に、
いろいろな個所で「<<」を多用した結果、
元のリソースオブジェクトを書き換えまくってしまったのです

Rubyはスクリプト系の言語なので、
どうしても「オブジェクト」の概念を忘れてしまいそうになりますが、
常に意識しておかないとこういう問題が発生します(´・ω・`)

対策としては・・・

    # share_data = Resource.getResource
    # share_data << 'hoge'
    share_data = Resource.getResource + 'hoge'


・・・こういうのでもいいのですが、
それでもやっぱり前述のようなコードを書きたくなります

要は、共有資産が書き変わらなければいいので・・・

class Resource
  @mydata = ['a', 'b', 'c'].freeze # 変更を許可しない

  def self.getResource
    return @mydata.dup # データコピーを返す
  end
end


・・・こうしておくと、渡した先で何をされようが、
Resource内のデータは安心、と(`・ω・´) b

ちなみに、データコピーには「clone」と「dup」がありますが、
「clone」はfreeze属性まで渡すので、渡した先で書き換えできません
「dup」はデータだけコピーします

あと、「clone」でも「dup」でも同じですが、
「浅いコピー」であることは要注意です
・・・意味がわからない人はググってくださいΣ(・ω・ノ)ノ



そういえば、同じような問題をJavaでも経験したな・・・

こういうのって、クラスをまたいでしまうとわかりづらいし、
ぱっと見た感じ論理的に合っているように見えるので、
コードレビューでも発見しづらいのです

JavaのObjectクラスにも「freeze」が欲しい気はする
でも、JavaのObject#cloneは簡単には使えないし・・・

あと、「final」をつけても禁止されるのは「参照の変更」であり、
「中身の変更」ではないので注意


[ Web技術::Ruby ] comments (0) trackback (0)
今はRubyでシステムを書いているのですが、
Railsなんて使わない、業務システムだったりします

ActiveRecordは単体で一部使ってますが、
やはり処理が3~5倍かかるので、
徐々に依存度を減らす方向にしています
(RailsもARも重すぎ( ゚Д゚)y─┛~~)

まあ、このあたりのノウハウはそのうちまとめるとして、
今日はRubyのメモリ管理・・・というか、
ガーベージコレクション(GC)について気になったことをメモ...φ(・ω・`)


最初に書いたコードはこんな感じ
class Hoge
 def execute
  (1..10).each do |i|
   obj = SomeHugeObject.new
   # SomeHugeObject は数百Mのサイズ

   # いろいろやる

   # ここでGCしてほしいなぁ・・・
  end
 end
end

とてつもなくメモリを食うオブジェクトをループ内で生成していて、
ループの終わりで破棄されることを期待したわけですが、
実際には際限なくメモリを食い続け、プロセスを強制停止しました(´・ω・`)

ということで、対策を練るため、RubyのGCの仕組みというか、
Rubyのメモリ管理について調べてみたわけですが、
当然ながらJavaとは結構違います

当然言語のポリシーが違うので、どちらがいい、
というものではないのですが、少なくともGCの仕組みに関しては、
Javaの方が先行している分、利があるように思います

まあ、このあたりの話は面倒なので、
各自調べていただくとして・・・Σ(・ω・ノ)ノ
(Javaでいうこういう本は、Rubyだとどれになるんだろう・・・)

では、実際にどうしたのかというと・・・
# うまくいったやり方
class Hoge
 def execute
  (1..10).each do |i|
   obj = SomeHugeObject.new

   # いろいろやる

   obj = nil # 参照を明示的に切る
   GC.start # GCを強制実行
  end
 end
end

これだと常にobj一つ分のメモリしか使いませんでした(`・ω・´) b

要は、ループの中で定義した参照であっても、
ループを抜けないと、自動では開放されないってことでしょうか
(本当はもうちょっと違うと思いますが・・・うまく説明できない(´・ω・`))

もっとも、最終的には生成するオブジェクト自体もスリム化しましたが、
こういった「その言語特有のチューニング」は、
言語の原理がわかってないと難しいところですよね・・・

more**
[ Web技術::Ruby ] comments (0) trackback (0)
ここのところ、今動かしてるシステムをRailsで書き直してみたり、
仕事で使っていたPerlのテストツールをRubyで書いたりと、
いろいろRubyをいじっていたわけですが・・・

(RailsでGv出欠管理を書き直してみた話はまた後日)

技術系のサイトで、「Java屋はRubyを覚えるべき」くらいはともかく、
「JavaはRubyで置き換わる」的な恐ろしい記述を見かけますが、
正直、JavaがRubyで置き換わることはありえませんΣ(・ω・ノ)ノ

Rubyの方が確かに記述しやすいですし、
手軽に動作を確認できるのは大きなメリットですが、
だからといって、RubyでJava並みのコードがかけるかというと違うと思います

(勘違いしてほしくないのは、Java>Rubyってことではなくて、
 適材適所ってことです)

具体的に何が引っかかったのかというと、
ズバリ、「例外処理」です

Rubyの事を調べ始めたとき、Perlと違って例外の概念があるので、
きっとPerlより書きやすいだろうと思ったのですが、
それはJavaの例外処理ほど便利なものではありませんでした

(でもまあ、Rubyがサーバにデフォルトでインストールされているようなら、
 サーバの管理スクリプトをRubyで書くのは十分「あり」だと思います
 Perlとの比較だと、Ruby>Perlかなと)

Javaの例外と違ってRubyの例外は、
呼び出し側に例外処理を強制できないのです
これ、ものすごく大きな違いです

もちろん、Rubyが動的型付け言語であり、
ましてインタプリタ方式であることを考えれば、
実際に実行されるまでに何の例外が上がるのか
(どこで「raise」が呼ばれるのか)わからないのはあります

それでも、メソッドで何の例外があがるか、
つまりJavaでいう「throws」節を書くことはできたのではないかと

何が問題かというと、以下の2点が挙げられます

 ・リスクを認知できない
 ・責任の分散ができない

(Javaの例外を「面倒だ」とか、
 「catch (Exception e)」とか平気で書いちゃう人は、
 このあたりの機構がわかってないと思われます(`・ω・´))

メソッドがthrows節を明示することで、
そのメソッドを使うことで、どんなエラーが発生するのか、
呼び出し側が知ることができます

つまり、そのメソッドを使用することの「リスク」が示されるので、
呼ぶ側はその問題をどう対処するか決めることができます

一方、Rubyの場合、メソッドが何の例外を上げるのか、
ただ呼んだだけでは知ることができません

もちろん、ドキュメントを読めばわかるのは確かで、
Javaであっても、その例外が何を意味するかは、
ドキュメントを見るまではわかりません

ですが、Rubyの場合はドキュメントを読まない限り、
その例外の存在すらわからないのです
この違いは大きいかと

そしてもう一つが「責任」の問題です

あるメソッド(あるいはクラスやモジュール、ライブラリ)が
例外を投げるということは、
呼び出し側に処理のハンドリング=責任を渡すことを意味します

つまり、自分でこの問題は解決できないから、
あなたが問題の解決方法を決めてね・・・と、
責任の所在を明け渡しているわけです

例外を受け取った側はやはり、自分で処理するか、
あるいは自分の呼び出しに処理を任せるのか、
責任を持って決めることができます

それがたとえ、「catch(Exception e){}」ってコードだとしても、
そのコードを書いた側が責任を持ってそうするのであり、
それえ何か問題が起こったとしても、それはその受け取った側の責任になります

なぜ「責任の分離」が重要なのか、というのは、
まさに「オブジェクト指向」の原点に戻る話かと
(なので、今回は触れない方向でΣ(・ω・ノ)ノ)

というわけで、JavaとRubyの違いを例外機構から見てきましたが、
繰り返しになりますが、どちらが優れている、という話ではないです

Javaは厳格に書けるのが利点であり、
Rubyはその開発スピードが利点です

それぞれの長所を把握した上で、
システムに最適な言語を選んでなんぼかと

ちなみに、こんな話もあります

オブジェクト指向開発にRubyを使うメリット:ITpro

ここのコラムにあるように、設計段階でのプロトタイプとして、
さくっと書けるRubyを用い、実装はJavaで厳格にというのは、
実用的ですし、いいアイデアだと思います

何でもJava、なんでもRuby(on Rails)と思考停止せずに、
一番合ったものを使いたいですね(`・ω・´) b

[ Web技術::Ruby ] comments (0) trackback (0)
NEW ENTRIES
RECENT COMMENTS
CATEGORIES
ARCHIVES
LINK
PROFILE
POWERED BY
 Script by ⇒ BLOGN+(ぶろぐん+)
 Skin by ⇒ vivid*face
OTHER
SEARCH
LOGIN
現在のモード: ゲストモード
ID:
PASS:
AdSense

  PAGETOP