¿Cuáles son las restricciones para los nombres de método en Ruby?

Por ejemplo, encontré el bundler? nombre del método bundler? en el siguiente fragmento, y no sé si el ? personaje es una palabra clave especializada o solo parte del nombre del método.

 # This is a predicate useful for the doc:guides task of applications. def bundler? # Note that rake sets the cwd to the one that contains the Rakefile # being executed. File.exists?('Gemfile') end 

Los nombres de los métodos en Ruby pueden contener letras mayúsculas y minúsculas, números, guiones bajos _ y los signos de punteo ! , ? , = .

¡Un nombre de método no puede comenzar con un número y los caracteres ! , ? y = solo puede aparecer al final.

Los caracteres que no son ASCII se pueden usar en el nombre de un método, pero esto puede llevar a situaciones muy confusas y no debe ser una práctica común.

Es una buena práctica, aunque no obligatoria, iniciar el nombre del método con un carácter en minúscula, porque los nombres que comienzan con letras mayúsculas son constantes en Ruby. Todavía es posible usar un nombre constante para un método, pero no podrá invocarlo sin paréntesis, ya que el interperador buscará el nombre como una constante:

 def Capital nil end Capital # NameError: uninitialized constant Capital Capital() # => nil 

Algunas convenciones utilizadas de forma muy amplia y consistente al definir nombres de métodos son:

  1. Los nombres de los métodos están completos en minúsculas, con guiones bajos _ como separadores de palabras en el nombre (p. Ej., Math::sqrt , Array#each_index , …).

  2. Los predicados tienen un signo de interrogación ? como último carácter (por ejemplo, Array#empty? Hash#has_key? …). Mientras que los predicados usualmente devuelven valores booleanos, este no es siempre el caso: estos métodos solo necesitan devolver nil o false si el predicado se evalúa como falso, de lo contrario cualquier otro valor (ej. File::size? Devuelve nil si el archivo no existe, el tamaño del archivo como un Integer contrario).

  3. Los métodos que modifican el estado del objeto en el que se invocan o que tienen un comportamiento inusual tienen un signo de exclamación ! como último personaje; estos métodos a veces se llaman mutadores porque generalmente son versiones destructivas o in situ de otros métodos (por ejemplo, Array#sort! Array#slice! …).

  4. Los Setters tienen un signo igual = como el último carácter (por ejemplo, Array#[]= , …); el interperador Ruby ofrece azúcar sintáctico para la invocación de métodos setter:

     a = [4, 5, 6] a[0] = 3 # Shorthand for a.[]=(0, 3) 

Ruby también permite definir operadores que usan el símbolo del operador como el nombre del método:

 ╔═══════════════════════════╦═════════════════════════════════════════════╦═══════╗ ║ Operators (by precedence) ║ Operations ║ Arity ║ ╠═══════════════════════════╬═════════════════════════════════════════════╬═══════╣ ║ ! ~ + ║ Boolean NOT, bitwise complement, unary plus ║ 1 ║ ║ ║ (define with method name +@, Ruby 1.9+) ║ ║ ║ ║ ║ ║ ║ ** ║ Exponentiation ║ 2 ║ ║ ║ ║ ║ ║ - ║ Unary minus (define with method name -@) ║ 1 ║ ║ ║ ║ ║ ║ * / % ║ Multiplication, division, modulo ║ 2 ║ ║ ║ ║ ║ ║ + - ║ Addition, subtraction ║ 2 ║ ║ ║ ║ ║ ║ << >> ║ Bitwise shift ║ 2 ║ ║ ║ ║ ║ ║ & ║ Bitwise AND ║ 2 ║ ║ ║ ║ ║ ║ | ^ ║ Bitwise OR, Bitwise XOR ║ 2 ║ ║ ║ ║ ║ ║ < <= => > ║ Ordering ║ 2 ║ ║ ║ ║ ║ ║ == === != =~ !~ <=> ║ Equality, pattern matching, comparison ║ 2 ║ ╚═══════════════════════════╩═════════════════════════════════════════════╩═══════╝ 

Los métodos de operador unario se pasan sin argumentos; los métodos del operador binario se pasan un argumento, y operan en él y en self .

Es importante adherirse estrictamente a la aridad de los operadores; si bien es posible definir métodos de operador con una aridad diferente (por ejemplo, un método + que toma dos argumentos), Ruby no le permitiría llamar al método con la syntax del operador (sin embargo, funcionaría con syntax de punto).

Es una buena práctica adherirse a la semántica original de los operadores tanto como sea posible: debe ser intuitiva para alguien que conoce el significado original del operador cómo funciona con las clases definidas por el usuario.

El lenguaje también ofrece azúcar sintáctico para el método especial, sin operador , [] que normalmente se usa para acceder a los valores de matriz y hash. El método [] se puede definir con aridad arbitraria.

Para cada operador binario en la tabla, excepto ordenamiento, igualdad, comparación y coincidencia de patrones, Ruby también ofrece una abreviatura de asignación abreviada (por ejemplo, x += y expande a x = x + y ); no puede definirlos como métodos, pero puede modificar su comportamiento definiendo los operadores en los que se basan.

Ninguno de estos caracteres se puede utilizar dentro de los nombres de métodos normales (por ejemplo, do&print o start-up no son nombres de métodos válidos).

Lo que otros dicen es cierto para la syntax incorporada, sin embargo, parece que no hay restricciones de back-end en lo que se puede usar si usas métodos como define_method + send :

 define_method(:'$% ^&') { 0 } define_method(:'你好') { 1 } send(:'$% ^&') == 0 or raise send(:'你好') == 1 or raise 

Este hecho puede ser útil: por ejemplo, el método ActiveSupport :: Testing :: Declarative.test de Rails lo usa para no realizar conversiones complejas en:

 test 'Some Controller#Method' do 

a un nombre más seguro, que podría entrar en conflicto con otra prueba llamada:

 test 'Some Controller_Method' do 

Esto se menciona en la Guía de prueba .

Curiosidad: algo similar sucede en Java, donde el nombre del método bytecode da lugar a más opciones que el lenguaje Java: ¿Por qué la JVM nos permite nombrar una función que comienza con un dígito en bytecode?

¡Los nombres de los métodos pueden terminar ! , ? o = . Los subrayados también están permitidos. Además de eso, hay varios métodos que se parecen a los operadores (por ejemplo, + , * , >> , [] ) que puede definir para sus propias clases.

Para agregar una cosa: también puedes decirle a un objeto que ejecute un método sin ningún nombre e intentará invocar un método llamado call :

 #!/usr/bin/env ruby class Foo =begin def call(*args) puts "received call with #{args.join(' ')}" end =end def method_missing(m, *args, &block) puts "received method_missing on `#{m}(#{args.join(', ')})`" end end f = Foo.new f.('hi') # Not a syntax error! method_missing with m of :call f.send :'', 'hmm' # method_missing with m set to :'' f.send nil, 'bye' # raises an error 

En realidad, no hay ningún método llamado call definido en Object , pero hay uno en las clases Method y Proc .

En algunos idiomas () es un operador para la invocación de funciones, y eso parece bastante similar a lo que está sucediendo aquí.

Esto se usa, por ejemplo, en JBuilder de Rails:

https://github.com/rails/jbuilder

Está documentado en la página 196 del libro de O’Reilly Ruby:

Ruby 1.9 ofrece una forma adicional de invocar un objeto Proc ; como alternativa a los corchetes, puede usar paréntesis con el prefijo de un punto:

 z = f.(x,y) 

.() parece una invocación al método al que le falta el nombre del método. Este no es un operador que se puede definir, sino que es un azúcar sintáctico que invoca el método de call . Se puede usar con cualquier objeto que defina un método de call y no está limitado a objetos Proc .