在Ruby中使用eval函数来调用其他函数

时间:2014-02-28 12:29:35

标签: ruby

我正在使用processQuestion函数下面的类来调用其他方法。

通过调用其他类的CONSTANTS来调用此函数。

# Is responsible for executing a particular question. Question types are in the Question object. A question will 
# always have a responding method in this class. That method will take the parameters defined by the question and
# should provide the answer in the format expected.
class QuestionProcessor
  NO_ROUTE = "NO SUCH ROUTE"

  def initialize(routeList)
    @routeList = routeList
  end


  # Finds the method and runs it. This should provide the answer object
  def processQuestion(question)
    return eval("get"+question.command+"(question)")
  end


  # Finds the total distance using the exact stations specified, or returns NO_ROUTE if no route was stored in the route list
  # this method ignores the constraints and actions
  def getDistance(question)
    distance = 0
    currentStation = nil

    question.parameters.each do |nextStation|
      if (! currentStation.nil?)
        route = @routeList.getDirectRoute(currentStation, nextStation)
        if (route.nil?)
          return NO_ROUTE
        end
        distance += route.distance
      end
      currentStation = nextStation;
    end

    return distance;
  end


  # Finds the shortest route possible for the given constraint. This method requires a constraint and action to be provided
  def getShortestRoute(question)
    startStation = question.parameters[0]
    endStation = question.parameters[1]

    routeProcessor = ShortestRouteProcessor.new(@routeList, question.constraint, question.action)
    routeProcessor.getRoute(startStation, endStation)

    return routeProcessor.shortestRoute == Constants::INTEGER_MAX ? NO_ROUTE : routeProcessor.shortestRoute
  end


  # Counts the number of routes based on the condition provided. Intended to count the number of routes, but could potentially provide a total distance
  # or anything else produced by the action.
  def getCountRoutes(question)
    startStation = question.parameters[0]
    endStation = question.parameters[1]

    routeProcessor = RouteProcessor.new(@routeList, question.constraint, question.action)
    routeProcessor.getRoute(startStation, endStation)

    return routeProcessor.totalSuccessfulRoutes 
  end
end

我认为这是保持DRY的好方法,但我听说eval是邪恶的。

这是一种好方法,还是应该以更面向对象的方式寻找其他方法?

2 个答案:

答案 0 :(得分:3)

在这种情况下,您可以安全地使用send代替eval,如下例所示:

def processQuestion(question)
  return send("get#{question.command}", question)
end

请注意,send可能与eval一样危险,如果您没有清理您的输入(在这种情况下为question.command)。

如果可能,请在调用send(或eval)之前执行白名单过滤,否则有人可以传递执行您不想做的事情的命令

答案 1 :(得分:3)

正是因为这个原因,ruby中有一个函数,即send函数。它是Object类的一部分,所以一切都有它。

在这里阅读更多内容: http://ruby-doc.org/core-2.1.1/Object.html#method-i-send

进行元编程我建议你阅读整个教程: https://rubymonk.com/learning/books/2-metaprogramming-ruby/