在 ruby​​ 中定义全局方法的方法

发布于 2024-12-01 11:35:10 字数 451 浏览 1 评论 0原文

我正在编写一个小 gem,我想定义一个类似 DSL 的方法,与 Rakedesc 和 task 方法几乎相同强>。

Rake 将它们定义为 Rake::DSL 模块中的私有方法,然后

self.extend Rake::DSL

将模块混合到主对象中? (我是新手,错了请笑)

这样做有什么好处?是因为将这些方法设为私有可以阻止任何其他对象使用它们(即阻止类似 some_obj.desc 的东西)吗?

如果我在 Kernel 中定义方法

module Kernel
  private

  include Rake::DSL
end

会有什么区别吗?

I'm writing a small gem, and I want to define a DSL-like method, pretty much the same as the desc and task methods in Rake.

Rake defines them as private methods in the Rake::DSL module and then

self.extend Rake::DSL

to mix the module into the main object? (I'm a newbie and go ahead laugh if I'm wrong)

what are the benefits by doing so? is it because making these methods private can prevent any other objects to use them (that is, to prevent something like some_obj.desc) ?

what if I define the methods in Kernel

module Kernel
  private

  include Rake::DSL
end

Is there any difference?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情丝乱 2024-12-08 11:35:10

如果您在 Kernel 模块中定义私有方法,它将在整个项目中可用。您还将重写项目用于定义 rake 任务的 desc 方法。但是,如果您在子模块中编写方法,然后在超类或某个模块中扩展它 - 您可以轻松编写任何类型的 DSL lang,就像您在 Rake 或 RSpec 中看到的那样.
PS 使方法private 阻止其他模块或类(但不是子类)使用它们(但不是owerwrite) - 我的意思是模块嵌套层次结构。

If you define private method in Kernel module it will be available in the whole project. You will also rewrite desc method that project use to define rake task. But if you write your methods in your submodule and then extend it in superclass or some module - you can easily write any kind of DSL lang like you might saw in Rake or RSpec.
P.S. Making methods private prevents other moludes or classes (but not subclasses) to use them (but not owerwrite) - I mean module nesting hierarchy.

撞了怀 2024-12-08 11:35:10

只是为了扩展 bor1s 给出的关于 private 方法的答案:

在 ruby​​ 中,您有“私有”和“受保护”方法。在谈论“受保护”方法时,bor1s 所说的是正确的。将方法声明为“私有”还可以防止同一类的其他实例使用该方法。

当您调用“私有”方法时,您不能在其前面使用点 - 您甚至不能使用 self.,即使使用或省略 self 通常具有相同的效果影响。

class Xyzzy
  private
  def foo
    puts "Foo called"
  end

  public
  def do_it
    foo       # <= Is OK
    self.foo  # <= raises NoMethodError
  end
end

Xyzzy.new.do_it

如果您在上面的代码中将“private”更改为“protected”,则不会出现错误。

关于模块:

Kernel中定义方法并使用某个模块中定义的方法扩展Kernel的最终结果是相同的:在两者中情况下该方法是全局的。

使用模块只是更优雅一点,因为它将您的更改分组到一个地方,但我想说这是个人品味的问题。

通常,您不会在内核或对象中包含方法(因为这可能有点危险),但您包含(或扩展)需要这些方法的特定类或对象,在这种情况下,您需要您的方法分组在一个模块中。

甚至 Rake 0.9.0 版本也停止在 Object 中包含 DSL 命令:

==版本0.9.0

  • 不兼容 *更改*:Rake DSL 命令(“任务”、“文件”等)是
    不再是 Object 中的私有方法。如果你需要在里面调用'task :xzy'
    您的班级,将 Rake::DSL 包含到班级中。 DSL 仍然可用:
    顶级范围(通过扩展 Rake::DSL 的顶级对象)。

Just to extend the answer given by bor1s, about the private methods:

In ruby you have "private" and "protected" methods. What bor1s says, is correct when talking about "protected" methods. Declaring a method "private" additionally prevents other instances of the same class from using the method.

When you call a "private" method, you cannot use a dot in front of it - you cannot even use self., even though using or omitting self has usually the same effect.

class Xyzzy
  private
  def foo
    puts "Foo called"
  end

  public
  def do_it
    foo       # <= Is OK
    self.foo  # <= raises NoMethodError
  end
end

Xyzzy.new.do_it

If you change 'private' to 'protected' in the code above, no error will be raised.

And about modules:

The final result of defining a method in Kernel and extending Kernel with the method defined in some module is the same: in both cases the method is global.

Using a module is just a little more elegant, as it groups your changes in one place, but I would say it's a matter of personal taste.

Usually you do not include methods in Kernel or Object (as it may be a little dangerous), but you include (or extend) a specific class or object which needs these methods, and in this case you need your methods grouped in a module.

Even Rake in version 0.9.0 stopped including the DSL commands in Object:

== Version 0.9.0

  • Incompatible *change*: Rake DSL commands ('task', 'file', etc.) are
    no longer private methods in Object. If you need to call 'task :xzy' inside
    your class, include Rake::DSL into the class. The DSL is still available at
    the top level scope (via the top level object which extends Rake::DSL).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文