Pergunta

Uma coisa que eu amo sobre ruby ??é que a maioria é uma linguagem muito legível (que é ótimo para código de auto-documentando)

No entanto, inspirado por esta pergunta: código Ruby explicou ea descrição de como ||= trabalha em rubi, eu estava pensando sobre os idiomas de rubi que não usam, como francamente, eu não grok-los totalmente.

Então, minha pergunta é, semelhante ao exemplo da questão referenciados, o que comum, mas não é óbvio, expressões idiomáticas rubi que eu preciso estar ciente de que ser um programador ruby ??realmente proficientes?

A propósito, a partir da pergunta referenciada

a ||= b 

é equivalente a

if a == nil || a == false
  a = b
end

(graças a Ian Terrell para a correção)

Editar: Acontece que este ponto não é totalmente incontroverso. A expansão correta é na verdade

(a || (a = (b))) 

Veja estas ligações para isso:

Graças à Jörg W Mittag para apontar isto.

Foi útil?

Solução

A magia se cláusula que permite que o mesmo arquivo servir como uma biblioteca ou um script:

if __FILE__ == $0
  # this library may be run as a standalone script
end

embalar e desembalar matrizes:

# put the first two words in a and b and the rest in arr
a,b,*arr = *%w{a dog was following me, but then he decided to chase bob}
# this holds for method definitions to
def catall(first, *rest)
  rest.map { |word| first + word }
end
catall( 'franken', 'stein', 'berry', 'sense' ) #=> [ 'frankenstein', 'frankenberry', 'frankensense' ]

O açúcar syntatical para hashes como argumentos de método

this(:is => :the, :same => :as)
this({:is => :the, :same => :as})

initializers Hash:

# this
animals = Hash.new { [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {}
# is not the same as this
animals = Hash.new { |_animals, type| _animals[type] = [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]}

metaclass sintaxe

x = Array.new
y = Array.new
class << x
  # this acts like a class definition, but only applies to x
  def custom_method
     :pow
  end
end
x.custom_method #=> :pow
y.custom_method # raises NoMethodError

variáveis ??de instância de classe

class Ticket
  @remaining = 3
  def self.new
    if @remaining > 0
      @remaining -= 1
      super
    else
      "IOU"
    end
  end
end
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> "IOU"

Blocos, procs e lambdas. Viver e respirar-los.

 # know how to pack them into an object
 block = lambda { |e| puts e }
 # unpack them for a method
 %w{ and then what? }.each(&block)
 # create them as needed
 %w{ I saw a ghost! }.each { |w| puts w.upcase }
 # and from the method side, how to call them
 def ok
   yield :ok
 end
 # or pack them into a block to give to someone else
 def ok_dokey_ok(&block)
    ok(&block)
    block[:dokey] # same as block.call(:dokey)
    ok(&block)
 end
 # know where the parentheses go when a method takes arguments and a block.
 %w{ a bunch of words }.inject(0) { |size,w| size + 1 } #=> 4
 pusher = lambda { |array, word| array.unshift(word) }
 %w{ eat more fish }.inject([], &pusher) #=> ['fish', 'more', 'eat' ]

Outras dicas

Este slideshow é bastante completo sobre os principais idiomas do rubi, como em:

  • Trocar dois valores:

    x, y = y, x

  • Parâmetros que, se não especificado, assumir algum valor padrão

    def somemethod(x, y=nil)

  • lote em parâmetros estranhos em uma matriz

    def substitute(re, str, *rest)

E assim por diante ...

Alguns mais idiomas:

O uso dos %w, %r e %( delimitadores

%w{ An array of strings %}
%r{ ^http:// }
%{ I don't care if the string has 'single' or "double" strings }

comparação Digite instruções case

def something(x)
  case x
    when Array
      # Do something with array
    when String
      # Do something with string
    else
      # You should really teach your objects how to 'quack', don't you?
  end
end

... e abuso geral do método === nas demonstrações de casos

case x
  when 'something concrete' then ...
  when SomeClass then ...
  when /matches this/ then ...
  when (10...20) then ...
  when some_condition >= some_value then ...
  else ...
end

Algo que deve olhar natural para Rubistas, mas talvez não tão para pessoas que vêm de outras línguas: o uso de each em favor de for .. in

some_iterable_object.each{|item| ... }

Em Ruby 1.9+, Rails, ou remendando o método # to_proc Símbolo, este está se tornando uma expressão cada vez mais popular:

strings.map(&:upcase)

método condicional / definição constante

SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT)

métodos de consulta e métodos destrutivos (explosão)

def is_awesome?
  # Return some state of the object, usually a boolean
end

def make_awesome!
  # Modify the state of the object
end

parâmetros splat implícitas

[[1, 2], [3, 4], [5, 6]].each{ |first, second| puts "(#{first}, #{second})" }

I assim:

str = "Something evil this way comes!"
regexp = /(\w[aeiou])/

str[regexp, 1] # <- This

O que é (aproximadamente) equivalente a:

str_match = str.match(regexp)
str_match[1] unless str_match.nil?

Ou pelo menos é o que eu usei para substituir tais blocos.

Gostaria de sugerir a leitura através do código de plugins populares e bem desenhados ou gemas de pessoas que admiro e respeito.

Alguns exemplos eu correr em:

if params[:controller] == 'discussions' or params[:controller] == 'account'
  # do something here
end

correspondente a

if ['account', 'discussions'].include? params[:controller]
  # do something here
end

que mais tarde viria a ser reformulado para

if ALLOWED_CONTROLLERS.include? params[:controller]
  # do something here
end

Eis alguns, abatidos a partir de várias fontes:

uso "a menos" e "até que" em vez de "se não" e "enquanto não". Tente não usar "a menos que" quando uma condição "else" existe, no entanto.

Lembre-se que você pode atribuir várias variáveis ??de uma vez:

a,b,c = 1,2,3

e variável de swap, mesmo sem um temp:

a,b = b,a

Use arrastando condicionais quando apropriado, por exemplo.

do_something_interesting unless want_to_be_bored?

Lembre-se de uma forma comumente usada, mas não imediatamente óbvio (para mim pelo menos) de definir métodos de classe:

class Animal
  class<<self
    def class_method
      puts "call me using Animal.class_method"
    end
  end
end

Algumas referências:

A propósito, a partir da referência pergunta

a ||= b 

é equivalente a

if a == nil   
  a = b 
end

Isso é sutilmente errada, e é uma fonte de erros em aplicações Ruby dos recém-chegados.

Uma vez que tanto (e única) nil e false avaliar a uma falsa boolean, a ||= b é realmente (quase *) equivalente a:

if a == nil || a == false
  a = b
end

Ou, para reescrevê-lo com outra linguagem Ruby:

a = b unless a

(* Uma vez que cada declaração tem um valor, estes não são tecnicamente equivalente a a ||= b. Mas se você não está contando com o valor da declaração, você não vai ver a diferença.)

Eu mantenho uma página wiki que cobre algumas expressões idiomáticas Ruby e formatação:

https://github.com/tokland/tokland/wiki/RubyIdioms

Eu sempre esquecer a sintaxe exata desta forma abreviada se else (eo nome do operador comentários ninguém.?) Eu acho que é fora amplamente utilizado de rubi, mas caso alguém quer a sintaxe aqui está:

refactor < 3 ? puts("No need to refactor YET") : puts("You need to refactor this into a  method")

expande para

if refactor < 3
  puts("No need to refactor YET")
else
  puts("You need to refactor this into a  method")
end

update

chamado o operador ternário:

myvar retorno? myvar.size: 0

Você pode deepcopy com empacotamento objeto facilmente. - tirado de The Ruby Linguagem de programação

def deepcopy(o)
  Marshal.load(Marshal.dump(o))
end

Note que os arquivos e I / O, como fluxos bem como método e vinculativa objetos, são muito dinâmico para ser empacotado; há seria nenhuma maneira confiável para restaurar seu estado.

a = (b && b.attribute) || "default"

é aproximadamente:

if ( ! b.nil? && ! b == false) && ( ! b.attribute.nil? && ! b.attribute.false) a = b
else a = "default"

Eu uso isso quando b é um registro que pode ou pode não ter sido encontrado, e eu preciso para obter um de seus atributos.

Eu gosto de como if-then-elses ou caso quando poderia ser encurtado porque eles retornar um valor:

if test>0
  result = "positive"
elsif test==0
  result = "zero"
else
  result = "negative"
end

poderia ser reescrito

result = if test>0
  "positive"
elsif test==0
  "zero"
else
  "negative"
end

O mesmo poderia ser aplicado ao caso quando:

result = case test
when test>0 ; "positive"
when test==0 ; "zero"
else "negative"
end

Array.pack e String.unpack para trabalhar com arquivos binários:

# extracts four binary sint32s to four Integers in an Array
data.unpack("iiii") 

método faltando magia

class Dummy  
  def method_missing(m, *args, &block)  
    "You just called method with name #{m} and arguments- #{args}"  
  end  
end

Dummy.new.anything(10, 20)
=> "You just called method with name anything and arguments- [10, 20]"

Se você chamar métodos que não existe em objetos Ruby, intérprete Ruby vai chamar método chamado 'method_missing' se a sua definido, você poderia utilizador isso para alguns truques, como escrever wrappers da API, ou DSL, onde você don; t saber tudo métodos e parâmetros nomes

pergunta agradável!

Como eu acho que o mais intuitivo e mais rápido do que o código é, um software melhor que estamos construindo. Eu vou te mostrar como eu expressar meus pensamentos usando Ruby em pequenos trechos de código. Leia mais aqui

Map

Podemos usar o método de mapa de diferentes maneiras:

user_ids = users.map { |user| user.id }

Ou:

user_ids = users.map(&:id)

Amostra

Podemos usar o método rand:

[1, 2, 3][rand(3)]

Aleatório:

[1, 2, 3].shuffle.first

E o idiomática, simples e maneira mais fácil ... amostra!

[1, 2, 3].sample

Duplo Tubo Igual / Memoização

Como você disse na descrição, podemos usar memoization:

some_variable ||= 10
puts some_variable # => 10

some_variable ||= 99
puts some_variable # => 10

Método estático Método / Class

Eu gosto de métodos de classe de uso, eu sinto que é realmente uma maneira idiomática para criar e uso classes:

GetSearchResult.call(params)

Simples. Lindo. Intuitivo. O que acontece no fundo?

class GetSearchResult
  def self.call(params)
    new(params).call
  end

  def initialize(params)
    @params = params
  end

  def call
    # ... your code here ...
  end
end

Para obter mais informações para escrever código Ruby idiomática, leia aqui

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top