motivation driven!!

このブログでは雑多なプログラミング関連記事を載せてます。

svchostが重くて何かをダウンロードし続けてるみたいなので  [windows]  [日記]

いろいろ調べた結果、ICS (Internet Connection Sharing)というのを止めた。

後で何か影響が出た場合のため、ここにメモ。(colinuxとかshareしてる気がする。。調べるの面倒)


vimでchangelogの折り畳み(folding)  [vim]  [environment]

changelogを書いているときに簡単に折り畳んでタイトルだけ並べられるように.vimrcいじった

vimrc changelog関連部分

autocmd BufRead *.chg setf changelog
autocmd FileType changelog set foldexpr=ChgLogFoldLevel(v:lnum) foldmethod=expr foldlevel=0
let g:changelog_username ="hassy"
function! ChgLogFoldLevel(lnum)
  let l1 = getline(a:lnum)  
  if l1 =~"^\\t\\*[^*]"
    return '>1'
  elseif l1 =~"^\\t"
    return 1
  else
    return 0
  endif
endfunction

これでだいぶ読みやすくなった


Ruby RSS::MakerでCDATAを扱えるようにしてみる  [ruby]  [sample_code]  [tips]

RubyのRSS::MakerでRSS1.0生成すると、content:encodedが自動的にhtml_escapeされてしまい、CDATAとして埋め込んでくれないので、モンキーパッチングしてみた。

rss_cdata.rb

require 'rss'

module RSS
  module BaseModel
    def install_cdata_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
      name ||= tag_name
      disp_name ||= name
      self::ELEMENTS << name
      add_need_initialize_variable(name)
      install_model(tag_name, uri, occurs, name)

      def_corresponded_attr_writer name, type, disp_name
      convert_attr_reader name
      install_element(name) do |n, elem_name|
        <<-EOC
        if @#{n}
          rv = "\#{indent}<#{elem_name}>"
          value = "<![CDATA[" + eval("@#{n}") + "]]>"
          if need_convert
            rv << convert(value)
          else
            rv << value
          end
          rv << "</#{elem_name}>"
          rv
        else
          ''
        end
EOC
      end
    end
  end 
  
  module ContentModel
    def self.append_features(klass)
      super 
      
      klass.install_must_call_validator(CONTENT_PREFIX, CONTENT_URI)
      %w(encoded).each do |name|
        klass.install_cdata_element(name, CONTENT_URI, "?", "#{CONTENT_PREFIX}_#{name}")
      end
    end
  end 
  
  class RDF
    class Item; include ContentModel; end
  end
end

試してみる

require 'rss'
require './rss_cdata'
 
rss = RSS::Maker.make("1.0") do | maker |
  maker.channel.about = "http://hoge.fuga/index.rdf"
  maker.channel.title = "harahoro"
  maker.channel.description = "hirehare"
  maker.channel.link = "http://hoge.fuga/"
  item = maker.items.new_item
  item.link = "http://hoge.fuga/piyo.html"
  item.title = "aheaheuhiha"
  item.content_encoded = "<p>aheuhihaaa</p>"
  item.dc_date = Time.now()
end 
puts rss.to_s

結果

<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:image="http://web.resource.org/rss/1.0/modules/image/"
  xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
  xmlns="http://purl.org/rss/1.0/">
  <channel rdf:about="http://hoge.fuga/index.rdf">
    <title>harahoro</title>
    <link>http://hoge.fuga/</link>
    <description>hirehare</description>
    <items>
      <rdf:Seq>
        <rdf:li resource="http://hoge.fuga/piyo.html"/>
      </rdf:Seq>
    </items>
    <taxo:topics>
      <rdf:Bag/>
    </taxo:topics>
  </channel>
  <item rdf:about="http://hoge.fuga/piyo.html">
    <title>aheaheuhiha</title>
    <link>http://hoge.fuga/piyo.html</link>
    <content:encoded><![CDATA[<p>aheuhihaaa</p>]]></content:encoded>
    <dc:date>2009-12-02T13:14:24+09:00</dc:date>
    <taxo:topics>
      <rdf:Bag/>
    </taxo:topics>
    <content:encoded><![CDATA[<p>aheuhihaaa</p>]]></content:encoded>
  </item>
</rdf:RDF>

どうよ。


vim (ver.7以降)でやるtab設定  [vim]  [environment]

以下を".vimrc"に追記

map ,t <ESC>:tabnew<CR>
map ,h <ESC>:tabp<CR>
map ,l <ESC>:tabn<CR>

これで、タブ移動、タブ作成が楽になる


Rubyで動的にクラスファイル(プラグイン)を読み込む  [ruby]  [sample_code]

いろいろな処理をするファイルをプラグインとして適当なディレクトリに入れておくと、それらをロードしてオブジェクト化するやりかた。

バッチ処理とかでカスタムな方法をインプリしたいときとかに使えるかと思う。

plugin_loader.rb

class PluginLoader
  attr_reader :plugins
  def initialize(plugin_base, extension = 'rb')
    @plugin_base = plugin_base
    @plugins = []
    Dir.glob(@plugin_base + "*.#{extension}").each do |p|
      require p
      @plugins << Object.const_get(to_classname(p)).new
    end
  end
  private
  def to_classname(str)
    str.sub(/^#{@plugin_base}/){""}.sub(/\.rb$/){""}.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
  end
end

使い方はこんな感じ(あらかじめpluginsディレクトリにxxxx.rbファイルを作っておく)

test.rb

require './plugin_loader' 

pl = PluginLoader.new(File.dirname(__FILE__) + "/plugins/")
pl.plugins.each do | p |
  p.run
end

RubyでTest::Baseっぽいのを作る  [ruby]  [TDD]  [sample_code]

Rubyで動的に関数定義3

で書いた方法をつかって、PerlのTest::Baseっぽいのを書いてみる。

(Ruby Test::Baseってのがすでにあるみたいだけどね。)

まずは、test_base.rb

require 'test/unit' 
class TestBase < Test::Unit::TestCase
  @@test_template = {}
  def run(*args)
    return if@method_name.to_s == "default_test"
    super
  end
  def self.start_test
    self.parse if(@@test_template.empty?)
    self.generate_tests 
  end
  private
  def self.parse
    test_name = ""
    buf = ""
    buf_mode = ""
    while line = DATA.gets do 
      line.chomp!
      if(line =~ /^(===|---)/)
        if(buf != "" && test_name != "" && buf_mode != "")
          @@test_template[test_name][buf_mode] = eval(buf)
          buf = ""
        end
        if(line =~ /^=== (.*)$/)
          test_name = $1
          @@test_template[test_name] = {}
        elsif(line =~ /--- input (.*)$/)
          @@test_template[test_name][:method_name] = $1
          buf_mode = :input
        elsif(line = ~/--- expected/)
          buf_mode= :expected
        end
      else
        buf += line
      end
    end
    if(buf != "" && test_name != "" && buf_mode != "")
      @@test_template[test_name][buf_mode] = eval(buf)
      buf = ""
    end
  end
  def self.generate_tests
    @@test_template.each do |test_name,test_args|
      define_method(test_name) do
        result=__send__(test_args[:method_name],test_args[:input])
        assert_equal test_args[:expected], result, " error on #{test_name}"
      end
    end 
  end
end

DATAの処理のところが、ちょっと(かなり?)スパゲッティーだけど、generate_testsの所でテスト用の関数をDATA内容に合わせて作成してる。

Test::Unit::TestCaseのrunメソッドで"default_test"を無視するようにして、TestCaseがテスト未定義時に勝手にdefault_testを実行するのを防いでる。(この部分を抜くとどうなるか試せば言ってる意味がわかるはず)

実際のテストのほうは、こんな感じで書く。

require './test_base'
require './testee' 

class TestBaseTest < TestBase
  def setup #setupとかは通常のTestCaseと同じ
    @testee = Testee.new
  end
  def login_test(login_name) # DATAを利用するテストはtest_以外のメソッド名
    @testee.login(login_name)
    @testee.who_am_i?
  end
  def test_without_data # DATAを使わないテストはtest_で始まるメソッド名
    true
  end
end
TestBaseTest.start_test #最後にstart_testでテストを生成しておく
__END__ #ここからテストに渡すパラメータ
=== test_should_login_by_hoge
--- input login_test #inputの後ろに利用するメソッド名
:hoge
--- expected
:hoge
=== test_should_login_by_fuga
--- input login_test
:fuga
--- expected
:fuga

inputの後ろのメソッド名が一個しかかけなかったり、フィルタとか便利なものがなかったり、"ruby Test::Base"よりかなりはしょってるけど、1ファイルで出来てるのでその辺はしょうがないと割り切る。

じゃあの。


マジカジャパンの羽生社長と飲み会  [日記]  [business]

先週の金曜日マジカジャパン羽生社長と飲み会があった。

有名人との飲み会は初めてなのでちょっと緊張したけど、アルコールと羽生さんの毒舌っぷり(?)のせいで最終的にはべろんべろんの飲み会になってしまった。

飲みながら書いたメモ(いわゆる腰リールなんだけど、リールが壊れたのでただのメモ帳。。)を発表してみます。
  • 本質と製品のGAPの部分に自分の価値がある
    • 要は製品だけで売れるなら自分の価値は無いんじゃないのとかそういうこと
  • ソリューションから離れる
    • 「売りたい」から「買いたいと思わせる」への変換みたいなことだったかなぁ。
    • ソリューションは一旦おいておいて、顧客の課題や要望が大事でしょうということ。
  • Recordingで気付くことの重要性
    • PDCAの前にCheck(Recording & Review)するほうが大事じゃね?みたいな。
  • 価値がわかるレベルまで人を育てることが必要
    • 何がすごいかはある程度勉強した人じゃないとわからない
  • クラスターの大きさ知ってる?
    • はてブ、技術書、ビジネス啓蒙書みたいなのを買う人って実は決まった人たちで、クラスターは小さい

もっといろいろ話したけど、書いちゃいけないこともありそうなので、この辺で。

いやぁ、いい刺激になった。


人工知能はむれっとゲーム  [人工知能]

><

強化学習によって学習させたニューラルネットワークを使ったハムレット(4目並べ)ゲームを作った。

だいぶ前からニューラルネットワークとか人工知能とかに興味があったんだけど、なかなかプログラミングする暇がなくてほったらかしにしてた。

そのうち、内容を解説していくつもり。

今回は、そのさわりの部分。

アーキテクチャ

アーキテクチャは、ざっくりこんな感じ。

                   +-----------------+
         +-------->lRL Agent         |
         |         |                 |
         |   +---->|[Value Function] |
         |   |     +-------------+---+
         |   |                   |
   State |   | Reward            | Action
         |   |                   |
         |   |   +-----------+   |
         |   +---|Environment|<--+
         |       |           |
         +-------|           |
                 +-----------+

  • RL Agent: 強化学習エージェント(今回の場合プレイヤー)
  • Value Function: 各State(ボードの状態)の価値を算出する関数
  • Environment: 環境(今回の場合ゲームボード)

実際の動き

動きとしては、

  • RL Agent(プレイヤー)が、現在のState(盤面)を取得する: Environment --> RL Agent
  • RL Agentが、最も価値の高い次のStateを自分の価値関数(Value Function)から調べる: RL Agent --> Value Function
  • 上記のStateに移行するためのActionをEnvironment(環境)になげる。: RL Agent --> Environment
  • 環境からのReward(報酬)をえる。: Environment --> RL Agent
  • 報酬を元に価値関数をアップデートする。: RL Agent --> Value Function
    V(s)<-V(s) + α[reward + γV(s')-V(s)] :TD(0)方式

言葉にすると、現在のStateの価値は、次のステートの価値+rewardに近づくように学習されるということ

で、RL Agentが持つ価値関数[Value Function]の部分はどのような関数になるのかは未知であるので、ニューラルネットワークでState -> Valueの対応付けを学習させることにした。

今回のサイトに関して

  • 10万回以上のRL Agent同士のゲームにより学習させたニューラルネットワークを用いています。
  • 学習部分は割愛しています。(もともと学習部分はjavaでデスクトップように作っていたので。。そのうちperlに移植して学習機能付きにします)
  • ニューラルネットワークの重みデータ + 百行程度のperl + javascript(GUIとか用)で出来ています。
  • 同ディレクトリのhamlett.cgiに以下のデータをつけることによりjsonpデータが返ります。
    • board=0_0_1_2_.... #ボードの盤面。1(先攻player)、2(後攻)、盤面(左下から左上、左から右に順次"_"で区切って並べたもの)
    • player=1 or 2 # 自分(1=先攻、2=後攻)
    • callback=xxxx #jsonpのcallback関数

参考書籍:


amazonのpaapiをxsltのdocument関数でどうすればいいのか  [日記]

こまった。xslt内でawsのクエリーをつなげるということをしていたのだが、今回の認証系の変更により全滅。

xslt内でHMAC-SHAの変換って出来んのかなぁ?

まいった


Perlでバイナリをいじるためのいろいろ  [perl]  [tips]

Perlでバイナリファイルをいじる場合にいろいろと同じ問題に遭遇するので、忘れないようにメモ。

バイナリファイルの読み込み

読み込む場合に"getc"使うと、ファイルが終わってないのに終了してしまうことがある。

正しくは"read"を使う。

my $filename = $ARGV[0];
open my $file,'<',$filename or die;
binmode $file; 
my $val;
while(read($file, $val, 1)){
}

これで1byteづつ処理できる。実際はバイナリの構造にあわせてreadするバイト数を変える。

読んだバイナリの処理

バイナリを数値として処理するためには、その構造にあわせてunpackする。

unpack("C",$val); #unsigned byte
unpack("S",$val); #unsigned short
unpack("L",$val); #unsigned long
unpack("c",$val); #signed byte
unpack("s",$val); #signed short
unpack("l",$val); #signed long

bit処理の場合は、いろいろ問題がある。

ビット反転"~"は、ビット長にあわせてpackしてから処理する。

~pack("c",$i); # $iは数値。一旦byteにしてからビット反転

ビットの"&(and),|(or),^(xor)"は、両方同じビット長にする。

もしくはunpackしてから処理する(unpackしても同じビット長(環境依存)になるからね)

pack("s",$j) ^ pack("s",$i); # $i,jは数値。両方shortにしている
unpack("s",$val) ^ $i; # $valは読んだバイナリ,$iは数値。

ビットシフト"<<", ">>"は、数値化(unpack)してからじゃないと動かない。。。(何故?)

unpack("S",$i) << 1

と、いうことで、実は「ビット反転」以外はunpackして処理する。ということ。

例として、μ-lawとPCMの変換(なんのこっちゃ?という人はwavファイルの勉強を。。)

my $mantissa = unpack("C",~$val); #$valが読み込んだバイナリ
my $sign = (unpack("C",$val) < (0x0080))? -1:1;
my $exponent = ($mantissa >> 4) & (0x0007);
my $segment = $exponent + 1;
$mantissa = $mantissa & (0x000F);
my $step = (0x0004) << $segment;
my $g191_value = pack("S",$sign * (((0x0080) << $exponent) + $step*$mantissa + $step/2 - 4*33));
#最後に"S"でpackしてunsigned shortに

バイナリの書き出し

書き出したい構造にあわせてpackしてやる。

wavファイルのヘッダとかだとこうなる。

my $form = "";
$form .= "RIFF";
$form .= pack("L",$size + 36); #data size + headersize(-8) 
$form .= "WAVE";
$form .= "fmt ";
$form .= pack("L",16); #fmt chunk size
$form .= pack("S",1); # pcm
$form .= pack("S",1); # mono
$form .= pack("L",8000); # 8k sampling
$form .= pack("L",16000); # Byte/sec = sampling * 2byte(16bit 量子化) * 1(mono)
$form .= pack("S",2); # Byte/sample(8bit量子化) * channel(mono)
$form .= pack("S",16); # 8bit量子化
$form .= "data";
$form .= pack("L",$size); #data size

おまけ

signedとunsignedを変換するにはpackしてunpackというややこしい方法が必要。

<p>my $i = -100;</p>
<p>my $unsigned_value = unpack("C",pack("c",$i));</p>

wav関連でもぞもぞしてるのバレバレですね。


ゲートウェイルータ冗長化(VRRP, HSRP)とNATの共存(cisco)  [network]  [tips]

ルータの冗長化の方式としてVRRPとHSRP(Cisco only)がある。

これは、通常「マスター側ルータ」がarp応答するのに対し、マスターダウン時には「スタンバイ側ルータ」がarp応答するようになって対応するというもの。

で、これにNATを組み合わせて下図のように組もうとすると、問題が起こった。


+-----------+     +-----+    192.168.1.251 +-------+ 192.168.10.251
|my server  |-----|L2 SW|------------------|Master |-----
|192.168.1.1|     |     | Virtual Router   +-------+ 
+-----------+     |     | (192.168.1.254)
                  |     |                  +-------+
                  |     |------------------|Standby|-----
                  +-----+    192.168.1.250 +-------+ 192.168.10.250
 
        	                            NAT変換:
                                  192.168.1.1 <=> 192.168.10.1

VRRPの場合の設定(f0が外側)

Router1(config)# track 1 interface f0 line-protocol
Router1(config)# int f1
Router1(config-if)#vrrp 1 ip 192.168.1.254
Router1(config-if)#vrrp 1 priority 150
Router1(config-if)#vrrp 1 track 1 decrement 100
Router1(config-if)#ip nat inside
Router1(config)# int f0
Router1(config-if)#ip nat outside
 
Router2(config)# int f1
Router2(config-if)#vrrp 1 ip 192.168.1.254
Router2(config-if)#ip nat inside
Router2(config)# int f0
Router2(config-if)#ip nat outside
 
Router1/2共通(config)# ip nat inside source static 192.168.1.1 192.168.10.1

問題は、Standby側のルータがNAT設定したIPのarpに応答してしまい、duplicate addressとなってしまう問題。

HSRPでは、NATのredundancyオプションを利用して回避できる。(NATのredundancyオプションにstandbyで設定した名前を指定する)

HSRPの場合の設定(f0が外側)

Router1(config)# track 1 interface f0 line-protocol
Router1(config)# int f1
Router1(config-if)#standby 1 ip 192.168.1.254
Router1(config-if)#standby 1 priority 150
Router1(config-if)#standby 1 track 1 decrement 100
Router1(config-if)#standby 1 preempt
Router1(config-if)#standby 1 name hsrp1
Router1(config-if)#ip nat inside
Router1(config)# int f0
Router1(config-if)#ip nat outside
 
Router2(config)# int f1
Router2(config-if)#standby 1 ip 192.168.1.254
Router2(config-if)#standby 1 preempt
Router2(config-if)#standby 1 name hsrp1
Router2(config-if)#ip nat inside
Router2(config)# int f0
Router2(config-if)#ip nat outside
 
Router1/2共通(config)# ip nat inside source static 192.168.1.1 192.168.10.1 redundancy hsrp1

VRRPでも、descriptionを設定してredundancyやればできるはずなんだけど、できなかった。

久々のネットワークねたでした。


ドメイン変えた  [日記]

drivendevelopment.jp を driven-development.jpに変えた。

また、検索にひっかからなくなるな。

あと、コメント欄(はてなブックマーク)も空になっちゃう。

追記 ~~~

ドメイン元に戻した。

理由: ハイフンないのが流行みたい。


Railsのmodelをカスタマイズしてメソッドの呼び出しにオプションを追加する  [rails]  [tips]

Railsである特定のmodelの検索(find)時に必ずsortをかけたいというような場合には、modelのfindをカスタマイズするのが便利。

class Hoge < ActiveRecord::Base
  class << self
    alias_method :find_org, :find
    def find(*params)
      options = {:order => "fuga desc"}
      options.update(params.last.is_a?(::Hash)? params.pop : {})
      find_org(*params.push(options))
    end
  end
end

もとのfind(find_org)を呼び出すときに、paramsを'*'でもとに戻すの忘れてえらい目にあった。


Ruby メソッド呼び出しからオプション(Hash)部分を取り出す  [ruby]  [idiom]

railsで使えるidiomを見つけた。

rubyで、あるメソッドの呼び出しが以下のようになっている場合、

hoge(:param, :option1 => true , :option2 => false)

以下のやり方でオプション部分だけを取り出せる

def hoge(*prams)
  options = params.last.is_a?(::Hash)? params.pop : {}
  pp options
  pp params
end

参考:

ActiveSupport::CoreExtensions::Array::ExtractOptions#extract_options!


Railsのvalidationの流れをもうちょっと細かく  [rails]  [tips]

ActiveRecord::Errors関係をいろいろいじりたいと思って、まずは、ActiveRecord::Validationをかじってみた。

Validationの流れの参考にでもなれば。

  • ActiveRecord::Baseが、Module ActiveRecord::Validationsをinclude
  • ActiveRecord::Validationsでは、
    • validate, validate_on_create, validate_on_updateのそれぞれのメソッドを定義。
    • これらのメソッド呼び出しにより、個々のvalidatorをCallbackChainに登録できる
      (validate do |record| true;end とやると validate_callback_chainにこのブロックが登録される。)
  • これらのメソッドを利用して
    validates_each, validates_confirmation_of, vaidates_acceptance_of, vaidates_presence_of, validates_length_ofをCallbackChainに登録
  • :save_with_validation :save_with_validation! を定義
    valid?メソッド経由でcallbackchainを順番に呼び出し
  • alias_method_chainによるsaveのリプレース
    • alias_method_chain :save, :validation
    • alias_method_chain :save!, :validation
      これにより
      save => save_with_validation, save! => save_with_validation!
      オリジナルのsave/save!は、
      :save_without_validation , :save_without_validation!
      にalias

最終的に、save/save!を契機にvalidation関連が呼ばれる。

だいたいそんな感じっぽい

参考:

  • validations.rb
    • ActiveRecord::Validations
    • ActiveRecord::Errors
  • callbacks.rb
    • ActiveSupport::Callbacks

IE"インターネットサイトxxxを開けません。"のバグ  [javascript]  [bug_or_spec]  [IE]

またでたよ。IE。

jasonpとかでスクリプトを読み込んで実行するときに、最初のkicker(loader?)的なスクリプトを書く場所によってエラーが発生する。

「インターネットサイトxxxを開けません。操作は中断されました」というエラーウィンドウがでて、サイトは表示されない状態となる。

例:

kicker.js

function kicker(){
  var script = document.createElement("script");
  script.setAttribute("type","text/javascript");
  script.setAttribute("src","./callee.js");
  document.body.appendChild(script);
  return true;
}

scriptタグを作ってcallee.jsを読み込むだけ。

callee.js

function callee(){
  document.getElementById("hogefuga").appendChild(document.createTextNode("hogefuga"));
  return true;
} 
callee();

テキストノードを埋め込むだけ。最後に自分を呼んでいる。

buggy.html(動かないケース)

<html>
  <head>
    <script type="text/javascript" src="./kicker.js" charset="utf-8" ></script>
  </head>
  <body>
    <div>
      <div id="hogefuga"></div><!-- ここにテキストノードが書き加わる -->
      <script>
      <!--
        kicker();
      //-->
      </script>
    </div>
  </body>
</html>

問題は、scriptタグがdivに囲まれていることらしい。

下記のように変更すると動く

:
<div>
  <div id="hogefuga"></div>
</div>
<script>
<!--
  kicker();
//-->
</script>
:

でも、いつもいつも外側に書けるわけでもないよね?

そういう時はeventListenerだそうだ。

if(window.addEventListener){
  window.addEventListener("load",kicker, false);
}else{
  window.attachEvent("onload",kicker);
}

もう、いい加減面倒くさいよ。

参考: http://yusuke.homeip.net/diary/2006/03/12/1142155862799.html

ちなみに、何を作っていて気付いたかというと、このブログの「コメント」欄。

といっても、「はてなブックマーク」をコメント欄代わりに表示しているだけ。


実践パターン(本):  [books]  [review]

今読んでる。

ところどころややこしい言い回し(日本語のせい?)があるものの、じっくり読めば筆者の言おうとしている「伝わるコーディング」がわかってくる。

Javaならではの問題も多いけど、思想的にはプログラマーは知っていて損はなと思う。

スクリプト言語やってるとすぐにハッシュで引数とか渡しがちだけど、筆者の言うように、それにより伝わりにくいコードになるのは確かだ。

でも、それをやらないと面倒くさいコーディングが増えるのも確かだ。

そのあたりのビミョーなところも読みながら自分なりに結論を出すのだろう。。。


メールアドレスのバリデーション by Ruby  [ruby]  [tips]  [sample_code]

javascriptによる簡易regexでは対応できないケースがでてしまったので、いろいろ参考にしつつruby版を作った。

require 'resolv'
require 'pp'

class MailAddressValidator
  def self.validate(address)
    return validate_by_regex(address) && validate_by_MX(address)
  end
  def self.validate_by_regex(address)
    addr_spec = %r{^(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+))*)|(?:"(?:\\[^\r\n]|[^\\"])*")))\@(?:(?:(?:(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+)(?:\.(?:[a-zA-Z0-9_!#\$\%&'*+/=?\^`{}~|\-]+))*)|(?:\[(?:\\\S|[\x21-\x5a\x5e-\x7e])*\])))$}
    address =~addr_spec
  end
  def self.validate_by_MX(address)
      mxdomain = address[/[^@]+$/]
      Resolv::DNS.new.getresource(mxdomain,Resolv::DNS::Resource::IN::MX) rescue nil
  end
  private_class_method :validate_by_regex, :validate_by_MX
end

使うときはこんな感じ

require File.dirname(__FILE__) + '/mail_address_validator'
print (MailAddressValidator.validate('hogefuga@hogefugadennnenn.naiyo')) 'ok':'ng' #=> ng

これをつかって、同期Ajaxでチェックしてる。

日本語が変だな。。。要は javascriptでxmlhttprequest.open('GET',"xxxxxx", false)という形で同期的にチェックしてる。

参考:

http://blog.livedoor.jp/dankogai/archives/51189905.html

http://www.ruby-lang.org/ja/man/html/resolv.html

追記 2009-04-13:

spellミスを直しました。id:Uchimataさんありがとうございます。

はてなブックマークがはじめてコメント欄として機能した記念すべき日です。


ActionMailerでメール送信@Sakuraレンタルサーバ  [ruby]  [tips]  [sample_code]

Railsを使わないで、rubyからActionMailerでメールを送信したくなったので、やり方のメモ。

ActionMailerは、gemでインストール済みと仮定。

Sakuraレンタルサーバ(さくら)の場合、"POP before SMTP"なので、送信前にpop認証が必要となります。

require 'rubygems'
require 'action_mailer'
require 'net/pop'

class MyMailer < ActionMailer::Base
  alias_method :base_perform_delivery_smtp, :perform_delivery_smtp
  @@pop3_auth_done = nil
  def self.setup_for_sakura
    self.delivery_method = :smtp
    self.smtp_settings = {
      :address => 'xxx.sakura.ne.jp',
      :port => 587,
      :domain => 'xxx.sakura.ne.jp',
      :pop3_auth => {
        :server => 'xxx.sakura.ne.jp',
        :user_name => 'hoge@xxx.sakura.ne.jp',
        :password => 'passw0rd',
        :expires => 1.hour,
        :authentication => :login
      }
    } 
    self.template_root = File.dirname(__FILE__) + "/templates"
    self.perform_deliveries = true
  end
  def mail_contents(user,contents)
    from "hoge <hoge@xxx.sakura.ne.jp>"
    recipients "#{user} <#{user}>"
    subject "日本語タイトルほげふが"
    body :user => user, :contents => contents
  end
  private
  def perform_delivery_smtp(mail)
    do_pop_auth if !@@pop3_auth_done or (Time.now - smtp_settings[:pop3_auth][:expires]) >= @@pop3_auth_done
    base_perform_delivery_smtp(mail)
  end
  def do_pop_auth
    pop = Net::POP3.new(smtp_settings[:pop3_auth][:server])
    pop.start(smtp_settings[:pop3_auth][:user_name], smtp_settings[:pop3_auth][:password])
    @@pop3_auth_done = Time.now
    pop.finish
  end
end 

で、./templates/my_mailer/mail_contents.erbに、テンプレートを適当に作成。

<%= @user %> 様
<%= @contents[:hello] %>ですねん。
ほな

これを利用する側はこんな感じ。

require 'rubygems'
require File.dirname(__FILE__) + "/my_mailer"
MyMailer.setup_for_sakura
MyMailer.deliver_mail_report('user@hogefuga.com', {:hello => "こんにちは"})

rubygemsへのパスが通ってない場合は、$LOAD_PATH.push("パス"), ENV['GEM_HOME'] = "パス"、でライブラリ及びGEM_HOMEのパスを通しておきましょう。

参考: http://railsforum.com/viewtopic.php?pid=47672


IE javascriptではRadioのchecked属性はドキュメントにappend後じゃないと変更できない  [javascript]  [bug_or_spec]  [IE]

またしてもIE。

ラジオボタンを動的に生成する場合、デフォルトとか以前の結果とかをチェックした状態で表示するために

var myRadio = document.createElement('input'); 
myRadio.type = 'radio';
myRadio.value = 'hoge';
myRadio.checked = true;

とかやるじゃないですか。

IEの場合、これではチェックが付かない。

ドキュメントにappendした後に変更する必要があるんだって。

いい加減にしてくれよIE


IE javascriptではformのname属性を変更できない  [javascript]  [bug_or_spec]  [IE]

javascriptでformをname属性でアクセスする手法は良く使う。

var abc = document.formname.hoge.value;

これを、動的に生成させたformで行おうと思った場合、IEで問題が起こる。

var myNode = document.getElementById('fuga');
var myForm = document.createElement('form');
myForm.name = 'formname';
var myInput = document.createElement('input'); 
myInput.name = 'hoge'; 
myInput.type = 'text';
myInput.size = "40";
myForm.appendChild(myInput);
myNode.appendChild(myForm);

dom生成時に.nameでname属性を変更しているにもかかわらず、IEでは独自のIDがつけられてしまい、上記のname属性を利用したアクセス方法ではアクセスできないのだ!

有り得ないよ。

そこで、こんなユーティリティ関数が必要になる。

function createNamedElement(tag,name){
  var isIE =/*@cc_on!@*/false;
  var element;
  if (name) {
    element = (isIE)? document.createElement('<' + tag + ' name="' + name + '">'): document.createElement(tag);
    element.name = name;
  } else {
    element = document.createElement(tag);
  } 
  return element;
}

IE恐るべし。

ちなみに'cc_on'の所は、IEの判定で良く使われる方法(らしい)。

この記事のタグ名'bug_or_spec'のネーミングセンスの良さに自画自賛


Perlのオブジェクト内関数の間接的な呼び出し  [perl]  [tips]

以下の方法では動かない。

package hoge; 
sub new{
  my $class=shift;
  my $self={'msg2' => 'harahoro','hoge' => \&hoge};
  bless $self,$class;
  return $self;
} 
sub fuga{
  my $self=shift;
  my $msg =shift;
  my $classname=ref $self;
  print "from $classname : hello! $msg\n"; 
} 
sub hoge{
  my $self=shift;
  my $msg = shift;
  print "I am calling fuga\n";
  $self->fuga("hoge : $msg and ". $self->{"msg2"});
} 
1;
package main; 
my $moga=hoge->new;
$moga->{'hoge'}->('self hash'); 

当然、以下も動かない。

package hoge; 
sub new{
  my $class=shift;
  my $self={'msg2' => 'harahoro'};
  bless $self,$class;
  $self->init;
  return $self;
} 
sub init{
  my $self=shift;
  $self->{"hoge"} = \&hoge;
} 
sub fuga{
  my $self=shift;
  my $msg =shift;
  my $classname=ref $self;
  print "from $classname : hello! $msg\n"; 
} 
sub hoge{
  my $self=shift;
  my $msg = shift;
  print "I am calling fuga\n";
  $self->fuga("hoge : $msg and ". $self->{"msg2"});
} 
1;
package main; 
  my $moga=hoge->new;
  $moga->{'hoge'}->('self hash'); 

以下の2点が問題

  • $self->funcのリファレンス取得方法がない
  • \&funcとするとinvocantが渡らない

なので、以下のような解決方法になる。

package hoge;
sub new{
  my $class=shift;
  my $self={'msg2' => 'harahoro'};
  bless $self,$class;
  $self->init;
  return $self;
} 
sub init{
  my $self=shift;
  $self->{"hoge"} = $self->hoge_invocant;
} 
sub fuga{
  my $self=shift;
  my $msg =shift;
  my $classname=ref $self;
  print "from $classname : hello! $msg\n"; 
} 
sub hoge_invocant{
  my $invocant=shift;
  return sub {  hoge($invocant, @_);};
} 
sub hoge{
  my $self=shift;
  my $msg = shift;
  print "I am calling fuga\n";
  $self->fuga("hoge : $msg and ". $self->{"msg2"});
} 
1;
package main; 
my $moga=hoge->new; 
$moga->{'hoge'}->('self hash');

hoge_invocantが

「invocantをレキシカルクロージャとして保持しhogeをinvocantつきで呼び出す無名関数」

を返す。

ここで無名関数を使うべきだということに気付いた。

sub init{
  my $self=shift;
  $self->{"hoge"} = sub {hoge($self, @_);};
}

追記~~

本屋で↑を立ち読みしたら(買え! >> 俺) 載ってた。

同じ結論になってたようなので、買わなくてもいいってことか?

~~追記終わり


Rails dbの fixtures形式バックアップ  [rails]  [tips]

こんなのをlibに入れて利用してる。

module YamlFixture
def record_to_yaml_fixture(rec_class_name)
  eval(rec_class_name).find(:all).inject({}){|h, v| h.merge(v.attributes["id"] => v.attributes)}.to_yaml
  end
end

rails to_json と to_yaml  [rails]  [tips]

to_jsonのときはattributesを取り出してjson化してる。

to_yamlのときはオブジェクトそのものをyaml化してる。

なので、

@items.to_json

@items.attributes.to_yaml

が等価

ということかな。


perlの改行自動出力がくせもの  [perl]  [bug_or_spec]

Perlは、内部的に改行をLFとして扱い、入力時・出力時に環境に合わせたコードで出力する。

なので、Windows上のperl (Strawberry perl使用)で、以下のようにすると

perl -e 'print "\x0a";'

出力に 0x0d0a (CR+LF)がでてしまう。

Windows環境でもLFで出したい時もある。

そのときは、こうしなければならないみたい。

perl -e 'binmode STDOUT; print "\x0a";'

$/とか$\とかいろいろいじったけど、できなかった。


RubyでHash Slice  [ruby]

Rubyってハッシュスライスがないんだよね。

Perlで簡単に

@hash{@fields}=@values;

とかできることができない。。

かなりつらいんですけど。。

hashの一部をupdateする場合のやり方はこんな感じらしい。

hash.update(Hash[*keys.zip(vals).flatten])

Subversionのproxy設定場所 serversファイル (XP/2000/Vista)  [environment]  [windows]  [subversion]

%APPDATA%\Subversion\serversにある。

XP/2000だと、

c:\Document and Settings\ユーザ名\Application Data\Subversion\servers

Vistaだと、

c:\Users\ユーザ名\AppData\Roaming\Subversion\servers

このファイルで

[global]
http-proxy-host=xxxxx.xxx.xxx
http-proxy-port=8080

とか設定する


英語キーボードで半角/全角キーを変更  [windows]  [tips]

英語キーボードで日本語入力するときいちいち

左Alt + ~ (チルダ)

とかめんどくさいので、変更した。(AXキーボードのドライバを使うパターンで)

  • (会社のPCの設定をそのままもってきた。Webで調べたらみんなそうしてるみたい。)

regedit

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters 
LayerDriver JPN : REG_SZ : kbdax2.dll
OverrideKeyboardIdentifier: REG_SZ : AX_105KEY
OverrideKeyboardSubtype: REG_DWORD : 0x00000001 (1)
OverrideKeyboardType: REG_DWORD : 0x00000007 (7)

あと、CAPS -> Ctrlへの変換も忘れないように書いておく

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Keyboard Layout
Scancode Map : REG_BINARY
0000  00 00 00 00 00 00 00 00
0008  02 00 00 00 1D 00 3A 00
0010  00 00 00 00 

今のCtrlはCtrlのまま変更しない

PC買ったら必ずやる。


バッチファイルのショートカットアイコン設定  [dos]  [tips]

バッチファイルのアイコンとか、.jarのアイコンとかを変更する方法。(かなり前のメモ)

Javaのアプリケーションで利用される".jar"ファイルは、Windowsではファイルの関連付けの機能でjavawに関連付けされ、全て同一のアイコンに設定されています。

バッチファイルも、同様に変な歯車のアイコンに設定されています。

これでは、アイコンがどのアプリケーションでも同じになってしまい、プロフェッショナルな感じがしません。

そこで、JScript (JavaScriptに似て非なるWindowsのスクリプト)を用いてアイコン付きのショートカットを作成する方法で解決します。

用意するもの。

  • アプリケーションを起動するためのバッチファイル。(.batファイル)
  • アイコンファイル(.ico)(フリーウェアなどで作成)
  • JScriptファイル(以下に記述)

上記を同一フォルダにおいてJScriptをダブルクリックで実行する形になります。

JScriptファイル内容(makeShortcut.js):

hello.batをhello.lnk/hello.icoと関連付けてデスクトップに作成する場合

Shell = new ActiveXObject("WScript.Shell");
DesktopPath = Shell.SpecialFolders("Desktop"); //デスクトップにショートカット作成
link = Shell.CreateShortcut(DesktopPath + "\\hello.lnk");
link.Arguments = ""; // .batファイルに引数を渡す場合ここに記述
link.Description = "hello.bat shortcut";
link.HotKey = "";
link.IconLocation = Shell.CurrentDirectory + "\\hello.ico";
link.TargetPath = Shell.CurrentDirectory + "\\hello.bat";
link.WindowStyle = 3;
link.WorkingDirectory = Shell.CurrentDirectory;
link.Save();

multipartメールのbase64の解凍方法  [perl]  [tips]

multipart/mixedのメールが複数分割されて送られてきました。メール本文は空っぽで、全て添付ファイルになっていました。

どうやら、outlook expressで送信した場合に起こる現象のようですが、こちらで読めないので困ってしまいます。

中身を見ると、テキストの本文に続き、

Content-Type: application/octet-stream;
Content-Transfer-Encoding: base64

となっていて、この部分以降に怪しげな文字列が延々と続いています。

この部分以降は、base64でエンコードされたバイナリ添付ファイルなわけです。

この部分を取り出してエンコードを解けば(デコードすれば)、添付されていたファイルを復活できるはずです。

で、perlの出番です。

Step1:base64部分だけのファイルを作る

> ls
xxx[1_3].dat
xxx[2_3].dat
xxx[3_3].dat
> cat *.dat > abc.dat
> vim abc.dat
#ここで、必要な部分(怪しげな文字列の部分)以外を削除

Step2: perlでデコード

Perlのソース

#!/usr/bin/perl -w
use MIME::Base64;
binmode STDOUT,'raw';
binmode STDIN,'raw'; 
while(<>){
  print decode_base64($_);
}

楽勝だね。


Railsテスト時に日付を固定にする方法 (for Test::Unit)  [ruby]  [rails]  [TDD]

Railsで試験をする時に、日付に依存する機能(次の誕生日までの日数を求めるとか。。)がある時、今までならfixtureに

date: <%= Date.today().to_s %>

とか、動的にfixtureを定義していたのですが、いろいろロジックが複雑になりだしたので、発想を逆にすることにしました。

つまり、テストの日付を固定するという方法です。

基本的に、Date.today()や、Time.now()を上書きしてやるのですが、他のテストに影響を与えないようにやる必要があります。

そこで、Test::Unit::TestCaseのsetup/teardown内で、関数の再定義、もとの定義への戻しをやってやります。

hoge_controller_test.rb

:
#このテストは2008年9月で試験
class Date
  def self.fixed_today
    return Date.new(2008,9,1)
  end
end

class HogeControllerTest < Test::Unit::TestCase 
  def setup
    Date.instance_eval do
      alias :orig_today :today
      alias :today :fixed_today
    end
  end
  def teardown
    Date.instance_eval do
      alias :fixed_today :today
      alias :today :orig_today
    end
  end
:
end

特異メソッドのaliasを作成するので、instance_evalを利用してaliasによる関数の入れ替えをしています。


CGIでリファラ(HTTP_REFERER)を取る方法  [perl]  [javascript]  [tips]

あいかわらず、初歩的なところにいます。。。(-_-;)

perlのCGIでアクセス解析のためにリファラ(訪れた人が前に見ていたページ)を取ろうとしてたのですが、検索サイトによって文字が化けたりしてたので、utf8に統一してみようということで、以下のようにしました。

- ページに埋め込むjavascript

<script language="JavaScript">
  <!--
    document.write('<img src="http://hoge.fuga.funya/access.cgi?rr=' + escape(document.referrer) + '" />');
  // -->
</script>

imgタグ内でアクセス解析用のcgiを呼んでいます。cgi側でHTTP_REFERERを取ると、このスクリプトを入れたページ自身になるので、パラメータとしてrrにリファラを入れています。

  • cgi側(perl)
#!/usr/bin/perl -w
use strict;
use CGI;
use Encode;
use Encode::Guess qw/euc-jp shiftjis 7bit-jis/;
use utf8; 

my $file="access.log";

my $q=new CGI;
my $ref = url_decode($q->param('rr')); #前のページ
my $referer = url_decode($q->referer()); #見られてるページ

my $result="\"$ref\",\"$referer\"\n";

open(FILE,">>:encoding(utf8)", $file) or error($q, "can't open");
print(FILE $result);
close(FILE); 

&printimg;
exit;
 
sub url_decode{
  my $str = shift;
  return 'hoge' unless $str;
  $str =~ tr/+/ /;
  $str =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg;
  my $decoder = Encode::Guess->guess($str);
  return $decoder->decode($str) if(ref($decoder));
  return decode("utf8",$str);
}
sub printimg{
  open(COUNTERIMG, "./counter.gif") or error($q, "can't open");
  binmode(COUNTERIMG);
  print "Content-type: image/gif\n\n";
  print <COUNTERIMG>;
  close(COUNTERIMG);
}

urlエンコードされた文字を一旦もどしてからEncode::Guessでデコードしてファイルに書き込んでいます。

これにより、文字コードが統一されます。

urlエンコードをデコードするときにpackを利用しているのでutf8フラグ関係が心配なので、utf8フラグをつける前にurlデコードしています。

最後にimgを転送して終了。

なんか美しくないけど、動く。


ノートPCのリカバリ(EISA)領域を消す方法  [vista]

さて、我が愛機のVaioですが、リカバリソフトが入っている領域として「EISA」というのがあるのですが、これを消すことができなくて困ってました。

リカバリディスクを作成した後は不要となるのですが、これを消すには作成したディスクからOSの再インストールというのが常套手段のようでした。

僕は、そういうことを知らずに山ほどソフトを入れたので、いまさらインストールしなおしは勘弁して欲しいと思っていたのですが、ようやく解決方法がわかりました。

  • diskpart.exeを管理者権限で起動 (dos窓)
  • EISAのあるディスクとパーティションを選択(list disk, select disk, list partition, select partition)
  • delete partition
  • その後、visitaの管理画面(ディスクの管理)から、EISAのあったパーティションをフォーマット & Cドライブのどこかのフォルダにマウント

となります。

僕の場合、colinuxが数ギガあったので、colinuxフォルダごとマウントしたドライブに入れ替えました。

(別ドライブとすることもできますが、マウントしてオリジナルフォルダごとコピーするほうがcolinuxを丸ごと移動できてよかった。)


バイナリの文字列表現(ucs-2)をバイナリに変換  [perl]  [java]

言語によっていろいろ違うなぁと実感。

Perl

use Encode;

binmode STDOUT, ":encoding(shiftjis)"; 

my @str = qw(00110000 01000010);
my $final = join('',map{pack('B8',$_)} @str);
$final = decode('UTF-16BE',$final); 
print $final;

Perlのmap関数の使い勝手は最強ですね。

java

import java.io.*; 

public class BinaryDecode{
  public static void main(String[] args) {
    String[] strArray = {"00110000","01000010"};
    byte[] bytes = new byte[2];
    int i = 0;
    for(String s : strArray){
      int j = Integer.parseInt(s,2);
      if(j > 127){ j = j - 256;} //-128~127に収める処理
      bytes[i++] = (byte)j;
    }
    try{
      System.out.println(new String(bytes,"UTF-16BE"));
    }catch(IOException e){
      e.printStackTrace();
    }
  }
}

javaの場合、文字列が可変長の場合、"byte[]"の代わりに"List"を使う必要が出てきてさらにややこしくなる。

また、javaでは、Byte.parseByteは、内部的にIntegerに変換して128以上だとエラー出すので、しょうもない処理が必要。


Windows IPv6のプレフィックスポリシー参照方法  [dos]  [network]

いずれ、こういうコマンドも必要になるんだろう。

netsh interface ipv6 show prefixpolicy

知っておく。

ipv6 install

も忘れないようにしなきゃ


選択したURLに飛ぶブックマークレット  [bookmarklet]  [javascript]

マウスで選択したURLに飛ぶブックマークレット。

ttpで始まるものにも飛べるように改造してもいいかもしれない。

javascript:(function()%20%7Bvar%20w='';if(window.getSelection)%7Bw=window.getSelection();w=''+w;%7Delse%20if(document.selection)%7Bw=document.selection.createRange().text;%7Dif(w.length%3E0)%7Bwindow.open(w);%7Delse%7Balert(%22nothing%20selected%22);%7D%7D)()

選択したURLにジャンプ


RFM分析(営業・マーケティング)  [business]

R(recency:最新購買日) いつ買ったか、最近購入しているか

F(frequency:累計購買回数) どのくらいの頻度で買っているか

M(monetary:累計購買金額) いくら使っているか


http://www.atmarkit.co.jp/aig/04biz/rfm.html


xargsとか忘れがちなのでメモ。  [unix]  [perl]  [one_liner]

便利なワンライナー


grep -r -l xxxxx . | xargs perl -pi.bak -e "s/xxxxx/yyyyy/g"

xxxxxの含まれているファイルを抽出して、中身のxxxxxをyyyyyに書き換え。

バックアップファイルとして.bakを作成


Unixのフォアグラウンドとかバックグラウンドとか(fg/bg/jobs)  [unix]  [tips]

すぐ忘れるのでメモ。

>xxxx &   #バックグラウンドで実行
>jobs     #バックグラウンドで動いてるやつをリストアップ
[1] - xxxx
>fg 1     #jobsで出た番号のやつをフォアグラウンドにもってくる
>[ctrl-z] #フォアグラウンドのやつをサスペンド
>bg       #フォアグラウンドのやつをバックグラウンドに持っていく

Rubyで動的に関数定義3(for Test::Unit)  [ruby]  [tips]  [TDD]

Rubyで動的に関数定義 Rubyで動的に関数定義2

からの続き。

で、今回いろいろ調べていた大元の理由である「テストケースの自動生成」だけど、こんな感じで使えそう。


テスト対象

class Testee
  def login(login_user)
    @login_user ||=login_user
  end
  def who_am_i?
    @login_user
  end
end

一つのテストケース内でログインの試験を複数回やると、初回のログイン情報が残るためにfailする。

require 'test/unit'
require 'testee' 

class TesteeTest < Test::Unit::TestCase
  def test_should_login
    @testee.login(:hoge)
    assert_equal :hoge, @testee.who_am_i? # => ok
    @testee.login(:fuga)
    assert_equal :fuga, @testee.who_am_i? #=> fail :hogeが残ってる
  end
end

今までなら、複数の試験を手書きしてた。


そこで、今回勉強してきた、define_methodを利用してテストケースを自動生成してみる。

require 'test/unit'
require 'testee' 

class TesteeTest < Test::Unit::TestCase
  def self.generate_test
    while login_name = DATA.gets do
      login_name.chomp!
      define_method("test_should_login_by_#{login_name}") do
        @testee.login(login_name)
        assert_equal login_name, @testee.who_am_i? , " error on login by #{login_name}"
      end
    end 
  end
  def setup
    @testee = Testee.new
  end
end
__END__
:hoge
:fuga

うまくやれば、PerlのTest::Baseくらい使い勝手が良くなるかもね。



Rubyで動的に関数定義2  [ruby]  [tips]

Rubyで動的に関数定義

からの続き。

生成後のインスタンスに関数を動的に生やす場合は、いろいろ試したが、以下の方法が一番よさそう。

インスタンス変数、クラスインスタンス変数、ローカル変数(クロージャ)が利用できる。


class Dog
  @dog_counter = 0
  def initialize(name)
    self.class.class_eval { @dog_counter += 1 }
    @dog_name = name
  end
  def perform
    puts "*****"
    puts "I am #{@dog_name}." # instance variable @
    puts "Total Dogs are #{self.class.class_eval {@dog_counter}}." # class instance variable @
    puts "bow!"
  end
end
dog_hoge = Dog.new('hoge')
dog_hoge.perform
dog_fuga = Dog.new('fuga')
dog_fuga.perform

インスタンスdog_fugaにだけ関数をオーバライドしてやる。

instance_eval, define_methodを利用することにより、外部ローカル変数を利用できる。


lexical_local_variable = 'Wooooo!'
(class << dog_fuga;self;end).instance_eval do
  define_method(:perform) do
    puts "*****"
    puts "I am #{@dog_name}." # instance variable @
    puts "I am one of the #{self.class.class_eval {@dog_counter}} Dogs." # class instance variable @
    puts "#{lexical_local_variable}" # lexical closure(local variable)
  end
end
dog_hoge.perform
dog_fuga.perform

いろいろ使えそうだ。


追記

Rubyで動的に関数定義3(for Test::Unit)

unixのマニュアルのテキスト保存方法  [unix]  [tips]

会社の重鎮に教えてもらった。


man xxx | col -bl > xxx.txt

こうすると、下線とかboldとかが取れてきれいなテキストで落とせる。


perlでナベアツ(FizzBuzz改)  [日記]  [perl]

FizzBuzzってはやってたけど、3の倍数と3の付く数字でアホになる場合はどうなるかやってみた。


perl -e'print+(aho)[$_%3 and (/3/)?0:1]||$_,$/for 1..100'

もっと短くなるのだろうか。。。


参考:

FizzBuzz - Golf Challenge

追記: 3項演算子いらないみたい。

perl -e'print+(aho)[$_%3 and !/3/]||$_,$/for 1..100'


sqlで日付を月初にしてグループ化する方法  [tips]  [mysql]

レポート用のクエリーとかで、日付を月初にあわせてグループ化したかったりする。

sqlでは以下のようにすればできる。


select cast(date_format(date_column,'%Y-%m-01') as Date) from table
group by cast(date_format(date_column, '%Y-%m-01') as Date);

本当にcastが必要なのかが良くわからん。



Rubyで動的に関数定義  [ruby]  [tips]

module_eval(= class_eval),instance_evalがある。

なんで、この機能を調べているかというと、Railsで試験しているときに、ログインユーザを切り替えようと、一つのテスト関数内でログインを繰り返してたら、同じテスト関数内は同一セッションになって「すでにログインしてます」とかなったわけさ。(俺のインプリでは)


で、いちいちログアウトさせるのも面倒なので、いっそのことテスト関数を自動生成しようと思った。


そのうち詳しく書こうと思うので[todo]タグ。


追記:


module_eval(=class_eval)は、レシーバのクラスにインスタンス関数を定義。

irb> class Hoge
irb> end
irb> hoge = Hoge.new
irb> Hoge.module_eval {def fuga() p 'fuga';end}
irb> Hoge.fuga #=> error
irb> hoge.fuga #=> 'fuga'
irb> Hoge.new.fuga #=> 'fuga'

instance_evalは、レシーバがクラスの場合、クラス関数を定義(def self.xxxってやるやつと同等)

irb> class Hoge
irb> end
irb> hoge = Hoge.new
irb> Hoge.instance_eval {def fuga() p 'fuga';end}
irb> Hoge.fuga #=> 'fuga'
irb> hoge.fuga #=> error
irb> Hoge.new.fuga #=> error

instance_evalは、レシーバがobjectのインスタンス場合、そのobjectのインスタンス関数を定義

irb> class Hoge
irb> end
irb> hoge = Hoge.new
irb> hoge.instance_eval {def fuga() p 'fuga';end}
irb> Hoge.fuga #=> error
irb> hoge.fuga #=> 'fuga'
irb> Hoge.new.fuga #=> error

これに変数のスコープとからむとさらにややこしそうだ。

そのうち調べよう。ということでまだ[todo]

追記:

Rubyで動的に関数定義2 Rubyで動的に関数定義3(for Test::Unit)

マインドマップ作成ソフトウェアって  [lifehack]  [日記]

マインドマップはlifehackツールの一つとしてとても面白いと思う。

だけど、マインドマップをソフトウェアで描くのはどうもしっくり来ない。

どう見てもただの「ツリー作成」ソフトにしか見えない。


WBS(Work Breakdown Structure)作成にマインドマップ使えと勧める記事

とかいうのを見ると余計にそう思う。


amazonのサービス切れを直す  [todo]  [aws]

対象の探し方

find ./-name "*.xsl" | xargs grep -l amazon | xargs grep -L AWSE

ほっときすぎていろいろなサイトで問題が出ているのが発覚


RubyのYAMLの変な挙動  [ruby]  [rails]  [bug_or_spec]

railsでto_yamlでactiverecordのオブジェクトをyaml化すると、日付関連がこのようになった。

mydate: !timestamp 08/10/10

で、これをrubyのYAML::loadで、読ませると'argument out of range'というエラーになる。

日付で問題なのはなぜか10月(他にもあるかもしれない。)


irb> require 'yaml'
irb> YAML::load("mydate: !timestamp 08/10/10")
ArgumentError: argument out of range
irb> YAML::load("mydate: !timestamp 08/11/10")
=> {"mydate"=>Thu Jan 10 00:00:00 UTC 2008}

(あれ?、よくみると11月も1月になってるし。。。)


irbでDateをyaml化すると、以下のようなフォーマットになる。

irb> Date.new(2008,10,10).to_yaml
=> "--- 2008-10-10\n"

なので、きっとrailsがto_yamlで変なことをしてるんだろう。


いろいろ調べて、environment.rbの記述を変更することで対処できた。

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.update :default => "%Y/%m/%d"

なぜか、'%y'で設定してたので、'%Y'に変えた。


俺のミスってことだな。



Rubyのクラスのインスタンス変数  [ruby]  [tips]

Rubyにはクラスにもインスタンス変数を作成することができる。

class Hoge
  def self.count_instance
    @num = 0 if @num.nil?   #クラスのインスタンス変数
    @num += 1
  end
  def self.get_count
    @num
  end
  def initialize(num)
    self.class.count_instance
    @num = num
    self
  end
  def get_count
    @num
  end
end

これがあるんならクラス変数(@@)とかっていらないのかな?


App::Chariot改変2  [perl]  [chariot]

テンプレート内に日本語を書くと文字化けする。

utf-8がTemplateで読まれるときのフラグの関係だと思われる。

いろいろ調べてTemplate::Provider::Encodingという、かの有名なmiyagawaさんのモジュールを使えば良いことがわかった。

Index: Chariot.pm
===================================================================
--- Chariot.pm	(revision 13330)
+++ Chariot.pm	(working copy)
@@ -7,6 +7,7 @@
 use YAML;
 use App::Chariot::Config;
 use Template;
+use Template::Provider::Encoding;
 use File::Spec;
 use XML::RSS;
 use Scalar::Util;
@@ -55,9 +56,11 @@
         my $self = shift;
         Template->new(
             {
+                LOAD_TEMPLATES => [ Template::Provider::Encoding -> new({
                 INCLUDE_PATH =>
                   File::Spec->catfile( $self->config->assets_dir, 'tmpl' ),
                 ABSOLUTE => 1,
+                })]
             }
         );
     }

実は、このサイトがずっと英語メニューだったのはこのためだったのだ。:-p


CrossReviewのサイトに参加  [日記]

crossreview(クロスレビュー) || レビューで繋がる、みんなの輪 » hassylin

に参加した。

主にプログラミング関連の本をレビュー予定。

読むのが遅いので、dankogaiさんのように速攻レビューというようには行かないけど。

参考にしてもらえれば幸い。


本当なら自分で作りたかった。


vim changeLogの設定2  [environment]  [vim]  [changelog]

書くの忘れてた。

autocmd BufRead *.chg setf changelog

これを付け加えておくと、拡張子.chgのものは全てvimでchangelogとして扱われる。


Railsのテスト中の出来事  [bug_or_spec]  [日記]

<0.5> expected but was
<0.5>.

意味不明

調べてみると、floatの誤差の問題だった。

irb > 0.05 + 0.05 + 0.05 + 0.05 + 0.05 + 0.02 + 0.02 + 0.02 + 0.02 + 0.02 + 0.15 == 0.5
false

困った。全部100倍して計算するのか。。。あほくさ


assert_in_deltaというのがあるのでこれを利用することにした。


MVCアーキテクチャでのテストの分け方  [TDD]  [programming]  [idea]

こういう風に分けると意外とうまくいく気がする。

  • Security:主にController
  • Routing:主にController
  • Logic:主にController。
    (ActiveRecordアーキテクチャ(Railsとか)だとControllerだけど、他のフレームワークの場合ModelとControllerの間の層にもこのあたりの機能が入ると思われる。)
  • Server Side Validation:主にModel
  • Client Side Validatoin:主にjavascript
  • Server Side View:主にView。
    テンプレートによるView生成とか
  • Client Side View:主にjavscript。
    Formの入力制御とか、Viewフィルタとか、Tableのsortとか。Ajaxとか。

このブログではコメントとかが入らないので反応が見れないのが残念。(はてぶとかに載ればいいけどね。)


Dateアップデート時の注意事項  [programming]  [tips]

どんな言語でもそうだと思うけど、日付のアップデート時には、月→日の順番でアップデートする。

先に日をアップデートすると、31日の処理にバグが出る。


オブジェクト指向開発の指針  [programming]  [OO]  [tips]

たまには振り返っておく。

  • OCP: Open Closed Principle
    拡張に開き、修正に閉じる。
  • DRY: Don't Repeat Yourself
    適切な場所一箇所で処理する。(複数個所に同じようなコードがあるのは、あやしい。)
  • SRP: Single Responsibility Principle
    一つのことをうまくやる。
  • LSP: Liskov Substitution Principle
    サブクラスは親クラスと同じインタフェースを持つ。(2Dimensionクラスのサブクラスで3Dimensionクラス作るのはだめ。)

Railsのform_forとpartial  [rails]  [tips]

form_forを使いつつpartialレンダリングするには、以下の方法でpartial側

formにform_forのブロックパラメータを渡す必要がある。


例: ':locals => {:f => f}'のところ。

<h1><%= _('Create a New Account') %></h1>
<% form_for :user, @user, :url =>{:action => 'signup'} do |f| -%>
  <%= render :partial => 'signup_form', :locals => {:f => f}  %>
  <%= submit_tag _('Sign up') %>
<% end -%>

App::Chariot改変  [perl]  [chariot]

タグ別アーカイブに対応した。(但し、複数タグの絞込みはできない。)

複数タグでの絞り込みは、オンラインアーキテクチャじゃないと厳しそうなので。。


package App::Chariot::C::TagIndex;
use Moose;
with 'App::Chariot::Role::C';

sub create {
    my ($self, $c) = @_;

    my $ifile = File::Spec->catfile($c->config->assets_dir, 'tmpl', 'tagindex.tt');
    my %tags = ();
    for my $entry (@{$c->dat->list}) {
        for my $item (reverse @{$entry->items->list}) {
            for my $t (@{$item->tags}){
                $tags{$t} = [] unless $tags{$t};
                unshift(@{$tags{$t}},$item);
            }
        }
    }
    for my $t (keys %tags){
        my $cnt =1;
        my @list = @{$tags{$t}};
        my $ofile = File::Spec->catfile($c->config->output_dir, "$t.html");
        $c->render(
            $ifile => $ofile, {
                tag => "[$t]",
                items  => [@list],
            },
        );
    }
}

1;

App::Chariotのコントローラ群にApp::Chariot::C::TagIndexというモジュールを追加するやり方にした。

きっと、もっと「モダン」なやり方があるのだろうけど、とりあえずこれで対処。


App::Chariot改変Todoリスト  [todo]  [perl]  [chariot]

  • Done: タグ別アーカイブ
  • Monthly, Daily アーカイブ
  • コメント、トラックバック、RSS Ping。。。
    やっぱりオンライン系がいるなぁ

prototype.jsでのradioの扱い方  [javascript]

$A(document.getElementsByName(element_name)).each(function(elm){
  if(elm.checked){
    ほげほげ;
  }
});

でおけ。


過去のchanglogをChariot形式に変更  [日記]

あとは、css等をいじる必要がある。


Text::Hatenaのsuper_pre改変  [perl]  [chariot]

super_preとpreが同じ処理になっているので、(&")等を変換するように改変


MVPen買ったよ  [日記]  [gadget]

すごくいい。

[http://motivation.drivendevelopment.jp/images/mvpen.jpg:image]

perlのModule-Installでのincディレクトリ  [perl]  [CPAN]  [environment]

Module::Installで作ったモジュールには通常incディレクトリとMANIFEST等が

入るが、svnで管理する場合にははずすことが多い。

Module::Installが利用できる環境でperl Makefile.PLすればよい。

その後、

make manifest

make dist

等する。


strawberry-perlのPathToolsのバージョン  [perl]  [CPAN]  [bug]

PathTools-3.2501を使う必要がある。


CPANモジュールをバージョン指定でインストール  [perl]  [CPAN]  [tips]

Version指定するときは、CPANのダウンロードリンクのid/以下を使う


perlのgrepで空文字を配列から消す  [perl]  [tips]  [idiom]

my @result = grep{$_} @array;

App::Chariot入れた  [perl]  [chariot]  [日記]

tokuhiromさんのApp::Chariotという簡易ブログツールを入れた。


モダンなPerlということで、かなりすっきりしたソースでわかりやすい。

これから勉強。とりあえず、以下の変更をした。


-*pでプライベートとなるようにData::Clmemo::Itemを改変 -タイトルにPerlモジュール名(::)が入っても処理できるようにData::Clmemo::Itemを改変
Index: Item.pm
===================================================================
--- Item.pm	(revision 13612) 
+++ Item.pm	(working copy)
@@ -8,7 +8,7 @@
sub parse {
  my ($class, @lines) = @_; 
  
  -    my ($title, $tag, $body) = (shift @lines) =~ /\*(.*?)(\[.*\])?:(.*)/;
  +    my ($title, $tag, $body) = (shift @lines) =~ /\*([^p][^[]*)(\[.*\])?:(.*)/;
  return unless $title;
  
  $title =~ s/(^\s*|\s*$)//g;

perlの最新版の機能の読み方  [perl]  [tips]

perldoc perldelta

で読む。


Y-combinator  [algorithm]

再帰的な関数を無名で扱うためのアルゴリズム。

rubyの例:

 Y= proc{|g|
    proc{|f|
      g[f[f]]
    }[
      proc{|f|
        g[proc{|y| f[f][y]}]
      }
    ]
  }
  fact = proc {|f| proc{|n| n==0 ? 1: n * f[n-1]}}
  p Y[fact][5] #=> 120

perlのimportで&amp;プロトタイプ関数が使えない  [perl]  [Question]  [bug_or_spec]

解説希望。 よくわかりません。

複数パッケージを含む以下のようなperlスクリプトで(&)プロトタイプ宣言した関数を実行すると、動きません。(Can't call method 'fuga' without a package or object....)

package hoge;
use base 'Exporter';
our @EXPORT = qw/ fuga foo/; 

sub fuga(&){ print $_[0]->();}
sub foo(){ print $_[0];}
1; 
package main;
import hoge;
# 駄目パターン
fuga {'fuga'};
#プロトタイプ宣言(&)してないやつはOK
foo('foo');
#関数として渡すとOK
fuga(sub{'fuga'});

プロトタイプで'&'を指定した場合、subをつけない無名関数(ブロック)を渡せるはずですが、渡せません。

で、package hogeを別ファイルに置くと、動きます。

use 'hoge' 
fuga {'fuga'}; #OK

なんか変だなぁ。

importとuseは違うのかなぁ?

なんか間違ってる?


IE DOM table tips  [javascript]  [bug_or_spec]  [IE]

  • DOM作成時にtbody書かないとIEはtableを表示しない
  • colspan は colSpanとして設定する必要がある

rails_calenderの表示まで  [javascript]  [mylib]

  • Done: CSSによるスタイル定義
  • Done: DOMによる生成
  • Done: 日クリックevent
  • Done: Closeクリックevent
  • Done: 本日クリックevent
  • Done: 月クリックevent

javascript event tips  [javascript]  [tips]

eventの標準機能を止めないと思わぬことがおこる。

   _disable_default_event: function(evt){
     if (evt.preventDefault) {
       evt.preventDefault();
     } else {
       evt.returnValue = false;
     }
   };

この関数をイベント処理後に呼び出す。


DOM builder作成  [javascript]  [mylib]

2008-05-29 のideaどおり


DOMの効率的な生成方法案  [javascript]  [idea]

  • 階層の深いDOMツリーをどうやって効果的に作成するか
  • いい案がないようなので、Builderパターンのライブラリを作る。
 idea: Directorは、以下の基本creatorを組み合わせる
  build_element(type, attr={});
  build_elements(function, params = []);	
    where function(v,i) -> [type, attr[]]
    params.map.function.map.function(v,i){bild_element.apply(null.v);};

applyの引数展開  [javascript]  [tips]

func.apply(null, array)とするとarrayが展開される。


strawberry-perl  [perl]  [news]

  • strawberry-perl-5.10.0.1-1がリリースされてた。
  • VistaはXSモジュールがインストールできないらしい。

strawberry-perl  [todo]  [perl]  [environment]

Vista対応されたらVaio に入れる。


Changelogはじめてみた。  [lifehack]  [changelog]

日々のメモ用

バッチファイル起動時にウィンドウを開かない方法  [dos]

changelogは拡張子が無いので、ファイルのダブルクリックではエディタ(gvim)が開かない。

なので、dosのバッチファイルを書く。

でも、gvim起動後にもdos窓が開きっぱなしになってしまう。

以下のやり方で開かなくできる。

"START コマンド名"

changelogはclmemo形式にする  [lifehack]  [changelog]

 *タイトル[タグ]:ボディー

という形式

'*p'とするとプライベート


vim changelog設定  [environment]  [vim]  [changelog]

vimでは、\+oで追加できる。

  let g:changelog_username = "hassy"

としてユーザ名を指定する。(.vimrc)