2010/10/27

doc-support-HT3200

Mac OS X v10.6 Snow Leopard 以降搭載の Macintosh コンピュータで「消去してからインストール」する方法

5, Mac OS X インストール DVD を選択し、その下の矢印をクリックして、インストール DVD からシステムを起動します。
6, Mac OS X Leopard インストーラ画面が表示されたら、「続ける」をクリックします。


ここのstep 5,6 の間、もしくは
step 6から step 11(第 1 段階)の間のどこかでAirMac電源をオフにすべきステップがあるべきなのでは?ははん?
と思った。
# DVDから起動したマシン、そこにOSをインストールする場合。== ネットワークを介してターゲットマシンにインストールするんじゃない場合。

なぜなら
OS をインストールしている間ずっとAirMac電源が入っていて周囲をサーチし続ける必要はあるんだろうか?=> ないだろ
と思うから。

アップル公式ドキュメントにおいてこの件については全く触れられていない。
おそらくそんなこと気にするなってことなんでしょう。
でも少し気になる。
私は今後も自ら手動でメニューバーのAirMacアイコンをクリックし電源をオフにしてからインストールすることだろう。

Install MacRuby

http://www.macruby.org/

から MacRubyをダウンロードして遊んでみた。

% macruby -v
MacRuby 0.7.1 (ruby 1.9.2) [universal-darwin10.0, x86_64]

サンプルをデスクトップにコピー。

% cp /Developer/Examples/Ruby/MacRuby/Scripts/hello_world.rb ~/Desktop/sample_hello_world.rb

このサンプルと

http://macruby.labs.oreilly.com/ch01.html

に掲載されてる hello_world.rb を見比べつつ クラスを作ってみた。

framework 'AppKit'

module Hello3
  module MyWindow
    def window(ary, title, obj)
      @w = NSWindow.alloc.initWithContentRect(ary,
        styleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask,
        backing:NSBackingStoreBuffered,
        defer:false)
      @w.level = 3
      @w.title = title
      @w.delegate = obj
      return @w
    end
  end
  class MyButton
    attr_reader :b
    def initialize(ary, title, obj)
      @b = NSButton.alloc.initWithFrame(ary)
      @b.title = title
      @b.bezelStyle = 4
      @b.target = obj
    end
  end
  class Myapp
    include MyWindow
    attr_reader :app
    def initialize
      @app = NSApplication.sharedApplication
      @app.delegate = self
    end
    def windowWillClose(notification)
      puts "Bye!"
      exit
    end
    def sayHello(sender)
      puts "Hello again, World!"
    end
    def sayBye(sender)
      puts "bye"
      exit
    end
    def setup
      # button
      b1 = MyButton.new([150, 30, 100, 50], "Hello World!", @app.delegate).b
      b1.action = 'sayHello:'
      b2 = MyButton.new([30, 30, 100, 50], "Stop", @app.delegate).b
      b2.action = 'sayBye:'
      # window
      w = window([200, 300, 300, 100], "HelloWorld.app", @app.delegate)
      w.contentView.addSubview(b1)
      w.contentView.addSubview(b2)
      # display
      w.display
      w.orderFrontRegardless
      return @app
    end
  end
  def self.run
    Myapp.new.setup.run
  end
end
Hello3.run

実行

% macruby hello3.rb

Interface Builder.app 起動しなくてすむ。すごい!。快適。

[2010-10-28]

@b1, @b2, @w を b1, b2, w に修正。

2010/10/14

全体主義

『全体主義』 / エンツォ•トラヴェルソ / 平凡社新書 / 9784582855227
の感想。

P.22 

マックス•ヴェーバーが「合法的支配権」(legale Herrschaft)と定義したものの完全な否定に行きつく。言い換えれば<犯罪国家>の登場である。
だが、全体主義は、文明のパラダイムとは正反対の退行的非合理主義を、歴史の舞台に立たせたのではない。
それはむしろ、西洋近代のただなかを流れる<反=合理主義>を展開し、その破壊力のすべてを悲劇的なかたちで露にしたのである。


当時のドイツは法治国家だった。選挙だってあったし、人々は今の私たちと同じように迷信ではない「歴史」を知りえた。
人権思想だってとうの昔に誕生していたのだし、地球がだいたい丸いことも人々は知ってた。はず。
けれども、あれよあれよという間に恐ろしい事態が人々を支配してしまった。
その坂を転げ落ちていくような悲惨な出来事に対し、ヴェーバーだけじゃない、カントやヘーゲルも何もかも、
それまでに培われたはずの「合理的」な人類の叡智などなんの役にも立たなかった。
そればかりか、むしろその「合理性」がアダになってしまった。

では、合理性をも利用する全体主義の正体とは何なのか?

P.101 からの引用

カール•ヤスパースは、全体主義を、共産主義やファシズムをはるかに超えた現象として、「どの体制よりも普遍的であり、人類の未来にのしかかる<文明>の脅威である」と述べている。


確かに全体主義は時代を超越してる。ようだ。
ある時代では奴隷制、またある時代では魔女狩りや宗教裁判、強制労働、大虐殺。
ある国ではいまだに!言論統制、一党独裁。
各地での焚書も全体主義的現象と呼べるし、日本でも長く続いた江戸時代を全体主義の時代として捉え直すことは十分可能だろう。
徳川による独占支配、五人組による相互監視制、士農工商エタ非人のピラミッド構造、踏み絵、人質を強要し謀反を抑圧する参勤交代...etc.
『一九八四年』は江戸時代の日本において既に実現してたってわけだ。

P.106

ベネデット•クローチェは、
...(略)
その結論に彼はこう書いた。...
決して忘れてはいけない。ギリシャ=ローマにはじまる文明の凋落という以上に、さらに途方もなく重大な何かが起ることを。...
人類は、自然に対して、人間本性に対して巨大な罪を背負い、あらゆる腐敗の保管者たる思想自体を堕落させて死滅するだろう。

クローチェはいつか死滅するだろうと警告している。

ニ千年以上にわたって、世界各地で発生した(している)あらゆる人権侵害や大規模犯罪は、
封建制だとか植民地主義だとか帝国主義だとか資本主義だとか共産主義だとか
まるでてんでばらばらな呼び方に隠蔽され教えられる羽目に陥っているわけだけども、
結局、みえてくるものは、
その社会が全体主義的かどうか「だけ」なのかもしれない。極論だけど。
# どの程度、その社会が全体主義的か?それは測定できるようなものなのか?は、さておき
# 全体主義的現象に共通する特徴についてはこの本でも言及されてる。
思うに...
全体主義的現象の発生を許してしまう「共通必要条件」のようなものはあるのでしょうか。
また、時として、概念による制度的枠組みなど、特定の恣意が影響力を持ちうるような現実においては、無意味の烙印を押されるに等しくむなしく儚い。
といえなくもないのであれば、制度って何?

ところで、今、「正義について」考えたりディスカッションすることは有意義なのだろうけど、
合理性を善とする西洋哲学が全体主義に対して非力であったと同時に、結果的には理論加担させられた歴史を無視したまま、
あたかも絶対的善や絶対的正義が、独立して是とされるような倫理観が助長されるようであれば、あれば、
仮にだよ!あくまでも仮定として仮にそうであった場合(春樹的method)...
それは、いかに合理性が全体主義に利用できるかのロジックを図らずも暴露し、再正当化してしまう滑稽な議論にもなりかねないかも。
などと思った。

#『 これからの「正義」の話をしよう』ISBN 9784152091314

2010/08/07

instance_variable

http://midorex.blogspot.com/2010/07/attraccessor.html
http://midorex.blogspot.com/2010/08/singletonclass.html
http://midorex.blogspot.com/2010/08/selfclass.html
これらに関連して...

class Test
  @x = 'x'
  class << self
    attr_accessor :x
  end
end

class Test1
  def initialize
    self.class.singleton_class.send(:attr_accessor, :x)
    self.class.x = 'x1'
  end
end

t, t1 = Test.new, Test1.new
puts "t = Test.new, t1 = Test1.new"
puts "t.class.x=> #{t.class.x}"
puts "t1.class.x=> #{t1.class.x}"
puts "t.class.instance_variables=> #{t.class.instance_variables}"
puts "t1.class.instance_variables=> #{t1.class.instance_variables}"

結果

t = Test.new, t1 = Test1.new
t.class.x=> x
t1.class.x=> x1
t.class.instance_variables=> [:@x]
t1.class.instance_variables=> [:@x]

以上をふまえて

class Test オブジェクトと
それを new した オブジェクトと
class Test の特異クラスになったオブジェクト
この3つのオブジェクトにそれぞれ @x と attr_accessor, :x を定義してみる練習

  4 class Test
  5   @x = 'x'
  6   class << self
  7     @x = 'singleton-xxx'
  8     attr_accessor :x
  9     self.class.send(:attr_reader, :x)
 10   end
 11   def initialize
 12     @x = 'ini-xyz'
 13   end
 14   attr_accessor :x
 15 end
 16
 17 t  = Test.new
 18 puts "t = Test.new"
 19 puts "t.x=> #{t.x}"
 20 puts "t.instance_variables=> #{t.instance_variables}"
 21 puts "--\n"
 22 puts "t.class.x=> #{t.class.x}"
 23 puts "t.class.instance_variables=> #{t.class.instance_variables}"
 24 puts "--\n"
 25 s = t.class.singleton_class
 26 puts "s = t.class.singleton_class"
 27 puts "s=> #{s}"
 28 puts "s.x =>#{s.x}"
 29 puts "s.instance_variables=> #{s.instance_variables}"

実行結果

t = Test.new
t.x=> ini-xyz
t.instance_variables=> [:@x]
--
t.class.x=> x
t.class.instance_variables=> [:@x]
--
s = t.class.singleton_class
s=> #<Class:Test>
s.x =>singleton-xxx
s.instance_variables=> [:@x]


line5 の @x を外から読めるようにしているのは
line8 attr_accessor :x

同様に
line7 の@x は
line9 の self.class.send(:attr_reader, :x)

line12 の@x は
line14 attr_reader :x

おもしろいことに

  4 class Test
  5   @x = 'x'
  6   class << self
  7     @x = 'singleton-xxx'
  8     attr_accessor :x
  9     # self.class.send(:attr_reader, :x)
 10   end
 11   def initialize
 12     @x = 'ini-xyz'
 13     self.class.class.send(:attr_accessor, :x)
 14   end
 15   attr_accessor :x
 16 end

line9 のかわりに line13 にしても同じ結果を得ることができた。

+++ memo +++

あたりまえだけども
class Test
attr_reader :x
def initialize
@x = 'ini-xyz'
end
end
t = Test.new
t.x
=>'ini-xyz'
こうすると class Test のインスタンスが定義したインスタンス変数に代入された値を得られる。

new した class Test のインスタンスではなくて、
class Test そのものや、class Test の特異クラスにも
それぞれインスタンス変数を定義できるしそれらのアクセサを定義できるということを
『プログラミングRuby1.9 言語編』(ISBN: 978-4-274-068096) P.351 から学ぶことができた。

# P.351 あたりをうろうろしたままぜんぜん先に進んでいない。それにしても暑い。

self.class

<http://midorex.blogspot.com/2010/08/singletonclass.html> 前回からの続き

class Test
   def initialize(h)
     h.each{|k,v|
       self.class.send(:attr_accessor, k)
       self.send("#{k}=", v)
     }
  end
end

h={:cat=>'cat'}
t = Test.new(h)
t.cat = 'ddd'
p t

これを実行すると
#<Test:0x00000 @cat="ddd">
となる。でもでも :cat を attr_reader にしたかった場合はこのままだとうまくいかない。んで考えてみたこと。

まずは通常の書き方

class Test
  attr_reader :cat, :dog
  def initialize
    @cat = 'meow'
    @dog = 'bowwow'
  end
end

t = Test.new
p t.instance_variables
p t.class.instance_methods[0..2]
p t.cat
t.cat = "cat"

実行結果

[:@cat, :@dog]
[:cat, :dog, :nil?]
"meow"
./draft.rb:15:in `<main>': undefined method `cat=' for #<Test:0x00000 @cat="meow", @dog="bowwow"> (NoMethodError)

最後の行でcat に代入しようとしても attr_reader だから代入できないことを確認。

この結果と同じ結果を導きだすには?

class Test1
  def initialize(h)
    h.each{|k,v|
      self.class.send(:attr_reader, "#{k}")
      self.send("#{k}=", v)
    }
  end
end

h = {:cat=>'meow', :dog=>'bowwow'}
t = Test1.new(h)
p t.instance_variables
p t.class.instance_methods[0..2]
p t.cat
t.cat = "cat"

実行結果

... `block in initialize': undefined method `cat=' for #<Test1:0x00000> (NoMethodError)

self.send("#{k}=", v) は attr_accessor の時は使えるけど attr_reader の時は使えない。
文字通り reader だから getter であって setter じゃないため instance 変数に"cat"を代入できないためにエラーがかえってきた。
ならば
self.send のかわりに普通に instance_variable_set を使ってみた。

class Test1
  def initialize(h)
    h.each{|k,v|
      instance_variable_set("@#{k}", v)
      self.class.send(:attr_reader, "#{k}")
    }
  end
end

h = {:cat=>'meow', :dog=>'bowwow'}
t = Test1.new(h)
p t.instance_variables
p t.class.instance_methods[0..2]
p t.cat
t.cat = "cat"

実行結果

[:@cat, :@dog]
[:cat, :dog, :nil?]
"meow"
./draft.rb:25:in `<main>': undefined method `cat=' for #<Test:0x00000 @cat="meow", @dog="bowwow"> (NoMethodError)

うまくいった。
instance_variable_set でインスタンス変数に値を代入しておいてその後に、getter を設定した。
self.class.send(:attr_reader, "#{k}")
を削除すると、[通常の書き方]から attr_reader を削除した場合と等しくなる。

# --------------------

次はインスタンス変数を定義しないし attr も必要ない場合。
定義したいのはinstance_method def cat と def dog だけ。

通常の書き方。

class Test
  def initialize
  end
  def cat
    "meow"
  end
  def dog
    "bowwow"
  end
end

t = Test.new
p t.instance_variables
p t.class.instance_methods[0..2]
p t.cat

実行結果

[]
[:cat, :dog, :nil?]
"meow"

上記と同じ結果を導くには?

class Test1
  def initialize(h)
    h.each{|k,v|
      self.class.send(:define_method, k){v}
    }
  end
end

h = {:cat=>'meow', :dog=>'bowwow'}
t = Test1.new(h)
p t.instance_variables
p t.class.instance_methods[0..2]
p t.cat

実行結果

[]
[:cat, :dog, :nil?]
"meow"


まとめ
1, getter setter をinitialize 内で使う
self.class.send(:attr_accessor, k)
self.class.send(:attr_reader, k)
self.class.send(:attr_writer, k)

2, @cat のようなインスタンス変数に値を代入する (k はシンボル)
instance_variable_set("@#{k}", v)
# setter が定義されていることが必要条件
self.send("#{k}=", v)

3, def cat のようなインスタンスメソッドを定義する
self.class.send(:define_method, k){v}

+++ 追記 +++

attr_accessor は通常は クラス内の def initialize の上とか下に書く。
initialize の中には書かない。つか普通にエラーになる。
ということは、class Test のinstance が保有するメソッドじゃなくて
class Test が知っているメソッドだとわかるわけだけども
p Test.methods
とかやったって表示されない。じゃ一体どこにあるんだ?ということで下記を作ってみた。

  4 module My
  5   def self.search_method(x, key)
  6     ary = x.methods
  7     print "=== OBJECT:#{x} ===\n"
  8     ary.each{|m|
  9       next unless /methods/.match(m.to_s)
 10       next if m == :methods
 11       eval "a = x.send(m)
 12         if a.index(key)
 13           print \"[:#{key}] exist in #{m}\n\"
 14         else
 15           print \"# #{m}\n\"
 16         end"
 17     }
 18   end
 19 end
 20
 21 class Test
 22   def initialize
 23     My::search_method(self.class, :attr)
 24     # My::search_method(self, :nil?)
 25   end
 26 end
 27
 28 Test.new


# 実行結果

=== OBJECT:Test ===
# instance_methods
# public_instance_methods
# protected_instance_methods
# private_instance_methods
# singleton_methods
# protected_methods
[:attr] exist in private_methods
# public_methods


クラスの「private_methods」に属していることがわかった。
結局...
self.class.send(:attr_accessor, k)
self.send("#{k}=", v)

こういう方法でインスタンス変数を定義するってことは、親の遺伝子を子供が外側から操作しているように思えてきてよくないような気もしてきた。

2010/08/01

singleton_class

昨日のその後

% ruby192 -v
ruby 1.9.2dev (2010-07-11 revision 28618) [x86_64-darwin10.4.0]

module My
  def self.detail(s)
    p s
    puts "ParentName: #{s.class.name}"
    puts "Object_id: #{s.object_id}"
    puts "Methods 1to5: #{s.methods[0..4]}"
    begin
      puts "Method_define? Hello: #{s.class.method_defined?(:hello)}"
      puts "Class.Ancestors: #{s.ancestors}"
      puts "Superclass: #{s.superclass}"
      puts "Singleton_class #{s.singleton_class}"
      puts "Singleton_class #{s.singleton_class.object_id}"
    rescue
    end
    puts "\n"
  end
end
class Test1
  @@top = self
  puts "# -- main of class Test1 --"
  My::detail(self)
  class << self
    @@top_self = self
    puts "# -- class << self of class Test1 --"
    My::detail(self)
  end
  def initialize
    puts "# -- def initialize of class Test1 --"
    My::detail(self)
    puts "="*10
    puts "# TEST: @@top.singleton_class.equal?(@@top_self)"
    p @@top.singleton_class.equal?(@@top_self)
    puts "#"*5
    puts "self.class:: #{own1 = self.class}"
    puts "self.class.singleton_class::  #{own2 = self.class.singleton_class}"
    puts "# TEST: @@top.equal?(self.class)"
    p @@top.equal?(own1)
    puts "# TEST: @@top_self.equal?(self.class.singleton_class)"
    p @@top_self.equal?(own2)
  end
  def hello
    return self
  end
end
t = Test1.new.hello


実行結果

# -- main of class Test1 --
Test1
ParentName: Class
Object_id: 2151885720
Methods 1to5: [:allocate, :new, :superclass, :freeze, :===]
Method_define? Hello: false
Class.Ancestors: [Test1, Object, Kernel, BasicObject]
Superclass: Object
Singleton_class #<Class:Test1>
Singleton_class 2151885700

# -- class << self of class Test1 --
#<Class:Test1>
ParentName: Class
Object_id: 2151885700
Methods 1to5: [:nesting, :constants, :allocate, :new, :superclass]
Method_define? Hello: false
Class.Ancestors: [Class, Module, Object, Kernel, BasicObject]
Superclass: #<Class:Object>
Singleton_class #<Class:#<Class:Test1>>
Singleton_class 2151884980

# -- def initialize of class Test1 --
#<Test1:0x00000100864970>
ParentName: Test1
Object_id: 2151883960
Methods 1to5: [:hello, :nil?, :===, :=~, :!~]
Method_define? Hello: true

==========
# TEST: @@top.singleton_class.equal?(@@top_self)
true
#####
self.class:: Test1
self.class.singleton_class::  #<Class:Test1>
# TEST: @@top.equal?(self.class)
true
# TEST: @@top_self.equal?(self.class.singleton_class)
true


# TEST: @@top.singleton_class.equal?(@@top_self)
は一体何をやっているのか?

Test1 直下における self が .singleton_class メソッドを呼び出すと
#<Class:Test1>
が得られる。
その #<Class:Test1> は、class << self した self 自身と同等のオブジェクトだろうか?
これを確かめたかった。

結果は ture だった
実際

# -- main of class Test1 --
...略

Singleton_class #<Class:Test1>
Singleton_class 2151885700

# -- class << self of class Test1 --
#<Class:Test1>
ParentName: Class
Object_id: 2151885700

同じobject_id をさしている。

一方
initialize の中から呼び出した
self.class と
self.class.singleton_class
に関しても 同様に true がかえってきた。

# TEST: @@top.equal?(self.class)
true
# TEST: @@top_self.equal?(self.class.singleton_class)
true


# TEST: detail(self.class) in initialize もこの(true)結果を裏付けた。

own1 に代入された self.class はTest1 である。
それは class Test1 直下の self と同等。その証拠に同じobject_id を指している。
own2 に代入された self.class.singleton_class は、#<Class:Test1>である。
それは class << self 内の self と同等。同じobject_id を指している。

あらためて...
Test1.new して出来上がったオブジェクトは、class Test1 自身 のインスタンスだってことを思い知らされた。
class Test1 直下のself と、Test1.new されインスタンスとして登場した self とはそれぞれ異なるオブジェクト。
その証拠に異なる object_id を持つ。

class Test1
class << self
end
end

この時点で2つのオブジェクト(Test1 と #<Class:Test1>)にアクセスできる準備ができており
Test1.new することでインスタンスが生成されて3つめのオブジェクトができあがる、と。

2010/07/31

attr_accessor

『プログラミングRuby1.9 言語編』(ISBN: 978-4-274-068096) を読みながら試してみたこと
# P.351 にクラスレベルのアクセサを定義する方法と解説がありました。

class Test
@var = 99
class << self
attr_accessor :var
end
end

puts "Original value = #{Test.var}"
Test.var = "cat"
puts "New value = #{Test.var}"

# 実行結果

Original value = 99
New value = cat


# 少し書き換えself を表示してみると

class Test
  p self
  @var = 99
  class << self
    p self
    attr_accessor :var
  end
end

# 実行結果

Test
#<Class:Test>
Original value = 99
New value = cat


# P.351 には

... 次のように特異クラス内で attr_accessor を呼び出す必要があります。

# とあるのだからして
# <Class:Test> が特異クラスなのだと理解していいのだろうか?
# #<Class:#<MyClass:xxxxx>> のような形式になっていないのが気になる...
# という疑問は一旦おいといて

# で、この class << self を使わないかぎり attr は定義できないのだろうか?
# class << self と書くのとは異なる方法はないのかな?

class Test1
  @var = 89
  self.class.attr_accessor :var
end

実行結果

# =>
./test.rb:30:in `<class:Test1>': private method `attr_accessor' called for Class:Class (NoMethodError)
  from ./test.rb:28:in `<main>'

# エラーだ。
# attr_accessor は <class:Test1> にとって private method だから外から呼べないよと言われてしまった。
# そんなメソッドは知らない、とは言われてない、てことは?

class Test2
  @var = 123
  self.class.send(:attr_accessor, :var)
end

puts "Original value = #{Test2.var}"
Test2.var = "dog"
puts "New value = #{Test2.var}"

# 実行結果

Original value = 123
New value = dog

# やったー
# では、これをinitialize の中でも使えるかな?

class Test3
  def initialize
    @var = "99-dayo"
    self.class.send(:attr_accessor, :var)
  end
end

t = Test3.new
puts "Original value = #{t.var}"
t.var = "apple"
puts "New value = #{t.var}"

# 実行結果

Original value = 99-dayo
New value = apple


# 使えた!ので ...

# @varなど予め定義されたインスタンス変数が不要な場合で(というか用意したハッシュの値を既定値にしたい)
# 尚かつインスタンス変数を定義する時になんら制限をもたせなくてよい条件下。
# ハッシュをうけとった class Test4 が
# 受け取ったハッシュをもとにインスタンス変数とアクセサを定義するには?

class Test4
  def initialize(h)
    @now ||= Time.now
    h.each{|k,v|
      ks = k.downcase.to_sym
      self.class.send(:attr_accessor, ks)
      self.send("#{ks}=", v)
    }
  end
end

h = {"Now"=>"123","Cat"=>"meow", "Dog"=>"bowwow"}
t = Test4.new(h)
p t, t.cat, t.dog

puts "----\n"
print "Instance_variables: #{t.instance_variables}\n"
print "Singleton: #{t.singleton_methods} \n"
print "Singleton_class: #{t.singleton_class}\n"

# 実行結果

#<Test4:0xxxxxx @now="123", @cat="meow", @dog="bowwow">
"meow"
"bowwow"
----
Instance_variables: [:@now, :@cat, :@dog]
Singleton: []
Singleton_class: #<Class:#<Test4:0xxxxxx>>


# あれーTest4 の中に singleton_class が存在しているのはなぜかしら
# self.class してる時点で自動的に特異クラスができあがっているのだろうか。

# 一瞬 object_id 同じなのか!?とぎょっとしたけど
# print "Object_id: #{t.object_id}, #{t.singleton_class.object_id}\n"
# を実行してみたら同じじゃなかった。

+++ memo +++

これ <http://midorex.blogspot.com/2010/05/selfsend2.html> を書いた頃...
ハッシュを受け取ったクラスがインスタンス変数を定義する際、アクセサによる一定の制限があればいいと考えた。
なぜなら Amazon から受け取る値の[全て]が必要ではないだろうと判断したから。

でも、全ての値をinstanceにしてもいっかと考えれば
アクセサによる制限は必要なくなるので上記のように書き換えてもいいのかもしれない..がよくわかっていない...。

<http://github.com/midore/get_item_amzon>

2010/07/06

mdiaryについて

mdiary はメモ帳、日記帳、ToDo管理、Blogに投稿したファイルの管理、本の管理、思いついたことをどんどん書き込んでいくだけの雑記帳 ...etc. いろいろな用途に利用できます。

[特徴]
1, ファイルタイプ
mdiary が管理する全てのファイルはテキストファイルであることを前提としています。

2, ファイル内の表記について
当初、Blogspot.com に投稿する記事を管理したかった為下記のような項目になっています。

1 --date
2 2010/07/04 Sun PM 12:40:52
3 --control
4 yes
5 --category
6 diary
7 --title
8 NewTitle
9 --content

3, 必要なもの
Mac OS X 10.6.x
Ruby 1.9.x

4, その他
自分が作成した文書(テキストファイル)は、常に統一した文書フォーマットを維持し、尚かつ素早く検索閲覧できるようにするにはどうすべきか?mdiary はこういった自問自答に対する1つの答えだったりしています。
あと、Ruby で遊ぶための口実のようなものが欲しかったというのもあります。口実が目的でもあり Ruby で遊ぶのが目的でもあり、そのあたりは曖昧模糊としています。いわゆる趣味で作ったやつなのです。
[mdiayr の使い方]
# 設定方法などはREADME を読んでください。
0) 新しい entry の作成
% diary -a 
を実行するとTerminal.app で新しいWindow が開き vim が起動します。
こんな感じです。


# 設定ファイルを編集すると vim 以外の editor に変えることもできます。
# テキストエディット.app に変更することもできます。(参照:README)

category と content を編集します。
category は,で区切ることができます。
content には test ... と記入。
編集し終えたら editor を終了し exit します。

1) リスト表示
% diary -l
1 [-] [2010/07/03 Sat PM 13:51:10] [NewTitle] (diary,mdiary)
Select [i/e/r]:

entry が1つしかない場合はすぐにオプションを訊ねられます。
entry が複数ある場合は entry 番号を選んだ後にオプション選択となります。
何も選択しないでこのまま終了する場合はリターンキーか CTRL + C で終了します。

i を選択すると entry ファイルのパスや生成時刻、カテゴリーなどをみることができます。
e を選択すると 先ほどと同じように entry ファイルを開きます。
r を選択すると 選択された entry ファイルは ~/.m_diary/trash に移動し2度とリストに現れなくなります。

2) 日時とタイトルを指定して新しい entry を作る場合
% diary -a 'お菓子ストック' -t '2010/07/30 18:00'

-a でタイトルを指定しています。
-a だけを指定し -t がなかった場合は自動的に現在の日付時刻になります。
-t は '2009/12/01 1:00:00' など過去の日付を指定することもできます。秒数もOKです。

control と content を編集します。
お菓子ストックは重要なので control を 「yes」 から 「must」 にしてファイルを保存します。



保存したらexit します。

リストをみます。
% diary -l
1 [+] [2010/07/30 Fri PM 18:00:00] [お菓子ストック] (diary)
2 [-] [2010/07/03 Sat PM 13:51:10] [NewTitle] (diary,mdiary)
Select NO:

controlを yes 「以外」にすると [-] だったところが [+] になります。

3) [+] マークがついた entry の表示
% diary -s +
1 [+] [2010/07/30 Fri PM 18:00:00] [お菓子ストック] (diary)

-s をつけると tilte, category, control を検索し該当する entry を表示します。
-s '7/30'
でも同様の結果を得られます。

お菓子も大事だけど水と缶詰も重要だったことに気づきました。
2つ目のentryを追加します。
% diary -a 水と缶詰のストック -t '2010/07/30 18:00'
2
Same name file is exist.

先ほどと全く同じ時刻を指定しまった為エラーになりました。
時刻を少し変え 18:10 にすると entry を追加できます。
% diary -a 水と缶詰のストック -t '2010/07/30 18:10'

水と缶詰も重要なので
editor でcontrol を 「yes」 から 「must」 に変えておきます。

[+] の entry を検索します。
% diary -s +
1 [+] [2010/07/30 Fri PM 18:10:00] [水と缶詰のストック] (diary)
2 [+] [2010/07/30 Fri PM 18:00:00] [お菓子ストック] (diary)

4) 今日の日付を持つ entry の表示
% ./test.rb -today
1 [-] [2010/07/03 Sat PM 13:51:10] [NewTitle] (diary,mdiary)
です。

5) 検索について
-s をつけると category, title, control, date 内を検索します。
-st をつけると content 内を検索します。
-today は今日の日付のentry を検索します。

6) 予定の entry の追加
来月になったら思い出すべき事柄があったとします。
未来の日時を指定して entry を追加します。
% diary -a 'Watch TV' -t '2010/08/19 23:00'

editor で編集します。
プラスマークを検索した時に表示させたいので control を 「yes」 から 「enjoy」 にしておきます。
category を TV,music にします。
content に .... 要注意! と記入しファイルを保存し editor を終了します。


リストで来月(現在:2010/07/03) のentry をみるためには -d 2010-08 をつけます。
% diary -d 2010-08 -l
1 [+] [2010/08/19 Thu PM 23:00:00] [Watch TV] (TV,music)
Select [i/e/r]:

-d がない限り、今月の entry 「だけ」を表示します。
# ToDo : 今月の entry しかリストにあらわれないのはやっぱり不便かな...と考え中です。
(コンピュータの日付が8月以降になれば  % diary -l  と打つと 2010年08月の日付をもつentry があらわれます。)

7) content の検索
content の内容に'要注意'という単語が含まれているentry を表示します。
% diary -d 2010-08 -st '要注意'
1 [+] [2010/08/19 Thu PM 23:00:00] [Watch TV] (TV,music)
Select [i/e/r]:

検索する時も -d で検索する月を指定します。-d がなければ今月の entry 内だけを検索します。
# 私のmdiary を vim で検索してみたところ
% diary -s vim
1 [-] [2010/07/02 Fri PM 22:57:36] [vim-practice-autocommand] (vim)
2 [-] [2010/07/02 Fri AM 10:00:00] [vim-practice-filetype] (vim)
3 [+] [2010/07/01 Thu PM 23:00:00] [safari.scpt] (vim, SnowLeopard)

めんどい時は最初から grep などを使ってください。# え"

+++ memo +++
実際の放送予定
2010/08/19 Thu PM 23:30:00

2010/07/01

safari.scpt

インターネットでなにかをみていると、これは!と思うことがあります。ふとみれば vim が立ち上がっている。今開いているファイルにこのURL をメモしておきたいと思ったらどうしたらいいんだろ...

昔(OS 9 の頃か?)今みているブラウザのURL とタイトルをクリップボードにコピーするAppleScript をどなたかが公開していた思うのですが、それに近いことを vim 内でできないかな?って試みです。

vim から osascript を呼び出せると最近知りましたので使ってみました。

# home に戻ります。
$ cd
# テキストファイルを作ります。
$ vim 01.txt
# .applescript でも .txt でもどっちでもいいみたい。

$ 01.txt

tell application "Safari"
  tell current tab of window 1
    set str to "-- 
" & name & "
" & URL
  end tell
  return str
end tell


# コンパイルしてみます。# この時 Safari が起動します。(起動していなかった場合)
$ osacompile -o ~/01.scpt 01.txt

$ vim memo.txt
# vim で memo などしています。と思いきやインターネットもみているとします。

# !!と思ったら
:r !osascript ~/01.scpt


--
Apple - Support - Discussions - Forum Home
http://discussions.apple.com/index.jspa


# ↑こんな感じに title とulr が書き込まれます。
# でも
# Safari の window を開いない時に誤って :r! osascript ... したとすると
... Can’t make name of «class cTab» of window 1 of application "Safari" ....
# ↑このようになっちゃいます。これを修正しつつあらたまった風情にしてみます。

$ cat 02.applescript

script get_title_url
  to main()
    set n to ASCII character (10)
    tell application "Safari"
      try
        tell current tab of window 1
          set str to "--" & n & name & n & URL & n & "<a href='" & URL & "'>" & name & "</a>"
          if URL is "" then return
          return str
        end tell
      end try
    end tell
  end main
end script

on run
  tell get_title_url
    return main()
  end tell
end run


$ osacompile -o ~/safari.scpt 02.applescript
# test
:r !osascript ~/safari.scpt


--
Mac OS X clipboard sharing - Vim Tips Wiki
http://vim.wikia.com/wiki/VimTip687
<a href='http://vim.wikia.com/wiki/VimTip687'>Mac OS X clipboard sharing - Vim Tips Wiki</a>


# うまくいきました。
# -- INSERT -- で \safari と打つとタイトルとURL とリンク形式文字列が埋め込まれるようにしてみる?
# inoremap <Leader>safari <ESC>:<C-u>read !osascript ~/safari.scpt<CR>kkkddjjA

osascript から受け取る文字列の行頭には \n が混入されている為(\n--\n になる)受け取った後にvim側で kkkdd とかしてます。osascript 側からこれを制御できればいいけどどうしてもわりませんでした。

+++

もっと他の方法(or 適切なのはこうだよ or coolなのあるよ or ふつうこうだよ or plug-in あるよ)などをご存知の方は教えてくださいませ。どのようなコメントも大歓迎です。

[2010-07-08]
fileencodings=utf-8 以外を設定しているとおかしなことになるかもしれません。 アマゾンの本のトップページをsafariで開き、上記の safari.scpt をvim 経由で動かすと下記のようになります。 こうならない場合は :set fileencodings? あたりをみてみてください。

# アマゾンの本トップページ
--
Amazon.co.jp: 本 (和書) 
http://www.amazon.co.jp/%E6%9C%AC-%E5%92%8C%E6%9B%B8/b/ref=sa_menu_jb0/377-9481435-0601213?ie=UTF8&node=465392
109 
<a href='http://www.amazon.co.jp/%E6%9C%AC-%E5%92%8C%E6%9B%B8/b/ref=sa_menu_jb0/377-9481435-0601213?ie=UTF8&node=465392'>Amazon.co.jp : 本 (和書)</a>

# 日本語の本を一冊選んだ場合
--
Amazon.co.jp: 床下の小人たち (岩波少年文庫): メアリー ノートン, ダイアナ・スタンレー, Mary Norton, 林 容吉: 本
http://www.amazon.co.jp/%E5%BA%8A%E4%B8%8B%E3%81%AE%E5%B0%8F%E4%BA%BA%E3%81%9F%E3%81%A1-%E5%B2%A9%E6%B3%A2%E5%B0%91%E5%B9%B4%E6%96%87%E5%BA%AB-%E3%83%A1%E3%82%A2%E3%83%AA%E3%83%BC-%E3%83%8E%E3%83%BC%E3%83%88%E3%83%B3/dp/4001140624/ref=pd_ts_zgc_b_526266_1/377-9481435-0601213?_encoding=UTF8&s=books&pf_rd_m=AN1VRQENFRJN5&pf_rd_s=right-4&pf_rd_r=0EK1B90C9XBKZFDFK6AT&pf_rd_t=1401&pf_rd_p=95969149&pf_rd_i=3077031496
<a href='http://www.amazon.co.jp/%E5%BA%8A%E4%B8%8B%E3%81%AE%E5%B0%8F%E4%BA%BA%E3%81%9F%E3%81%A1-%E5%B2%A9%E6%B3%A2%E5%B0%91%E5%B9%B4%E6%96%87%E5%BA%AB-%E3%83%A1%E3%82%A2%E3%83%AA%E3%83%BC-%E3%83%8E%E3%83%BC%E3%83%88%E3%83%B3/dp/4001140624/ref=pd_ts_zgc_b_526266_1/377-9481435-0601213?_encoding=UTF8&s=books&pf_rd_m=AN1VRQENFRJN5&pf_rd_s=right-4&pf_rd_r=0EK1B90C9XBKZFDFK6AT&pf_rd_t=1401&pf_rd_p=95969149&pf_rd_i=3077031496'>Amazon.co.jp: 床下の小人たち (岩波少年文庫): メアリー ノートン, ダイアナ・スタンレー, Mary Norton, 林 容吉: 本</a>

2010/06/29

RubyCocoa

先日<http://ashplanning.blogspot.com/2010/06/google.html>のコメントの中でちゃらんさんに
RubyCocoa 入門を教えていただきました。
こちらを経由し
Programming - RubyCocoa wiki
ここを読みながら遊んでみました。

# サンプル通りに警告音を鳴らす。
% irb
>> require 'osx/cocoa'
=> true
>> names = Dir['/System/Library/Sounds/*.aiff'].grep(/([^\/]+)\.aiff/){ |i| $1 }
=> ["Basso", "Blow", "Bottle", "Frog", "Funk", "Glass", "Hero", "Morse", "Ping", "Pop", "Purr", "Sosumi", "Submarine", "Tink"]
>> OSX::NSSound.soundNamed(names[0]).play
=> true

# OSX::NSSound のpublic メソッドをみてみた。
>> OSX::NSSound.methods
=> ["objc_class_method", "_ns_enable_override?", "kvc_wrapper_writer", "objc_instance_method_type", 
... 略

# OSX::NSSound を管理している OSX モジュールのメソッドをみてみた。
# ものすごい量に驚いてしまった!
>> OSX::methods
=> ["CFRelease", "CGColorSpaceRelease", "CGRectIntersectsRect", "frozen?", "CFNumberGetTypeID", "CGAffineTransformConcat", "launch_data_dict_lookup", "CGPaletteCreateWithByteSamples", "CGPDFDocumentAllowsCopying", "CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes", "to_a"
... 略

# サンプルにあるテキストクラスの生成
>> str = OSX::NSString.stringWithString 'hello'
=> #<NSCFString "hello">

# 'hello'.methods と同じことをしたつもり
>> str.methods
=> ["upcase!", "to_f", "to_yaml", "lines", "sub", "methods", "send", "replace", "empty?", "squeeze", "crypt", "chr", "gsub!", 
... 略

# RubyのString と同じように扱えるようだ。
>> str.upcase
=> #<NSCFString "HELLO">
>> str.reverse
=> #<NSCFString "olleh">

# class String は OSX::NSCFString 
>> str.class
=> OSX::NSCFString

>> str.object_id
=> 216018122

# OSX::NSCFString を str2 に代入
# さっきの str は OSX::NSString.stringWithString だった。
>> str2 = OSX::NSString
=> OSX::NSString

# メソッドの表示
>> str2.methods
=> ["objc_class_method", "_ns_enable_override?", "kvc_wrapper_writer", "objc_instance_method_type", 
... 略

# send でstringWithStringを設定してみる
>> str2.send(:stringWithString, "hi")
=> #<NSCFString "hi">
# ちょっと感動!

# OSX::NSCFString のクラスは?
>> str2.class
=> Class


あ? Class なんだ。

% irb
>> str = String
=> String
>> str.class
=> Class

これと同等てことかな。

+++ memo +++
% sw_vers
ProductName: Mac OS X
ProductVersion: 10.6.4
BuildVersion: 10F569

% ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]

2010/06/27

Blogger Preview

 デザイン->HTMLの編集 画面を表示し
何も編集しないで「プレビュー」をクリックすると
about:blank
になってしまった。まっしろけの画面。はっこれは!? なぜだろう。

Safari の設定を変えて(ポップアップ開く、サイト固有のハックを無効にしない、Runawy JavaScript タイマーを無効にしない、クッキーを常に受け入れる)みたが、やはり about:blank になった。

編集して保存はできたのでよかった。

2010/06/23

launchd.db

一般ユーザが

% launchctl unload -w /System/Library/LaunchAgents/com.apple.midiserver.plist

を実行したとするとその記録はどこにあるんだろうか?

/private/var/db/launchd.db/com.apple.launchd.peruser.XXX/overrides.plist
だった。(XXX は userid)

% cat /private/var/db/launchd.db/com.apple.launchd.peruser.XXX/overrides.plist


一般ユーザの launchctl list の中には
% launchctl unload してもなぜかエラーがかえってきてしまって unload させることができないような agent がたまにある。
そんな場合 overrides.plist に書きこむと確実に unload させることができる。
# 再度ログインしなおすことが必要

+++

as general user

% launchctl list | grep UI

# unload ScreenReaderUI agent
% launchctl unload -w /System/Library/LaunchAgents/com.apple.ScreenReaderUIServer.plist
# => returned error message

# user's id 
% id
uid=XXX(foo) ...

# change directory
% cd /private/var/db/launchd.db/com.apple.launchd.peruser.XXX

# files
% ls
overrides.plist

# look
% cat overrides.plist

# add element
% vi overrides.plit

# logout and login as general user.
% launchctl list | grep UI

vi -i

OS X 10.6.4 で

$ su admin-user
$ vi foo.txt

として保存終了しようとすると

E138: Can't write viminfo file /Users/foo/.viminfo!
Press ENTER or type command to continue

と言われるようになってしまった。いつからこうなったのかはよくわからない。

$ vi -i "NONE" foo.txt
-i オプションをつけて起動するとすんなり終了できた。

GoogleCL post file

GoogleCL から

$ google blogger post --draft --title "test-01" post.txt 

で post する場合

Blogger にログインして
設定->フォーマット->改行の変換を[はい]にしておく必要がある。

こうしておかないと改行のない本文になってしまうようだ。

また --title オプションをつけないでファイルの1行目をタイトルにさせた場合、
実際1行目がタイトルになるんだけど本文にも1行目が残ってしまう...ようだ。

2010/06/21

googleCL

Google のコマンドラインツールを使ってみる をよみまして GoogleCL を試してみました。

(~/home 以下にインストールしたので)

% export PATH=$PATH:/Users/foo/path/to/bin  

投稿してみました。
% google blogger post --title "try-googleCL-1" "command line posting." --tags="google,blogger"
成功しました。

削除してみました。

% google blogger delete --title "try-googleCL-1"
Are you SURE you want to delete post "try-googleCL-1"? (y/N): y
ほんとに削除していいのですか?と訊ねられて y を入力すると投稿は削除されました。

下書きで投稿するには、--draft をつければいいらしい

% google blogger post --draft --title "test-try-googleCL" "command line posting." --tags="test,blogger"
ファイルを指定してみる

% google blogger post post.txt

2010/06/16

refe.rb を読む

これの続き。

たとえば

$ rurema String 

とすると

bitclust の

bitclust/bin/refe.rb String -d db_path

を実行させているってことがわかったので↓
rurema/myrurema/bin/rurema

 92     sh "#{bitclust_path/'bin/refe.rb'}" +
 93           " #{query} -d #{db_path(ver)}", :silent => true


それでふと refe.rb は "String" などの文字列うけとった後どうしているのだろう?と思っておいかけてみた。
(デバッガーみたいなものを使い倒せる人じゃないので p self;exit を付け足すといった原始的な方法)

bitclust/bin/refe.rb

def _main
  refe = BitClust::Searcher.new


BitClust::Searcher をnew して、class Searcher の method parse に "String" という引数を渡しているらしきことがわかったので
class Searcher を探す...

% grep Searcher lib/bitclust
class Searcher は searcher.rb ファイルに納められていることがわかった。

bitclust/lib/bitclust/searcher.rb

 20 module BitClust
 21 
 22   class Searcher


public method parse は80行あたりにあった。

 81     def parse(argv)
 82       @parser.parse! argv


引数としてうけとった argv の中身は
["String", "-d", "/path/to/data/db/1.9.2"]
配列になっていて "/path/to/data/db/1.9.2" は、myrurema でいうところの db_path がわたされていた。

そして条件分岐した後に
refe_mode_check argv
を実行していた。この時 refe_mode_check に渡している argv には ["String"] がおさめられていた。

refe_mode_check をみてみると、(line 118あたり)
@target_type によって条件分岐していて、@target_type が :class だった場合とそうでない場合の処理があった。

でも
% rurema String を実行した場合 @target_type は nil になるので case 中の条件のどれにもあてはまらない。
case がおわった後の箇所から実行されることになる。
(line 135 あたり)

       @view = TerminalView.new(compiler,
...略


class TerminalView を new して @view にそれを代入していることがわかった。
それでこのあとの続きはどこにあるのだろうか?
@view には class TerminalView が代入されているだけで、ほかにメソッドが与えられていない。

これまで辿ってきた道を引き返していくほかなさそうだ... 。
最初までもどってみたら続きがあった。

bitclust/bin/refe.rb

def _main
  refe = BitClust::Searcher.new
  refe.parse ARGV
  refe.exec nil, ARGV

要は
1, _main は ローカル変数 refe に class Searcher を代入する。
2, class Searcher のパブリックメソッドである parse を実行し@view にTerminalView.new を代入する。
3, class Searcher のパブリックメソッドである exec を実行。

ということのようだ。

では早速続きにあたる3番目の箇所 class Searcher の method exec をみてみよう。

 90     def exec(db, argv)
 91       if @listen_url


@listen_url 変数に何か値がはいっていたら spawn_server を、そうでなければ search_pattern を実行する、と。
% rurema String を実行した時 @listen_url は nil なので
line 94 の search_pattern
が実行される。

def search_pattern みてみよう。

200     def search_pattern(db, argv)
201       db ||= new_database()
202       case @target_type || db
203       when :class
...略
214       else


引数として "String" を渡した時は @target_type は nil なので line 214 以降に移動する。移動すると argv のサイズによっての条件分岐が始まる。サイズが 1 の場合は

219         when 1
220           find_class_or_method db, argv[0]

find_class_or_method を実行する...

262     def find_class_or_method(db, pattern)
263       case pattern


pattern の値によって処理を分けている。
pattern には "String" がおさまっている。
db には#<BitClust::MethodDatabase>
 
"String" という文字列受け取った場合は when /\A[A-Z]/ に該当するのでそれに続く begin以降にジャンプする。

270       when /\A[A-Z]/   # Method name or class name, but class name is better.
271         begin
272           find_class db, pattern

次に探すべきメソッドは find_class 。

find_class

241     def find_class(db, c)
242       @view.show_class db.search_classes(c)
243     end


をーここで @view と出会いました。やっと話がつながった感じがします。
つまり

1, _main は ローカル変数 refe に class Searcher を代入する。
2, class Searcher のパブリックメソッドである parse を実行し@view にTerminalView.new を代入する。
3, class Searcher のパブリックメソッドである exec を実行。


この3番目の処理が line 242line 90 にあたると。
2番目の処理で「あらかじめ」Searcher のインスタンス変数である @view に class TerminalView が代入されているからここ(line 242 )で@view.show_class を使うことができるわけね、と。

一応、確認してみると

def find_class(db, c)
  p @view.class, c ; exit
end

% rurema String
BitClust::TerminalView
"String"

ちゃんと TerminalView が代入されている。

ではでは
class TerminalView の methods show_class をみてみよう。

324     def show_class(cs)
325       if cs.size == 1

def show_class は cs をうけとって そのサイズが1だった場合とそうじゃなかった場合とで処理を分岐させている。

% rurema String
の場合、cs は [#<class String>]

% rurema Hash 
の場合、cs は [#<class Hash>]
と変化する。@line が false の場合で、csのサイズが1ならば describe_class を実行する。

なので
% rurema String
した時は

line. 329 describe_class cs.first
を実行するのだとわかった。
では def describe_class はどこだろう? line 411 あたりにあった。

describe_class

411     def describe_class(c)
...略
416       puts "#{c.type} #{c.name}#{c.superclass ? " < #{c.superclass.name}" : ''}"
417       p c.class.name; p c; exit


line. 417 を上のようにしてみると

% rurema String
class String < Object
"BitClust::ClassEntry"
#<class String>

と返ってきたのでローカル変数c には ClassEntry が代入されていてそのクラスは type や name といったメソッドを持っているとわかった。
つづいて

417       unless c.included.empty?
...略
423       unless c.source.strip.empty?

とあって c (すなわち BitClust::ClassEntry)のincluded が empty じゃなかったら空行を1行出力し
c.included.each ...
を実行し
同様に、c.source.strip.empty? がempty じゃなかったら空行を1行出力し
@compiler.compile(c.source.strip)
を実行する。
ようだ。

% rurema String
を実行した場合は何行目の処理が実行されるのか?

line 417 のunless c.included.empty? にキャッチされるとわかった。従ってこの部分

419         c.included.each do |mod|
420           puts "include #{mod.name}"
421         end

を実行していることになる。

変数c には class ClassEntry が代入されているので c.included は、ClassEntryクラスの included メソッド。included メソッドはブロックを受け取ることができるのだなぁ、と。

では class ClassEntry がどうなっているかをみてみよう...。 classentry.rb を開いてみると

bitclust/lib/bitclust/classentry.rb

class ClassEntry < Entry

Entry クラスを継承していた。searcher.rb が使っていた included はどこだろ?継承元の Entry の方なのかな?いや無い。てことは ClassEntry が自分でもっている?ないみたい。

うむむ、どうやら何かにくるまれているようだ...。

hash のキーとしてならあるんだけども...

bitclust/lib/bitclust/classentry.rb

 77       property :included,   '[ClassEntry]'


included のゆくえがわからなくなってしまった。

こういう時は最初に initialize がどうなっているかをみてみよう。

 16   class ClassEntry < Entry
 ... 略 
 36       init_properties


init_properties って何かな?classentry.rb ファイル中にその実態は無いようだ。
継承元のクラスのファイルを開いてみると
% vim entry.rb
init_properties は module_eval によって定義されていた...。

もう一度頭を整理して考えてみよう。呼び出した側は下記のようになっていて
bitclust/lib/bitclust/searcher.rb

419         c.included.each do |mod|
420           puts "include #{mod.name}"
421         end


ClassEntryクラスのパブリックメソッドの中に included という名前のメソッドはない。
classentry.rb ファイル中に included という名前で存在しているのはハッシュのキーのみ。

最終的なところまで近づいてきた感じがしつつもこの先はちょっと難しそうだな。読み解けるかなぁ...
今日はここまで。

2010/06/08

install-rurema

Rubyの新リファレンスマニュアルをコマンドラインから簡単に引くためのツールを書いた

うわっこれいいな。早速 install

http://github.com/yhara/myrurema

README を読むと gem を使ってインストールできるとあったんですが、ちょっと gem 苦手な為 gem を使わないで動せないものかな?と、try してみました。 (OS X 10.6.3)

$ git clone git://github.com/yhara/myrurema  rurema
$ cd rurema/myrurema/bin
$ vim rurema
# shebang を自分の ruby 1.9.2 のパスに修正。#!/usr/bin/env ruby #  changed
$ pwd
/path/to/rurema/myrurema/bin

# とりあえず

$ ./rurema
Usage: rurema [options]
         --init                       initialize rurema
         --update                     update documents and database
...(略)

# README を読みながら
# Init

$ ./rurema --init --ruremadir=/path/to/rurema/data

# これを実行すると ~/home に.subversion ディレクトリができた。

try

$ ./rurema Array#index
You don't have a database for ruby 1.9.2.
109 Make it now? [y/n]
...略

y としたけど ~/home/.rurema を作っていないのだからアップデートできない。

$ ln -s /path/to/rurema/data ~/.rurema

シンボリックはってみた

# Update

$ ./rurema --update --ruremadir=/path/to/rurema/data

# この時勢いよくファンが回りはじめてちょっと不安になった。$ top してみると ruby(OS X に標準インストールされてる方) 一時的に50% 台になったりしつつも基本的には10% 台で動いてた。ずっとみていたら急に90% 近くなってあ”と思ったとたんに終了してほっとした。

# try

$ pwd
$ /path/to/rurema/myrurema/bin
$ ./rurema Array#index
Array#index
--- index(val)           -> Integer | nil 
--- index {|item| ...}   -> Integer | nil 

指定された val と == で等しい最初の要素の位置を返します。
等しい要素がひとつもなかった時には nil を返します。
...(略)


わい
動かすことができたのでエイリアスにしちゃう。

$ vim ~/.bashrc
# alias 'rurema'='/path/to/myrurema/bin/rurema'

$ source ~/.bashrc
$ rurema String#size
String#size
--- length -> Integer
--- size -> Integer

文字列の文字数を返します。バイト数を知りたいときは bytesize メソッドを使ってください。

@see [[m:String#bytesize]]


コマンドラインからるりまをみることができました。うれしいな。便利だなー。

+++ まとめ +++

# Download rurema 
$ git clone git://github.com/yhara/myrurema rurema
$ cd rurema/myrurema/bin

# shebang を自分がインストールした ruby 1.9.2 のパスに修正。#!/usr/bin/env ruby #  changed
$ vim rurema

# 確認 & ヘルプ
$ ./rurema

# database directory
$ mkdir /path/to/rurema/data

# リンク作成
$ ln -s /path/to/rurema/data ~/.rurema

# init and update
$ ./rurema --init --rubyver=1.9.2 --ruremadir=/path/to/rurema/data
$ ./rurema --update --rubyver=1.9.2 --ruremadir=/path/to/rurema/data

# みてみる
$ ./rurema String#size

# alias
# $ vim ~/.bashrc 
# $ source ~/.bashrc


参照
http://ja.wikipedia.org/wiki/Subversion
SnowLeopard には標準でSubversion入っていた。知らなかった。

2010/06/05

plutil

無駄な試みかもしれないけれども下記のヘルプをもう2度とみたくないために書いてみる...。

% plutil -h
unrecognized option: -h
plutil: [command_option] [other_options] file...
  (略)


[ -lint: シンタックスエラーがないかどうかみてくれる! ]

% plutil -lint /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist 
/System/Library/LaunchDaemons/com.apple.mDNSResponder.plist: OK

% plutil -lint ~/.MacOSX/environment.plist 
/Users/foo/.MacOSX/environment.plist: OK


-s で silent mode。OK ならば黙っている。

% plutil -lint -s ~/.MacOSX/environment.plist
%


[ -convert: binary を text にしたり逆にbinary にしたり ]

cat とかで読めない plist を読めるようにする為には convert する。
convert したファイルをいきなり上書きするのがいやな時は -o オプションをつける。

binary plist to text plist

% plutil -convert xml1 ~/.MacOSX/environment.plist  -o ~/test-dot-environment.plist
% 

失敗すると ... file does not exist or is not readable or is not a regular file とかなんとか言われる。

成功すると

% more ~/test-dot-environment.plist

読めるようになる。

今つくったファイルをbinary にするテスト
text plist to binary plist

% plutil -convert binary1 ~/test-dot-environment.plist -o ~/test-dot-bin-environment.plist

% more test-dot-bin-environment.plist 
"test-dot-bin-environment.plist" may be a binary file.  See it anyway? 

% defaults read ~/test-dot-bin-environment


-e オプションについてはわからず。

+++ memo +++

defaults コマンドを使うと設定内容を閲覧できる。
こんなかんじで。
% defaults read /Library/Preferences/SystemConfiguration/com.apple.PowerManagement
/Library 配下の plist ファイルを指定する時は必ずフルパスで指定する必要がある。

で、おもむろに
% defaults read com.apple.Finder
などとうってみたりするとすんなり返事をかえしてくれる。
(たとえ cd /Volumes していて ~/home にいなかったとしても)
ログインユーザ所有の plist を指定した場合は admin 所有のplist 等とは異なり
必ずしもフルパスを要求されない。

以前は、こうじゃなかったような気もするんだけど
(つまりユーザplist もフルパスを毎度毎度要求されていたような記憶があるんだけども)
おもいっきり記憶違いかもしれない。とりあえず OS X 10.6.3 では今このようになってる。

2010/06/02

install-ruby-1.9.2-preview3

さっそく

% autoconf
% ./configure --prefix=/Volumes/foo/ruby192 --program-suffix=192 --with-x=no
% make
% make test
% make install


% make test の時

PASS all 932 tests
 ./miniruby -I./lib -I.ext/common -I./- -r./ext/purelib.rb  ./tool/runruby.rb --extout=.ext  -- "./bootstraptest/runner.rb" --ruby="ruby1    92"  ./KNOWNBUGS.rb

Driver is ruby 1.9.2dev (2010-05-31 revision 28117) [x86_64-darwin10.3.0]
Target is ruby 1.9.2dev (2010-05-31 revision 28117) [x86_64-darwin10.3.0]


KNOWNBUGS.rb .
PASS all 1 tests

となりましたが KNOWNBUGS とあったので気にしないで install してみました。

github.com/midore/mblogger
をruby 1.9.2 preview3 でもって「この投稿」を投稿してみました。どうかな?
=> 成功しました。
put はどうかな?
=> OK.

github.com/midore/mdiary
こっちも、検索できなくなったかな?と思ったけどできてるみたい。

github.com/midore/2010-amazon-jp-api
は動かない!と思ったらruby 1.9.2 はとはぜんぜーん関係ない問題でした。ショック。ずっと気づいてなかった。

2010/06/01

Mac OS X Security Configuration Guides

Mac OS X にはファイル共有機能があるので、例えば自宅にある複数のコンピュータ間でデータをやりとりできるし、iTunes 共有機能を使えば メインのコンピュータのiTunes を複数のコンピュータで共有できます。
また、sshd など 使えば外出先からでも自宅のコンピュータにアクセスできます。
そういった様々な OS X に付随してるサービス機能をふる活用させている方も世の中にはいらっしゃるのでしょう。

けれども、いまどき自宅コンピュータをサーバ化させたい人のうち Mac OS X を選択する人ってどれだけの割合なのでしょうか?もし仮に私がそういう必要に迫られたとしたら迷わず Ubuntu を使うと思います。

多くの人が、OS X をクライアントとして使用しているにすぎなくて、たまに iPodやiPhoneやiPad と同期させるくらい。
だとするならば...
下記のドキュメントはより多くの Mac OS X Users に読まれるべき文章なんじゃないかと思います。

Mac OS X Security Configuration Guides

ただ、日本語化されていません。
過去の Leopard 時代の文書ですら未だに日本語化されていないようです。

で、英語ですがコマンドに慣れてる人なら最後の index 眺めてみるだけでもポイントを押さえられます。

コマンドを使ったことない方でも、
手始めにターミナル(Applications->Utilities->Terminal.app)のヘルプの中の「UNIX の基礎」に目を通し、興味を持てそうであればUNIX関連の書籍や、コマンドリファレンス的な本やそもそも shell って何?的な本を眺めつつ、簡単なコマンドの練習などしながら、これを機会にコマンドに慣れていけば大丈夫かと思います。

+++ 追記:上記ドキュメントを読む読まない以前の最低限のセキュリティ +++

1, たとえ自宅にたった1台しかコンピュータがない場合でも ルータ を使用する。
2, 無線ルータの WEP の使用を避ける。
3, ウイルス対策用のアプリケーションを購入する。また、そのアップデートを怠らない。
4, OS X のソフトウエア•アップデートは定期的に必ず行うか自動アップデート(システム環境設定->ソフトウエア•アップデート->アップデートを自動的にダウンロード)にしておく。
5, ファイアウォール機能を有効にする。(システム環境設定->セキュリティ->ファイアウォール)
6, 自分ユーザにファイル共有させる必要がないのであれば FileValut を 入 にする。
7, システム環境設定->共有 不必要なサービスを起動しない。
8, 必要がないかぎり、システム環境設定->アカウント->ゲストアカウント は無効にしておく。

2010/05/20

self.send()[2]

http://midorex.blogspot.com/2010/05/selfsend.html
の続き。

  class Foo
    ary = [
      "Author", "Binding", "Creator",
      "EAN", "ISBN", "Label",
      "Manufacturer", "NumberOfPages",
      "ProductGroup", "ProductTypeName",
      "PublicationDate", "Publisher", "Studio",
      "Title", "MediumImage", "Price", "Edition",
      "Rank", "DetailPageURL", "Artist",
      "Format", "NumddberOfDiscs", "OriginalReleaseDate",
      "PackageQuantity", "ReleaseDate", "UPC", "RunningTime"
    ].each{|x| attr_accessor x.downcase.to_sym}

    def initialize(h)
      return nil unless h
      set_up(h)
      #@created ||= Time.now.to_s
    end

    def detail
      str = ""
      ins_a.each{|i| str << i.to_s.gsub("@",'').upcase + ":\s" + self[i] + "\n" }
      return str
    end

    def set_up(h)
      h.each{|k,v| 
        begin
          self.send("#{k.downcase.to_sym}=", v)
        rescue NoMethodError
          next # ignore new value.
        end
        }
    end

    # def detail needs [] and ins_a
    alias [] instance_variable_get
    alias ins_a instance_variables

    private :set_up, :[], :ins_a

  end
  h = {'Artist'=>'artist-name','Title'=>'music-title'}
  p Foo.new(h)


% ./test-item.rb
#<Foo:0x000000000 @artist="artist-name", @title="music-title">

h = {'Artist'=>'artist-name','Title'=>'music-title'}
h['noindex'] = 'noindex'
p Foo.new(h)
% ./test-item.rb
#<Foo:0x000000000 @artist="artist-name", @title="music-title">

git => github.com/midore/get_item_amzon

2010/05/16

self.send()[1]

gdata-1.1.1 を読んでいたら gdata-1.1.1/lib/gdata/client/base.rb に

41           self.send("#{key}=", value)

とあった。

それで
クラスを初期化する際 hash をもちいてインスタンス変数を一気に設定したい場合について考えてみた。

1) 最初にgdataでも使われている self.send() を使った場合

  3 class My_1
  4   attr_writer :id, :name
  5   attr_reader :name
  6   def initialize(h={})
  7     h.each{|k,v| self.send("#{k}=", v)}
  8   end
  9 end
 10 
 11 h = {:id=>'123', :name=>'abc'}
 12 p My_1.new(h)


実行結果
#<My_1:0xxxxxxxx @id="123", @name="abc">

ハッシュのキーと値がinstance 変数に設定されていることがわかる。
また attr_writer によって :id と :name 以外のkey を受け付けないよう設定されている。
これを確認する為、
h = {:id=>'123', :name=>'abc', :title=>'ddd'}
に変更し実行してみると
...(NoMethodError)

:title は attr_writer に定義されていないので instance 変数として定義できないことが確認できた。

2) 次に self[]= をつかってinstance 変数を設定するクラスの場合

 15 class My_2
 16   attr_writer :id, :name
 17   attr_reader :name
 18   def initialize(h={})
 19     h.each{|k,v| self[:"@#{k.downcase}"] = v}
 20   end
 21    alias []= instance_variable_set
 22    alias [] instance_variable_get
 23    private :[], :[]=
 24 end
 25 p My_2.new(h)


実行結果

#<My_2:0xxxxxxxx @id="123", @name="abc">

My_1 の場合と全く同じ結果を得ることができる。
では、My_1 の場合と同様に h を変更し
h = {:id=>'123', :name=>'abc', :title=>'ddd'}
として実行してみるとどうなるか?

実行結果

#<My_2:0xxxxxxxx @id="123", @name="abc", @title="ddd">


attr_writer とは無関係になんなく :title が定義されてしまった。
15行目のattr_writer :id, :name は class My_2 においては無意味のようだ。

では、あたかも attr_writer を設定したかのようにさせるにはどうすればいいのだろうか?

 14 class My_2
 15   @@ins_keys = [:id, :name]
 16   @@ins_keys.each{|x| attr_reader x}
 17   def initialize(h={})
 18     h.each{|k,v|
 19       key = k.downcase.to_sym 
 20       self[:"@#{key}"] = v if @@ins_keys.index(key)}
 21   end
 22   alias []= instance_variable_set
 23   alias [] instance_variable_get
 24   private :[], :[]=
 25 end
 26 h = {:id=>'123', :name=>'abc', :title=>'ddd'}
 27 p m = My_2.new(h)
 28 p m.name

実行結果

#<My_2:0xxxxxxxx @id="123", @name="abc">
"abc"


@@ins_keys を定義し19行目に if @@ins_keys.has_key?(k) を追加することで
attr_writer に「似た」役目をはたしてもらうことにした。
attr_reader は16行目にまとめた。
配列の要素を全て attr_reader にした。
配列の要素をチョイスして attr_reader したい場合はさらに2行加える必要あり。

@@ins_keys に登録されていない :title は定義されなくなった。
つまり定義したい instance 以外 が定義されるようなことはおこらないという意味で My_1 と同じ結果を得られるようになった。
ただし、My_1 ではerrorが返ってくるが My_2 では error にはならない。
error を返す必要があれば20行目直前に raise unless @@ins_keys.index(key) などすればいいのかも。

+++ メモ +++

0) self[] を initialize で使用しつつどの key を instance 変数として定義するかをちゃんと制御したい時
attr_writer で設定したつもりになっていてもそれは意味をなさないので、別途 式を用意するなどする必要がある。
あるいは最初から My_1 のような方法を採用した方がいいかも。
あるいは通常どおりに def initialize で @id = nil などと定義しておいて instance_variable_defined? を使う。

1) (派手に間違えているかもしれない)書きながら浮かんだイメージ
self.send()
は、一旦廊下に出て attr_writer ドアをノックしてから self 部屋に入るが、
self[]=
は、既にself 部屋の内側に入っていて attr_writer ドアの存在を意識していない。
といったようなイメージ。

2) git にあげてある 2010-amazon-api-jp に、上記の内容を反映する予定は未定。

続き

2010/04/21

2010-amazon-api-jp

SnowLeopard で OpenSSL がバージョンアップしたことに伴い
amazon-jp-api を作り直した。
=>
2010-amazon-jp-api

[参考になったURL]
OpenSSL SHA 256 の使い方はhttp://diaspar.jp/node/239 を参考にしました。

[主な変更点]
1, Mac OS X 10.6.3 で SHA256 を使えるようになったことに伴う変更。
module AmazonAuth => 新規に作ったモジュール。認証用。
2, 設定ファイル => 2つのモジュールにわけた。
3, class AwsItem => インスタンス変数の持ち方の変更。
4, class AmazonAccess => アマゾンにアクセスしデータを獲得したのちに AwsData.new(data).add_data でアイテムまで生成していたが、アイテム生成は他のクラスに移動させて、このクラスはアマゾンにアクセスしデータを獲得するだけのクラスに変更した。
5, class AwsDataWriter => 新規に作ったクラス。マーシャルデータを変更するためのクラス。
6, class AwsDataReader => 新規に作ったクラス。マーシャルデータを読み込んで表示させるためのクラス。
7, module AmazonAuth => 新規に作ったモジュール。アマゾン認証を行うためのもの 。

[変更されていない点]
1, ローカルで使うもの。
2, Ruby 1.9.1 だけで動き Ruby 1.8 系はサポートしていない。
3, マーシャルデータを使用している。
4, 指定したEAN の本やCDのデータをアマゾンから受け取ることができるがアマゾンサーバに対して検索はできない。
5, README に書いたオプション引数はそのまま。

[少しだけ気になっている点]
1, もともとのものは force_encodig を使わないように 変更している。今回もこの状態でうまくいったので受け取ったXMLデータが valid? かどうかだけチェックするにとどめ encode 変換は行っていない。このことによってなにか弊害があるのかないのかは謎。
2, timeout を使っている。使わないバージョンも作ってみたがあっさり挫折。
3, exec を使っている。exec を使わないバージョンを考えてみたがわからなくなって中断。
4, send を使っている。最近使い方を覚えたため、使ってみたかったから使っているにすぎない。あえて使う必要はないのかもしれない。

[このブログ内の関連する投稿]
=> http://midorex.blogspot.com/2009/06/amazon-web-with-ruby-191.html
=> http://midorex.blogspot.com/2009/08/amazon-product-advertising-api.html
=> http://midorex.blogspot.com/2009/12/forceencoding.html
=> http://midorex.blogspot.com/2008/12/amazon-aws-with-ruby191.html

[Amazon ラベルをもつ全ての投稿]
Amazon

2010/04/03

はじめての send

ISBN: 978-4048678841 | リファクタリング:Rubyエディション (大型本)

この本、私は対象読者ではなかった。飛ばし読みしていたらあっという間に p.165 までたどり着いてしまった。

そこで目にしたもの
p.165

サンプル
引数をまとめたHash を受け付けて、それらの引数をインスタンス変数に代入する SearchCriteria クラスがあるものとする。

とあり
p.166

Class.send :include, CustomInitilizers


send って何?といろいろ試してみた。

  1 #!/usr/local/bin/ruby191
  2 # coding: utf-8
  3 
  4 module Items
  5   module Setup
  6     def base(h)
  7       h.each{|k,v| self["@#{k}"] = v}
  8     end
  9     alias []= instance_variable_set
 10     alias [] instance_variable_get
 11   end
 12   class Music
 13     def initialize(h)
 14       self.base(h)
 15     end
 16   end
 17   class Book
 18     def initialize(h)
 19       base(h)
 20     end
 21   end
 22   Object.send :include, Setup
 23 end
 24 
 25 h = {:isbn=>'978xxx', :title=>'book-title', :price=>'1000'}
 26 p b = Items::Book.new(h)
 27 h = {:isbn=>'077xxx', :title=>'music-title', :price=>'2000'}
 28 p b = Items::Music.new(h)
 29 p b['@title']

=>
#<Items::Book:0xxxx @isbn="978xxx", @title="book-title", @price="1000">
#<Items::Music:0xxx @isbn="077xxx", @title="music-title", @price="2000">
"music-title"


最近知った あのaliasを使ってみた。

そして
「プログラミング言語 Ruby」p.285
を読み直した
Book.public_send :include, Setup
にしてもOKだった。

さらに
「Ruby Way」( Second edition)
にて send を探してみたら p.350 にsort_by のカスタムバージョン例の中で send を使う例があった。

self.sort{|x,y| x.send(sym) <=> y.send(sym)


この場合、x はArrayの要素でその要素のひとつひとつには Preson.new() Object が入っていて、
で、Presonの@name は attre_reader で読み込めるようになっている。ここがミソ。従ってソート対象として:name を指定することができる、と。
attre_writer :name だったらこれは成功しないだろう。
p.350 をジーとみているとうっかり send(@name)なのだと勘違いして理解しそうになるが、
send は「シンボル」を受けつけるのだから、send(@name) ではダメ。

+++ まとめ +++
send or public_send (Ruby 1.9) はシンボルを受けつける

module XXX
  module Setup ... end
  class Book ... end
  class Music ... end
  Object.send :include, Setup
end

Object.send とした場合は module が内包する[全て]のクラスのinclude メソッドに Setup module をおくりつけたことになる、と。
Object.send を Class.send としてみたら
`initialize': undefined method `base'
のエラーになった。

module XXX
  module Setup ... end
  class Book ... end
  class Music ... end
  Book.send :include, Setup
end

とした場合は module XXX が内包するBook クラスに[だけ]Setupをおくったことになる
従ってこの場合

module XXX
  module Setup ... end
  class Book
    include Setup
  end
end

と全くおなじ、と。

2010/03/18

git-clone-port

memo

github.com で公開されてるプロジェクトを clone したい時
TCP 9418
が出て行くのを許可されてないと clone できない。

2010/03/16

The Catcher in the Rye

「The Catcher in the Rye」by J.D. Salinger
は二人の訳者によって日本語に訳されています。

ISBN: 978-4-560-07051-2 | ライ麦畑でつかまえて | J.D.サリンジャー | 野崎孝訳
ISBN: 978-4-560-04764-4 | The Catcher in the Rye | J.D.サリンジャー | 村上春樹訳

下記は、両者の相違を通しイチ読者としての勝手で野暮な感想を述べたものです。

1) 書き出し
野崎孝訳 p.5

もしも君が、ほんとうにこの話を聞きたいんならばだな、まず、僕がどこで生まれたかとか、チャチな幼年時代はどんなだったかとか、そういった<<デーヴィッド•カパーフィールド>>式のくだんないことから聞きたがるかもしれないけどさ、

村上春樹訳 p.5

こうして話を始めるとなると、君はまず最初に、僕がどこで生まれたかとか、どんなみっともない子ども時代を送ったかとか、僕が生まれる前に両親が何をしていたかとか、その手のデイヴィッド•カッパーフィールド的なしょうもないあれこれを知りたがるかもしれない。


2003年春。村上春樹訳の「The Catcher in the Rye」のこの冒頭の1行目を目にした時、この本は私がかつて読んだあの「ライ麦畑でつかまえて」とマルッキリ!違う本だぞと瞬時に認識しました。正直に言うと、みてはいけないものをみてしまった感に襲われました。その日からあっというまに何年か経過してしまいました。

サリンジャーのこの作品についてふれることは私にはちょっとヘビーなので、できれば永久に避けたいと思っていましたが村上春樹訳「The Catcher in the Rye」が手元にあったことで何かが変わりました。

2) 走ることへの衝動
野崎孝訳 p.11

何のために駆けたりなんかしたのか、自分でもよくわかんないーたぶん、なんということもなく、ただ駆けたくて駆けたんだろう。
いやあ、スペンサー先生の家につくが早いか、いきなり僕はベルを鳴らしたね。

村上春樹訳 p.12

なんでわざわざ走らなくちゃならないのか、自分でもそのへんはよくわからないけど、たぶんただ走りたかったんじゃないかな。
やれやれ、やっとの思いでスペンサー先生の家にたどり着くと、僕はすごい勢いで玄関のベルを鳴らした。


この文の前後ははしょりましたが、主人公はまるで10歳くらいの子どものように突然走り出します。冬の寒い日、ふいに何かに背中を押されれたかのようにして、ぶったおれるかと思うくらいの勢いで走り出すわけですが、村上春樹氏の訳はこの年頃のこの感覚をすっかり忘れてしまったか、もともとそれを知らない人(たぶん走るのが好きじゃなかった人)が訳したかのような印象をうけます。

村上春樹氏が書いた小説の中に、貧乏を経験したことのある人間かそうでないかはそれを知っている人間にはすぐわかる(正確にはこのとおりではない)、
といったようなことを主人公に語らせている作品が確かあったと思うのですが...もう子どもじゃないと自覚してるのに、無性に駆け出したくなったことがある人間か、そうでないかは、この訳の違いを読むとわかるような気がします。

3) 会話
野崎孝訳 p.52

「おれにわかるはずないだろ。どいてくれ。おまえ、おれのタオルに坐ってるじゃねえか」と、ストライドレイターは言った。僕は奴の間抜けなタオルの上に坐ってたんだ。

村上春樹訳 p.56

「よくわからねよ、そんなこと。とにかくそこをどいてくれよ。お前な、俺のタオルの上に座ってるんだぜ」とストライドレイターは言った。僕はたしかに彼のくだらないタオルの上に座っていた。


奴の間抜けなタオルがいかに間抜けになるか?はストライドレイターにいかにカッカして言い放ってもらうか、にかかっていると思います。そして奴の間抜けなタオルにはちゃんと間抜けになってもらってコールフィールド的な笑いを読者に受け止めてもらわないと、ここではなにもかもが台無しなんだと思います。
で、野崎孝訳では「...じゃねえか」と「...坐ってたんだ」がその役割を果たしています。

が、村上春樹訳では、「... に座ってるんだぜ」と、...ぜ、が使われていることと、その直前に「とにかく」って単語が加わることでストライドレイターのカッカが薄く間延びしたものになってしまっています。また「僕はたしかに...」と「たしかに」って単語が加わることで、間抜けなタオルの間抜けさは間抜けでもなんでもないただの退屈なタオルになりさがってしまってます。この感覚。
コールフィールド特有の奴に対するワライはすべってませんか?

4) 時間に関するジョーク
野崎孝訳 p.59

...まるでこっちが恩恵を施されてるみたいな感じなんだ。
奴は支度するのに、五時間ばかしかかった。

村上春樹訳 p.64

... 君はきっとアックリーの方がこっちに恩恵を施していると思うだろうよ。
アックリーが出かける支度をするのに、だいたい五時間かかった。


この抜粋された文だけを、今、生まれて初めて目にした方はアックリーが支度をするのに5時間かかったのが、ジョークだなんてピンとこないんだろうけれども、最初からこの作品を読んできている読者にはこれがコールフィールドのジョークだとすぐにわかります。野崎孝訳においては。
村上春樹訳によってこの作品を初めて読んでいる読者が、これがジョークだとすぐにわかるものなのかどうか、私には疑問です。

他にもこれと同じように、実際とは無関係なおおげさな数字が書かれている箇所がいくつかあって、そのたびに読者はちょっとクスッとなります。
野崎孝訳p.312

校長の姿は見えなかったけど、百歳ばかしの年取った女の人が、...

これも同様のパターン。

5) 叫び
野崎孝訳 p.84

「ガッポリ眠れ、低能野郎ども!」

村上春樹訳 p.89

「ぐっすり眠れ、うすのろども!」


おそらく、読者はここで一旦お茶をいれるか一旦本を閉じるか、俺も(or私も)寝るわと電気を消すなどすると思うんだけども
「ああ、ガッポリ寝るわ、豚のようにね」(笑)
などと冗談を言いかえしたくなるのは野崎孝訳であって村上春樹訳を読んでいてもそんな気持ちにはなれそうにありません。私は。

ガッポリってところが、ちょっといいわけです。このちょっとした笑い「クスッ」感がとてつもなく大事なのです。どれだけ大事かというと、なにはともあれ、なにをさしおいても大事、としかいいようがありません。しかもそんな馬鹿げた声が静かな廊下にこだましちゃってたところが尚面白いわけです。

このニュアンスを持つか持たないかが両者の大きな違いのようにも感じます。とらえどころが難しいけども決定的な違い。主人公コールフィールドは始終まともな話ができる人と話をすることに飢えていますが、同じ作品を訳したにもかかわらず、村上氏の訳ではその切実感が薄いのはこのあたりにも秘密があるような気もします。

6) 恩師との会話
野崎孝訳 p.284

「英語はどうだった?英語をしくじったなんて言おうものなら、さっさと出て行ってもらうからな。この若き作文の天才め」

村上春樹訳 p.303

「英語の成績はどうだった?もし君が英語を落としたというのなら、すぐさまこの場を退出していただくことになる。なにしろ君は作文に関しては文句なしのエースだったもんな」


野崎孝訳では、さっさと出て行ってもらうからな... と一瞬すごみをきかした先生が、 この...天才め、と言い放つと同時に笑顔になっている様がよく伝わってきます。先生の顔をみながら主人公の顔も少しほほえんでいるのが(視覚的に)よくみえるような気がします。この先生が冗談好きな明るい人間だってことも一瞬に理解できるし、主人公がなぜこの人を訪ねたのかもよくわかります。それで安心して私も主人公が座った椅子の隣にこしかけたい気持ちになります。

しかし村上春樹訳で読むと、この先生、なんともまわりくどい言い方をする人だなって印象を持ちかねません。退場していただく、と品のある言い方で書かれているせいか先生の陽気さが半減してしまってます。読者である私はそこに同席したいなど感じません。
これでは、なぜ主人公がこの人に会いにやってきたのかが読者に伝わりにくいのではなかろうか?と心配になります。

この文によって、読者はなぜ主人公はこの人に会いにやってきたのかを知ることができるので、ここは話の構成上でも重要なんじゃないかと思います。
その後、この恩師の家を出ていくことになる出来事とのギャップを浮き彫りにする上でも大切に感じます。

...

全体を通して、村上春樹訳では重要な何かが「ガッポリ」ぬけおちているように感じます。単語の多さとまるで反比例しているのは興味深いところです。

野崎孝訳ではコールフィールド独特のささやかな笑いや、ちょっとした気の利いた言い回しなんかによって、この少年がどういう人物かってことが読者には手にとるようにわかるようになっていると、私は思うのですが、そのあたりのおもしろみが村上訳からは消えさってしまっているように思います。

たとえば「やれやれ」って言葉を村上春樹氏の小説の中に登場する主人公が口にした時、それはまるで彼によく似合う服のようだから、読んでいてなんのさしさわりも感じないし、むしろほどよく彼の気持ちが伝わってきます。こういう時にこういう感じ方をするのが彼なんだなとぐっと彼に近づきますが、サリンジャーの主人公は「やれやれ」が似合うような主人公じゃないと思うんです。決して。彼はそんなにクールでもないし。

ディケンズの名作をくだらないって言ってのけちゃう少年。しいていえば、夏目漱石なんてくだらない、あたりまえだろって言っている少年と同じなわけです。
日本語の「やれやれ」が持つニュアンスを多少の笑いを含んで言えるような人物が、
「その手のデイヴィッド•カッパーフィールド的なしょうもないあれこれ...」
あるいは
「そういった<<デーヴィッド•カパーフィールド>>式のくだんないこと」
と、斬って捨てるような言い方をするだろうか?と、違和感を感じます。
例えば「そういった<<坊ちゃん>>的なくだらないこと...」
などとは、そういう人は言わない、いや、言えないんじゃないのかな。

だから、そもそも「やれやれ」などとコールフィールドが心の中で口にすることができていたのなら、この小説自体生まれなかったんじゃないの?とも思うのです。「やれやれ」と心の中でつぶやきつつその場をやりすごすことができるかできないか、そのハードルを超えるか超えないかの、違い。そのハードルこそがコールフィールドにとってはとてつもなく巨大で重要で真っ暗な出来事として描かれていると、私は思うので、そこをまるっきり無視しちゃっうのならこの作品の存在自体を否定しかねないのではないか?と考えてしまいます。
実際、野崎孝氏は一度も「やれやれ」なんて使わないで訳を完了させてしまってますしね。ところどころ言葉遣いの古さは否めないけど。

私は作品の主人公とほぼ同年齢に野崎孝氏訳の「ライ麦畑でつかまえて」に巡り会えてよかったと思ってます。大人になってからこの作品を読んだ人の感想をどこかで信用していない悪い癖がついてしまったのは、それはしかたのないことだと言いかねないほど。

2010/03/08

NASAが...

NASAが1000日後にアバターを月に送り込む予定
によると

もしヒューマロイドを月に送り込み、科学者達自身での探索が可能になったら、それは全ての科学者を実際に月に送り込むのと同じくらいの意味があります
。科学者達が彼ら自身で探索し研究の対象となるサンプルを探すことができるのです。遠隔操作はほんの3秒くらいのタイムラグだそうですよ。

だそうだ。

ヒューマロイドがロビイになったりしませんように。
ディヴになったりしませんように。
ハーヴィーになったりしませんように。
どうかロボットデカルトさまになったりしませんように^^;

instance_variable

http://ujihisa.blogspot.com/2009/12/left-hand-values-in-ruby.htmlを読んで試してみたこと。

  1 #!/usr/local/bin/ruby191
  2 # coding: utf-8
  3 
  4 class Diary
  5   def initialize
  6     @title, @date = nil, nil
  7   end
  8   alias [] instance_variable_get
  9   #alias []= instance_variable_set
 10   def []=(i, v)
 11     instance_variable_set(i, v) if i_defined?(i)
 12   end
 13   def i_defined?(i)
 14     instance_variable_defined?(i)
 15   end
 16 end
 17 
 18 d = Diary.new
 19 d['@title'] = "NewTitle"
 20 d['@date'] = Time.local(2010,02,01)
 21 d['@ddd'] = 'ddd'
 22 p d['@title']
 23 p d
 24 # =>
 25 # "NewTitle"
 26 #<Diary:0xxxx @title="NewTitle", @date=2010-02-01 00:00:00 +0900>


initialize をとりさり i_defined? もとりさってみる

 29 class Diary
 30   alias [] instance_variable_get # instance_variable_defined?
 31   alias []= instance_variable_set
 32 end
 33 
 34 d = Diary.new
 35 d['@title'] = "NewTitle"
 36 d['@date'] = Time.local(2010,02,01)
 37 p d

% ./try.rb
#<Diary:0xxxx @title="NewTitle", @date=2010-02-01 00:00:00 +0900>

勉強になった。

self.instance_variable_set
にしなくちゃいけないと思っていた。
instance_variable_set
だけで動くなんて知らなかった!

alias [] instance_variable_get
これでinstance の値をとれるなんて!

instance_variable_get
のところを
alias [] instance_variable_defined?
に変えてみたら値をとるかわりに定義されているか否かを true or false で返してくれた!びっくり。

alias [] instance_variable_get
alias []= instance_variable_set
alias [] instance_variable_defined?

のようなことをしてみたくなったが
[] methods
は1度使ってしまったら2個目は使えない。の overwrite されちゃう。あたりまえかも。
1回目の [] と
2回目の [] を
区別させる方法はない? ぽい。

2010/03/04

部分変更重要

入門Git のp.57-58 を読みながら試してみたこと

# 複数のファイルが git diff に表示されていた場合、git add -p する際にファイル名を指定することもできた。
% git add -p filename
% git add -p
してすぐにリターンするとヘルプをみることができた。

思い通りに hunk が分かれていなかった場合は s 選択するとより細かく分割してくれるようだ。今回のコミットに反映したい箇所は y で反映したくない時は n。 q で終了。

% git diff --cached
今からコミットする内容を確認

% git commit -v
変更箇所の詳細内容をみながらコミット文を作成できる。書式ルールは

1行目が要約文
2行目空行
3行目以降に詳細文

これからは要点と合致した commit を心がけようと思った。

2010/02/26

UTF8-MAC [2]

UTF8-MAC みなおし。

要は \\ があればいいんでしょ?とお気楽な発想を展開してみました。
が、以下は非常によろしくないことをしている可能性あり。
あくまでも実験なので試さない方がいいです。おい

macustr.rb

  1 #!/usr/local/bin/ruby19
  2 # coding: utf-8
  3 
  4 exit unless Encoding.default_external.name == 'UTF-8'
  5 
  6 require 'nkf'
  7 def macustr(line)
  8   str = String.new # p str.encoding
  9   line.chars.entries.each{|x| str << "\\" + x}
 10   #line.codepoints.entries.each{|x| str << "\\" + [x].pack("U*")}
 11   mustr = NKF::nkf('--ic=UTF-8 --oc=UTF8-MAC', str)
 12   return mustr
 13 end
 14 
 15 ARGF.each{|line|
 16   exit unless line.encoding.name == "UTF-8"
 17   next unless line.valid_encoding?
 18   mustr = macustr(line.strip)
 19   next unless  mustr.valid_encoding?
 20   sh = system("mkdir #{mustr}")
 21   print "Maked Directory: #{line}" if sh
 22 } 
 23 


line 4 : 環境変数LANGが UTF-8 でない場合はおいかえす。
line 16: 読み込んだ文字列が UTF-8 でなければすぐ終了。
line 17: valid でなければ次
line 18: def macustr に一行わたす
line 9 : 冒頭に"\\" を付け加えて一文字ずつ str に追加。最初は line 10 にしたのだが line 9 にしておいた。
line 11: str を UTF8-MAC に変換
line 19: valid でなければ次
line 20: mkdir コマンド
line 21: コマンドが成功したらメッセージ表示

./macustr.rb utf8_text.txt

を実行すると utf8_text.txt を一行ずつ読み込み
同名のDirectory を同じ階層に作成します。
utf8_text.txt は UTF-8 で保存されたテキストファイル。

[2010-02-27]
s/chomp/strip/g

[2010-03-08]
追記
# 失敗例

  1 #!/usr/local/bin/ruby19
  2 # coding: utf-8
  3 # test-encode.rb
  4 
  5 text = 'utf8-text.txt'
  6 # % cat utf8-text.txt 
  7 # and two &three
  8 
  9 File.open(text, "r:utf-8"){|f|
 10   f.each_line{|x|
 11     #  行末\n や行頭\s を削除
 12     line = x.strip
 13     # print out
 14     puts "Line: \"#{line}\"| Encoding: #{line.encoding}| Valid: #{line.valid_encoding?}\n"
 15     puts "# Calling encode\n"
 16     # encode で変換
 17     mustr = line.encode("UTF8-MAC")
 18     # print out
 19     puts "String: \"#{mustr}\"| Encoding: #{mustr.encoding}| Valid: #{mustr.valid_encoding?}\n"
 20     print "# Calling system\n"
 21     # Directory 作成
 22     sh = system("mkdir #{mustr}")
 23     puts "Result: #{sh}\n--\n"
 24   }
 25 }
 26 
 27 =begin
 28 % ./test-encode.rb 
 29 Line: "and two &three"| Encoding: UTF-8| Valid: true
 30 # Calling encode
 31 String: "and two &three"| Encoding: UTF8-MAC| Valid: true
 32 # Calling system
 33 sh: three: command not found
 34 Result: false
 35 
 36 % ls -F
 37 and/            test-encode.rb* two/            utf8-text.txt
 38 =end


17行目

mustr = ine.encode("UTF8-MAC")

mustr = line.force_encoding("UTF8-MAC")

にしても同様の結果だし

require 'nkf'
mustr = NKF::nkf('--ic=UTF-8 --oc=UTF8-MAC', line)

としてみても結果は同じ

検索して次を読んでみたけど よくわかってないというか...。
<http://redmine.ruby-lang.org/issues/show/1411>
<http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/40233?help>

+++ 感想 +++

通常 Mac OS X を使用する上で自ら日本語名のフォルダを作る人はあまりいないだろうし、スペースが混入した文字列をわざわざフォルダの名前にする人もあまりいないはずなので、じゃあ一体どういった場面で上のような必要が生じるかというと
ずばり
iTunes のための iTunes による Folder 生成 | File 生成なのかな? と。
2010/03/08 現在ではこれ以外の場面で UTF8-MAC への変換なんて一般的には必要とされてないことなのかもしれません。

ただ、今後 iPad が登場しまた新しくiのつく名前のアプリケーションがでてきたりすると UTF8-MAC への変換に対する需要は増えるかもしれませんね?電子書籍を買って読むための iBooks.app が OS X に搭載される日は案外近い将来かもしれません。
iPad

それで、例えば iBooks.app が生成するであろう著書名のついたファイルにアクセスする際、もしも著書名に\& や\s が含まれていたり日本語だったりしたらRuby からそれらのファイルにアクセスしようとするのはちょっと困難がありそうです。いまの iTunes ファイル群と同様に。
# Ruby からはそういうファイル群にアクセスしないから大丈夫...といった意見の人もいるかもしれません。
# あるいは上に書いた失敗例を[ちゃんとした]成功例にする方法を私が知らないだけのことなのかもしれません。
# macustr.rb は一見成功してるようにみえるけどもちゃんとはしていないだろうし。

はたまた違う観点からみた場合、セキュリティ的にどうなんだろう?って問題も私にはよくわからないけどきっとあるんだろうと思います。そっちが優先された上で現在こうなっているのであればこのままの方がうれしい人も多いのかもしれません?。

ということで、幾日経過後のまとまりのない&とりとめないのない感想でした。

# 私が間違った認識をしている可能性は多分にあります。何かお気付きの方はコメントお願いします。

2010/02/24

mdiary 最近の変更点

  5     def initialize(arg)
  6       @err = false
  7       k, @h = nil, Hash.new
  8       arg.each{|x| m = /^-(.*)/.match(x); (m) ? (k = m[1].to_sym; @h[k] = nil) : @h[k] ||= x}
  9     end


arg は ARGV の値

% .mdiary-run.rb -d 2010-01 -s music

を実行した場合 arg は

arg = ["-d", "2010-01", "-s", "music"]

になる。line 8 はこの配列を

@h = {:d=>"2010-01", :s=>"music"} 

のようなハッシュにするためのもの。

arg = ["-d", "2010-01", "-l", "3"] だった場合
@h={:d=>"2010-01", :l=>"3"}

arg = ["-d", "2010-01", "-l"] だった場合
@h={:d=>"2010-01", :l=>nil}
になる。

line 7-8 をくだいて書くと

  1 # arg = ["-d", "2010-01", "-s", "music"]
  2 k, @h = nil, Hash.new
  3 arg.each{|x| 
  4   m = /^-(.*)/.match(x)
  5   if m
  6     k = m[1].to_sym
  7     @h[k] = nil
  8   else
  9     @h[k] ||= x
 10   end
 11 } 


line 4: x が '-' で始まっていたら m の値は #<MatchData "-d" 1:"d">
line 5: m の値に何か入っていたら(マッチしたら)
line 6: k に m の1番目のマッチの値を代入。
line 7: ハッシュキーが k で 値が nil のペアを @h に格納。
line 8: m の値に何もはいっていなければ(マッチしなかったら)
line 9: @h[k] が nil の場合は x を代入。@h[k] の値が nil でなく何か値が入っていたら何もしない。

+++ memo +++

1) @h[k] ||= x

line 9 の @h[k] ||= x を @h[k] = x にしてしまうと
あやまって
arg = ["-d", "2010-01", "xxx", "-s", "music"]
が与えられてしまった時
@h = {:d=>"xxx", :s=>"music"}
になってしまう。これでは意図した結果と異なる為 ||= にしている。

2) k = nil

line 2 の k = nil を書き忘れ
line 2 は @h = Hash.new だけだった場合
arg = ["-d", "2010-01", "-s", "music"] を与えると
@h={:d=>nil, nil=>"2010-01", :s=>nil}
になってしまう。
なぜなら...
{} の外側に k が存在していなければ k は {} の中だけで使える変数となり
m == nil でなければ
k = m[1].to_sym なので k には m[1].to_sym が代入されるが

m == nil だった場合、すなわち else 節においては
k = nil が代入されてしまうから。そして
line 9: @h[k] ||= x
で nil を ハッシュキーとしたペア(nil=>"2010-01")を @h に格納することになってしまう。

だから{} の外側の k = nil はとても大切。
外側で定義された k があることによって else 節においても k は m[1].to_sym を保持していてくれる。

[2010-02-26]
arg.each{|x| m = /(^-(.*))/.match(x); (m) ? (k = m[2].to_sym; @h[k] = nil) : @h[k] ||= x}
arg.each{|x| m = /^-(.*)/.match(x); (m) ? (k = m[1].to_sym; @h[k] = nil) : @h[k] ||= x}

2010/02/22

UTF8-MAC

ここを読んで

私も perl でためしてみました。
% cat test.pl

#!/usr/bin/perl
while(<>) {
    chop;
    print "Making a folder $_...\n";
    mkdir();
}

% cat 02.txt

ABC_a'bc 織田 信長
ABC_e'fg 豊臣 秀吉
ふげふが リファレンス& ドロー


% ./test.pl 02.txt
Making a folder ABC_a'bc 織田 信長...
Making a folder ABC_e'fg 豊臣 秀吉...
Making a folder ふげふが リファレンス& ドロー...

わざと\s や ' や濁点や & を入れてみましたがちゃんとおかしな名前のフォルダが出来上がりました。

で、Ruby ではどうなのでしょ。
% cat test.rb

#!/path/to/ruby19
# coding: utf-8
ARGF.each{|line|
  system ("mkdir #{line}")
}


% ./test.rb 02.txt

% ./test.rb 02.txt 
sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
sh: ドロー: command not found

こうなるのは予測していたので

http://gihyo.jp/dev/serial/01/ruby/0004?page=2 を読み直し

#!/path/to/ruby19
# coding: utf-8
require 'nkf'
ARGF.each{|line|
  ustr = NKF::nkf('--ic=UTF-8 --oc=UTF8-MAC', line)
  system ("mkdir #{ustr}")
}

nkf を使ってみました。が、最初と同じエラーが現れ ふげふが/ リファレンス/ の2のフォルダができました。

結果をみると \s のところでパスが区切られてしまったようなので
gustr = ustr.gsub(/\s/, "\\ ")
を挟んでみたものの ”&” でまたパスを区切られてしまいました。結局エラーになりそうな文字(て何?)を全て gsub しないとだめなのかもしれません。いやいやそんなことじゃなく正しい指定(nkf の)さえ分かればいいだけのことなのかもしれません。
あーわからない。

このままで話が終わるのはなんだか後味が悪いので AppleScript で Ruby を呼んでみました。

tell application "Finder"
  activate
  set cf to choose file with prompt "読み込みたいテキストファイル_UTF-8_を選択してください。"
  set dst to choose folder with prompt "保存先フォルダを選択してください。"
  set f to quoted form of POSIX path of cf
  set rubyfile to quoted form of POSIX path of (((folder of file cf) as text) & "ioread.rb")
  # ---------------------------
  try
    set str to do shell script "/usr/bin/ruby" & space & rubyfile & space & f
    set ary to paragraphs of str
    if (count of ary) > 3 then # this line
      return display dialog "体力の限界です。" buttons {"OK"} default button 1 with title "Oh, NO "
    end if
    repeat with fname in ary
      make new folder at (dst) with properties {name:fname}
    end repeat
  on error error_str
    display dialog error_str buttons {"OK"} default button 1 with title "Error"
  end try
end tell
# return AppleScript's version => "2.1.1"

% cat ioread.rb 
#!/usr/bin/ruby
f = ARGV[0]
print nil unless f
ary = IO.readlines(f)
ary.delete("\n")
print ary

% ls -F
ABC_a'bc 織田 信長/                                  ふげふが リファレンス& ドロー/
ABC_e'fg 豊臣 秀吉/


ちゃんとおかしな名前のフォルダができました。
テストなんでフォルダの数は3つまでに制限かけておきました。# this line のところ。


+++ 追記 +++
2010-02-22
しばらくしたら思いつきました。文字ごとに gsub してみようと。

% cat 02.txt

ABC_&a'bc 織田 信長
ABC_e'fg 豊臣 秀吉
ふげふが リファレンス& ドロー


test.rb

  1 #!/path/to/ruby19
  2 # coding: utf-8
  3 
  4 require 'nkf'
  5 def ex(line)
  6   mu = String.new("")
  7   ary = line.each_char{|x|
  8     gx = x.gsub(
  9       /[\s\'\(\)\+\!\&\,\[\]\;]/,
 10       " "=>"\\ ", "'"=>"\\'",
 11       "("=>"\\(", ")"=>"\\)",
 12       "+"=>"\\+", "!"=>"\\!",
 13       "&"=>"\\&", "."=>"\\.",
 14       "ï"=>"\\i", ","=>"\\,",
 15       "["=>"\\[", "]"=>"\\]",
 16       ";"=>"\\;"
 17     ) 
 18     mu << gx
 19   } 
 20   p macustr = NKF::nkf('--ic=UTF-8 --oc=UTF8-MAC', mu)
 21   p macustr.encoding
 22   system ("mkdir #{macustr}")
 23 end
 24 
 25 ARGF.each{|line| ex(line)}


% ./test.rb 02.txt

"ABC_\\&a\\'bc\\ 織田\\ 信長"
#<Encoding:UTF8-MAC>
"ABC_e\\'fg\\ 豊臣\\ 秀吉"
#<Encoding:UTF8-MAC>
"ふげふが\\ リファレンス\\&\\ ドロー"
#<Encoding:UTF8-MAC>


% ls -F

02.txt                                               test.rb*
ABC_&a'bc 織田 信長/                                 ふげふが リファレンス& ドロー/
ABC_e'fg 豊臣 秀吉/


line 10 "'" を "\\'" とスラッシュバックスラッシュ2つにしてみたらうまくいった。それがなぜなのかは分かっていない。
こういうのは力技と呼ばれることなんだろう。

UTF8-MAC [2] へ続く


[2011-02-19]

2010-02 時点での敗因はただ単にchomp しわすれとsystem コマンド発行する引数を'' で囲まなかったこと。それだけ。びっくりする愚かなおち。
nkf とかね関係ありません...。
それにしても今読み返してつくづく...単純ミスから泥沼していく様は自分でもあきれました。

% cat a.txt
ふげふが &どろー
% cat test.rb
# coding: utf-8

ARGF.each{|x|
  s =  "\'#{x.strip}\'"
  p sh = system("mkdir #{s}")
}
% ruby -v test.rb a.txt
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]
true
% ls
a.txt                            test.rb                          ふげふが &どろー


ruby 1.9.2
でも同様の結果。

2010/02/17

git push error

% git push origin master
を実行したら

 ! [rejected]        master -> master (non-fast-forward)

error: failed to push some refs to (...略) 
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'non-fast-forward'
section of 'git push --help' for details.


となってしまった。思い当たることとしては OS を再インストールして git repository へのパスを変えてしまったことと git のバージョンをあげたこと。

% git push --help

/non-fast-forward
next していたら次のような文章があった。

       There is another common situation where you may encounter non-fast-forward rejection when you try to push, and it is possible even
       when you are pushing into a repository nobody else pushes into. After you push commit A yourself (in the first picture in this
       section), replace it with "git commit --amend" to produce commit B, and you try to push it out, because forgot that you have pushed A
       out already. In such a case, and only if you are certain that nobody in the meantime fetched your earlier commit A (and started
       building on top of it), you can run "git push --force" to overwrite it. In other words, "git push --force" is a method reserved for a
       case where you do mean to lose history.

辞書をひきつつ 2 回読んでみたけどもなぜこうなってしまったのか?や、どうすればいいのか?は読み解けない。

Google にて "non-fast forward"
を検索してみたところ
http://blog.digital-squad.net/article/132085683.html

こういうときは --forceオプションをつけてやることで強制的にpushできる。
git push origin master --force

とありまして --force をつけて試してみるとあっさり git push に成功しました。とても助かりました。
一時は ssh-keygen で鍵を作りなおさなくちゃいけないのかと思った。

さて、落ち着いてから上の英文を読みなおすと

you can run "git push --force" to overwrite it. In other words, "git push --force" is a method reserved for a
       case where you do mean to lose history.

... "git push --force" はあなたが歴史を失うケースに備えての予備のメソッド?
間違えて読んでる可能性大だけど歴史を失うとはどういうことだろ。
OS 再インストールしてパスが変わってるから何かが失われたってことなのかな。何が?

% git log
ちゃんと動いてる。最初からのlog もみえてる。はて?

+++ 教訓 +++

% git push midore@github.com:midore/mblogger.git

などしても

...
Permission denied (publickey).
fatal: The remote end hung up unexpectedly

エラーになる。だからといって ~/.ssh/ の中の鍵のパーミションが関係してる?とか考えない。

remote 先を明示したい時は

% git push git@github.com:midore/mblogger.git


~/.gitconfig や ~/.ssh/ にゆるぎない自信があれば

% git push origin master

で OK.

[後日談]
入門Git(秀和システム) を読みましてこの時何がおこっていたか?を考えてみました。
p81 に non fast forward エラーについて解説がありました。

私の場合OS を入れ替える前にバックアップをとり、OS を新規インストールした後にこのバックアップから
local git repository を読み込んだわけだけどもバックアップした直後で新規インストールする直前に
github.com/midore/mdiary に対してgit push しちゃっていたのかもしれません(驚)
だとすればこの挙動はものすごく納得がいきます。
バックアップとった後に git push した記憶がない自分が怖い...

私がうっかり git push していたのならば上記の対処は正しいやり方じゃなかったようです。
% git pull
を使い
(pull 先は add remote した先を指し、clone したproject の場合は自動的にclone 元になるそうだ)
github.com においてあるリポジトリの最新コミットと手元のリポジトリのコミットをマージさせるべきでした。
git pull してみればどこで conflict していたか明らかになったはずなのでした。
(ただしgit push した記憶がない状態で pull する勇気をもてたかは不明)
conflict メッセージがでていたのならそのファイルを編集した上でcommit するべきだったのかもしれません。

2010/02/16

Remove resource fork in AppleScript

私は Twitter に参加していませんが何日か前に Google Reader で
急募: OS XのiTunesから、mp3ファイルを_リソースフォークなしに...
を見かけました。

早速 AppleScript で try

tell application "Finder"
  set src to quoted form of POSIX path of (choose folder)
  set dst to quoted form of POSIX path of (choose folder)
  set str to "ditto -v --norsrc  " & src & "  " & dst
  do shell script str
end tell

日本語名のフォルダを指定しても大丈夫でした。でもこれだけだと愛想がないのでいろいろ付け足し。

# remove-resource-forlk.scpt
tell application "Finder"
  # フォルダを選択
  set src to quoted form of POSIX path of (choose folder with prompt "リソースフォークをまるっと取り除きたいフォルダを選択してください。")
  # 保存先フォルダの選択
  set dst to quoted form of POSIX path of (choose folder with prompt "保存先であるフォルダを選択してください。")
  # コマンド文字列
  set str to "ditto -v --norsrc  " & src & "  " & dst
  if src is dst then
    set err_str to "指定したフォルダと保存先であるフォルダが同じです!異なるフォルダを選択してください。"
    display dialog err_str buttons {"OK"} default button 1 with icon 2 with title "Error"
    return
  end if
  set warn_str to "多くのファイルが含まれているフォルダを選択した場合時間がかかる(数分)場合があります。よろしいですか?"
  display dialog warn_str buttons {"OK", "Cancel"} default button 2 with icon 2 with title "Warning"
  try
  # コマンドの実行
  set res to do shell script str
  on error num
    display dialog "エラーが発生しました。" buttons {"OK"} default button 1
    return
  end try
  if res is "" then display dialog "おわりました。" buttons {"OK"} default button 1 with icon 1 with title "Success"
end tell


[用途]
フォルダに含まれるファイルからリソースフォークを削除したファイルを保存先フォルダに保存します。(もとのファイル名は維持されます。)
複数のフォルダを内包しているフォルダを指定した場合、保存先フォルダの階層は、もとのフォルダの階層を維持します。

# iTunes Music フォルダにあるミュージシャン(Artist) の名前がついたフォルダを選択すると、そこに含まれるアルバム名のついたフォルダにある音楽ファイル( 末尾に.m4a .mp3 などの名前のついたファイル)から、リソースフォークを削除したものを、保存先フォルダに保存します。
# ターミナルからコマンドを叩くことなく、操作できます。

[使い方]
Finder メニュ-> 移動-> アプリケーションを開く (Command + Shift + A でApplication フォルダ を表示)
->ユーティリティ ->AppleScript Editor.app(AppleScript エディタ.app) をダブルクリックで起動し新しいファイルを作り上記をコピー and ペーストします。

1, コマンドKey(⌘) + K でコンパイルします。
2, コマンドKey(⌘) + S で File 保存(必ずスクリプト として)
3, コマンドKey(⌘) + R で実行 です。

処理がおわると『おわりました。』と表示します。エラーが発生した場合は『エラーが発生しました。』と表示します。

複数のアルバムフォルダが含まれている ミュージシャン(Artist) のフォルダなどを選択するとファイル数にして何百曲などのファイルを処理することになります。その場合ものすごく時間がかかる(数分)こともあります。なので最初は下記の手順でテストしてみてどのくらい時間がかかるものかを体感してみてください。

[テスト手順]
(1) デスクトップに2つ新規フォルダを作りそれぞれ「SRC」「DST」と名付けておく。
(2) 「SRC」フォルダの中にリソースフォークを取り除きたいフォルダを1 つだけコピーしておく。
  その際極力ファイル数の少ないフォルダを選ぶ。
「DST」フォルダは空っぽのままにしておく。
(3) 保存しておいた AppleScript ファイルを開いてから コマンドKey(⌘) + R をおす。または「実行」ボタンを押す。
「リソースフォークをまるっと...」ときかれたら「SRC」を選ぶ。
「保存先...」 ときかれたら 「DST」を選ぶ。

処理している間はなんのメッセージも表示しません。
10 枚程のファイルを処理した場合 2,3 秒でおわります。

# 注意1:
OS X 10.5x 時代のファイルにはリソースフォークがついてるけど、Snow Leopard 時代に作ったファイルにはついてません。

# 注意2:
指定フォルダとしてミュージシャン(Artist)名のついたフォルダを指定し
保存先フォルダには適当な名前(「test」とか)のフォルダを指定し実行した場合

iTunes->詳細->”iTunes Media”フォルダを整理する
にチェックをいれてから保存先フォルダ(「test」とか)を iTunes に取り込むと本来のミュージシャン(Artist)名のついたフォルダ名に自動変換されます。
(iTunes 9.03)

[ターミナルで確認]

# % ditto -h
# % xattr -h

# 指定フォルダ: test-src
# 保存先フォルダ: test-dst


指定フォルダ内

% ls -FRl test-src/
total 0
drwx------  3 foo  staff  102  2 15 16:35 Makana/
drwx------  3 foo  staff  102  2  4 11:48 平沢 進/

test-src//Makana:
total 0
drwx------  17 foo  staff  578  2 15 16:33 Different Game/

test-src//Makana/Different Game:
total 92824
-rw-------@ 1 foo  staff  4428672  6  6  2009 01 Away.m4p
-rw-------@ 1 foo  staff   623834  2  4 18:09 02 Interlude I.m4p
-rw-------@ 1 foo  staff  3821305  6  6  2009 03 Mars Declares.m4p
# ... 略

test-src//平沢 進:
total 0
drwx------  4 foo  staff  136  2  4 11:48 時空の水/

test-src//平沢 進/時空の水:
total 15344
-rw-------@ 1 foo  staff  4542192  4  4  2008 01 ハルディン・ホテル.m4p
-rw-------@ 1 foo  staff  3311160  4  4  2008 10 金星.m4p

% xattr -x test-src/Makana/Different\ Game/01\ Away.m4p 
# => com.apple.FinderInfo

% xattr -x test-src/平沢\ 進/時空の水/01\ ハルディン・ホテル.m4p
# => com.apple.FinderInfo


AppleScipt 実行後
保存先フォルダ内

% ls -FRl test-dst/
total 0
drwx------  3 foo  staff  102  2 15 16:35 Makana/
drwx------  3 foo  staff  102  2  4 11:48 平沢 進/

test-dst//Makana:
total 0
drwx------  17 foo  staff  578  2 15 16:33 Different Game/

test-dst//Makana/Different Game:
total 92824
-rw-------  1 foo  staff  4428672  6  6  2009 01 Away.m4p
-rw-------  1 foo  staff   623834  2  4 18:09 02 Interlude I.m4p
-rw-------  1 foo  staff  3821305  6  6  2009 03 Mars Declares.m4p
# ... 略

test-dst//平沢 進:
total 0
drwx------  4 foo  staff  136  2  4 11:48 時空の水/

test-dst//平沢 進/時空の水:
total 15344
-rw-------  1 foo  staff  4542192  4  4  2008 01 ハルディン・ホテル.m4p
-rw-------  1 foo  staff  3311160  4  4  2008 10 金星.m4p

% xattr -x test-dst/Makana/Different\ Game/01\ Away.m4p
# => 何もかえってこない。

% xattr -x test-dst/平沢\ 進/時空の水/01\ ハルディン・ホテル.m4p
# => 何もかえってこない。


[2010-02-16]
s/errr_str/err_str/g
s/warm_str/warn_str/g
s/やめる/Cancel/g
[2010-02-18]
s/folk/fork/g

2010/02/11

Snow Leopard Re-Install memo

# backup
$ sudo launchctl bslist -j > default-launchctl-bslist.txt
# PRAM Clear
# $ sudo nvram -c -xp

0) Remove Extensions
# Bluetooth
$ sudo srm -rf /System/Library/Extensions/IOBluetooth*
# iSight
$ sudo srm -rf /System/Library/Extensions/Apple_iSight.kext/
$ sudo srm -rf /System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/AppleUSBVideoSupport.kext/

# Touch
$ sudo touch /System/Library/Extensions/

# blued
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.blued.plist
$ sudo chmod 600 /usr/sbin/blued

$ sudo reboot

1) mDNSResponder.plist
$ ps aux | grep mDNS
# => ... /usr/sbin/mDNSResponder -launchd

$ sudo vi /System/Library/com.apple.mDNSResponder.plist
$ sudo vi /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist

        <array>
                <string>/usr/sbin/mDNSResponder</string>
                <string>-launchd</string>
                <string>-NoMulticastAdvertisements</string>
        </array>


# Reload com.apple.mDNSResponder.plist
$ sudo launchctl unload /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist
$ sudo launchctl load /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist

$ ps aux | grep mDNS
# => .... /usr/sbin/mDNSResponder -launchd -NoMulticastAdvertisements

See: support.apple.com/kb/HT3789

2) change mode
$ man samba
$ apropos smbd

$ sudo chmod 600 /usr/sbin/nmbd
$ sudo chmod 600 /usr/sbin/smbd
$ sudo chmod 600 /usr/sbin/cupsaddsmb

$ sudo chmod 600 /usr/bin/smb*
$ sudo chmod 600 /usr/bin/nmblookup
$ sudo chmod 600 /etc/smb.conf
$ sudo chmod 600 /etc/smb.conf.template

# httpd
$ sudo chmod 600 /usr/sbin/httpd

# sshd
$ sudo chmod 600 /usr/sbin/sshd

# ftpd
# sudo chmod 600 /usr/libexec/ftpd

# nfsd
$ sudo chmod 600 /sbin/nfsd

# Apple FileServer
# $ ls -la /usr/sbin/AppleFileServer
$ sudo chmod 0 /System/Library/CoreServices/AppleFileServer.app/Contents/MacOS/AppleFileServer

# ae server (Apple Event)
# $ more /System/Library/LaunchDaemons/com.apple.eppc.plist
$ sudo chmod 0 /System/Library/Frameworks/CoreServices.framework/Frameworks/AE.framework/Versions/A/Support/AEServer

# Problem Reporter
$ sudo chmod 600 /System/Library/CoreServices/Problem\ Reporter.app/Contents/MacOS/Problem\ Reporter

See: http://www.macosxhints.com/

# Plug-Ins
$ ls -la /Library/Internet\ Plug-Ins/
$ sudo chmod 700 /System/Library/Frameworks/JavaVM.framework/Resources/JavaPluginCocoa.bundle
$ sudo chmod 700 /Library/Internet\ Plug-Ins/Flash Player.plugin
$ sudo chmod 700 /Library/Internet\ Plug-Ins/QuickTime Plugin.plugin
$ sudo chmod 0 /Library/Internet\ Plug-Ins/NP-PPC-Dir-Shockwave
$ ls -la /Library/Internet\ Plug-Ins/

3) launchctl unload
$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.cups.cupsd.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.x.privileged_startx.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.webdavfs_load_kext.plist

# com.apple.smb.server.preferences.plist com.apple.smb.sharepoints.plist com.apple.smbfs_load_kext.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.smb.sharepoints.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.smb.server.preferences.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.smbfs_load_kext.plist

$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.RFBRegisterMDNS_ScreenSharing.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.RFBRegisterMDNS_RemoteManagement.plist

$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.printtool.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.portmap.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.nfsd.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.RemoteDesktop.PrivilegeProxy.plist
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.IIDCAssistant.plist

# 2010-03-30
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.dashboard.advisory.fetch.plist

# /System/Library/Filesystems/AppleShare/check_afp.app/Contents/MacOS/check_afp
# $ more /System/Library/LaunchDaemons/com.apple.afpfs_checkafp.plist

# /System/Library/Filesystems/AppleShare/afpLoad
# $ more /System/Library/LaunchDaemons/com.apple.afpfs_afpLoad.plist

# /System/Library/PrivateFrameworks/SoftwareUpdate.framework/Resources/suhelperd
# $ more /System/Library/LaunchDaemons/com.apple.suhelperd.plist

$ sudo launchctl bslist -j
$ sudo lsof -i

4) Spotlight
# as admin-user
$ sudo chmod 600 /System/Library/CoreServices/Search.bundle/Contents/MacOS/Search
$ sudo mdutil -i off /Volumes/abc
$ sudo mdutil -E /Volumes/abc
$ sudo mdutil -s /Volumes/abc

See: http://www.macosxhints.com/article.php?story=20091030173117381

5) fseventsd
$ sudo touch /Volumes/abc/.fseventsd/no_log
$ sudo touch /Users/foo/.fseventsd/no_log
$ sudo chmod 644 /Users/foo/.fseventsd/no_log
$ sudo chown -R foo:staff /Users/foo/.fseventsd/

See: ファイルシステムイベントストレージの防止

# default value "ttyskeepawake" of pmset is 1.
$ sudo pmset ttyskeepawake 0

See: http://forums.applenova.com/showthread.php?t=33172

$ sudo reboot
$ Login as admin-user
$ syslog -w 120 | more

# fseventsd[xx] <Critical>: Logging disabled completely for device:1: /Users/foo

6) Login as User foo
% rm ~/.fseventsd/000000*
% mdutil -i off /Users/foo
% mdutil -E /Users/foo
% mdutil -s /Users/foo
% pmset -g

% syslog -w 30
# What is this warning ?
# (com.apple.ReportCrash) <Warning>: Falling back to default Mach exception handler. Could not find: com.apple.ReportCrash.Self

% more /System/Library/LaunchAgents/com.apple.ReportCrash.Self.plist

% launchctl list | grep Repo

-	0	com.apple.ReportPanic
-	0	com.apple.ReportCrash.Self
-	0	com.apple.ReportCrash


See: http://www.insanelymac.com/forum/index.php?showtopic=192563

# User foo
% mkdir ~/Library/LaunchAgents
# if you did't set umask
# % chmod 700 ~/Library/LaunchAgents

% cd ~/Library/LaunchAgents
% cp /System/Library/LaunchAgents/com.apple.ReportCrash.Self.Plist .

# User admin
$ su admin-user
$ cd /path/to/backup-dir/
$ sudo mv /System/Library/LaunchAgents/com.apple.ReportCrash.Self.Plist .

# logout and login as User foo
% syslog -w
# not found, "... (com.apple.ReportCrash) <Warning>: (...) Could not find: com.apple.ReportCrash.Self"

[2010-02-11]
# RemotManagement
# $ sudo srm -rf /System/Library/CoreServices/RemoteManagement/
# or
# cd /path/to/backup-dir/
# $ sudo mv /System/Library/CoreServices/RemoteManagement/ .

[2010-02-12]
# User foo
# % launchctl list | grep Remote
# => exist.

# Admin user
# $ grep 'Remote' /System/Library/LaunchAgents/*
# $ sudo mv /System/Library/LaunchAgents/com.apple.RemoteDesktop.plist /path/to/backup-dir/
# $ sudo mv /System/Library/LaunchAgents/com.apple.ScreenSharing.plist /path/to/backup-dir/

# reboot

# User foo
# % launchctl list | grep Remote
# => not exist.


[2010-05-31]
Apple Releases Snow Leopard Security Configuration Guide
http://blog.intego.com/2010/05/26/apple-releases-snow-leopard-security-configuration-guide/

Apple has released their Snow Leopard Security Configuration Guide,


Mac OS X Security Configuration Guides
http://www.apple.com/support/security/guides/