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:
- http: //DABlog.RubyPAL. COM / 2008/3/25 / um curto-circuito de ponta-case /
- http://DABlog.RubyPAL.Com/ 2008/3 / 26 / curto-circuito-pós-correção /
- http://ProcNew.Com/ruby-short-circuit -Edge-case-resposta.html
Graças à Jörg W Mittag para apontar isto.
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 ??p>
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:
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