トップ 最新 追記

3 日坊主日記


2007-01-02 [長年日記]

_ ruby-refm phase 2: tk tkextlib

作業量の少ない moriq です。

ruby-1.8.1/ext/tk で rdoc --ri。

はうあ。

1.8.2以降はTkディレクトリの中に入るので構造が違うんだけど@sinceはこの辺考慮するんだろうか。するんだろうなあ。

_ ruby-refm phase 2: tk tkextlib (2)

ext/tk に対する ri -c。

なんで TkRoot TkWindow とかは出ないんだろう。

_ ruby-refm phase 2: tk tkextlib (3)

わかった。 ext/tk じゃなくて ext/tk/lib で作れば ok。

明らかに多い。

追記: 見苦しいのでファイルに追い出しました。


2007-01-03 [長年日記]

_ ruby-refm phase 2: tk tkextlib (4)

tkextlib/blt/component.rb:
module Tk::BLT
module Tk::BLT::PlotComponent
module Tk::BLT::PlotComponent::OptKeys
class Tk::BLT::PlotComponent::Axis
class Tk::BLT::PlotComponent::Crosshairs
class Tk::BLT::PlotComponent::Element
class Tk::BLT::PlotComponent::Bar
class Tk::BLT::PlotComponent::Line
class Tk::BLT::PlotComponent::GridLine
class Tk::BLT::PlotComponent::Legend
class Tk::BLT::PlotComponent::Pen
class Tk::BLT::PlotComponent::Postscript
class Tk::BLT::PlotComponent::Marker
class Tk::BLT::PlotComponent::TextMarker
class Tk::BLT::PlotComponent::LineMarker
class Tk::BLT::PlotComponent::BitmapMarker
class Tk::BLT::PlotComponent::ImageMarker
class Tk::BLT::PlotComponent::PolygonMarker
class Tk::BLT::PlotComponent::WindowMarker

たくさんあるなあ。

むう。本文は誰が書くんだろう…


2007-01-04 [長年日記]

_ ruby-refm phase 2: 特異クラス定義をうまく読めない (win32 ri)

調子よく変換していたのだが

# tkextlib/blt/winop.rb:-
require 'tk'
require 'tkextlib/blt.rb'

module Tk::BLT
  module Winop
    extend TkCore

    TkCommandNames = ['::blt::winop'.freeze].freeze
  end
  WinOp = Winop
end

class << Tk::BLT::Winop
  def changes(win)
    tk_call('::blt::winop', 'changes', win)
  end
   ...
end

こういう特異クラス定義を ri が読めてないなあ。

 ruby -v
 ruby 1.8.5 (2006-08-25) [i386-mswin32]
 cd c:\tmp
 rdoc --ri --op ri c:\arc\ruby-1.8.5-p12\ext\tk\lib
 ri -d c:\tmp\ri\ri Tk::BLT::Winop
 (特異クラス中のメソッドが出ない)

どうしたものか。

(win32 で rdoc --ri するとなぜか --op のディレクトリが2重になる)

追記:

 ruby 1.8.5 (2006-12-25 patchlevel 12) [i686-linux]

でも同じだった。

追記: わかった。module として定義してから class << ほげ した場合うまくいかないようだ。

@methods を full_name で検索するメソッドがないみたいなので find_symbol を使ってみた。うまくいったように見える。


2007-01-07 [長年日記]

_ [] 化物語

化物語(上) 化物語(上) これはやばい。


2007-01-18 [長年日記]

_ [Rails] where plugin の Cond を Rio 的な遅延評価で書けたら

ActiveRecord で

 S.find(:all, :conditions => ["city = ?", "Paris"])

 S.find(:all).select { |s| s.city == "Paris" }

と書くと、速度・メモリに深刻なダメージを受けるけど、 where plugin の Cond を Rio 的な遅延評価で書けたら

 S.select { |s| s.city == "Paris" }.find(:all)

と書けて嬉しいかも。

select の alias として conditions, where, restrict 辺りを用意。

 && -> Rel.and (Rel#& ??)
 || -> Rel.or  (Rel#| ??)
 !  -> Rel.not
 :select option -> Rel.project("city")
 :joins, :include option -> Rel.join("S", "P")

また、ActiveRecord と SQL (RDBMS) の間に何かがあるとすれば、こういうことは当然できるに違いない。

_ [Rails] 関係演算ぽく表現

妄想ネタの続き。

関係演算ぽく表現してみる。 比較演算は実装が難しそうなので theta にしておく。

_ scoped_access

 class UserMemoController < MemoController
   scoped_access Memo, :restricted
 protected
   def restricted
     ScopedAccess::MethodScoping.new(:user_id => session[:user].id)
   end
 end
 memo_rel = Memo
 user_memo_rel = Memo.select { |m| Rel.theta("=", m.user_id, session[:user].id) }
 ...
 user_memo_rel.find(:all)

_ acts_as_view

 class Member < ActiveRecord::Base; end
 class ActiveMember < Member
   acts_as_view :deleted => false
 end
 class InheritedActiveGrade2Member < ActiveMember
   acts_as_view :grade=>2
 end
 member_rel = Member
 active_member_rel = member_rel.select { |m| Rel.theta("=", m.deleted, false) }
 active_grade2_member_rel = active_member_rel.select { |m| Rel.theta("=", m.grade, 2) }

_ has_many

 class S
   has_many :ps  # P
 P.semijoin(S)
 P.matching(S)

_ extend

拡張はそのまま module の extend で表現できそうだ。

 module M
   def gmwt
     weight * 454
 P.extend(M)

_ [Rails] Tagged Rails 1.2.0

キター


2007-01-20 [長年日記]

_ [Rails] 次回から自動でログインする

 <%= check_box_tag "auto" %>

何かしらチェックしたときには

 ActionController::Base.session_options[:session_expires] = Time.now + 1.month

セッションを長期間有効にする。

チェックしないときには

 ActionController::Base.session_options[:session_expires] = nil

セッションはブラウザを閉じるまで有効 (デフォルト)。

これが単純には実現できない。

 class XController
   def authenticate
     auto = params[:auto]
     # これは無効
     request.session_options[:session_expires] = auto ? Time.now + 1.month : nil

session_options はいつ反映される? session を用意するとき (初めて session にアクセスしたとき)。

session はどこで用意される?

 action_controller/cgi_process.rb:
 module ActionController
   class CgiRequest < AbstractRequest
     def session
       unless defined?(@session)
         ...
         @session = CGI::Session.new(@cgi, session_options_with_string_keys)

CGI::Session って何?

 lib/ruby/1.8/cgi/session.rb:
 class CGI
   class Session

     def initialize(request, option={})
       request.instance_eval do
         @output_hidden = {session_key => session_id} unless option['no_hidden']
         @output_cookies =  [
           Cookie::new("name" => session_key,
                       "value" => session_id,
                       "expires" => option['session_expires'],
                       "domain" => option['session_domain'],
                       "secure" => option['session_secure'],
                       "path" => if option['session_path'] then
                                   option['session_path']
                                 elsif ENV["SCRIPT_NAME"] then
                                   File::dirname(ENV["SCRIPT_NAME"])
                                 else
                                   ""
                                 end)
         ] unless option['no_cookies']
       end
 # ここでの request はたいてい CGI インスタンス

CGI::Cookie って何?

 action_controller/cgi_ext/cookie_performance_fix.rb:
 # Rails では cgi.rb のではなくこっちを使う
 CGI.module_eval { remove_const "Cookie" }

 class CGI
   class Cookie < DelegateClass(Array)

     attr_accessor("name", "value", "path", "domain", "expires")
     attr_reader("secure")

結局、session を作ってしまってから expires を書き換えるには CGI::Cookie#expires= を使えばよく、 CGI::Session から session 用の CGI::Cookie を見るには @output_cookies.first を使えばよい。

 lib/raw_session_cookie.rb:
 class CGI
   def session_cookie
     @output_cookies && @output_cookies.first
   end
 end

 module ActionController
   class CgiRequest
     def session_cookie
       @cgi.session_cookie
     end
   end
 end
 require 'raw_session_cookie'
 class XController
   def authenticate
     auto = params[:auto]
     # これは有効
     request.session_cookie.expires = auto ? Time.now + 1.month : nil

しかし、毎回 Set-Cookie ヘッダは出力されるので、filter を使わないとだめだろう (いまここ)。

(追記): RailsChat には書いたけど filter 版。

# migration
add_column :members, :auto, :boolean

# controller
def set_session_expires
  return unless @member
  request.session_cookie.expires = @member.auto ? Time.now + 1.month : nil
end
private :set_session_expires

after_filter :set_session_expires

2007-01-26 [長年日記]

_ [Rails] やわらかな DB

とある Rails app の migration count が 100 の大台を突破!

やわらかな DB とは…… 変更が楽ちんな仕組みがある。 or 7NF or XML-DB or まだ見ぬ何か。

Refactoring Databases: Evolutionary Database Design Refactoring Databases: Evolutionary Database Design


2007-01-29 [長年日記]

_ [Capistrano] rollback_migrate タスクを実装するスレ

capistrano の standard recipe は migration の扱いがいまいち。

基本的に migrate タスクは deploy, update 系列と独立している。 deploy_with_migrations だけ連動しているけど、これは rollback できない。デプロイツールとしては片手落ちだ。

やるなら deploy 時点の schema version をどこかに保存しておく必要がある。