我有以下课程:
module APIWrapper
include HTTParty
BASE_URI = 'https://example.com/Api'
def self.const_missing(const_name)
anon_class = Class.new do
def self.method_missing method_name, *params
params = {
'Target' => const_name.to_s,
'Method' => method_name.to_s,
}
APIWrapper.call_get params
end
end
end
def self.call_get(params)
get(APIWrapper::BASE_URI, {:query => params})
end
def self.call_post(params)
post(APIWrapper::BASE_URI, params)
end
end
我希望能够像这样调用我的包装器:
APIWrapper::User::getAll
我的堆栈级别太深了错误:
1) Error:
test_User_getAll(APITest):
SystemStackError: stack level too deep
api_test.rb:16
我做错了什么?
答案 0 :(得分:3)
使用关键字def
后,会创建一个新范围,因此这里的问题是const_name
变量不再位于method_missing
方法体内的范围内。 / p>
您可以使用以下块来保持变量的范围:
def self.const_missing(const_name)
anon_class = Class.new do
define_singleton_method(:method_missing) do |method_name, *params|
params = {
'Target' => const_name.to_s,
'Method' => method_name.to_s,
}
APIWrapper.call_get params
end
end
end
您可能还想将常量设置为刚刚创建的匿名类:
anon_class = Class.new do
...
end
const_set const_name, anon_class
答案 1 :(得分:0)
问题是const_name
递归调用method_missing
。将块传递给Class.new
时,将在类的范围内计算块。 (见docs)
答案 2 :(得分:0)
方法没有看到任何局部外部变量。在你的情况下,它是const_name,它以递归方式触发method_missing。
name = "Semyon"
def greet
puts "hello, #{name}!"
end
greet # undefined local variable or method ‘name’
您可以使用const_set
在Ruby中命名匿名模块(和类),然后可以从中轻松查看名称。我也不建议为每个类定义新方法,这就是模块的用途。这是我的简短,独立的例子:
module Greeting
module Base
def method_missing(word)
Greeting.greet word, self.name.split("::").last
end
end
def self.greet(word, name)
puts "#{word}, #{name}!"
end
def self.const_missing(name)
const_set name, Module.new.extend(Base)
end
end
Greeting::Semyon.hello # hello, Semyon!