significa rails que metodos funciones ejemplos def ruby hidden-features

rails - que significa en ruby



Características ocultas de Ruby (30)

Continuando con el meme de "Funciones ocultas de ...", compartamos las características menos conocidas pero útiles del lenguaje de programación Ruby.

Trata de limitar esta discusión con el núcleo de Ruby, sin nada de Ruby on Rails.

Ver también:

(Por favor, solo una característica oculta por respuesta).

Gracias


module_function

Los métodos de módulo que se declaran como función_de_módulo crearán copias de ellos mismos como métodos de instancia privada en la clase que incluye el Módulo:

module M def not! ''not!'' end module_function :not! end class C include M def fun not! end end M.not! # => ''not! C.new.fun # => ''not!'' C.new.not! # => NoMethodError: private method `not!'' called for #<C:0x1261a00>

Si usa module_function sin ningún argumento, entonces cualquier método de módulo que venga después de la sentencia module_function se convertirá automáticamente en module_functions.

module M module_function def not! ''not!'' end def yea! ''yea!'' end end class C include M def fun not! + '' '' + yea! end end M.not! # => ''not!'' M.yea! # => ''yea!'' C.new.fun # => ''not! yea!''


Advertencia: este artículo fue votado como el truco número 1 más horrendo de 2008 , así que úselo con cuidado. En realidad, evítelo como la peste, pero sin duda es Hidden Ruby.

Los superadores agregan nuevos operadores a Ruby

¿Alguna vez ha querido un operador súper secreto de handshake para alguna operación única en su código? Me gusta jugar al golf de código? Pruebe operadores como - ~ + ~ - o <--- Ese último se usa en los ejemplos para invertir el orden de un artículo.

No tengo nada que ver con el Proyecto Superators más allá de admirarlo.


De Ruby 1.9 Proc # === es un alias de la llamada Proc #, lo que significa que los objetos Proc se pueden usar en sentencias case como esta:

def multiple_of(factor) Proc.new{|product| product.modulo(factor).zero?} end case number when multiple_of(3) puts "Multiple of 3" when multiple_of(7) puts "Multiple of 7" end


Descargue la fuente de Ruby 1.9 y publique make golf , entonces puede hacer cosas como esta:

make golf ./goruby -e ''h'' # => Hello, world! ./goruby -e ''p St'' # => StandardError ./goruby -e ''p 1.tf'' # => 1.0 ./goruby19 -e ''p Fil.exp(".")'' "/home/manveru/pkgbuilds/ruby-svn/src/trunk"

Lee el golf_prelude.c para obtener más cosas ordenadas que se esconden.


El binario "ruby" (al menos las imágenes de resonancia magnética) es compatible con muchos de los conmutadores que hacen que los one-liners de Perl sean bastante populares.

Significativos:

  • -n Configura un bucle externo con solo "obtiene", que mágicamente funciona con el nombre de archivo dado o STDIN, configurando cada línea de lectura en $ _
  • -p Similar a -n pero con una posición automática s al final de cada ciclo de iteración
  • - Una llamada automática a .split en cada línea de entrada, almacenada en $ F
  • -i Archivos de entrada de edición in situ
  • -l Llamada automática a .chomp en la entrada
  • -e Ejecutar un fragmento de código
  • -c Verificar el código fuente
  • -w Con advertencias

Algunos ejemplos:

# Print each line with its number: ruby -ne ''print($., ": ", $_)'' < /etc/irbrc # Print each line reversed: ruby -lne ''puts $_.reverse'' < /etc/irbrc # Print the second column from an input CSV (dumb - no balanced quote support etc): ruby -F, -ane ''puts $F[1]'' < /etc/irbrc # Print lines that contain "eat" ruby -ne ''puts $_ if /eat/i'' < /etc/irbrc # Same as above: ruby -pe ''next unless /eat/i'' < /etc/irbrc # Pass-through (like cat, but with possible line-end munging): ruby -p -e '''' < /etc/irbrc # Uppercase all input: ruby -p -e ''$_.upcase!'' < /etc/irbrc # Same as above, but actually write to the input file, and make a backup first with extension .bak - Notice that inplace edit REQUIRES input files, not an input STDIN: ruby -i.bak -p -e ''$_.upcase!'' /etc/irbrc

Siéntase libre de googlear "ruby one-liners" y "perl one-liners" para obtener más ejemplos utilizables y prácticos. En esencia, le permite usar ruby ​​como un reemplazo bastante poderoso para awk y sed.


El método send () es un método de uso general que se puede usar en cualquier clase u objeto en Ruby. Si no se reemplaza, send () acepta una cadena y llama al nombre del método cuya cadena se pasa. Por ejemplo, si el usuario hace clic en el botón "Clr", la cadena "press_clear" se enviará al método send () y se llamará al método "press_clear". El método send () permite una forma divertida y dinámica de llamar funciones en Ruby.

%w(7 8 9 / 4 5 6 * 1 2 3 - 0 Clr = +).each do |btn| button btn, :width => 46, :height => 46 do method = case btn when /[0-9]/: ''press_''+btn when ''Clr'': ''press_clear'' when ''='': ''press_equals'' when ''+'': ''press_add'' when ''-'': ''press_sub'' when ''*'': ''press_times'' when ''/'': ''press_div'' end number.send(method) number_field.replace strong(number) end end

Hablo más sobre esta característica en Blogging Shoes: The Simple-Calc Application


Engañar a alguna clase o módulo diciéndole que ha requerido algo que realmente no ha requerido:

$" << "something"

Esto es útil, por ejemplo, cuando se requiere A que, a su vez, requiere B, pero no necesitamos B en nuestro código (y A no lo usará a través de nuestro código):

Por ejemplo, bdrb_test_helper requires de bdrb_test_helper requires ''test/spec'' , pero no lo usa en absoluto, entonces en su código:

$" << "test/spec" require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")


Gran parte de la magia que ves en Rubyland tiene que ver con la metaprogramación, que es simplemente escribir código que escribe código para ti. El attr_accessor , attr_reader y attr_writer son todos metaprogramación simple, ya que crean dos métodos en una línea, siguiendo un patrón estándar. Rails realiza una gran cantidad de metaprogramación con sus métodos de administración de relaciones como has_one y belongs_to .

Pero es bastante simple crear tus propios trucos de metaprogramación usando class_eval para ejecutar código escrito dinámicamente.

El siguiente ejemplo permite que un objeto envoltorio reenvíe ciertos métodos a un objeto interno:

class Wrapper attr_accessor :internal def self.forwards(*methods) methods.each do |method| define_method method do |*arguments, &block| internal.send method, *arguments, &block end end end forwards :to_i, :length, :split end w = Wrapper.new w.internal = "12 13 14" w.to_i # => 12 w.length # => 8 w.split(''1'') # => ["", "2 ", "3 ", "4"]

El método Wrapper.forwards toma símbolos para los nombres de los métodos y los almacena en la matriz de methods . Luego, para cada uno de los dados, usamos define_method para crear un nuevo método cuyo trabajo es enviar el mensaje, incluidos todos los argumentos y bloques.

Un gran recurso para los problemas de metaprogramación es por qué The Lucky Stiff "Ver Metaprogramación Claramente" .


Hashes con valores predeterminados! Una matriz en este caso.

parties = Hash.new {|hash, key| hash[key] = [] } parties["Summer party"] # => [] parties["Summer party"] << "Joe" parties["Other party"] << "Jane"

Muy útil en la metaprogramación.



La función Symbol # to_proc que proporciona Rails es realmente genial.

En lugar de

Employee.collect { |emp| emp.name }

Puedes escribir:

Employee.collect(&:name)


Llego tarde a la fiesta, pero:

Puede tomar fácilmente dos matrices de igual longitud y convertirlas en hash con una matriz que proporciona las claves y la otra los valores:

a = [:x, :y, :z] b = [123, 456, 789] Hash[a.zip(b)] # => { :x => 123, :y => 456, :z => 789 }

(Esto funciona porque Array # zip "comprime" los valores de las dos matrices:

a.zip(b) # => [[:x, 123], [:y, 456], [:z, 789]]

Y Hash [] puede tomar una matriz así. He visto a gente hacer esto también:

Hash[*a.zip(b).flatten] # unnecessary!

Lo cual produce el mismo resultado, pero el splat y flatten son totalmente innecesarios, ¿quizás no estaban en el pasado?


Me parece que usar el comando define_method para generar dinámicamente métodos es bastante interesante y no tan conocido. Por ejemplo:

((0..9).each do |n| define_method "press_#{n}" do @number = @number.to_i * 10 + n end end

El código anterior usa el comando ''define_method'' para crear dinámicamente los métodos "press1" a "press9". En lugar de escribir los 10 métodos que contienen el mismo código, el comando definir método se usa para generar estos métodos sobre la marcha según sea necesario.


No sé qué tan oculto es esto, pero lo he encontrado útil cuando necesito hacer un hash fuera de una matriz unidimensional:

fruit = ["apple","red","banana","yellow"] => ["apple", "red", "banana", "yellow"] Hash[*fruit] => {"apple"=>"red", "banana"=>"yellow"}


Operadores booleanos en valores no booleanos

&& y ||

Ambos devuelven el valor de la última expresión evaluada.

Por eso, ||= actualizará la variable con la expresión de valor devuelto en el lado derecho si la variable no está definida. Esto no está documentado explícitamente, sino que es de conocimiento común.

Sin embargo, el &&= no es tan conocido.

string &&= string + "suffix"

es equivalente a

if string string = string + "suffix" end

Es muy útil para operaciones destructivas que no deberían continuar si la variable no está definida.


Otra adición divertida en la funcionalidad 1.9 Proc es Proc # curry, que le permite convertir un Proc aceptando n argumentos en uno aceptando n-1. Aquí se combina con la sugerencia de Proc # === que mencioné anteriormente:

it_is_day_of_week = lambda{ |day_of_week, date| date.wday == day_of_week } it_is_saturday = it_is_day_of_week.curry[6] it_is_sunday = it_is_day_of_week.curry[0] case Time.now when it_is_saturday puts "Saturday!" when it_is_sunday puts "Sunday!" else puts "Not the weekend" end


Otra pequeña característica: convertir un Fixnum en cualquier base de hasta 36:

>> 1234567890.to_s(2) => "1001001100101100000001011010010" >> 1234567890.to_s(8) => "11145401322" >> 1234567890.to_s(16) => "499602d2" >> 1234567890.to_s(24) => "6b1230i" >> 1234567890.to_s(36) => "kf12oi"

Y como ha comentado Huw Walters, la conversión al revés es igual de simple:

>> "kf12oi".to_i(36) => 1234567890


Peter Cooper tiene una buena lista de trucos de Ruby. Quizás mi favorito es permitir que se enumeren tanto los artículos individuales como las colecciones. (Es decir, tratar un objeto que no es de colección como una colección que contiene solo ese objeto). Se ve así:

[*items].each do |item| # ... end


Un truco que me gusta es usar el expansor splat ( * ) en objetos que no sean Arrays. Aquí hay un ejemplo de una coincidencia de expresión regular:

match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)

Otros ejemplos incluyen:

a, b, c = *(''A''..''Z'') Job = Struct.new(:name, :occupation) tom = Job.new("Tom", "Developer") name, occupation = *tom


Una de las mejores cosas de Ruby es que puedes invocar métodos y ejecutar código en lugares que otros lenguajes ignorarían, como en el método o las definiciones de clases.

Por ejemplo, para crear una clase que tenga una superclase desconocida hasta el tiempo de ejecución, es decir, que sea aleatoria, podría hacer lo siguiente:

class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample end RandomSubclass.superclass # could output one of 6 different classes.

Esto usa el método de Array#sample 1.9 Array#sample (en 1.8.7-only, vea la Array#choice ), y el ejemplo es bastante artificial, pero puede ver el poder aquí.

Otro buen ejemplo es la capacidad de poner valores de parámetros predeterminados que no son fijos (como suelen exigir otros lenguajes):

def do_something_at(something, at = Time.now) # ... end

Por supuesto, el problema con el primer ejemplo es que se evalúa en tiempo de definición, no en tiempo de llamada. Entonces, una vez que se ha elegido una superclase, permanece esa superclase para el resto del programa.

Sin embargo, en el segundo ejemplo, cada vez que llame a do_something_at , la variable at será el momento en que se llamó al método (bueno, muy muy cerca)


Uno final: en ruby ​​puede usar cualquier caracter que quiera para delimitar cadenas. Toma el siguiente código:

message = "My message" contrived_example = "<div id=/"contrived/">#{message}</div>"

Si no quiere escapar de las comillas dobles dentro de la cadena, puede simplemente usar un delimitador diferente:

contrived_example = %{<div id="contrived-example">#{message}</div>} contrived_example = %[<div id="contrived-example">#{message}</div>]

Además de evitar tener que escanear delimitadores, puede usar estos delimitadores para cadenas multilínea más bonitas:

sql = %{ SELECT strings FROM complicated_table WHERE complicated_condition = ''1'' }



Wow, nadie mencionó el operador de flip flop:

1.upto(100) do |i| puts i if (i == 3)..(i == 15) end


crea una matriz de números consecutivos:

x = [*0..5]

establece x a [0, 1, 2, 3, 4, 5]


use cualquier cosa que responda a ===(obj) para las comparaciones de casos:

case foo when /baz/ do_something_with_the_string_matching_baz when 12..15 do_something_with_the_integer_between_12_and_15 when lambda { |x| x % 5 == 0 } # only works in Ruby 1.9 or if you alias Proc#call as Proc#=== do_something_with_the_integer_that_is_a_multiple_of_5 when Bar do_something_with_the_instance_of_Bar when some_object do_something_with_the_thing_that_matches_some_object end

Module (y, por lo tanto, la Class ), Regexp , Date y muchas otras clases definen un método de instancia: === (otro), y todos pueden utilizarse.

Gracias a Farrel por el recordatorio de que Proc#call recibió un alias como Proc#=== en Ruby 1.9.


Class.new()

Crea una nueva clase en tiempo de ejecución. El argumento puede ser una clase de la cual derivar, y el bloque es el cuerpo de la clase. Es posible que también desee ver const_set/const_get/const_defined? para obtener su nueva clase debidamente registrada, para que inspect imprima un nombre en lugar de un número.

No es algo que necesita todos los días, pero es bastante útil cuando lo hace.


Fixnum#to_s(base) puede ser realmente útil en algún caso. Uno de estos casos es la generación de tokens aleatorios (pseudo) únicos mediante la conversión de un número aleatorio a una cadena con una base de 36.

Token de longitud 8:

rand(36**8).to_s(36) => "fmhpjfao" rand(36**8).to_s(36) => "gcer9ecu" rand(36**8).to_s(36) => "krpm0h9r"

Token de longitud 6:

rand(36**6).to_s(36) => "bvhl8d" rand(36**6).to_s(36) => "lb7tis" rand(36**6).to_s(36) => "ibwgeh"


Definir un método que acepte cualquier cantidad de parámetros y que simplemente los descarte a todos

def hello(*) super puts "hello!" end

El método hello anterior solo necesita puts "hello" en la pantalla y llamar a super - pero dado que la superclase hello define los parámetros que tiene, sin embargo, dado que en realidad no necesita usar los parámetros en sí, no tiene para darles un nombre.


Destructuring a Array

(a, b), c, d = [ [:a, :b ], :c, [:d1, :d2] ]

Dónde:

a #=> :a b #=> :b c #=> :c d #=> [:d1, :d2]

Usando esta técnica podemos usar la asignación simple para obtener los valores exactos que queremos de la matriz anidada de cualquier profundidad.


Hash auto vivificante en Ruby

def cnh # silly name "create nested hash" Hash.new {|h,k| h[k] = Hash.new(&h.default_proc)} end my_hash = cnh my_hash[1][2][3] = 4 my_hash # => { 1 => { 2 => { 3 =>4 } } }

Esto puede ser muy útil.