201

バックグラウンド:

いくつかのインスタンスメソッドを宣言するモジュールがあります

module UsefulThings
  def get_file; ...
  def delete_file; ...

  def format_text(x); ...
end

そして、クラス内からこれらのメソッドのいくつかを呼び出したいと思います。Rubyでこれを通常行う方法は次のとおりです。

class UsefulWorker
  include UsefulThings

  def do_work
    format_text("abc")
    ...
  end
end

問題

include UsefulThingsからすべてのメソッドを取り込みますUsefulThings。この場合、私は and だけが必要であり、明示的には必要ありformat_textません。get_filedelete_file

これに対するいくつかの可能な解決策を見ることができます:

  1. どういうわけか、どこにも含めずにモジュールで直接メソッドを呼び出します
    • これがどのように/できるかわかりません。(したがって、この質問)
  2. どういうわけUsefulthingsか、そのメソッドの一部を含めてのみ持ち込む
    • また、これを行う方法/可能かどうかもわかりません
  3. プロキシ クラスを作成し、そのクラスに含めて、そのプロキシ インスタンス UsefulThingsに委譲するformat_text
    • これは機能しますが、匿名プロキシ クラスはハックです。うん。
  4. モジュールを 2 つ以上の小さなモジュールに分割する
    • これも機能し、おそらく私が考えることができる最良の解決策ですが、何十ものモジュールが急増することになるため、避けたいと思います-これを管理するのは面倒です

1 つのモジュールに無関係な関数がたくさんあるのはなぜですか? それApplicationHelperは Rails アプリからのものであり、私たちのチームは事実上、他の場所に属するほど具体的ではないもののゴミ捨て場として決定しました。ほとんどの場合、どこでも使用されるスタンドアロンのユーティリティ メソッドです。個別のヘルパーに分割することもできますが、30 個のヘルパーがあり、それぞれに 1 つのメソッドがあります... これは非生産的です。

4

10 に答える 10

167

(既存のモジュールを変更したり、新しいモジュールを作成したりせずに)単一の呼び出しを破棄する最短の方法は次のようになると思います。

Class.new.extend(UsefulThings).get_file
于 2009-09-11T14:03:09.880 に答える
145

モジュールのメソッドがモジュール関数に変換された場合、次のように宣言されているかのように、Modからメソッドを呼び出すことができます。

module Mods
  def self.foo
     puts "Mods.foo(self)"
  end
end

以下のmodule_functionアプローチは、すべてのModを含むクラスを壊さないようにします。

module Mods
  def foo
    puts "Mods.foo"
  end
end

class Includer
  include Mods
end

Includer.new.foo

Mods.module_eval do
  module_function(:foo)
  public :foo
end

Includer.new.foo # this would break without public :foo above

class Thing
  def bar
    Mods.foo
  end
end

Thing.new.bar  

しかし、そもそもなぜ無関係な関数のセットがすべて同じモジュールに含まれているのか不思議です。

public :foo後に呼び出された場合でも作業を含むことを示すために編集module_function :foo

于 2008-11-26T23:27:24.890 に答える
93

モジュールを「所有」している場合にそれを行う別の方法は、を使用することmodule_functionです。

module UsefulThings
  def a
    puts "aaay"
  end
  module_function :a

  def b
    puts "beee"
  end
end

def test
  UsefulThings.a
  UsefulThings.b # Fails!  Not a module method
end

test
于 2008-11-26T23:23:05.353 に答える
23

別のクラスにモジュールを含めずにこれらのメソッドを呼び出したい場合は、それらをモジュール メソッドとして定義する必要があります。

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...
end

そして、あなたはそれらを呼び出すことができます

UsefulThings.format_text("xxx")

また

UsefulThings::format_text("xxx")

とにかく、関連するメソッドだけを 1 つのモジュールまたは 1 つのクラスに入れることをお勧めします。モジュールのメソッドを1つだけインクルードしたいという問題がある場合、それは悪いコードの匂いのように聞こえます。無関係なメソッドをまとめるのはRubyのスタイルとしては良くありません。

于 2008-11-26T23:18:29.793 に答える
20

モジュールをインクルードせずに (および中間オブジェクトを作成せずに) モジュール インスタンス メソッドを呼び出すには:

class UsefulWorker
  def do_work
    UsefulThings.instance_method(:format_text).bind(self).call("abc")
    ...
  end
end
于 2014-10-02T03:50:57.330 に答える
7

まず、モジュールを必要な便利なものに分割することをお勧めします。ただし、呼び出し用にそれを拡張するクラスをいつでも作成できます。

module UsefulThings
  def a
    puts "aaay"
  end
  def b
    puts "beee"
  end
end

def test
  ob = Class.new.send(:include, UsefulThings).new
  ob.a
end

test
于 2008-11-26T23:16:11.873 に答える
1

ほぼ9年後の一般的な解決策は次のとおりです。

module CreateModuleFunctions
  def self.included(base)
    base.instance_methods.each do |method|
      base.module_eval do
        module_function(method)
        public(method)
      end
    end
  end
end

RSpec.describe CreateModuleFunctions do
  context "when included into a Module" do
    it "makes the Module's methods invokable via the Module" do
      module ModuleIncluded
        def instance_method_1;end
        def instance_method_2;end

        include CreateModuleFunctions
      end

      expect { ModuleIncluded.instance_method_1 }.to_not raise_error
    end
  end
end

適用する必要がある不幸なトリックは、メソッドが定義された後にモジュールを含めることです。または、コンテキストが として定義された後に含めることもできますModuleIncluded.send(:include, CreateModuleFunctions)

または、 reflection_utils gemを介して使用することもできます。

spec.add_dependency "reflection_utils", ">= 0.3.0"

require 'reflection_utils'
include ReflectionUtils::CreateModuleFunctions
于 2017-11-13T23:27:40.967 に答える