2015-02-28 2 views
0

У меня есть функция, как это:не в состоянии сделать класс (аргумент) с Eval рубина

def check_if_correct_type(type, value) 
    # nil.test! 
    # eval(type.classify(value)) rescue return false 
    # true 
    case type 
    when "integer" 
     !!Integer(value) rescue return false 
    when "float" 
     !!Float(value) rescue return false 
    else 
     return true 
    end 
    true 
end 

Образец будет

check_if_correct_type("integer", "a") 

Я попытался изменить функцию так:

check_if_correct_type(type, value) 
    !!(eval(type.classify(value))) rescue return false 
    true 
end 

Это ошибка. Как это исправить. Я довольно новичок в мета-программировании, так что потерялся.


Update 1:

"adfadf".kind_of?(String) #=> true 
123.kind_of?(String)  #=> false 

# The "Fixnum" class is actually used for integers 
"adfadf".kind_of?(Fixnum) #=> false 
123123.kind_of?(Fixnum) #=> true 

12.3.kind_of?(Float)  #=> true 
"sadf".kind_of?(Float) #=> false 
12.kind_of?(Float)  #=> false 

выше не будет работать для меня, как kind_of? функция будет найти тип объекта, где, как для меня ответ требует, чтобы быть похожим на это:

check_if_correct_type("integer", "1221") #=> true 
check_if_correct_type("float", "1.24") #=> true 
check_if_correct_type("string", "asds12") #=> true 
check_if_correct_type("float", "asdasd1.24") #=> false 

где, как

"1,24" .kind_of (Float) # => ложный

? Вот почему преобразование работает для меня. Надеюсь, теперь вопрос более ясен.


Update 2:

Это то, что я получаю, если я использую общественный посыл.

!! public_send ("целое число" .capitalize ("1")) ArgumentError: неправильное количество аргументов (1 для 0) из (Поддеть): 4: в capitalize' [5] pry(main)> !!public_send("integer".classify("1")) ArgumentError: wrong number of arguments (1 for 0) from /home/aravind/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activesupport-4.2.0/lib/active_support/core_ext/string/inflections.rb:187:in КЛАССИФИЦИРУЙТЕ»

Примечание: классифицировать является частью Ruby on Rails, а не Ruby.

+0

Обратите внимание, что 'Kernel # Integer' и 'Kernel # Float' являются * конверсионными * методами и ограниченным использованием для проверки типов. 'Integer (2.5)' возвращает '2', хотя' 2.5' не является целым числом, а 'Integer (Time.new)' возвращает количество секунд. – Stefan

+0

Откуда берется 'value' и что означает' check_if_correct_type'? Как он используется? – Stefan

+0

@Stefan Проверьте вопрос сейчас, я обновил. – Aravind

ответ

0

Это, как я в конечном итоге решить мою проблему

def check_if_correct_type(type, value) 
    !!eval("#{type.classify}(value)") rescue return false 
    true 
end 

Пример вывода для этой функции ниже упаковывают вы интересно, если это слова или не

[25] pry(main)> value = "1" 
=> "1" 
[26] pry(main)> !!eval("#{type.classify}(value)") 
=> true 
[27] pry(main)> value = "a" 
=> "a" 
[28] pry(main)> !!eval("#{type.classify}(value)") 
ArgumentError: invalid value for Float(): "a" 
from (pry):28:in `eval' 
[29] pry(main)> value = "1.4" 
=> "1.4" 
[30] pry(main)> type = "integer" 
=> "integer" 
[31] pry(main)> !!eval("#{type.classify}(value)") 
ArgumentError: invalid value for Integer(): "1.4" 
from (pry):31:in `eval' 
+0

Вам следует избегать использования 'eval', см. [Ответ Jörg W Mittag] (http: //stackoverflow.com/a/28789815/477037) для альтернативы. – Stefan

0

Я не вижу смысла использовать метапрограммирование для этого примера. Вы не должны использовать его там, где это не нужно. Вообще говоря, логика вашей программы должна быть:

a) Проверьте тип введенного значения. b) Сравните тип с типом, введенным в качестве аргумента. Или в коде:

def check_if_correct_type(type, value) 
    actual_type = value.class.name 
    return actual_type.downcase == type.downcase 
end 

p check_if_correct_type('string', 'test') #=> true 
p check_if_correct_type('integer', 'test2') #=> false 

Это может можно было бы сделать еще короче в одной строке, но сделал это в двух более ясно, что происходит на демонстрации.

+0

Код OP будет возвращать 'true' для' check_if_correct_type ('integer', '123') ' – Stefan

+0

' "test" .class.name => "String" [4] pry (main)> "1.2". class.name => "String" ' Это не то, что я хочу. – Aravind

0

Если вы хотите, чтобы проверить класс объекта, правильный путь заключается в следующем:

"adfadf".kind_of?(String) #=> true 
123.kind_of?(String)  #=> false 

# The "Fixnum" class is actually used for integers 
"adfadf".kind_of?(Fixnum) #=> false 
123123.kind_of?(Fixnum) #=> true 

12.3.kind_of?(Float)  #=> true 
"sadf".kind_of?(Float) #=> false 
12.kind_of?(Float)  #=> false 

Там нет причин быть с помощью Integer() или Float() методов для проверки типа. Это методы преобразования , они преобразуют другие типы в Float или Fixnum. Если вы хотите попробовать преобразовать тип, он может быть конвертирован в Float или numeric, это один из способов сделать это, но могут быть лучшие способы.

В общем, вы никогда не планируете поднимать и спасать исключение как часть обычного потока программы; одна причина заключается в том, что она очень медленная.Исключения должны использоваться для ошибок и необычных/исключительных условий, а не для обычных условий, при которых часто возникают исключения.

И определенно не начинайте приносить eval в это, geez, почему бы вам это сделать?

+0

Это не сработает для меня, см. Обновленный вопрос. – Aravind

+0

Также посмотрите на то, что avdi должно сказать об этом использовании http: // stackoverflow.com/a/1235876/2143985 – Aravind

+1

Одной из проблем с использованием исключений для рутинного управления потоком является то, что он очень медленный в рубине - особенно в Jruby. Это может не иметь значения для вашей программы в зависимости от того, как часто вы это делаете, но это то, о чем нужно знать. Теоретический аргумент «исключения не должны использоваться для управления потоком только потому, что« не имеет для меня большого значения, но последствия для производительности - это то, о чем нужно знать. – jrochkind

1

Я предлагаю вам написать свой метод следующим образом:

def correct_type?(type, str) 
    case type.downcase 
    when "integer" 
    !!to_integer(str) 
    when "float" 
    !!to_float(str) 
    else 
    raise ArgumentError, "type must be 'integer' or 'float'" 
    end 
end 

где to_integer(value) (to_float(value)) представляет собой метод, который возвращает value.to_i (value.to_f), если value является строковым представлением целого числа (с плавающей точкой), в противном случае возвращает nil. Методы to_integer и to_float полезны, потому что они сообщают вам, может ли строка быть преобразована в заданный числовой тип, и если да, то вы можете дать числовое значение.

Прежде чем рассматривать, как вы можете реализовать to_integer и to_float, я хотел бы поставить под вопрос необходимость использования correct_type?. Вместо того, чтобы:

str = "33" 
if correct_type?("integer", str) 
    n = str.to_i 
    puts n 
else 
    ... 
end 

не было бы лучше написать:

if (n = to_integer("33")) 
    puts n 
else 
    ... 
end 

Есть два основных способа написания методов to_integer и to_float. Первый подход вы взяли:

def to_integer(str) 
    raise ArgumentError unless str.is_a? String 
    s = str.gsub(/\s/,'') 
    Integer(s) rescue nil 
end 

def to_float(str) 
    raise ArgumentError unless str.is_a? String 
    s = str.gsub(/\s/,'') 
    return nil if to_integer(s) 
    Float(s) rescue nil 
end 

to_integer("3")  #=> 3 
to_integer("-3") #=> -3 
to_integer("+ 3") #=> 3 
to_integer("cat") #=> nil 
to_integer("3.14") #=> nil 
to_integer(:cat) #=> ArgumentError: ArgumentError 

to_float("3.14") #=> 3.14 
to_float("-3.14") #=> -3.14 
to_float("+ 3.14") #=> 3.14 
to_float("cat")  #=> nil 
to_float("3")  #=> nil 
to_float(:cat)  #=> ArgumentError: ArgumentError 

Второй подход заключается в использовании регулярное выражение:

def to_integer(str) 
    raise ArgumentError unless str.is_a? String 
    s = str.gsub(/\s/,'') 
    s[/^[+-]?\s*\d+$/] ? s.to_i : nil 
end 

def to_float(str) 
    raise ArgumentError unless str.is_a? String 
    s = str.gsub(/\s/,'') 
    return nil if to_integer(s) 
    s[/^[+-]?\s*\d+\.\d+$/] ? s.to_f : nil 
end 

to_integer("3")  #=> 3 
to_integer("-3") #=> -3 
to_integer("+ 3") #=> 3 
to_integer("cat") #=> nil 
to_integer("3.14") #=> nil 
to_integer(:cat) #=> ArgumentError: ArgumentError 

to_float("3.14") #=> 3.14 
to_float("-3.14") #=> -3.14 
to_float("+ 3.14") #=> 3.14 
to_float("cat")  #=> nil 
to_float("3")  #=> nil 
to_float(:cat)  #=> ArgumentError: ArgumentError 
1

Там нет необходимости использовать eval, чтобы отправить сообщение. Вы можете просто использовать send вместо:

def check_if_correct_type(type, value) 
    !!send(type.capitalize, value) rescue return false 
    true 
end 

Примечания: нет метода с именем classify где-нибудь либо в основной библиотеке Ruby, или стандартные библиотеках Руби. Заметим также, что это очень плохая идея, просто слепо поймать все исключения.

+1

'classify' является частью библиотеки Ruby on Rails и работает. – Aravind

+2

@ Aravind: если у вас есть вопрос о Rails, вы должны пометить свой вопрос с помощью [tag: ruby-on-rails], и если вы используете методы из сторонних библиотек, вы должны упомянуть об этом в своем вопросе. Многие люди, которые знают Ruby, не знают Rails, поэтому вы исключаете, что многие люди помогают вам, если вы не упомянули что-то подобное. –

+0

Получил это в следующий раз – Aravind

Смежные вопросы