3

私は、とりわけ、いくつかの一般的な「ファインダー」タイプの機能を、それをミックスするクラスに追加するモジュールに取り組んでいます。問題: 利便性と美学の理由から、クラス自体と同じスコープで、クラスの外部にいくつかの機能を含めたいと考えています。

例えば:

class User
  include MyMagicMixin
end

# Should automagically enable:

User.name('Bob')   # Returns first user named Bob
Users.name('Bob')  # Returns ALL users named Bob 
User(5)            # Returns the user with an ID of 5
Users              # Returns all users

これらのメソッドで機能を実行できますが、問題ありません。そして、ケース 1 ( User.name('Bob')) は簡単です。ただし、ケース 2 ~ 4 では、 の外部で新しいクラスとメソッドを作成できる必要がありますUser。このModule.includedメソッドは、クラスへのアクセスを提供しますが、それを含むスコープへのアクセスは提供しません。クラスやモジュールで確認できる単純な「親」タイプのメソッドはありません。(名前空間については、つまり、スーパークラスでもネストされたモジュールでもありません。)

これを行う最善の方法は、クラスの文字列を解析し#nameて名前空間を分割し、文字列を定数に戻すことです。しかし、それは不器用に思えます。これが Ruby であることを考えると、もっとエレガントな方法があるべきだと思います。

誰にもアイデアはありますか?それとも、自分の利益のために賢すぎるだけですか?

4

3 に答える 3

3

私は賢すぎる傾向があります。

洗練された解決策があったとしても、クラスの外部にクラスを作成するモジュールをクラスに含めるのはかなり奇妙に思えます。

于 2010-03-20T04:02:50.663 に答える
2

これは、メーリングリストで時々発生する問題です。Railsで発生する問題でもあります。解決策は、すでにお察しのとおり、基本的に正規表現の変更です。

ただし、もっと根本的な問題があります。Rubyでは、クラスに名前がありません。クラスは、他のクラスと同じように単なるオブジェクトです。インスタンス変数、ローカル変数、グローバル変数、定数に割り当てることも、何にも割り当てないこともできます。このModule#nameメソッドは基本的に、次のように機能する便利なメソッドです。レシーバーを指す定数が見つかるまで、定義された定数のリストを調べます。見つかった場合は、最初に見つけたものを返します。それ以外の場合は、を返しますnil

したがって、ここには2つの障害モードがあります。

a = Class.new
a.name # => nil
B = a
B.name # => "B"
A = B
A.name # => "B"
  • クラスには名前がまったくない可能性があります
  • クラスには複数の名前がある場合がありますがModule#name、最初に見つかった名前のみが返されます

ここで、誰かがsのAsリストを取得するために呼び出しようとAすると、そのメソッドが存在しないことにかなり驚かれますが、Bs代わりに呼び出して同じ結果を取得できます。

これ実際には実際に起こります。MacRubyでは、たとえば、 String.namereturns NSMutableStringHash.namereturns NSMutableDictionaryObject.namereturns NSObject。これは、MacRubyがRubyランタイムとObjective-Cランタイムを1つに統合し、Objective-C可変文字列のセマンティクスがRuby文字列と同一であるため、Rubyの文字列クラスの実装全体が基本的に1行であるためです。 :String = NSMutableString。MacRubyはObjective-Cの上にあるため、Objective-Cが最初に開始されます。NSMutableStringつまり、最初にシンボルテーブルに挿入されます。つまり、最初に。によって検出Module#nameされます。

于 2010-03-20T07:51:14.153 に答える
1

あなたの例では、はオブジェクトUserを指す単なる定数です。が含まれている場合、別の定数ポインタClassを簡単に作成できます。MyMagicMixin

module MyMagicMixin
  class <<self
    def self.included(klass)
      base.extend MyMagicMixin::ClassMethods
      create_pluralized_alias(klass)
    end

    private

    def create_pluralized_alias(klass)
      fq_name = klass.to_s
      class_name = fq_name.demodulize
      including_module = fq_name.sub(Regexp.new("::#{class_name}$", ''))
      including_module = including_module.blank? ? Object : including_module.constantize
      including_module.const_set class_name.pluralize, klass
    end
  end

  module ClassMethods
    # cass methods here
  end
end

もちろん、これはあなたがそのようなことをすべきかどうかには答えません。

于 2010-03-20T15:20:43.987 に答える