我只是尝试重新实现扩展作为练习。
ruby 的extend() 不能这样工作:
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
例如,以下行不通:
module Dog
def self.greet
puts "hello"
end
end
class Cat
extend Dog
end
Cat.greet
--output:--
`<main>': undefined method `greet' for Cat:Class (NoMethodError)
extend() 是这样工作的:
module Dog
def greet
puts "hello"
end
end
class Cat
extend Dog
end
Cat.greet
--output:--
hello
换句话说,extend() 将模块实例方法——而不是模块方法(例如,以self 开头的方法名)——插入到 Cat 的单例类(这是 Cat 的类方法所在的位置)。在 ruby 中,include() 和 extend() 与模块方法无关(同样,方法名称以 self 开头)。模块在 ruby 中有两种用途:
- 作为命名空间,例如包含
def self.method_name
- 作为 mixin,例如包含
def some_method
include() 和 extend() 处理 #2。
以下解决方案不适用于@@variables,但试图弄清楚@@variables 在ruby 中展示的所有曲折是不值得的——只是不要使用它们。请改用 类实例变量,即在任何 def 之外指定 @variables:
def my_extend(some_module)
singleton_class.include some_module
end
module Dog
def greet
puts @greeting
end
private
def sayhi
puts "hi"
end
end
class Cat
@greeting = "hello"
my_extend Dog
end
Cat.greet
#Cat.sayhi #=>`<main>': private method `sayhi' called for Cat:Class (NoMethodError)
Cat.class_eval {sayhi} #Change self to the Cat class so the implicit
#self variable that calls sayhi is equal to Cat
--output:--
hello
hi
现在,您只需实现 my_include 并将其替换为 include。 :)
这是my_include() 的照片:
class Class
def my_include(module_)
#For public and protected methods:
module_.instance_methods(include_super=false).each do |meth_name|
meth = module_.instance_method(meth_name)
define_method(meth_name) do
meth.bind(self).call
end
end
#For private methods:
module_.private_instance_methods(include_super=false).each do |meth_name|
meth = module_.instance_method(meth_name)
define_method(meth_name) do
meth.bind(self).call
end
private :"#{meth_name}"
end
end
end
module Dog
def greet
puts "hello"
end
def go
puts "run, run run"
end
private
def sayhi
puts "hi"
end
end
class Cat
my_include Dog
end
c = Cat.new
c.greet
c.go
c.sayhi
--output:--
hello
run, run run
#=>`<main>': private method `sayhi' called for #<Cat:0x007fc014136f60> (NoMethodError)
与my_extend():
class Class
def my_include(module_)
#For public and protected methods:
module_.instance_methods(include_super=false).each do |meth_name|
meth = module_.instance_method(meth_name)
define_method(meth_name) do
meth.bind(self).call
end
end
#For private methods:
module_.private_instance_methods(include_super=false).each do |meth_name|
meth = module_.instance_method(meth_name)
define_method(meth_name) do
meth.bind(self).call
end
private :"#{meth_name}"
end
end
def my_extend(module_)
singleton_class.my_include module_
end
end
module Dog
def greet
puts @greeting
end
private
def sayhi
puts "hi"
end
end
class Cat
@greeting = "hello"
my_extend Dog
end
Cat.greet
#Cat.sayhi #=>private method `sayhi' called for Cat:Class (NoMethodError)
Cat.class_eval {sayhi}
--output:--
hello
hi