define_singleton_methodについて

このQ&Aのポイント
  • define_singleton_methodはClassに動的に生成したmethodを追加するメソッドです。
  • define_singleton_methodはdefine_methodの代わりに使用します。
  • 1.9.1p378から存在しており、名前が変わったわけではありません。
回答を見る
  • ベストアンサー

define_singleton_methodについて

define_singleton_methodについて 1.9.1p378を使用しています。 メタプログラミングに興味があって、 Classに動的に生成したmethodを追加する方法を調べてみると 色々な教科書にdefine_methodを使う例が書いてあるのを見つけました。 しかし、実際にプログラムしてみると"undefined method"になってしまいます。 Class.methods.grep /define/ してみると、"define_singleton_method"というものがあり、 define_methodの代わりに使ってみたら一応期待通りに動作しました。 googleで調べてみてもdefine_singleton_methodについて解説が見つけられませんでした。 1.9系になって名前が変わったのでしょうか? それとも似て非なるものなのでしょうか? 詳しい方、教えてください。<(_ _)>

  • Ruby
  • 回答数3
  • ありがとう数18

質問者が選んだベストアンサー

  • ベストアンサー
  • hoge_piyo
  • ベストアンサー率57% (15/26)
回答No.1

define_singleton_methodは1.9で追加されたもので、Objectクラスのメソッドです。 一方define_methodはModuleクラスのprivateメソッドなので、ModuleかClassの中から呼ばないといけません。 (ClassクラスはModuleクラスのサブクラス。Rubyのprivateはサブクラスからも見える) define_methodであとからメソッドを追加しようとする場合、直接外からは呼べないので、間接的にdefine_methodを呼ぶメソッドを作成しておくか、一度Classを開くなどをやらないといけませんが、 define_singleton_methodを使えば、そんなことはせずに、簡単にできるということです。

その他の回答 (2)

  • notnot
  • ベストアンサー率47% (4848/10262)
回答No.3

>Classに動的に生成したmethodを追加する方法を調べてみると と書きながら、補足のサンプルを見ると、オブジェクトの特異メソッドを定義しようとしているように見えるのですが。もしそうだとすると、特異クラスを使って、 module L class R module Login  def login_setup()   puts "Login login_setup()"   class << self    define_method(:login) do |id,pass|     puts "login() #{id} , #{pass}"    end   end  end end end end

ayudaia
質問者

補足

ありがとうございました。

  • koko_u_u
  • ベストアンサー率18% (216/1139)
回答No.2

ダメだったコードと、OKだったコードを補足にどうぞ。

ayudaia
質問者

補足

OKだったコード module L class R module Login  def login_setup()   puts "Login login_setup()"   # :loginの代わりに"login"でもよいのは理解している   define_singleton_method(:login) do |id,pass|    puts "login() #{id} , #{pass}"   end  end end end end class Y  include L::R::Login  def initialize   login_setup() # class Yのインスタンスにlogin()が追加されるのを期待  end end # # MAIN # c = Y.new p c.methods - Object.methods #=>[:login, :login_setup] if c.respond_to?(:login)  c.login("A", "B") #=>login() A , B end [NG] 1) define_singleton_method の代わりに define_method 2) __send__ 使用でdefine_method呼び出し(private methodを強制的に呼ぶ方法) 3) 他、「Rubyクックブック」などに書いてある方法=>全滅

関連するQ&A

  • javaで、オブジェクトを生成しないとメソッドは使えないんですか?

    javaで、オブジェクトを生成しないとメソッドは使えないんですか? そのように習ったのですが、サブクラスのメソッド定義の中で、オブジェクトを生成せずにスーパークラスのメソッドを使える例(下に簡単に書きました)をみて、分からなくなってしまいました。 おしえてください、よろしくおねがいします。 ------------------------------- class superclass { method_a(){ ~~~~ } } --------------------------- class subclass { method_b(){ super.method_a(); }

    • ベストアンサー
    • Java
  • RubyのDateクラスのメソッドが見つからない

    先日よりRubyでのプログラミングを始めてみたのですが DateクラスのDate::MOTHNAMESを参照しようとしたところ undefined method `MOTHNAMES' for Date:Class (NoMethodError) と返ってきてしまいました。 ほかにもDate::exist?メソッドもためしてみましたが、同じ様なコメントが 返ってきました。 undefined method `exist?' for Date:Class (NoMethodError) なお、 Date.newなどはつかえています どういった問題でどのように解決すれば良いのか、ご教示願えればと思います。 バージョンは ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0] で、Mac OSX Lionで動かしています。

  • singletonの使い方

    はじめまして。 singleton(GoF)で少し疑問に思ったところがありましたので、 アドバイスをいただけたらと思い質問させていただきます。 たとえば以下のようなプログラムですが、 ==form.html== <html> <body> <form action="./Main.php" method="post"> name:<br /> <input type="text" size="20" name="name" /><br /> text:<br /> <textarea rows="8" cols="40" name="text"></textarea><br /> <br /> <input type="submit" value="submit!" /> <input type="reset" value="reset!" /> </form> </body> </html> ==Main.php== <?php require_once "Data.php"; require_once "NullCheck.php"; $data =& Data::getInstance(); $data->setName($_POST["name"]); $data->setText($_POST["text"]); $nc = new NullCheck($data); $result = $nc->check(); if(!$result == ""){ echo $result; }else{ echo "ok"; } ?> ==Data.php== <?php class Data{ var $name; var $text; function &getInstance(){ static $instance; if(!isset($instance)){ $instance = new Data(); } return $instance; } function setName($name){ $this->name = $name; } function setText($text){ $this->text = $text; } function getName(){ return $this->name; } function getText(){ return $this->text; } } ?> ==NullCheck.php== <?php class NullCheck{ var $data; var $err = ""; function NullCheck($data){ $this->data = $data; } function check(){ if($this->data->getName() == ""){ $err .= "nameが空欄です。<br>"; } if($this->data->getText() == ""){ $err .= "textが空欄です。<br>"; } return $err; } } ?> 上記を作る際、 submitを押すたびにオブジェクトが作られるのは無駄だと思い、 singletonを使いました。 しかし、空欄チェックのときはnewでインスタンスを生成しています。 やはりこの場合もsingletonを使用したほうがいいのでしょうか? 仮にもっと複雑な問い合わせフォームを作成し、 利用者が多くなった場合、 いろいろとインスタンス化(空欄チェックや文字列チェック等)すると オブジェクトがたくさんできてしまい負荷がかかるで、 できる限り不必要なインスタンス化は避けたいと思っています。 長々と書いてしまい申し訳ありませんが、 なにとぞよろしくお願いします。

    • ベストアンサー
    • PHP
  • Module#method_addedの挙動

    すいません、Rubyのドキュメントを見ながら動作を追っていて、疑問に感じたので質問をさせてください。 Module#method_addedというメソッドが追加されたタイミングで動作するメソッドがあります。 定義場所がModuleクラスの中なので、Moduleにメソッドを追加したら、それがmethod_addedを呼び出すと思って試して見たのですが、何故かそうなりません。 何故なのか理由がわからないんですが、教えていただけないでしょうか? ------------------------------------------------------------------ class Object def self.method_added(*_) p self.class.name p __method__ p _ end def self.singleton_method_added(*_) p self.class.name p __method__ p _ end end class Module def self.method_added(*_) p self.class.name p __method__ p _ end def self.slngleton_method_added(*_) p self.class.name p __method__ p _ end end module Foo def self.foo end def foo2 end end class Bar def self.bar end def bar2 end end ------------------------------------------------------------------ 出力結果 ------------------------------------------------------------------ "Class" :singleton_method_added [:bar] "Class" :method_added [:bar2] ------------------------------------------------------------------ 動作環境は、Mac rubyのバージョンは2.4.0です。 ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16]

    • ベストアンサー
    • Ruby
  • Rubyのsuperclassメソッドについて

    Rubyについての質問です。処理系は1.8.7です。 class Foo def initialize(a) @a = a end end のようなクラスを作成し、そのインスタンスを foo = Foo.new(1) のように作成します。 このとき、 foo.superclassを呼び出すと NoMethodError: undefined method `ancestors' for #<Foo:0x2b691220cc88 @a=1> とエラーになります。 一方で class FooExt < Foo def initialize (a,b) @b = b super a end end のようにFooを継承したクラスを作り、 fooext = FooExt.new(1,2) fooext.superclass とすると => Foo とsuperclassメソッドが動作します。 このsuperclassメソッドはどこで追加されたものなのでしょうか?

  • クラスメソッドのみのクラスのオブジェクト生成は不可??

    あるテキストのjavaの問題です。 public class Draw{   static void pixel(int x,int y){     /*座標(x、y)に点を描画*/   }   static void line(int x1,int y1,int x2,int y2){     /*座標(x1、y1)~(x2、y2)に線を引く*/   } } で、これを実行するための以下のようなクラス public class TestDraw{ <ここに入力> } という問題なのですが2つまでは絞れたのですが、 (1) public static void main(String args[]){   Draw d = new Draw().line(10,10,20,30); } ↑× (2) public static void main(String args[]){   Draw.line(10,10,20,30); } ↑○ (2)はlineメソッドがstaticメソッドだからオブジェクト生成しなくても良い、ということなんですが (1)も正解のような気がするのですが・・・ 解説によると「lineはvoidなのでnew Draw().line(10,10,20,30);とすれば正解、とあります。 どうもいまいち理解できません。 クラスメソッドはオブジェクト生成しなくとも良い→オブジェクト生成できない ということなのでしょうか? それからちなみに、public classって2つ記述できないんではありませんでしたか?

    • ベストアンサー
    • Java
  • オープンクラスで再定義時に別で定義されたメソッドの

    オープンクラスで再定義時に別で定義されたメソッドの呼び出しについてです。 ある編集不可能なクラス Hoge の fuga メソッドの戻り値によって、新たなメソッド piyo を定義したいと考え、次のコードを試してみました。 irb(main):001:0> class Hoge irb(main):002:1> def fuga irb(main):003:2> 1 irb(main):004:2> end irb(main):005:1> end => :fuga irb(main):006:0> irb(main):007:0* class Hoge irb(main):008:1> if self.fuga == 1 irb(main):009:2> def piyo irb(main):010:3> puts "foobarbaz" irb(main):011:3> end irb(main):012:2> end irb(main):013:1> end NoMethodError: undefined method `fuga' for Hoge:Class from (irb):8:in `<class:Hoge>' from (irb):7 from /usr/bin/irb:11:in `<main>' この目的の場合、8~12行目はどのような記述をすれば良いのでしょうか。 なお、Hoge のインスタンス作成後に特異メソッドとして piyo を追加のが都合上、難しい状態です。 バージョンは ruby 2.1.5p273 です。 よろしくお願いします。

    • ベストアンサー
    • Ruby
  • C++ 継承したクラスのメソッド呼び出し

    C++で以下のようなコードを組んでいます。 // Class定義 CSuper{ public: Method1(int a); }; CSub : public CSuper{ public: Method1(int a); }; // インスタンス CSuper ins1; CSub ins2; // 管理テーブル struct _table{ int id; CSuper* p; }; // テーブル定義 _table Table[] = { {0, &ins1}, {1, &ins2} }; // 処理 int main(void) { int i; for(i = 0; i < 2; ++i) { Table[i].p->Method1(i); } return 0; } //////////////////////////// このときに、i=1のときは、p = &ins2となるので、 CSub::Method1() が呼ばれることを期待しているのですが、 i=0でもi=1でも、CSuper::Method1() が呼ばれてしまいます。 何か記述が間違っているでしょうか? または、認識が間違っているでしょうか? ご教示のほどよろしくお願いいたします。 環境:依存がないと思っています。 (VC++2008, Cygwin gcc, Fedora4 gcc で確認しましたが同じ結果)

  • 「Javaのクラスメソッド内でsuperキーワードは使える?」

    「Javaのクラスメソッド内でsuperキーワードは使える?」 Java言語仕様(第2版日本語訳初版)(注)の以下の記述をどう解釈するべきでしようか?  「8.4.6継承、オーバーライド、隠蔽」>「8.4.6.2隠蔽(クラス・メソッドによる)」において、staticメソッドがシグネチャが同じスーパークラスのメソッドを隠蔽し、それがインスタンスメソッドであればコンパイルエラーになる、との記述のあと、下記のような記述があります。 『隠蔽されたメソッドは、限定名、あるいはsuperキーワードやスーパークラス型へのキャストを含んだメソッド起動($15.12)を使用することによりアクセスすることができる』 まるで、「インスタンンスメソッドと同じようにクラスメソッドにおいてもsuperキーワードを使用することでスーパークラスのstaticメソッドを呼び出せる」ように読み取れます。 ちなみに該当部分の原典は、  http://java.sun.com/docs/books/jls/download/langspec-2.0.pdfから抜粋  8.4.6.2 Hiding (by Class Methods) (略)  A hidden method can be accessed by using a qualified name or by using a  method invocation expression (§15.12) that contains the keyword super or a cast  to a superclass type. In this respect, hiding of methods is similar to hiding of  fields. また、第3版原典も該当部分は同じ記述でした。  http://java.sun.com/docs/books/jls/download/langspec-3.0.pdf  8.4.8.2 Hiding (by Class Methods) なお、superキーワードについては、同書 15.11.2 「superを使用したスーパークラスのメンバへのアクセス」の項で、 『superキーワードを使用した特殊形式は、インスタンス・メソッド、インスタンス初期化子、コンストラクタ、あるいはクラスのインスタンス変数の初期化子中でのみ有効となる』 とあり、クラスメソッド中では使えないと読み取れます。(続けて、 superとthisの使用条件は全く同じ、としています。) Javaコンパイラは、クラスメソッド中のstaticキーワードを認識せず、エラーとします。 諸兄のお考えをお聞かせください。 注)http://www.amazon.co.jp/Java%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98-Java-%E3%82%B8%E3%82%A7%E3%83%BC%E3%83%A0%E3%82%BA-%E3%82%B4%E3%82%B9%E3%83%AA%E3%83%B3/dp/4894713063/ref=sr_1_2?ie=UTF8&s=books&qid=1270203134&sr=1-2

  • デフォルトの定義済みクラスについて

    自分で定義したクラスの継承関係やらを出力するサンプルスクリプトがあったので、それをまる写しして動かしたところ、エラーがおこりました。以下のスクリプトがそれです。 <?php function get_methods($object){ $methods=get_class_methods(get_class($object)); if(get_parent_class($object)){ $parent_methods=get_class_methods(get_parent_class($object)); $methods=array_diff($methods,$parent_methods); } return $methods; } function get_inherited_methods($object){ $methods=get_class_methods(get_class($object)); if(get_parent_class($object)){ $parent_methods=get_class_methods(get_parent_class($object)); $methods=array_intersect($methods,$parent_methods); } return $methods; function get_lineage($object){ if(get_parent_class($object)){ $parent=get_parent_class($object); $parent_object=new $parent; $lineage=get_lineage($parent_object); $lineage[]=get_class($object); } else{ $lineage=array(get_class($object)); } return $lineage; } function get_child_classes($object){ $classes=get_declared_classes(); $children=array(); foreach($classes as $class){ if(substr($class,0,2)=='__'){ //ここに問題があるようです。 continue; } $child=new $class; //ここで「引数が無効」のエラーになります。 if(get_parent_class($child)==get_class($object)){ $children[]=$class; } } return $children; } function print_object_info($object){ $class=get_class($object); echo '<h2>クラス</h2>'; echo "<p>$class</p>"; echo '<h2>継承関係</h2>'; echo '<h3>親クラス</h3>'; $lineage=get_lineage($object); array_pop($lineage); echo count($lineage)?('<p>'.join(' -&gt; ',$lineage).'</p>'):'<i>None</i>'; echo '<h3>子クラス</h3>'; $children=get_child_classes($object); echo '<p>'.(count($children)?join(',',$children):'<i>None</i>').'</p>'; echo '<h2>メソッド</h2>'; $methods=get_class_methods($class); $object_methods=get_methods($object); if(!count($methods)){ echo "<i>なし</i><br/>"; } else{ echo '<p>継承しているメソッドは、<i>斜体</i>で表示します。</p>'; foreach($methods as $method){ echo in_array($method,$object_methods)?"<b>$method</b>();<br/>":"<i>$method</i>();<br/>"; } } echo '<h2>プロパティ</h2>'; $properties=get_class_vars($class); if(!count($properties)){ echo "<i>なし</i><br/>"; } else{ foreach(array_keys($properties) as $property){ echo "<b>\$$property</b>=".$object->$property.'<br/>'; } } echo '<hr/>'; } //省略しましたがここにクラスA、B、Cを用意しました。 $a=new A; $a->foo='sylvie'; $a->bar=23; $b=new B; $b->foo='bruno'; $b->quux=true; $c=new C; print_object_info($a); print_object_info($b); print_object_info($c); ?> これを実行すると途中からエラーになります。$classがどんな値か出力するために、 foreach($classes as $renban=>$class){ print_r("{$renban}:{$class}\n<br/>"); } にして出力したら、 0:stdClass …… 139:A 140:B 141:C になりました。(get_declared_classes()が返す値は、スクリプト内で自分が定義したクラス以外に、PHPがデフォルトで定義しているクラスもあることに、昨日気づきました。) 本を書いた人は、foreach文の直後の if(substr($class,0,2)=='__'){ continue; } の所でデフォルトの定義済みクラスを除外する目的だったと思います。 ここを、 foreach($classes as $class){ if(substr($class,0,1)!='A||B||C'){ continue; } に変えたらちゃんと画面が表示されました。 本を書いた人はなぜ、if(substr($class,0,2)=='__')にしたのでしょうか?また、if(substr($class,0,1)!='A||B||C')だとあらかじめ自分が定義しているクラスを記述しているのでなにかぱっとしない感じがします。自分が定義したクラス以外を除外という書き方でなく、デフォルトの定義済みクラスをうまく除外する方法などございましたらアドバイスの方よろしくお願いします。 こちらの環境は、windows vistaにxampp1.6.5、php5.2.5です。よろしくお願いします。

    • ベストアンサー
    • PHP

専門家に質問してみよう