Question

Une des choses que j'aime à propos de ruby ??est qu'il s'agit principalement d'un langage très lisible (excellent pour le code auto-documenté)

Cependant, inspiré par cette question: code Ruby expliqué et la description de la façon dont || = fonctionne en ruby, je pensais aux idiomes de ruby ??que je n'utilise pas, car, franchement, je ne les aime pas complètement.

Ma question est donc, semblable à l'exemple de la question référencée, quels idiomes de ruby ??communs, mais non évidents, dois-je connaître pour être un programmeur de ruby ??vraiment compétent?

Au fait, à partir de la question référencée

a ||= b 

est équivalent à

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

(Merci à Ian Terrell pour la correction)

Modifier: Il s'avère que ce point n'est pas totalement controversé. Le bon développement est en fait

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

Voir ces liens pour savoir pourquoi:

Merci à J & # 246; rg W Mittag pour l'avoir signalé.

Était-ce utile?

La solution

La clause magic if qui permet au même fichier de servir de bibliothèque ou de 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

Emballage et déballage des tableaux:

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

Le sucre syntatical pour les hachages en tant qu'arguments de méthode

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

Initialiseurs de hachage:

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

syntaxe de la métaclasse

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"

variables d'instance de 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' ]

Blocs, procs et lambdas. Vivez et respirez.

<*>

Autres conseils

Ce diaporama est assez complet sur les principaux idiomes de Ruby, comme dans:

  • Échangez deux valeurs:

    x, y = y, x

  • Paramètres qui, s'ils ne sont pas spécifiés, prennent une valeur par défaut

    def somemethod (x, y = nil)

  • Combine les paramètres superflus dans un tableau

    def substitute (re, str, * rest)

Et ainsi de suite ...

Quelques autres idiomes:

Utilisation des % w , des % r et des % ( délimiteurs

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

Comparaison de types dans les instructions 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

... et abus général de la méthode === dans les instructions case

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

Quelque chose qui devrait sembler naturel aux rubyistes, mais peut-être pas aux personnes venant d'autres langues: l'utilisation de chaque en faveur de pour .. dans

some_iterable_object.each{|item| ... }

Dans Ruby 1.9+, Rails ou en appliquant un correctif à la méthode Symbol # to_proc, ceci devient un idiome de plus en plus populaire:

strings.map(&:upcase)

Définition de la méthode / constante conditionnelle

SOME_CONSTANT = "value" unless defined?(SOME_CONSTANT)

Méthodes de requête et méthodes destructives (bang)

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

def make_awesome!
  # Modify the state of the object
end

Paramètres de splat implicites

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

J'aime ça:

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

str[regexp, 1] # <- This

Ce qui équivaut (approximativement) à:

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

Ou du moins c'est ce que j'ai utilisé pour remplacer ces blocs.

Je suggérerais de lire le code de plugins populaires et bien conçus ou de trésors de personnes que vous admirez et respectez.

Quelques exemples rencontrés:

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

correspondant à

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

qui sera plus tard refactored à

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

En voici quelques exemples, issus de diverses sources:

utilisez " à moins que " et "jusqu'à" au lieu de "si pas". et "sans être". Essayez de ne pas utiliser " à moins que " quand un " else " condition existe, bien que.

N'oubliez pas que vous pouvez affecter plusieurs variables à la fois:

a,b,c = 1,2,3

et même permuter la variable sans temp:

a,b = b,a

Utilisez des conditions de fin, le cas échéant, par exemple

.
do_something_interesting unless want_to_be_bored?

Soyez conscient d'une façon couramment utilisée (mais du moins pas évidente pour moi) de définir les méthodes de classe:

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

Quelques références:

  

Au fait, à partir du référencé   question

a ||= b 
     

est équivalent à

if a == nil   
  a = b 
end

C'est subtilement incorrect et constitue une source de bugs dans les applications Ruby des nouveaux arrivants.

Etant donné que (et seulement) nil et false sont évalués à un booléen false, a || = b est en réalité (presque *) équivalent à:

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

Ou, pour le réécrire avec un autre idiome Ruby:

a = b unless a

(* Comme chaque instruction a une valeur, techniquement, cela n'est pas équivalent à a || = b . Mais si vous ne vous fiez pas à la valeur de l'instruction, vous ne verrez pas une différence.)

Je gère une page de wiki qui couvre certains idiomes et formats de Ruby:

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

J'oublie toujours la syntaxe exacte de ce raccourci si la commande else (et le nom de l'opérateur. commente quelqu'un?) Je pense qu'elle est largement utilisée en dehors de ruby, mais si quelqu'un d'autre veut la syntaxe, voici:

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

se développe en

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

mise à jour

appelé l'opérateur ternaire:

retourner myvar? myvar.size: 0

Vous pouvez facilement copier en profondeur avec un objet Marshaling. - extrait du langage de programmation Ruby

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

Notez que les fichiers et les flux d’E / S, comme   ainsi que des objets Method et Binding,   sont trop dynamiques pour être marshalés; Là   serait pas un moyen fiable pour restaurer   leur état.

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

est à peu près:

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

J'utilise ceci lorsque b est un enregistrement qui peut avoir été trouvé ou non, et je dois obtenir l'un de ses attributs.

J'aime le fait que les options If-then-else ou case-when puissent être abrégées car elles renvoient une valeur:

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

pourrait être réécrit

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

La même chose pourrait s'appliquer à la casse quand:

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

Array.pack et String.unpack pour l'utilisation de fichiers binaires:

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

méthode manquante 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]"

si vous appelez des méthodes qui n'existent pas dans les objets ruby, l'interpréteur ruby ??appellera une méthode appelée 'method_missing' si sa définition est définie, vous pouvez l'utiliser pour quelques astuces, comme écrire des wrappers api, ou dsl, où vous ne savez pas tout. méthodes et noms de paramètres

Belle question!

Comme je pense, le plus intuitif & amp; plus le code est rapide, meilleur logiciel que nous construisons. Je vais vous montrer comment exprimer mes pensées en utilisant Ruby dans de petits extraits de code. Lire la suite

Carte

Nous pouvons utiliser la méthode map de différentes manières:

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

Ou:

user_ids = users.map(&:id)

Échantillon

Nous pouvons utiliser la méthode rand:

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

Aléatoire:

[1, 2, 3].shuffle.first

Et le moyen idiomatique, simple et le plus simple ... un échantillon!

[1, 2, 3].sample

Double pipe équivalent / mémorisation

Comme vous l'avez dit dans la description, nous pouvons utiliser la mémorisation:

some_variable ||= 10
puts some_variable # => 10

some_variable ||= 99
puts some_variable # => 10

Méthode statique / Méthode de classe

J'aime utiliser des méthodes de classe, je pense que c'est une façon très idiomatique de créer & amp; utiliser des classes:

GetSearchResult.call(params)

Simple. Belle. Intuitif. Que se passe-t-il en arrière-plan?

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

  def initialize(params)
    @params = params
  end

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

Pour plus d'informations sur l'écriture de code Ruby idiomatique, lisez ici

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top