2014-11-28 6 views
1
나는 다음과 같은 오류가 점점 오전

:구문 오류, 예기치 않은 ':', 기대 끝 입력

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 

나는이 내가 응시 : 바로 여기에이 방법으로

syntax error, unexpected ':', expecting end-of-input 
      field :'lastapple info', type: String 
       ^

을 오류가 어디에 있는지 알 수 없습니다. 내가 heredocs를 사용하고 있기 때문에, 나는 class_eval에 do 끝을 요구하지 않는다. 사실, 그것은 콘솔에서 잘 작동하고 이전에 사용했기 때문에 이것이 문제가 될 수 없다는 것을 알고 있습니다. 그러면 문제는 무엇입니까?

+0

'field : # {_field}, type : # {_type}'이 아니어야합니까? 문자열이 아닌 기호를 만들고 싶습니다. 맞습니까? – marc

+0

@marc 문자열이없는 last_apple 정보는 공백이있는 잘못된 메서드를 생성하고 정의되지 않은 정보 오류가 발생하기 때문에 문자열이 필요합니다. – Donato

+0

그게 효과가있다. 어떤 Ruby 버전을 사용하고 있습니까? 'eval'을 사용하면 항상 걱정이됩니다. 그래서'klass.send (_field.to_sym, _type) '을 사용하여 이것을 피할 수 있기를 바랍니다. – tadman

답변

1

귀하의 문제는 당신이 여기에 너무 많은 것들에 대한 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 

fieldeval_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를 사용하는 것이 일반적입니다.

documentation

는 말한다 :

class_eval(string [, filename [, lineno]]) → obj

Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected. [...]

이, 루비와 보통 아주 상세하지 않거나 대단히 유용 할 정도로 구체적으로입니다.

우리가 소스를 보면 class_eval 실제로 단지 scope 인수에 Qnileval_string_with_cref를 호출 eval_under 호출 specific_eval 호출 rb_mod_module_eval in vm_eval.c 것을 우리는 볼 수 있습니다.

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 = &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는 소스 코드 문자열을 컴파일하는 데 사용됩니다 : 그 scope이에 의해 처리됩니다. 나는 MRI 소스에 대단히 익숙하지 않다. 그러나 그것은 의도적으로 범위를 class_eval에 사용하도록 설정 한 것처럼 보인다.당신은 혼자가 이름을두면

[:"pancakes house", {:type=>String}] 
"pancakes house" 

하지만 문자열 인수 field 전화 :

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 

말할 것이다 :

단순화 된 예는 도움이 될 다음

def eval_mongo(klass, field) 
    klass.class_eval <<-EOS 
    field '#{field}', type: String 
    field 
    EOS 
end 

그것도 작동하고있다 :

(210)
["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" 
기호와 0

:

> s = 'a' :'b' 
SyntaxError: (irb):2: syntax error, unexpected ':', expecting end-of-input 
s = 'a' :'b' 
     ^

아마도 여러 가지 다른 시간에 평가되고 있으며, 문자열이고 무엇을하지 무엇 루비 대해 혼란스러워지고 있습니다.

이 동작은 놀랍고 예기치 않게 발생하므로이 버그 또는 잘못된 기능을 호출하기 때문에 유감스럽게 생각합니다. class_eval의 행동이 (정당화와 의외의 행동에 대한 근거가있는) 더 잘 지정 되었다면 좋을 것입니다.하지만 그것은 루비 문화를 빨리 벗어나는 것처럼 보입니다.

왜 이런 일이 발생하는지 분명히 알 수 있다면 감사하겠습니다.

관련 문제