よたらぼ
自分の興味の赴くままにIT技術系のネタを取りとめもなくメモっています。
Ruby言語やLinuxのネタが多いです。

April 03, 2002 たまには脱線しよう、そうしよう

[Misc] 他の人の日記

tDiary作者のたださんはじめ、Web日記の作者ってみんなセンスあるよね。デザインのセンス、文章のセンス、どれもこれもすばらしい。

そんな中、自分のLinuxビボ〜ろくを省みると、どうも技術一辺倒でイマイチ面白味に欠ける。もちろん、タイトルが示すとおり方向性としてはそれで間違いないのだが、少しも気の利いたことが書けない自分が歯がゆい。

tDiaryのプラグインもいくつか書いてみたが、ほとんど実用性を重視したモノばかり(fortune.rbはちょっと違うけど)。それはそれで良いのだろうがsawadaさんのスミ消しプラグインのようなセンスのいいプラグインを書いてみたいと思った。

そんなわけで作ってみたプラグインがこれ。その名も「伏せ字プラグイン」

[tDiary] tDiaryプラグイン第5弾 「伏せ字プラグイン」

文字列の一部をランダムに伏せ字にするプラグイン。こんな感じ →

使い方

<%= fuseji 'ひみつ' %>
<%= fuseji 'ひみつ', 2, '★' %>
 
引数は、文字列、伏せる文字数(default=1)、伏せ字マーク(defaultは"○")の順。
文字列のみ必須。後はオプション指定。

ソースコード(こいつをEUC-JPでfuseji.rbというファイル名で保存してpluginフォルダに格納すればOK)。

def fuseji(str, num = 1, mark = "○")
  array = str.scan(/./)
  (0...num).each {array[rand(array.length)] = %Q[<span class="fuseji_mark">#{mark}</span>]}
  %Q[<span class="fuseji">#{array.join}</span>]
end

これを使えば、いつもは言えない本音をストレス無く語りつくすことができるはず。指定した文字列は、検索エンジンもまともにキーワードとして拾うことができないはずだし、ある意味、スミ消しプラグインを超える暗号化も実現できたのではないだろうか(うそ)。

[tDiary] 伏せ字プラグインにセキュリティホール

これでは、せっかくの暗号化が台無しだ(^^;)。

[Misc] うーむ

こんな調子でスミ消しプラグインを超えるプラグインを作れる日はくるのだろうか...(イヤ来ない(^^;))。

[Misc] 2002/4/11 追記

伏せ字プラグインはこの日記のものを使わず、こちらの新バージョンを使ってください。ただし、ここの伏せ字プラグインとは互換性がありません(引数が異なる)。もし、過去に、ここのプラグインを使ってしまった方は、新しいバージョンを使わないか、あるいは、過去の日記で伏せ字プラグインを使っているところは全て手作業で引数を修正してくださるようお願いします。

本日のツッコミ(全2件) [ツッコミを入れる]

アビー [初ツッコミ。十分センスいいとおもいますよ。僕もそのうちおもろいの作りたいな。]

むとぽん [どうもです(^^;)。期待してますね〜。]


April 03, 2003

[Hiki] Hiki/RD+-0.1.4

遅くなりましたが0.1.4です。ModuleNamesはいらなくなってるはず(^^;)。

それから、a.rbはHiki向けに最適化して名称もanchorlist.rbに変更しました。0.1.3を使っていた方は、a.rbを削除してください(削除しなくても大丈夫だけど)。


April 03, 2006

[] ハッカーは善

ロランに教わったのですが、フランスではこんなクルマが走っているそうです。

ナンバープレートまで良い感じです。クルマが日本車なところを見るともしかしたら日本マニアなのかもしれませんね(笑)。

[Misc] これってボット?

最近、Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)っていうUser-Agentがログに残ってるんだけど、これってボット?

(理由1)他のUAに比べてダントツに多い

(理由2)毎日ほぼ1000前後のアクセス

どなたか教えてプリーズ!

ってか、RSSとかボットとかUAで一発で判断できるような属性をつけてくれないものかなぁ。type=RSSとか、type=botとか。

本日のツッコミ(全2件) [ツッコミを入れる]

スクリチ [こんな車がフランスにあるなんて可笑しいと思ったんだからロランに聞いた。この写真はカリフォルニアに撮ったそうですよ。ま..]

むとう [おぉ、そうだったんだ(笑)。]


April 03, 2010

[Rails3] ActiveSupport::Concernを自分なりに調べてみた

Rails3の実装を見ていると、とにかくActiveSupport::Concernをextendする、という風になっているらしい。

ってか、ActiveSupport::Concernって何?なんなのこれ? Googleさんに聞いてもあまりまとまった情報がないみたいだし…。

ということで、自分なりに調べてみたのでメモってみる。補足や誤りのご指摘を歓迎します、ぜひ。

まず、ソースコードを見ると…、シンプルなんだけど今のところRDocもなし…orz。

貴重な情報源、現時点で唯一と言っても過言でないブログがこちらにあったのでそちらを参考に勝手な空想を織り交ぜつつ話を進めたいと思う。

まず、目的から。「ActiveSupport::ConcernはRails3のモジュラリティのための重要なツールで、モジュールの依存関係の管理を非常に簡単にかつ直感的にするものです。」とのこと。モジュールに対し、大きく分けて2つの機能を提供する。

ActiveSupport::Concern (1) included do ~ end

included do ~ endの使い方を説明する前に、以下のコードを見てみよう。

%cat test.rb
module Foo
  def self.included(base)
    p "Foo.included is called by #{base}."
  end
end
 
module Bar
  include Foo
  def self.included(base)
    p "Bar.included is called by #{base}."
  end
end
 
puts "ここからアプリケーション------"
class Host
  include Bar
end
Host.new
 
% ruby test.rb
"Foo.included is called by Bar."
ここからアプリケーション------
"Bar.included is called by Host."

Foo/BarはRailsのライブラリ等、Hostクラスがあなたが書くアプリケーションのクラスをイメージするとわかりやすいと思う。で、このHostから見た場合、BarはFooの機能を持っているのでBarだけをincludeしたい、と思うので上記のようなコードになる。大抵はそれで動作するのだけど、self.included()の動作がポイントになる。
先に比較のために同様のコードをActiveSupport::Concernを使って書いてみる。

% cat test2.rb
require 'rubygems'
require 'active_support/concern'
 
module Foo
  extend ActiveSupport::Concern
  included do
    p "Foo.included is called by #{self}"
  end
end
 
module Bar
  extend ActiveSupport::Concern
  include Foo
 
  included do
    p "Bar.included is called by #{self}"
  end
end
 
puts "ここからアプリケーション------"
class Host
  include Bar
end
 
Host.new
% ruby test2.rb
ここからアプリケーション------
"Foo.included is called by Host"
"Bar.included is called by Host"

test.rbとtest2.rbの実行結果から以下の2つの違いが言えると思う。

  1. 前者は呼び出し元(includedの引数)が直前のクラスになるのに対し、後者は呼び出し元(self)がHostになる。
    includedされるタイミングで呼び出し元に何らかの機能を追加するような場合、前者だと全ての呼び出し元クラスとネストされたクラスが連鎖している想定でFoo/Barモジュールを定義しないといけないことがあったりなかったりする。一方、後者は常に一番末端の呼び出し元のクラスを想定するだけで良いので挙動が想定しやすい。
  2. 後者はHostがincludeしたタイミングでFoo, Bar両方のincluded do ~ endブロックが呼び出される。
    Hostクラスの定義時に前者のself.included()の中で何らかの初期化処理を実施しようとした場合、Fooでの初期化処理は結局、Barの機能の一部となる。間接的にはHostクラスでも使えることが多いし実害がない場合も多いが、後者では、直接Hostクラスを初期化できることになるので前者よりもトラブルが少ないはず。

ちなみに、後者の動きをActiveSupport::Concernを使わずにするには以下のように書く。

class Host
  include Foo, Bar
end
% ruby test.rb
"Foo.included is called by Bar."
ここからユーザアプリケーション------
"Bar.included is called by Host."
"Foo.included is called by Host."

HostでFooもBarもincludeする。でも、先祖に遡って全てのモジュールをincludeしなおさなければいけないと言われるとちょっと厳しいよね。あ、それに、この場合でもいったんBarがFooをインクルードしたタイミングでFooが呼ばれてしまうので必ずしもActiveSupport::Concernとは同じにはならないのか。

ActiveSupport::Concern (2) ClassMethods/InstanceMethods

すでにRailsではお馴染みになっている実装だと思うんだけど、以下のように記述すると、クラスメソッド/インスタンスメソッドがそれぞれ定義可能になる。

% cat test3.rb
require 'rubygems'
require 'active_support/concern'
 
module Foo
  extend ActiveSupport::Concern
 
  module ClassMethods
    def test1
      p "test1 is called"
    end
  end
 
  module InstanceMethods
    def test2
      p "test2 is called"
    end
  end
end
 
puts "ここからアプリケーション------"
class Host
  include Foo
end
 
Host.test1
Host.new.test2
% ruby test3.rb
ここからアプリケーション------
"test1 is called"
"test2 is called"

悔しいことに上記の例と同様のことをRubyの標準的な文法(send等を使わずに)で記述するスマートな例が思いつかなかった。結局、includedでClassMethods的なモジュールをincludeしたりextendしたりすることになるのか…(他に良い案があれば教えてくださいませ)

ActiveSupport::Concern (3) まとめ

ActiveSupport::Concernは数十行の小さなモジュールでありながら、標準のRubyでソースを書く場合と書き方(文法というとちょっと語弊があるかな)がだいぶ違う印象があり、馴染んでしまうと元に戻れないと言う意味でかなり破壊力があるモジュールなんじゃないかと思う。

個人的にはこのようにきれいにクラスメソッド/インスタンスメソッドを定義できるとわかりやすいし良いなぁ、なんて思うけど、いかんせん標準のRubyの文法には無いので、Rails以外でActivesupportを使うことに対し心理的な抵抗があるのも事実。心を解き放ってrails信者(どんな場合でもactivesupportは呼ぶのが前提)になるのが一番楽なのかもなー。


追記