无法在ruby中使用eval进行Class(参数)

时间:2015-02-28 18:50:52

标签: ruby eval metaprogramming

我有这样的功能:

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

这是抛出错误。我该如何解决。我对元编程很陌生,所以有点迷失。


更新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

以上对我来说不合适吗?函数将找到对象的类型,对于我来说,答案需要如下:

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?(浮动)#=>假

这就是为什么转换对我有用。希望现在问题更清楚了。


更新2:

如果我使用公开发送,这就是我得到的。

!! public_send( “整数” .capitalize( “1”)) ArgumentError:参数数量错误(1表示0) from(pry):4:in 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 classify'

注意:classify是Ruby on Rails的一部分,而不是Ruby。

5 个答案:

答案 0 :(得分: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_ivalue.to_f)的方法,如果value是整数的字符串表示形式(浮点数) ,否则返回nil。方法to_integerto_float非常有用,因为它们可以告诉您字符串是否可以转换为给定的数字类型,如果可以,则为您提供数值。

在考虑如何实施to_integerto_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_integerto_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 :(得分:1)

无需使用eval发送消息。您只需使用send

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

注意:Ruby核心库或Ruby标准库中没有任何名为classify的方法。还要注意,只是盲目地捕捉所有异常是一个非常糟糕的主意。

答案 2 :(得分: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

这可以在一行中缩短,但在两行中做得更清楚,以更清楚地说明发生了什么。

答案 3 :(得分: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或数字,这是一种方法,但可能有更好的方法。

一般而言,作为普通计划流程的一部分,您绝不应该计划提出和拯救例外;一个原因是因为它很慢。异常应该用于错误和异常/异常情况,而不是常规条件,以便经常引起异常。

绝对不要开始将eval带入其中,geez为什么要这样做呢?

答案 4 :(得分: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'