本文介绍了Ruby元编程:如何使模块方法看到类的变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我有一个模块和一个类:

For example I have a module and a class:

module SimpleModule
  def self.class_hello
    puts "hello from #{@@name}"
  end
end

class SimpleClass
  @@name = 'StackOverFlow'
  def self.test
    SimpleModule.class_hello
  end
end

然后我通过调用类中的模块方法进行测试:

Then I test by calling module method from class:

SimpleClass.test

我遇到例外:

我在这里知道是因为模块的作用域与类作用域不同.所以我的问题是:如何为SimpleModule范围共享SimpleClass范围?

I know here because scope of module is not same as class scope. So my question is: How can I share SimpleClass scope for SimpleModule scope?

我之所以使用元编程,是因为这只是一个简单的示例,此后,我将通过从动态类中调用动态模块来进行高级编程. (这就是为什么我不想使用某些关键字,例如 include extend 的原因)

I put metaprogramming because here is just simple example, after that I will advanced by calling dynamic module from dynamic class. (that is the reason why I don't want to use some keyword such as include or extend)

@编辑实际上,我想自己实现Ruby扩展.这是我已经开发的版本:

@EditIn fact I want to implement Ruby extends on my own. Here is my already developed version:

# implementation
class Class
  def custom_extend(module_name)
    module_name.methods(false).each do |method|
      define_singleton_method(method) do |*args, &block|
        module_name.send(method, *args, &block)
      end
    end
  end
end

这是我的自定义模块和测试类:

And here is my custom module and class for testing:

# -------------------------------------------------------------
# Demonstration
module SimpleModule
  def self.class_hello_world
    puts 'i am a simple module boss'
  end

  def self.class_hello_name
    puts "hello from #{@@name}"
  end
end

class SimpleClass
  custom_extend  SimpleModule
  @@name = 'StackOverFlow'
end

这是我的两个测试:

SimpleClass.class_hello_world  # work
SimpleClass.class_hello_name   # not work

推荐答案

更新的答案

这是您的代码的稍作修改的版本.不需要includeextendappend_featuresmodule_function.添加具有相同结构的custom_include并不难.

Updated answer

Here's a slightly modified version of your code. No include, extend, append_features or module_function are needed. It wouldn't be hard to add custom_include with the same structure.

更新:请务必阅读@ 7stud的答案,其结构相似且解释很好.

UPDATE: Make sure to read @7stud's answer, with a similar structure and very good explanation.

class Class
  def custom_extend(module_name)
    module_name.instance_methods(false).each do |method|
      define_singleton_method(method) do |*args, &block|
        module_name.instance_method(method).bind(self).call(*args, &block)
      end
    end
  end
end

module SimpleModule
  def class_hello
    puts "hello from #{@name}"
  end
end

class SimpleClass
  @name = 'class'
  custom_extend SimpleModule

  def self.test
    class_hello
  end
end

SimpleClass.test
#=> hello from class


原始答案

常规方式

通常的方法是:


Original answer

Usual way

The usual way would be :

module SimpleModule
  def class_hello
    puts "hello from #{@name}"
  end
end

class SimpleClass
  @name = 'StackOverFlow'
  extend SimpleModule

  def self.test
    class_hello
  end
end

SimpleClass.class_hello

但是您不想要它. (为什么?)

but you don't want it. (why?)

在您的代码中,SimpleClassSimpleModule彼此完全独立.很明显,您得到了NameError.您需要以某种方式传递name信息.

In your code, SimpleClass and SimpleModule are totally independent from one another. It's clear that you get a NameError. You need to somehow pass the name information.

module SimpleModule
  def self.class_hello(name='')
    puts "hello from #{name}"
  end
end

class SimpleClass
  @@name = 'StackOverFlow'
  def self.test
    SimpleModule.class_hello(@@name)
  end
end

带有klass参数:

module SimpleModule
  def self.class_hello(calling_class=self)
    calling_class.class_eval{
      puts "hello from #{@name}"
    }
  end
end

class SimpleClass
  @name = 'StackOverFlow'
  def self.test
    SimpleModule.class_hello(self)
  end
end

SimpleClass.test

使用binding参数:

With binding parameter :

module SimpleModule
  def self.class_hello(b)
    puts "hello from #{b.eval('@@name')}"
  end
end

class SimpleClass
  @@name = 'StackOverFlow'
  def self.test
    SimpleModule.class_hello(binding)
  end
end

SimpleClass.test

使用my_ruby_extend SimpleModule

当然可以使用自定义的my_ruby_extend完成.不过,您需要显示所需的语法以及已经实现的内容.

With my_ruby_extend SimpleModule

It surely can be done with a custom my_ruby_extend. You'd need to show the desired syntax though, and what you already implemented.

这样,您可以告诉Ruby SimpleClassSimpleModule是链接的.如果在SimpleModule中找不到方法或变量,则可以在SimpleClass中进行查找.

This way, you could tell Ruby that SimpleClass and SimpleModule are linked. When a method or a variable isn't found in SimpleModule, it could be sought in SimpleClass.

这篇关于Ruby元编程:如何使模块方法看到类的变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 14:21