English 中文(简体)
How to create a method like ".find_by_something_and_something_else" using Ruby?
原标题:

Using Ruby I know you can get pretty creative with how you name your methods. For instance in rails you have .find_by_this_and_that.

How can I do this?

Example:

def get_persons_with_5_things
  res = []
  persons.each do |person|
    if person.number_of_things == %MAGICALLY GET THE NUMBER 5 FROM FUNCTION NAME%
      res << person
    end
  end
  return res
end

I m not even sure how you call this kind of things so any pointers would be appreciated.

问题回答

I m a little confused by your example. If you define the method with the hardcoded 5 in the method name, then you don t need to magically figure it out inside the body of the method. If you want to do something dynamic with method missing, it would be something like this:

def method_missing(name, *args)
  if name.to_s =~ /get_persons_with_(d+)_things/
    number_of_things = $1.to_i
    res = []
    persons.each do |person|
      if person.number_of_things == number_of_things
        res << person
      end
    end
    return res
  else
    return super(name, *args)
  end
end

[EDIT (Jörg W Mittag)]: This is a more Rubyish way of implementing that same method:

def method_missing(name, *args)
  return super unless name.to_s =~ /get_persons_with_(d+)_things/
  number_of_things = $1.to_i
  return persons.select {|person| person.number_of_things == number_of_things }
end
  • super without any arguments just passes the original arguments along, no need to pass them explicitly
  • an early return guarded by a trailing if or unless expression greatly clears up control flow
  • all the each iterator does, is select items according to a predicate; however, there already is an iterator for selecting items: select

Ruby has different meta programming techniches to do this kind of stuff.

First we need our variable method

class DB
  def get_persons_with_x_things(x)
    res = []
    persons.each do |person|
      if person.number_of_things == x
        res << person
      end
    end
    return res
  end
end

define_method

If there is a finite number of x s. We could use define_method to create all this methods. define_method creates a method. The first argument is the name of the method, the seccond argument or the given block is the stuff, which get s executed when the method is called.

This way, you don t realy create such method s, but It will look for the user if he calls it, as if it existed. But if the user relies on Object#methods and such, he will never see your inifinite number of fake methods.

class DB
  99.times do |i|
    define_method("get_persons_with_#{i}_things") do
      get_persons_with_x_things(i)
    end
  end
end

method_missing

If there is an infinite numbor of x s method_missing would be better suited for this Task. If someone tries to call a method which does not exist, method_missing is executed instead. The first argument for method_missing is the method name as symbol, the following arguments are the original arguments.

class DB
  def method_missing(name, *args)
    case name.to_s
    when /^get_persons_with_(d+)_things$/
      get_persons_with_x_things($1.to_i)
    else
      super(name, *args)
    end
  end
end

method_missing and send

To not use static regexe would be even cooler. But this could have some security implications. The method send I use here, calls a method by it s name.

class DB
  def method_missing(name, *args)
    name.to_s=~ /d+/
# always be carefull with $ variables, they are global for this thread, so save everything as fast as you can
    new_name= "#{$`}x#{$ }"
    number= $1.to_i
    if method_defined?(new_name)
      send(new_name, number)
    else
      super(name, *args)
    end
  end
end

you can do a lot of things like this with method missing:

Ruby Docs

StackOveflow method_missing

Have a look at Ruby s callbacks specially method_missing.





相关问题
Ruby parser in Java

The project I m doing is written in Java and parsers source code files. (Java src up to now). Now I d like to enable parsing Ruby code as well. Therefore I am looking for a parser in Java that parses ...

rails collection_select vs. select

collection_select and select Rails helpers: Which one should I use? I can t see a difference in both ways. Both helpers take a collection and generates options tags inside a select tag. Is there a ...

RubyCAS-Client question: Rails

I ve installed RubyCAS-Client version 2.1.0 as a plugin within a rails app. It s working, but I d like to remove the ?ticket= in the url. Is this possible?

Ordering a hash to xml: Rails

I m building an xml document from a hash. The xml attributes need to be in order. How can this be accomplished? hash.to_xml

multiple ruby extension modules under one directory

Can sources for discrete ruby extension modules live in the same directory, controlled by the same extconf.rb script? Background: I ve a project with two extension modules, foo.so and bar.so which ...

Text Editor for Ruby-on-Rails

guys which text editor is good for Rubyonrails? i m using Windows and i was using E-Texteditor but its not free n its expired now can anyone plese tell me any free texteditor? n which one is best an ...

热门标签