2011年6月19日日曜日

Ruby, JavaScript, Python で既存のクラスを拡張 - オープンクラス(モンキーパッチ) と Scala の暗黙の型変換

1. 「リストの要素を取得する」関数を例として、クラスの拡張を考える

Lisp でリストの先頭要素を得る関数は car 。先頭以外の残りの要素を取得するには cdr 。

(car '(1 2 3 4 5))   => 1
(cdr '(1 2 3 4 5))   => (2 3 4 5)

( cf. CAR and CDR – Wikipedia )

Haskell で上記に相当する関数は、

  • head
  • tail

類似した対照的な関数に

  • init
  • last

がある。

main = do let xs = [1..5]
          print $ head xs   -- 1
          print $ tail xs   -- [2,3,4,5]
          print $ init xs   -- [1,2,3,4]
          print $ last xs   -- 5

これらの関数名を、他の言語でも使えるように、拡張の方法をそれぞれ見ていく。

 

2. Ruby で組み込みのクラス Array を拡張

Ruby で同様の関数名を探すと、Array クラスに要素一つを取得する関数

  • first
  • last

が見つかる。

first -> object | nil

配列の先頭の要素を返します。要素がなければ nil を返します。

first(n) -> Array

先頭の n 要素を配列で返します。n は 0 以上でなければなりません。

[PARAM] n:
取得したい要素の個数を整数で指定します。

複数の要素を取得するには、引数に要素数を与える関数も定義されている。これは last も同じ。

ところで、Haskell と同じ関数名で呼び出したい場合、Ruby には既存のクラスを拡張する方法が用意されている。

まつもと直伝 プログラミングのオキテ 第21回 オープンクラスとRuby on Rails」によると、

Rubyでは既存のクラスに定義を追加できます。…

後から機能を追加できるクラスのことを「オープンクラス」と呼びます。

既存の Array クラスを拡張するには、同クラスを定義する要領で行えばよい。

class Array
  alias :head :first

  def tail
    last(length-1)
  end

  def init
    first(length-1)
  end
end

xs = (1..5).to_a

p xs.head   #=> 1
p xs.tail   #=> [2, 3, 4, 5]
p xs.init   #=> [1, 2, 3, 4]
p xs.last   #=> 5

他の言語から考えると、既存のクラスを変更できることは過激な仕様に見える。なぜなら、既に存在するクラスは、ある種グローバルで固定的な定数のようなイメージを持っていたため。

よって、オープンクラスを利用したら、変更を把握しておくためのコストが発生する。

デメリットは,オープンクラスには悪影響を及ぼす可能性があることです。オープンクラスはクラスライブラリの状態を大きく変更してしまうので,プログラム全体に影響を与えてしまいます。 …

複数のライブラリがオープンクラスを使って既存のクラスを変更した場合,お互いに矛盾があると回避する方法が存在しません。…

オープンクラスを利用したライブラリを使うときには,ライブラリ同士がお互いに矛盾しないかどうかをよく吟味する必要があります。…

(同上より)

オープンクラスの別名は モンキーパッチ – Wikipedia

オリジナルのソースコードを変更することなく、実行時に動的言語(例えばSmalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, など)のコードを拡張したり、変更したりする方法である。…

当初はモンキーパッチは、ルールを無視して実行時にこっそりとコードを変更することから、ゲリラパッチと呼ばれていた。これらのパッチを複数当てると、時折直感に反するような相互作用が生まれることがあり、Zope 2では、交戦中のパッチと呼ばれていた。

モンキーの語源はおもしろい。 ^^;

ゲリラゴリラ同音異字に近かったため、何人かの人がゲリラパッチの代わりにゴリラパッチという間違った用語を使用し始めた。交戦することのないゲリラパッチ開発者が作成するのが非常に難しかったため、より弱そうに聞こえるモンキーパッチという用語が作られることになった。[2]

 

3. JavaScript で既存の Array オブジェクトのプロトタイプを拡張

上記のような Ruby の仕組みは、プロトタイプベース的な性質と考えておけばいいのかな?

プロトタイプベースの言語と言えば JavaScript 。

Array オブジェクトのプロトタイプに head, tail, init, last を定義するなら、

Array.prototype.head = function(){ return this[0]; };
Array.prototype.tail = function(){ return this.slice(1); };
Array.prototype.init = function(){ return this.slice(0,this.length-1); };
Array.prototype.last = function(){ return this[this.length-1]; };

var ary = [1,2,3,4,5];
console.log(ary.head());   // 1
console.log(ary.tail());   // [2, 3, 4, 5]
console.log(ary.init());   // [1, 2, 3, 4]
console.log(ary.last());   // 5

 

4. Python で既存のクラスを拡張

組み込みクラスは拡張できない

Python では組込みクラスに手を出せない。

例えば「リスト」。

  • type 関数

で任意のリストに適用すると、返される値は

list

この list に属性を追加しようとすると、TypeError となる。

>>> list.x = 100
Traceback (most recent call last):
  File "", line 1, in 
TypeError: can't set attributes of built-in/extension type 'list'

つまり、list を拡張することはできない。

これに対処するには、組込みクラスを拡張することを諦め、リストをサブクラス化したものを使う。

(cf. ruby vs python | Lambda the Ultimate )

class List(list):
    def head(self):
        return self[0]

    def tail(self):
        return self[1:]

    def init(self):
        return self[0:-1]

    def last(self):
        return self[-1]

xs = List(range(1,6))

print xs.head()   #=> 1
print xs.tail()   #=> [2, 3, 4, 5]
print xs.init()   #=> [1, 2, 3, 4]
print xs.last()   #=> 5

 

ユーザが定義したクラスは、実行時に振舞いを変えることができる

ただし、ユーザが定義したクラスでは、後からメソッドを追加できる。

例えば、Ruby でユーザ定義したクラス Person に後からメソッドを追加するには、class 定義を繰り返せばよい。

class Person
    def initialize(name)
      @name = name
    end
end

ps = Person.new("Tarou")
p ps

class Person
  attr_accessor :age
end

ps.age = 30
p ps

ちなみに、Ruby が奇妙な言語だとはじめて感じたのは、この定義の仕方を見たとき。 class の定義が一つの場所に固定されてない。 Java であるなら、クラス定義は一箇所に限定され、実行時にそれが変化することはない。

この点に関して、「メタプログラミングRuby (p41) では class の役割について、わかりやすく説明されている。

Ruby の class キーワードは、クラス宣言というよりもスコープ演算子のようなものである。もちろん、存在しないクラスは作成する。しかしそれは、副作用と言ってもいいかもしれない。 class の主な仕事は、あなたをクラスのコンテキストに連れていくことである。そのコンテキストであなたがメソッドを定義する。

(太字は引用者による)

同様のことを、Python で書く場合は、

  1. クラスを定義
  2. 引数を一つ与える関数を別に定義
  3. 上記関数をクラスの属性として設定

( cf. 和訳 : なぜPythonのメソッド引数に明示的にselfと書くのか | TRIVIAL TECHNOLOGIES on CLOUD )

class Person:
    def __init__(self, name):
        self.name = name

def setAge(self, age):
    self.age = age

p = Person("Tarou")

Person.setAge = setAge
p.setAge(30)

print p.name
print p.age

 

5. Scala の暗黙の型変換は、既存のクラスを拡張したように見せかける

Scala では implicit conversion を利用すると、既存のクラスを拡張したように見せかけることができる。 implicit converson は、コンパイラがあるクラスのオブジェクトを別のクラスに自動的に変換してくれる機能。

定義の仕方は、

  1. 変換元のクラスをラップしたクラスを定義。
  2. 上記クラスに「拡張すると想定したメソッド」を定義。
  3. implicit def により、変換元から変換先を指定。

書き方は以下の通り。

implicit def 適当な名前(変換元のクラス) = 変換先のクラス

これにより、変換元のクラスに対して「拡張したと想定したメソッド」を呼び出したとき、コンパイラが自動的に変換先のクラスにしてくれる。

例えば、Scala の List クラスを拡張し、head, tail に相当するメソッド「先頭, 尾部」を定義したかのように見せかける。

class ListWrapper[T](xs : List[T]){ 
  def 先頭: T = xs.head
  def 尾部: List[T] = xs.tail
}

implicit def list2ListWrapper(xs: List[Any]) = new ListWrapper(xs)

val xs = Range(1,6).toList
println(xs.先頭)   // 1
println(xs.尾部)   // List(2, 3, 4, 5)

( cf. Ruminations of a Programmer: Why I like Scala's Lexically Scoped Open Classes )

コード上では、リストに対してメソッドを拡張したかのように見える。

 

6. Haskell はクラスとメソッドという関係がないので、自由に拡張できる

Haskell では、クラスとメソッドが結合している関係が存在しないので、既存のクラスを拡張という概念がそもそも存在しない。同様のことをしたいなら、単純に適用したい型を引数に与える関数を定義すればいい。

car, cdr をリストに対して適用できるようにするには、

car :: [a] -> a
car (x:_)  = x

cdr :: [a] -> [a]
cdr (_:xs) = xs

別名を付けるだけなら、

car = head
cdr = tail

 

オブジェクトは関数とデータ構造が密結合している

これを見て、「Why OO Sucks」のオブジェクト指向に対する批判を思い出した。

Objection 1 - Data structure and functions should not be bound together
Objects bind functions and data structures together in indivisible units. I think this is a fundamental error since functions and data structures belong in totally different worlds.

( cf. Matzにっき(2007-04-12) )

2011年6月6日月曜日

USB ポートに接続したプリンタが正常に動かない

印刷が途中で止まり、不適当なエラーメッセージ

プリンタを USB で接続している。

不思議なことに、一枚印刷された後に、必ずエラーで止まってしまう。

用紙が印刷されずに排出されたか、重なって給紙されました。

プリンタへの用紙のセット方法は正しいですか?専用紙には裏と表がありますので注意が必要です。

しかし、エラーで指摘されている問題はない。

 

状態を悪化させる思い込み

OS が 64bit なのでドライバに問題があるかと思い、何度か再インストールしたけれどダメ。同 USB ポートにキーボードとマウスを接続した場合、正常に動作するので物理的な問題はない … と思い込んだ。

忙しくて、切羽詰ったときほど、こういったトラブルに遭遇すると、ストレス爆発、焦るイライラ。原因分からずてんてこ舞い。

 

スキャナも使えなかった

ところで、画像を取り込むためにスキャナを同ポートに挿しても、ちゃんと動作してくれなかった。

ここに来てようやく、USB ポートに問題があること疑い始める。使っていたのが本体背面の USB なのでよほど大丈夫と思い込んでいた。これを筐体前面にある USB に変更したら、何の問題もなくスムーズに印刷できる。

 

原因は?

デバイスマネージャを見ても、特に問題となる USB ポートはなかった。

オーバークロックしていることが原因なのだろうか?

を読むと、メモリと関係がある場合もあるようだ。

そういえば、以前にオーバークロックの設定をしていたときも、背面の USB ポートにマウスのレシーバを取り付けると BSOD になることが多かった。

ともかく原因はわからないけれど、トラブルの対処は思い込みを排除して、基本的なところから確認するのがよろし。

 

アプリケーションの問題

追記 (2011.8.23): PDF-XChange の Version 2.5 で印刷を行なっていたら、同様のエラーメッセージが表示された。上記方法で対応したが、エラーメッセージは消えず。

そこで、印刷対象の PDF ファイルを Acrobat Reader で開いて印刷を試みたら、エラーメッセージは表示されなくなった。

アプリケーションとの相性もあるようだ。 (+_+)

2011年6月5日日曜日

Firefox で文字をドラッグして検索する - アドオン Easy DragToGo+

1. バージョンが更新されくなり、利用できなくなった Easy DragToGo

Firefox でアドオン Easy DragToGo を使うと、「検索、リンクを開く」操作を素早く行うことができる。

検索したい単語があったら、その単語を選択し、マウスをドラッグする。これによりウェブ検索が行われる。リンクを開く場合は、リンクをドラッグする。手首のスナップにより操作ができるので、思考を妨げられない。

操作の結果をバックグラウンド、または、フォアグラウンドで開くか指定することもできる。

残念ながら、最近はバージョンが更新されていないため、最新の Firefox では Firefox 4 で利用できない。(+_+)

 

互換性を無視して使うことはできる

最新の Firefox に対応してないアドオンを使うには、

により、互換性を無視してすれば良い。しかし、できるだけ正式に対応しているものを使いたい。

 

2. 派生品である Easy DragToGo+

https://addons.mozilla.org/ja/firefox/addon/easy-dragtogo-1/

Easy DragToGo+ は、Easy DragToGo と同じ機能を持つアドオン。説明には「実験的」とあるが、Firefox 4 に対応している。

追記(2011.9.26)

Firefox 6.0.2 では、Easy DragToGo+ 1.1.3.1 に対応してない。そこで、Easy DragToGo+ のバージョン履歴 より、バージョン 1.1.5.1 をインストールした。

追記(2012.3.26)

Easy DragToGo+ のページが消えた。そこで以下の URL より、

最新の easy_dragtogo-X.X.X.xpi をインストールした。

追記(2014/01/02)

Easy DragToGo+ から DragIt に戻した。 Add-ons for Firefoxに登録してあるアドオンの方が安心かな。

 

3. 操作方法の設定

Easy DragToGo+ の設定は、デフォルトのまま利用している。

上方向へのドラッグがフォアグラウンド、下方向がバックグラウンドで動作する。テキストを選択して行えば「検索」で、リンクをつかめばページを「開く」。

CropperCapture[201]-vert

 

4. 類似したアドオンの利用の変遷

Easy DragToGo+ 類似したアドオンに

がある。Easy DragToGo では代わりに試すように書かれている。

しかし、操作に対する反応が良くなかった。

この類の機能を持つアドオンの利用の変遷は以下の通り。

  1. Drag de Go
  2. Easy DragToGo
  3. QuickDrag
  4. DragIt (formerly Drag de Go)
  5. Easy DragToGo+

 

Google Chome では

Google Chrome では Gestures for Chrome を利用する

 

関連記事

SSL 接続におけるセキュリティの警告 - サイトの安全性を示すアイコン

1. Google Chrome のサイトの安全性を示すアイコン

Google Chrome で SSL 接続するページを開いたら、https に赤い斜線が表示された。

CropperCapture[198]

この表示になる理由は、「ウェブサイトのセキュリティ インジケータ - Google Chrome ヘルプ」 によると、

SSL を使用しているサイトですが、サイトのページにセキュリティで保護されていない危険なコンテンツが含まれているか、サイトの証明書に問題があることが Google Chrome で検出されました。このページでは機密情報を入力しないでください。証明書が無効であったり、https に重大な問題があったりする場合、サイトへの接続をだれかが改ざんしようとしている可能性があります。

SnapCrab_No-0469_thumb%255B2%255D

鍵のマークが緑色になるサイトでは Extended Validation 証明書 – Wikipedia が使用されている。

独立した監査によりWebTrust指針(もしくはそれと同等)の認定の一部を満たしたCAだけがEV SSL証明書の発行を許される。EV証明書は以下のような詳細な発行要件に従って発行される。

  • ウェブサイト所有者が運用上および物理的に実在しているだけでなく、法的実在性も確立されていること
  • ウェブサイト所有者により、該当URLに対する排他的な制御が確立されていること
  • ウェブサイト所有者のための作業者の同定と責任、および、責任ある役員によって署名された法的義務を伴う文書の確認

 

2. 外部サイトからリソースを読み込んでいることが理由

挿入された JavaScript

https に赤い斜線が表示されたページに問題となるものがあるか探したら、古い Google Analytics のコードが挿入されていた。

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>

外部サイトにある JavaScript を読み込んでいるのがいけなかったようだ。

ちなみに、現在の Google Analytics コードを使う場合は大丈夫。

*新しいトラッキングコードの JavaScript ファイル ga.js
ga.js は今後提供を予定している、Analytics の様々な新機能に対応しています。また e コマースのトラッキングの設定やSSL コンテンツ用のカスタマイズが容易になるなど設定面でも数多くのメリットがございます。

( アナリティクス 日本版 公式ブログ: [グラフの複数データ表示機能] と [新しいトラッキングコード用の JavaScript ] をリリースしました より)

 

画像

Flickr などの、外部にある画像を読み込んだ場合は、以下の表示となった。

CropperCapture[199]

ウェブサイトのセキュリティ インジケータ - Google Chrome ヘルプ」 によると、

SSL を使用しているサイトですが、サイトのページにセキュリティで保護されていないコンテンツが含まれていることが Google Chrome で検出されました。このページで機密情報を入力する場合は注意が必要です。セキュリティで保護されていないコンテンツは、だれかがページを操作するための抜け道になる可能性があります。

画像は自サイト内に置くことにより、上記表示を回避できる。

 

3. Firefox のサイトの安全性を示すアイコン

追記(2013/09/24): Firefox でも Google Chrome と同じようにサイトの種類によってアイコンの表示が変わる。

Web サイトへの接続が安全か確認するには | Firefox ヘルプ によると、

Web サイトを表示する時、サイト認証ボタンは、灰色の地球、灰色の錠前、灰色の警告、または緑色の錠前のいずれかのアイコンで表示されます。これらのアイコンをクリックすると、Web サイトについてのセキュリティ情報が表示されます。

Identity Icons 14

灰色の地球アイコンは次のことを示します:

  • Web サイトは認証情報を提供していません。
  • Firefox と Web サイトの間の接続は暗号化されていない、または部分的にしか暗号化されていないため、盗聴者の攻撃に対して安全であると考えてはいけません。

灰色の錠前アイコンは次のことを示します:

  • Web サイトのアドレスは検証されています。
  • Firefox と Web サイトの間の接続は暗号化されており、盗聴者の攻撃から保護されています。 …

しかし、実際に誰がドメインを所有しているかは検証されていません。

緑色の錠前アイコンは次のことを示します:

  • Web サイトのアドレスは Extended Validation (EV) 証明書で検証されています。
  • Firefox と Web サイトの間の接続は暗号化されており、盗聴者の攻撃から保護されています。 …

…そのサイトが Extended Validation (EV) 証明書 を使用していることを意味します。EV 証明書は他の証明書と明らかに異なり、さらに厳格な身元の検証プロセスを必要とする特別な形式のサイト証明書です。…緑色のサイト認証ボタンは、安全な接続がされており、さらにドメインの所有者が誰であるか確かめられていることを示しています。

更に「盾」のマークのアイコンが表示されることがある。

安全でないコンテンツがセキュリティに及ぼす影響 | Firefox ヘルプ によると、

訪れた HTTPS のページに HTTP で配信されているコンテンツが含まれていた場合、メインのページが HTTPS で配信されていても、それに含まれる HTTP のコンテンツが攻撃者に読まれたり変更されたりする恐れがあります。私たちは、HTTPS のページに含まれる HTTP で配信されたコンテンツを「混在コンテンツ」(mixed content) と呼びます。

SnapCrab_No-0470

2011年6月2日木曜日

NICI ジョリー・メイ - あのネコが抱き枕にしている ぬいぐるみは?

1. Tumblr で見たことがある猫とぬいぐるみ

を眺めていたら、Tumblr で見たことのあるネコの画像があった。

ネコもさることながら、気になるのは抱き枕にされているカバのような ぬいぐるみ。

 

2. NICI

知人に調べてもらったら、これはドイツ製らしい。カバではなく羊のようだ。 ^^;

3. ジョリー・メイ

件のぬいぐるみを Amazon において NICI で検索

この中の「ジョリー・メイ」。

25cm サイズ。

35 ~ 50 cm サイズ。

160cm と 80cm の巨大バージョン。

寝そべり バージョン

 

スタンディング バージョン。

Amazon で売り切れの場合、は以下で探す。

ローカルで SMTP サーバを利用してメールの送信 - BlackJumboDog, Mercury で OP25B への対応

ローカルで SMTP サーバを立て、PHP でメールの送信テストをしたい。

以前は MELON を利用してローカルからメールを送信。しかし、今回同じように試したところ、いつまで経ってもメールが送信されない。

 

ISP の OP25B による迷惑メールに対する対処

理由は「メールサーバの OP25B対策」によると、

インターネットに蔓延する迷惑メール(…)の対策として、大手 ISPはほぼ全てが OP25B(Outbound Port 25 Blocking)を実施するようになった。…

OP25Bとは、ISPが自社網内のユーザが撒き散らす迷惑メールを封じ込めることを目的として、自社網の動的IPアドレスのホストが網外の SMTPサーバに向けて25番ポートからメールを直送する処理を規制する技術である。 …

これに対する対処法は、

有効な解決策は、ISPが提供する中継サーバ(ポート番号は 25番あるいは 587番。ISPが特に指定したものがなくても、通常のメール送信用 SMTPサーバが使えるはず)を経由してメール送信するようにメールサーバを設定することである。

(同上より)

自分が利用している ISP の HP において、

OP25B

で検索したら、迷惑メール対策として、昨年より制限が加えられていたことがわかった。

このための新たなメールサーバのホストと、ポート番号 587 をメモ。

 

BlackJumboDog を利用する場合

SMTP サーバとして MELON を使う前は Radish を利用していた。

現在 Radish は サッポロワークス によると、

Radishの後継バージョンとして、ニューBlackJumboDog(Ver5.x) が開発されています

そこで BlackJumboDogダウンロード

BJD.exe を起動。

 

設定

SMTP サーバを起動するために、

  • メニューより、「オプション > メールサーバ > SMTP サーバ」

SMTP サーバを使用する」をチェック。

中継許可」タブにおいて、許可リスト優先に 127.0.0.1 を追加。

CropperCapture[190]

ホスト設定」タブにおいて、

  1. 対象ドメインを * とし、転送サーバは上記でメモした ISP で指定されている メールサーバ と ポート番号 を記入。
  2. SMTP 認証にチェックを入れ、ISP から渡されたメールサーバにアクセスするためのユーザ名とパスワードを入力して追加。

CropperCapture[191]

ACL」タブにおいて、127.0.0.1 からのアクセスのみを許可するように追加。

CropperCapture[192]

これによりメールを送信できるようになった。

ちなみに、上記「ホスト設定」の転送サーバに誤って空白文字を入力していたことに長いこと気づかず、なかなか使うことができなかった。 (+_+)

 

XAMPP の Mercury を利用する場合

xampp の中の Mercury には SMTP サーバの機能が含まれている。

XAMPP Control Panel を開き、Mercury の Start ボタンを押し、Admin を起動する。

CropperCapture[194]

メニューより Configuration > Protocol modules…

CropperCapture[197]

以下の 2 つを有効にする。

  • MercuryS SMTP server
  • MercuryC SMTP relaying clinent

 

SMTP server
  • メニューより、Configuration > Mercury SMTP Server

Connection control タブにおいて、 Do not permit SMTP relaying of non-local mail のチェックをはずす。

CropperCapture[195]

 

SMTP Client
  • メニューより、Configuration > SMTP Client
  1. Smart host name, Connection port/type には、上記でメモした ISP で指定されている メールサーバ と ポート番号を入力。
  2. Credentials for SMTP Authentication, if required に、ISP から渡されたメールサーバにアクセスするためのユーザ名とパスワードを入力。

CropperCapture[196]

これによりメールの送信が行えるようになった。

 

終了してない SMTP サーバのプロセスを確認

ところで、いくつか SMTP サーバを試していたら、プロセスが正常に終了してないものがあった。これにより、SMTP サーバの起動時にエラーとなることがある。

他のプログラムに80番ポートが専有されてApacheが起動できない場合の対処方法 - 床のトルストイ、ゲイとするとのこと」によると、

netstat -oan

これで、ポートを開いているプロセスの一覧が表示される。(-oはPIDの表示、-aは全ての接続を表示、-nはアドレス・ポートを数値で表示)

ここで、80番を使用しているプロセスのPIDを覚えておき、タスクマネージャでそのPIDに対応するプログラム名を調べる。

タスクマネージャのプロセスタブでPIDを出すには、「表示 > 列の選択」でPIDをチェック。PID順にソートすると見つけやすくなる。

上記の説明にある「80番」を「25番」と読み替えて対処する。

 

参考サイト