Our app uses the send
method to call functions on our objects.
Unfortunately, some times the string passed to send
may not be a legit method name in Ruby. Does anyone know of a regexp that would allow us to check this?
And by legit, I mean a method name that doesn't start with "?", etc. I don't care whether the object responds to the method, because we use method_missing
in this case, and we actually want it to be used, which would only happen for methods for which the object doesn't respond.
Technically, I'm looking for a regexp which does this :
Ruby identifiers are consist of alphabets, decimal digits, and the underscore character, and begin with a alphabets(including underscore). There are no restrictions on the lengths of Ruby identifiers.
You can take advantage of the fact that Symbol#inspect
quotes the name when it is not a valid identifier. A valid symbol becomes ":hello!"
when inspected, but an invalid one becomes ":\"invalid!?\""
. This handles exotic symbols like :foo=
, :[]=
, and any other valid method name.
Adding the additional requirement that @
-names are valid identifiers but not valid method names gives us this:
class Symbol
def method_name?
return /[@$"]/ !~ inspect
end
end
What if it is a legit method name, but the method doesn't actually exist on the object you're attempting to send it to?
Either way, you should check that the object responds to a method before attempting to invoke it, no matter if the string is a legit method name of not. You can do this by using the Object#respond_to?
method.
For example:
obj = Person.new
method = "set_name"
if obj.respond_to?(method)
obj.send(method, "foo")
end
If you want to make sure a string is a legit method name you'd want to use regular expressions.. something like /^([a-zA-Z_]+|\[\])[\?!=]?$/
should work for general methods. Regardless my point still stands for making sure this object responds to a method name
Ruby method identifiers allowed in source code can be matched by this:
# Yes, upper-case first letters are legal
/\A(?:[a-z_]\w*[?!=]?|\[\]=?|<<|>>|\*\*|[!~+\*\/%&^|-]|[<>]=?|<=>|={2,3}|![=~]|=~)\z/i
However, note that methods may be defined that don't match this pattern:
class Foo
define_method("!dumb~name"){ puts "yup" }
end
Foo.new.send('!dumb~name')
#=> yup
Edit: Updated to add all the Operator Expressions.
I'm not so sure regexp is the way to go here but here's a try
def could_be_method_name?(m)
match = /^([a-zA-Z_]([\w]*[\w!?=]$){0,1})/.match(m)
return match == nil ? false : match[1].length==m.length
end
Ruby method names must start with a letter or an underscore. They can only contain alphanumeric characters but the last character is allowed to also be !, ?, or =.
精彩评论