是否可以在Ruby中明确包含子模块或类?

时间:2017-01-14 04:18:43

标签: ruby

我希望能够静态分析我的代码。也就是说,从文件的纯文本中了解每个函数和变量的来源。 IDE和文本编辑器插件在跟踪每个符号的来源时也能更好地工作。

例如,如果我有这样的应用程序代码:

#...
Y.some_method()
#...

然后我想在页面的某个地方的include / import / require / extend / def语句中看到Y

在我使用的其他语言中,可以明确选择命名空间的哪些子部分引入当前上下文。

的Python:

from X import Y

Haskell中:

import X (Y)

药剂:

alias X.Y, as: Y

虽然可以在Python中导入所有包含的名称,但“通配符导入”is frowned upon

from X import *
  

“......他们不清楚命名空间中存在哪些名称,使读者和许多自动化工具都感到困惑。”

在Ruby中,似乎这种完全隐含的“通配符”方式是引入包含名称的唯一方式:

include X

这使得Y可用,但有哪些方法可以明确这一点? docs for Ruby include没有显示任何选项。

我真正喜欢在Ruby中做的事情就像其中之一:

from X include Y
include X::Y as Y

到目前为止,我提出的最好的是:

require 'x/y' ; Y = X::Y

这是a crazy hack在另一个问题的答案中可以实现此目的。

2 个答案:

答案 0 :(得分:2)

试试这个。但我同意@tadman你应该考虑用Ruby方式做这件事。

Object.define_singleton_method(:include) do |*mths, from: nil|
  mod = from || mths.first
  mod = mod.dup

  if from
     all_mths = mod.instance_methods
     (all_mths - mths).each { |mth| mod.send :undef_method, mth }
  end

  super(mod)
end

module Foobar
  def foo
    puts :foo
  end

  def bar
    puts :bar
  end
end

class Abc
  include Foobar
end

Abc.new.foo # => 'foo'
Abc.new.bar # => 'foo'

class AbcWithoutBar
  include :foo, from: Foobar
end

AbcWithoutBar.new.foo # => 'foo'
AbcWithoutBar.new.bar # => NoMethodError

答案 1 :(得分:2)

Ruby始终执行您require

的代码

由于没有部分执行文件,因此不能部分require

当你require一个功能时,Ruby使用$:中的加载路径找到相应的文件,然后对$"中加载的文件列表进行双重检查,如果文件还没有已加载执行文件。

Ruby是一种动态语言,推理其源代码的最佳方式是暂停正在运行的程序而不是静态。实际上,即使classdef也不是声明,而只是在运行时执行的方法调用。考虑一下这个人为的例子

class Surprise < [Array, Hash, Fixnum, Object].sample
end

如果您想知道定义方法或类的位置,请最好使用pry。您可以要求pry,然后使用binding.pry停止源代码中的任何位置,然后选择检查对象和源代码。两个最有用的命令是ls$

  • ls打印对象或类的所有方法
  • $打印方法的文件位置和源代码