ruby module_function vs include模块

时间:2022-04-27 04:04:15

In ruby, I understand that module functions can be made available without mixing in the module by using module_function as shown here. I can see how this is useful so you can use the function without mixing in the module.

在ruby中,我理解可以通过使用module_function(如图所示)在模块中混合使用模块函数。我可以看到这有多有用,这样你就可以不用在模块中混合使用这个函数了。

module MyModule
  def do_something
    puts "hello world"
  end
  module_function :do_something
end

My question is though why you might want to have the function defined both of these ways.

我的问题是为什么你想让函数同时用这两种方式定义。

Why not just have

为什么不有

def MyModule.do_something

OR

def do_something

In what kind of cases would it be useful to have the function available to be mixed in, or to be used as a static method?

在哪种情况下,可以将函数混合在一起,或者作为静态方法使用?

3 个解决方案

#1


36  

Think of Enumerable.

可列举的。

This is the perfect example of when you need to include it in a module. If your class defines #each, you get a lot of goodness just by including a module (#map, #select, etc.). This is the only case when I use modules as mixins - when the module provides functionality in terms of a few methods, defined in the class you include the module it. I can argue that this should be the only case in general.

当您需要在模块中包含它时,这是一个很好的例子。如果您的类定义了#each,那么只要包含一个模块(#map, #select,等等),您就会得到很多好处。这是我使用模块作为mixin的唯一情况——当模块以一些方法提供功能时,在类中定义的方法包括模块。我可以说,这应该是一般情况下的唯一情况。

As for defining "static" methods, a better approach would be:

关于定义“静态”方法,更好的方法是:

module MyModule
  def self.do_something
  end
end

You don't really need to call #module_function. I think it is just weird legacy stuff.

不需要调用#module_function。我认为这只是一些奇怪的遗产。

You can even do this:

你甚至可以这样做:

module MyModule
  extend self

  def do_something
  end
end

...but it won't work well if you also want to include the module somewhere. I suggest avoiding it until you learn the subtleties of the Ruby metaprogramming.

…但是如果您还想在某个地方包含模块,那么它就不能很好地工作。我建议您在了解Ruby元编程的微妙之处之前避免使用它。

Finally, if you just do:

最后,如果你这么做:

def do_something
end

...it will not end up as a global function, but as a private method on Object (there are no functions in Ruby, just methods). There are two downsides. First, you don't have namespacing - if you define another function with the same name, it's the one that gets evaluated later that you get. Second, if you have functionality implemented in terms of #method_missing, having a private method in Object will shadow it. And finally, monkey patching Object is just evil business :)

…它最终不会作为全局函数,而是作为对象上的私有方法(Ruby中没有函数,只有方法)。有两个缺点。首先,您没有命名空间—如果您定义另一个同名的函数,它将在稍后得到计算值。其次,如果您有按照#method_missing来实现的功能,那么在Object中有一个私有方法将会影响它。最后,猴子补补丁的对象是邪恶的生意:)

EDIT:

编辑:

module_function can be used in a way similar to private:

module_function的使用方式可以类似于private:

module Something
  def foo
    puts 'foo'
  end

  module_function

  def bar
    puts 'bar'
  end
end

That way, you can call Something.bar, but not not Something.foo. If you define any other methods after this call to module_function, they would also be available without mixing in.

这样,你就可以调用一些东西。巴,但不是什么。如果您在调用module_function之后定义任何其他方法,它们也可以在没有混合的情况下可用。

I don't like it for two reasons, though. First, modules that are both mixed in and have "static" methods sound a bit dodgy. There might be valid cases, but it won't be that often. As I said, I prefer either to use a module as a namespace or mix it in, but not both.

我不喜欢它有两个原因。首先,混合了“静态”方法的模块听起来有点可疑。可能有有效的案例,但不会经常发生。如前所述,我宁愿使用模块作为名称空间,也不愿将其混合在一起,但不是两者都使用。

Second, in this example, bar would also be available to classes/modules that mix in Something. I'm not sure when this is desirable, since either the method uses self and it has to be mixed in, or doesn't and then it does not need to be mixed in.

其次,在本例中,bar也可以用于混合在一起的类/模块。我不确定什么时候这是可取的,因为任何一种方法都使用self,它必须混合在一起,否则就不需要混合在一起。

I think using module_function without passing the name of the method is used quite more often than with. Same goes for private and protected.

我认为在不传递方法名称的情况下使用module_function要比在一起使用要频繁得多。私有和保护也是一样。

#2


13  

It's a good way for a Ruby library to offer functionality that does not use (much) internal state. So if you (e.g.) want to offer a sin function and don't want to pollute the "global" (Object) namespace, you can define it as class method under a constant (Math).

这是Ruby库提供不使用(很多)内部状态的功能的好方法。因此,如果您(例如)希望提供一个sin函数,并且不想污染“全局”(对象)名称空间,您可以将其定义为常量(Math)下的类方法。

However, an app developer, who wants to write a mathematical application, might need sin every two lines. If the method is also an instance method, she can just include the Math (or My::Awesome::Nested::Library) module and can now directly call sin (stdlib example).

然而,一个想要编写一个数学应用程序的应用程序开发人员,可能每两行就需要使用sin。如果这个方法也是一个实例方法,她可以只包含Math(或者My: Awesome::嵌套:::Library)模块,现在可以直接调用sin (stdlib示例)。

It's really about making a library more comfortable for its users. They can choose themself, if they want the functionality of your library on the top level.

它实际上是让一个库更适合它的用户。他们可以自己选择,如果他们想要你的库的功能在顶层。

By the way, you can achieve a similar functionality like module_function by using: extend self (in the first line of the module). To my mind, it looks better and makes things a bit clearer to understand.

顺便说一下,您可以通过使用:extend self(在模块的第一行)实现类似的功能,如module_function。在我看来,它看起来更好,让事情更清楚一些。

Update: More background info in this blog article.

更新:更多的背景信息在这篇博客文章。

#3


2  

If you want to look at a working example, check out the chronic gem:

如果你想看一个有用的例子,可以看看这个长期的珍宝:

https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb

https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb

and Handlers is being included in the Parser class here:

这里的解析器类包含了处理器:

https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb

https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb

He's using module_function to send the methods from Handlers to specific instances of Handler using that instance's invoke method.

他使用module_function将方法从处理程序发送到使用该实例的invoke方法的处理程序的特定实例。

#1


36  

Think of Enumerable.

可列举的。

This is the perfect example of when you need to include it in a module. If your class defines #each, you get a lot of goodness just by including a module (#map, #select, etc.). This is the only case when I use modules as mixins - when the module provides functionality in terms of a few methods, defined in the class you include the module it. I can argue that this should be the only case in general.

当您需要在模块中包含它时,这是一个很好的例子。如果您的类定义了#each,那么只要包含一个模块(#map, #select,等等),您就会得到很多好处。这是我使用模块作为mixin的唯一情况——当模块以一些方法提供功能时,在类中定义的方法包括模块。我可以说,这应该是一般情况下的唯一情况。

As for defining "static" methods, a better approach would be:

关于定义“静态”方法,更好的方法是:

module MyModule
  def self.do_something
  end
end

You don't really need to call #module_function. I think it is just weird legacy stuff.

不需要调用#module_function。我认为这只是一些奇怪的遗产。

You can even do this:

你甚至可以这样做:

module MyModule
  extend self

  def do_something
  end
end

...but it won't work well if you also want to include the module somewhere. I suggest avoiding it until you learn the subtleties of the Ruby metaprogramming.

…但是如果您还想在某个地方包含模块,那么它就不能很好地工作。我建议您在了解Ruby元编程的微妙之处之前避免使用它。

Finally, if you just do:

最后,如果你这么做:

def do_something
end

...it will not end up as a global function, but as a private method on Object (there are no functions in Ruby, just methods). There are two downsides. First, you don't have namespacing - if you define another function with the same name, it's the one that gets evaluated later that you get. Second, if you have functionality implemented in terms of #method_missing, having a private method in Object will shadow it. And finally, monkey patching Object is just evil business :)

…它最终不会作为全局函数,而是作为对象上的私有方法(Ruby中没有函数,只有方法)。有两个缺点。首先,您没有命名空间—如果您定义另一个同名的函数,它将在稍后得到计算值。其次,如果您有按照#method_missing来实现的功能,那么在Object中有一个私有方法将会影响它。最后,猴子补补丁的对象是邪恶的生意:)

EDIT:

编辑:

module_function can be used in a way similar to private:

module_function的使用方式可以类似于private:

module Something
  def foo
    puts 'foo'
  end

  module_function

  def bar
    puts 'bar'
  end
end

That way, you can call Something.bar, but not not Something.foo. If you define any other methods after this call to module_function, they would also be available without mixing in.

这样,你就可以调用一些东西。巴,但不是什么。如果您在调用module_function之后定义任何其他方法,它们也可以在没有混合的情况下可用。

I don't like it for two reasons, though. First, modules that are both mixed in and have "static" methods sound a bit dodgy. There might be valid cases, but it won't be that often. As I said, I prefer either to use a module as a namespace or mix it in, but not both.

我不喜欢它有两个原因。首先,混合了“静态”方法的模块听起来有点可疑。可能有有效的案例,但不会经常发生。如前所述,我宁愿使用模块作为名称空间,也不愿将其混合在一起,但不是两者都使用。

Second, in this example, bar would also be available to classes/modules that mix in Something. I'm not sure when this is desirable, since either the method uses self and it has to be mixed in, or doesn't and then it does not need to be mixed in.

其次,在本例中,bar也可以用于混合在一起的类/模块。我不确定什么时候这是可取的,因为任何一种方法都使用self,它必须混合在一起,否则就不需要混合在一起。

I think using module_function without passing the name of the method is used quite more often than with. Same goes for private and protected.

我认为在不传递方法名称的情况下使用module_function要比在一起使用要频繁得多。私有和保护也是一样。

#2


13  

It's a good way for a Ruby library to offer functionality that does not use (much) internal state. So if you (e.g.) want to offer a sin function and don't want to pollute the "global" (Object) namespace, you can define it as class method under a constant (Math).

这是Ruby库提供不使用(很多)内部状态的功能的好方法。因此,如果您(例如)希望提供一个sin函数,并且不想污染“全局”(对象)名称空间,您可以将其定义为常量(Math)下的类方法。

However, an app developer, who wants to write a mathematical application, might need sin every two lines. If the method is also an instance method, she can just include the Math (or My::Awesome::Nested::Library) module and can now directly call sin (stdlib example).

然而,一个想要编写一个数学应用程序的应用程序开发人员,可能每两行就需要使用sin。如果这个方法也是一个实例方法,她可以只包含Math(或者My: Awesome::嵌套:::Library)模块,现在可以直接调用sin (stdlib示例)。

It's really about making a library more comfortable for its users. They can choose themself, if they want the functionality of your library on the top level.

它实际上是让一个库更适合它的用户。他们可以自己选择,如果他们想要你的库的功能在顶层。

By the way, you can achieve a similar functionality like module_function by using: extend self (in the first line of the module). To my mind, it looks better and makes things a bit clearer to understand.

顺便说一下,您可以通过使用:extend self(在模块的第一行)实现类似的功能,如module_function。在我看来,它看起来更好,让事情更清楚一些。

Update: More background info in this blog article.

更新:更多的背景信息在这篇博客文章。

#3


2  

If you want to look at a working example, check out the chronic gem:

如果你想看一个有用的例子,可以看看这个长期的珍宝:

https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb

https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb

and Handlers is being included in the Parser class here:

这里的解析器类包含了处理器:

https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb

https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb

He's using module_function to send the methods from Handlers to specific instances of Handler using that instance's invoke method.

他使用module_function将方法从处理程序发送到使用该实例的invoke方法的处理程序的特定实例。