我收到以下错误:
syntax error, unexpected ':', expecting end-of-input
field :'lastapple info', type: String
^
使用这种方法就在这里:
def eval_mongo(klass, field)
_field = field['field'].to_sym
_type = FieldType.where(_id: field['field_type_id']).first.type_from_field
klass.class_eval <<-EOS
field :'#{ _field }', type: #{ _type }
EOS
end
我盯着这个,我不知道错误在哪里。由于我使用的是heredocs,因此不需要class_eval的do end。实际上,它在控制台中运行良好,并且我之前使用过它,所以我知道这不是问题。那么问题是什么呢?
您的问题是,您试图field
在此处将名称用于太多事情:
def eval_mongo(klass, field)
_field = field['field'].to_sym
_type = FieldType.where(_id: field['field_type_id']).first.type_from_field
klass.class_eval <<-EOS
field :'#{ _field }', type: #{ _type }
EOS
end
field
是的参数,eval_mongo
但您也想在class_eval
调用中将其用作类方法名称。在中class_eval
,Ruby认为您需要该field
参数,因此会出现语法错误。如果f
改用自变量命名:
def eval_mongo(klass, f)
_field = f['field'].to_sym
_type = FieldType.where(_id: f['field_type_id']).first.type_from_field
klass.class_eval <<-EOS
field :'#{ _field }', type: #{ _type }
EOS
end
那么事情应该起作用。
我希望我能对这里发生的事情提供清晰的解释,但我不能。取而代之的是,我将在MRI信号源周围徘徊,并尝试通过实验来弄清行为,以总结发现的结果。这种方法很容易出错,但通常是Ruby所具有的。
该文档说:
class_eval(字符串[,文件名[,lineno]])→obj
在mod的上下文中评估字符串或块,除了给出块时,常量/类变量查找不受影响。[...]
和Ruby一样,这还不够详细或不够具体,以至于无法使用。
如果我们看一下源,我们会看到,class_eval
实际上是rb_mod_module_eval
在vm_eval.c
刚刚调用specific_eval
它调用eval_under
它要求eval_string_with_cref
用Qnil
该值scope
的论点。可以这样scope
处理:
if (!NIL_P(scope)) {
/* ... */
}
else {
rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
if (cfp != 0) {
block = *RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp);
base_block = █
base_block->self = self;
base_block->iseq = cfp->iseq; /* TODO */
}
else {
rb_raise(rb_eRuntimeError, "Can't eval on top of Fiber or Thread");
}
}
然后base_block
使用来编译源代码字符串。我对MRI的信息并不十分熟悉,但这似乎是有意地设置了使用MRI范围的东西class_eval
。
一个简化的示例可能会有所帮助:
class K
def self.field(*args)
puts args.inspect
end
end
def eval_mongo(klass, f)
klass.class_eval <<-EOS
field :'#{f}', type: String
f
EOS
end
puts eval_mongo(K, 'pancakes house').inspect
那会说:
[:"pancakes house", {:type=>String}]
"pancakes house"
如果您不理会名称,而是field
使用字符串参数进行调用:
def eval_mongo(klass, field)
klass.class_eval <<-EOS
field '#{field}', type: String
field
EOS
end
然后它也起作用并说:
["pancakes house", {:type=>String}]
"pancakes house"
但是如果我们将其field
用作参数名称并使用符号:
def eval_mongo(klass, field)
klass.class_eval <<-EOS
field :'#{field}', type: String
field
EOS
end
我们得到语法错误:
in `class_eval': (eval):1: syntax error, unexpected ':', expecting end-of-input (SyntaxError)
field :'pancakes house', type: String
^
有趣的是,如果尝试使用Ruby有点晦涩的字符串粘贴功能,则会遇到相同的语法错误:
> s = 'a' 'b'
=> "ab"
带有符号:
> s = 'a' :'b'
SyntaxError: (irb):2: syntax error, unexpected ':', expecting end-of-input
s = 'a' :'b'
^
也许在不同的时期对不同的事物进行了评估,而Ruby对于什么是字符串和什么不是字符串感到困惑。
这种行为对我来说是令人惊讶和意外的,因此我很想将其称为错误或功能不当,但是我可能会遗漏一些明显的东西。如果可以class_eval
更好地指定的行为(具有令人惊讶的行为的理由和理由),那将是很好的选择,但这似乎违背了快速的“宽松” Ruby文化。
如果有人能澄清为什么会发生,我将不胜感激。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句