Domanda

Una cosa che adoro di ruby ??è che per lo più è un linguaggio molto leggibile (il che è ottimo per il codice auto-documentante)

Tuttavia, ispirato a questa domanda: Spiegazione del codice Ruby e la descrizione di come || = funziona in ruby, stavo pensando agli idiomi ruby ??che non uso, francamente non li scrivo completamente.

Quindi la mia domanda è, simile all'esempio della domanda di riferimento, di quali idiomi rubini comuni, ma non ovvi, di cui ho bisogno per essere consapevole di essere un programmatore rubino veramente abile?

A proposito, dalla domanda di riferimento

a ||= b 

è equivalente a

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

(Grazie a Ian Terrell per la correzione)

Modifica: Si scopre che questo punto non è totalmente controverso. La corretta espansione è infatti

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

Vedi questi link per il motivo:

Grazie a Jörg W Mittag per averlo segnalato.

È stato utile?

Soluzione

La clausola if magica che consente di utilizzare lo stesso file come libreria o script:

if __FILE__ == 
# 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' ]
# this library may be run as a standalone script end

Matrici di compressione e decompressione:

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

Lo zucchero sintetico per gli hash come argomenti del metodo

# 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]}

Inizializzatori di hash:

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

sintassi della metaclasse

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"

variabili dell'istanza di classe

 # 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' ]

Blocks, procs e lambdas. Vivi e respira.

<*>

Altri suggerimenti

Questa slideshow è abbastanza completa sui principali idiomi di Ruby, come in:

  • Scambia due valori:

    x, y = y, x

  • Parametri che, se non specificati, assumono un valore predefinito

    def somemethod (x, y = nil)

  • Esegue il raggruppamento di parametri estranei in un array

    def substitute (re, str, * rest)

E così via ...

Alcuni altri modi di dire:

Uso dei delimitatori % w , % r e % (

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

Confronto dei tipi nelle dichiarazioni dei casi

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 l'abuso generale del metodo === nelle dichiarazioni dei casi

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

Qualcosa che dovrebbe sembrare naturale per i rubyisti, ma forse non così per le persone che provengono da altre lingue: l'uso di ciascuno a favore di per .. in

some_iterable_object.each{|item| ... }

In Ruby 1.9+, Rails, o rattoppando il metodo Symbol # to_proc, questo sta diventando un linguaggio sempre più popolare:

strings.map(&:upcase)

Metodo condizionale / definizione costante

SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT)

Metodi di query e metodi distruttivi (bang)

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

def make_awesome!
  # Modify the state of the object
end

Parametri splat impliciti

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

Mi piace questo:

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

str[regexp, 1] # <- This

Che è (approssimativamente) equivalente a:

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

O almeno è quello che ho usato per sostituire tali blocchi.

Suggerirei di leggere il codice di plugin o gemme popolari e ben progettati da persone che ammiri e rispetti.

Alcuni esempi in cui mi sono imbattuto:

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

corrispondente a

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

che in seguito verrebbe refactored in

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

Eccone alcuni, scelti da varie fonti:

usa " a meno che " e " fino a " invece di " in caso contrario " e " mentre non & " ;. Cerca di non utilizzare " a meno che " quando un "altro" la condizione esiste, tuttavia.

Ricorda che puoi assegnare più variabili contemporaneamente:

a,b,c = 1,2,3

e persino scambiare la variabile senza temp:

a,b = b,a

Usa i condizionali finali ove appropriato, ad esempio

do_something_interesting unless want_to_be_bored?

Sii consapevole di un modo comunemente usato ma non immediatamente ovvio (almeno per me) di definire i metodi di classe:

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

Alcuni riferimenti:

  

A proposito, dal referenziato   domanda

a ||= b 
     

è equivalente a

if a == nil   
  a = b 
end

È leggermente errato ed è una fonte di bug nelle applicazioni Ruby dei nuovi arrivati.

Poiché entrambi (e solo) nil e false valutano un falso booleano, a || = b è in realtà (quasi *) equivalente a:

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

Oppure, per riscriverlo con un altro idioma di Ruby:

a = b unless a

(* Poiché ogni istruzione ha un valore, questi non sono tecnicamente equivalenti a a || = b . Ma se non fai affidamento sul valore dell'istruzione, non vedrai una differenza.)

Mantengo una pagina wiki che copre alcuni idiomi e formattazioni di Ruby:

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

Dimentico sempre l'esatta sintassi di questa istruzione if else (e il nome dell'operatore. commenta qualcuno?) Penso che sia ampiamente usato al di fuori di ruby, ma nel caso in cui qualcun altro voglia la sintassi qui è:

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

si espande in

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

update

chiamato l'operatore ternario:

restituisci myvar? myvar.size: 0

Puoi eseguire facilmente la copia in profondità con l'oggetto Marshaling. - tratto da The Ruby Programming Language

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

Si noti che i file e i flussi di I / O, come   nonché oggetti Method e Binding,   sono troppo dinamici per essere marshaled; Là   non sarebbe un modo affidabile per ripristinare   il loro stato.

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

è approssimativamente:

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

Lo uso quando b è un record che potrebbe essere stato trovato o meno e che devo ottenere uno dei suoi attributi.

Mi piace come If-then-else o case-when possano essere abbreviati perché restituiscono un valore:

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

potrebbe essere riscritto

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

Lo stesso potrebbe essere applicato a case-when:

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

Array.pack e String.unpack per lavorare con file binari:

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

metodo mancante magick

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 chiami metodi che non esistono negli oggetti ruby, l'interprete ruby ??chiamerà il metodo chiamato 'method_missing' se è definito, potresti usarlo per alcuni trucchi, come scrivere api wrapper o dsl, dove non conosci; nomi di metodi e parametri

Bella domanda!

Secondo me il più intuitivo & amp; più veloce è il codice, un software migliore che stiamo costruendo. Ti mostrerò come esprimo i miei pensieri usando Ruby in piccoli frammenti di codice. Leggi di più qui

Mappa

Possiamo usare il metodo della mappa in diversi modi:

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

o

user_ids = users.map(&:id)

Esempio

Possiamo usare il metodo rand:

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

Shuffle:

[1, 2, 3].shuffle.first

E il modo idiomatico, semplice e più semplice ... prova!

[1, 2, 3].sample

Uguali / memoizzazione doppio tubo

Come hai detto nella descrizione, possiamo usare la memoization:

some_variable ||= 10
puts some_variable # => 10

some_variable ||= 99
puts some_variable # => 10

Metodo statico / Metodo di classe

Mi piace usare i metodi di classe, penso che sia un modo davvero idiomatico di creare & amp; usa le classi:

GetSearchResult.call(params)

Semplice. Bellissimo. Intuitivo. Cosa succede in background?

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

  def initialize(params)
    @params = params
  end

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

Per maggiori informazioni su come scrivere il codice Ruby idiomatico, leggi qui

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top