web-dev-qa-db-fra.com

Fonctionnalités cachées de Ruby

Poursuivant le mème "Fonctions cachées de ...", partageons les fonctionnalités moins connues mais utiles du langage de programmation Ruby.

Essayez de limiter cette discussion avec le noyau Ruby, sans aucun Ruby on Rails stuff).

Voir également:

(S'il vous plaît, juste une fonction cachée par réponse.)

Merci

160
squadette

From Ruby 1.9 Proc # === est un alias de l'appel Proc #, ce qui signifie que les objets Proc peuvent être utilisés dans des instructions de cas comme ceci:

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
80
Farrel

Peter Cooper a une bonne liste de Ruby astuces. Peut-être que mon préféré est de permettre à la fois les articles uniques et les collections à être énumérés (c'est-à-dire, traiter un non objet de collection en tant que collection contenant uniquement cet objet.) Il ressemble à ceci:

[*items].each do |item|
  # ...
end
76
James A. Rosen

Je ne sais pas à quel point c'est caché, mais je l'ai trouvé utile lorsque j'ai besoin de créer un hachage à partir d'un tableau unidimensionnel:

fruit = ["Apple","red","banana","yellow"]
=> ["Apple", "red", "banana", "yellow"]

Hash[*fruit]    
=> {"Apple"=>"red", "banana"=>"yellow"}
64
astronautism

Une astuce que j'aime est d'utiliser le splat (*) développez sur des objets autres que des tableaux. Voici un exemple de correspondance d'expression régulière:

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

D'autres exemples incluent:

a, b, c = *('A'..'Z')

Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
54
tomafro

Wow, personne n'a mentionné l'opérateur de bascule:

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

L'une des choses intéressantes à propos de Ruby est que vous pouvez appeler des méthodes et exécuter du code dans des endroits où d'autres langages seraient désapprouvés, comme dans les définitions de méthode ou de classe.

Par exemple, pour créer une classe qui a une superclasse inconnue jusqu'au moment de l'exécution, c'est-à-dire qui est aléatoire, vous pouvez procéder comme suit:

class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample

end

RandomSubclass.superclass # could output one of 6 different classes.

Cela utilise le 1.9 Array#sample méthode (en 1.8.7 uniquement, voir Array#choice), et l'exemple est assez artificiel mais vous pouvez voir la puissance ici.

Un autre exemple intéressant est la possibilité de mettre des valeurs de paramètres par défaut qui ne sont pas fixes (comme d'autres langues l'exigent souvent):

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

Bien sûr, le problème avec le premier exemple est qu'il est évalué au moment de la définition, et non au moment de l'appel. Ainsi, une fois qu'une superclasse a été choisie, elle reste cette superclasse pour le reste du programme.

Cependant, dans le deuxième exemple, chaque fois que vous appelez do_something_at, la variable at sera l'heure à laquelle la méthode a été appelée (enfin, très très proche d'elle)

49
Bo Jeanes

Autre petite fonctionnalité - convertir un Fixnum en n'importe quelle base jusqu'à 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"

Et comme l'a commenté Huw Walters, la conversion dans l'autre sens est tout aussi simple:

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

Hash avec des valeurs par défaut! Un tableau dans ce cas.

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

parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"

Très utile en métaprogrammation.

40
August Lilleaas

Téléchargez Ruby 1.9 et lancez make golf, alors vous pouvez faire des choses comme ceci:

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"

Lis le golf_prelude.c pour cacher des choses plus soignées.

39
manveru

Un autre ajout amusant à la fonctionnalité 1.9 Proc est le curry Proc # qui vous permet de transformer un Proc acceptant n arguments en un acceptant n-1. Ici, il est combiné avec l'astuce Proc # === que j'ai mentionnée ci-dessus:

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
38
Farrel

Opérateurs booléens sur les valeurs non booléennes.

&& et ||

Les deux renvoient la valeur de la dernière expression évaluée.

C'est pourquoi le ||= mettra à jour la variable avec la valeur renvoyée expression sur le côté droit si la variable n'est pas définie. Ce n'est pas explicitement documenté, mais bien connu.

Cependant, le &&= n'est pas aussi bien connu.

string &&= string + "suffix"

est équivalent à

if string
  string = string + "suffix"
end

C'est très pratique pour les opérations destructrices qui ne devraient pas se poursuivre si la variable n'est pas définie.

35
EmFi

La fonction Symbol # to_proc que Rails fournit est vraiment cool.

Au lieu de

Employee.collect { |emp| emp.name }

Tu peux écrire:

Employee.collect(&:name)
29
hoyhoy

Un dernier - dans Ruby vous pouvez utiliser n'importe quel caractère pour délimiter des chaînes. Prenez le code suivant:

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

Si vous ne voulez pas échapper aux guillemets doubles dans la chaîne, vous pouvez simplement utiliser un délimiteur différent:

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

En plus d'éviter d'avoir à échapper les délimiteurs, vous pouvez utiliser ces délimiteurs pour des chaînes multilignes plus agréables:

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

Je trouve que l'utilisation de la commande define_method pour générer dynamiquement des méthodes est assez intéressante et moins connue. Par exemple:

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

Le code ci-dessus utilise la commande 'define_method' pour créer dynamiquement les méthodes "press1" à "press9". Plutôt que de taper les 10 méthodes qui contiennent essentiellement le même code, la commande define method est utilisée pour générer ces méthodes à la volée selon les besoins.

26

Utilisez un objet Range comme une liste paresseuse infinie:

Inf = 1.0 / 0

(1..Inf).take(5) #=> [1, 2, 3, 4, 5]

Plus d'informations ici: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-Ruby/

26
horseyguy

module_function

Les méthodes de module déclarées comme module_function créeront des copies d'eux-mêmes en tant que méthodes d'instance private dans la classe qui inclut le module:

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 vous utilisez module_function sans aucun argument, toutes les méthodes de module postérieures à l'instruction module_function deviendront automatiquement module_functions elles-mêmes.

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!'
23
newtonapple

Injection courte, comme telle:

Somme de la plage:

(1..10).inject(:+)
=> 55
23
user130730

Attention: cet article a été voté # 1 Le piratage le plus horrible de 2008, alors utilisez-le avec précaution. En fait, évitez-le comme la peste, mais c'est certainement Hidden Ruby.

Les superateurs ajoutent de nouveaux opérateurs à Ruby

Vous avez toujours voulu un opérateur de poignée de main super secret pour une opération unique dans votre code? Vous aimez jouer au golf à code? Essayez des opérateurs comme - ~ + ~ - ou <--- Ce dernier est utilisé dans les exemples pour inverser l'ordre d'un élément.

Je n'ai rien à voir avec le Superators Project au-delà de l'admirer.

21
Captain Hammer

Je suis en retard à la fête, mais:

Vous pouvez facilement prendre deux tableaux de longueur égale et les transformer en hachage avec un tableau fournissant les clés et l'autre les valeurs:

a = [:x, :y, :z]
b = [123, 456, 789]

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

(Cela fonctionne car le tableau # Zip "zippe" les valeurs des deux tableaux:

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

Et Hash [] peut prendre un tel tableau. J'ai vu des gens faire ça aussi:

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

Ce qui donne le même résultat, mais l'éclatement et l'aplatissement sont totalement inutiles - peut-être qu'ils ne l'étaient pas dans le passé?)

19
Jordan Running

hachages vivifiants automatiques 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 } } }

Cela peut être sacrément pratique.

19
Trevoke

Destruction d'un tablea

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

Où:

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

En utilisant cette technique, nous pouvons utiliser une affectation simple pour obtenir les valeurs exactes que nous voulons à partir d'un tableau imbriqué de n'importe quelle profondeur.

16
horseyguy

Class.new()

Créez une nouvelle classe au moment de l'exécution. L'argument peut être une classe à dériver et le bloc est le corps de la classe. Vous pouvez également consulter const_set/const_get/const_defined? pour enregistrer correctement votre nouvelle classe, de sorte que inspect imprime un nom au lieu d'un nombre.

Pas quelque chose dont vous avez besoin tous les jours, mais assez pratique lorsque vous le faites.

15
Justin Love

créer un tableau de nombres consécutifs:

x = [*0..5]

définit x sur [0, 1, 2, 3, 4, 5]

13
horseyguy

Une grande partie de la magie que vous voyez dans Rubyland a à voir avec la métaprogrammation, qui consiste simplement à écrire du code qui écrit du code pour vous. Ruby attr_accessor, attr_reader, et attr_writer sont tous de simples métaprogrammations, en ce sens qu'ils créent deux méthodes sur une seule ligne, suivant un modèle standard. Rails fait beaucoup de métaprogrammation avec leurs méthodes de gestion des relations comme has_one et belongs_to.

Mais il est assez simple de créer vos propres astuces de métaprogrammation en utilisant class_eval pour exécuter du code écrit dynamiquement.

L'exemple suivant permet à un objet wrapper de transférer certaines méthodes vers un objet interne:

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"]

La méthode Wrapper.forwards prend des symboles pour les noms des méthodes et les stocke dans le tableau methods. Ensuite, pour chacun de ceux donnés, nous utilisons define_method pour créer une nouvelle méthode dont le travail consiste à envoyer le message, y compris tous les arguments et les blocs.

Une excellente ressource pour les problèmes de métaprogrammation est Pourquoi "Voir clairement la métaprogrammation" de Lucky Stiff .

13
TALlama

utilisez tout ce qui répond à ===(obj) pour les comparaisons de cas:

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 (et donc Class), Regexp, Date, et de nombreuses autres classes définissent une méthode d'instance: === (autre), et peuvent toutes être utilisé.

Merci à Farrel pour le rappel de Proc#call ayant un alias en tant que Proc#=== in Ruby 1.9.

12
James A. Rosen

Le binaire "Ruby" (au moins les IRM) prend en charge un grand nombre des commutateurs qui ont rendu les monolignes Perl très populaires.

Les plus importants:

  • -n Configure une boucle externe avec juste "gets" - qui fonctionne comme par magie avec un nom de fichier donné ou STDIN, en définissant chaque ligne de lecture dans $ _
  • -p Similaire à -n mais avec un puts automatique à la fin de chaque itération de boucle
  • -un appel automatique à .split sur chaque ligne d'entrée, stocké dans $ F
  • -i Modification des fichiers d'entrée sur place
  • -l Appel automatique à .chomp en entrée
  • -e Exécute un morceau de code
  • -c Vérifier le code source
  • -w Avec avertissements

Quelques exemples:

# 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

N'hésitez pas à google "Ruby one-liners" et "Perl one-liners" pour des tonnes d'exemples plus utiles et pratiques. Il vous permet essentiellement d'utiliser Ruby comme un remplacement assez puissant pour awk et sed.

11
minaguib

La méthode send () est une méthode à usage général qui peut être utilisée sur n'importe quelle classe ou objet dans Ruby. S'il n'est pas remplacé, send () accepte une chaîne et appelle le nom de la méthode dont il est passé. Par exemple, si l'utilisateur clique sur le bouton "Clr", la chaîne "press_clear" sera envoyée à la méthode send () et la méthode "press_clear" sera appelée. La méthode send () permet une façon amusante et dynamique d'appeler des fonctions dans 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

Je parle plus de cette fonctionnalité dans Blogging Shoes: The Simple-Calc Application

10
private unless Rails.env == 'test'
# e.g. a bundle of methods you want to test directly

On dirait un hack/fonctionnalité sympa et (dans certains cas) sympa/utile de Ruby.

9
Szymon Jeż

Fixnum#to_s(base) peut être très utile dans certains cas. Un tel cas génère des jetons aléatoires (pseudo) uniques en convertissant un nombre aléatoire en chaîne en utilisant une base de 36.

Jeton de longueur 8:

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

Jeton de longueur 6:

Rand(36**6).to_s(36) => "bvhl8d"
Rand(36**6).to_s(36) => "lb7tis"
Rand(36**6).to_s(36) => "ibwgeh"
9
sickill

Tromper une classe ou un module en disant qu'il a requis quelque chose qu'il n'a vraiment pas requis:

$" << "something"

Ceci est utile par exemple lorsque vous avez besoin de A qui nécessite à son tour B mais nous n'avons pas besoin de B dans notre code (et A ne l'utilisera pas non plus via notre code):

Par exemple, Backgroundrb's bdrb_test_helper requires'test/spec', mais vous ne l'utilisez pas du tout, donc dans votre code:

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

Définir une méthode qui accepte n'importe quel nombre de paramètres et les ignore tous

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

La méthode hello ci-dessus n'a besoin que de puts"hello" à l'écran et appelez super - mais comme la superclasse hello définit les paramètres, elle doit également le faire - mais comme elle n'a pas réellement besoin d'utiliser les paramètres elle-même - elle ne le fait pas doivent leur donner un nom.

9
horseyguy

Pour combiner plusieurs expressions rationnelles avec |, vous pouvez utiliser

Regexp.union /Ruby\d/, /test/i, "cheat"

pour créer une expression rationnelle similaire à:

/(Ruby\d|[tT][eE][sS][tT]|cheat)/
8
J-_-L

Je trouve cela utile dans certains scripts. Il permet d'utiliser directement des variables d'environnement, comme dans les scripts Shell et Makefiles. Les variables d'environnement sont utilisées comme solution de repli pour les constantes non définies Ruby.

>> class <<Object
>>  alias :old_const_missing :const_missing
>>  def const_missing(sym)
>>   ENV[sym.to_s] || old_const_missing(sym)
>>  end
>> end
=> nil

>> puts Shell
/bin/zsh
=> nil
>> TERM == 'xterm'
=> true
8
Ropez

Que diriez-vous d'ouvrir un fichier basé sur ARGV [0]?

readfile.rb:

$<.each_line{|l| puts l}

Ruby readfile.rb testfile.txt

C'est un excellent raccourci pour écrire des scripts uniques. Il y a tout un tas de variables prédéfinies que la plupart des gens ne connaissent pas. Utilisez-les judicieusement (lisez: ne jetez pas une base de code que vous prévoyez de conserver avec eux, cela peut devenir désordonné).

8
Scott Holden

Je suis fan de:

%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]

C'est assez drôle combien de fois c'est utile.

5
Judson

Valeurs de retour multiples

def getCostAndMpg
    cost = 30000  # some fancy db calls go here
    mpg = 30
    return cost,mpg
end
AltimaCost, AltimaMpg = getCostAndMpg
puts "AltimaCost = #{AltimaCost}, AltimaMpg = #{AltimaMpg}"

Affectation parallèle

i = 0
j = 1
puts "i = #{i}, j=#{j}"
i,j = j,i
puts "i = #{i}, j=#{j}"

Attributs virtuels

class Employee < Person
  def initialize(fname, lname, position)
    super(fname,lname)
    @position = position
  end
  def to_s
     super + ", #@position"
  end
  attr_writer :position
  def etype
     if @position == "CEO" || @position == "CFO"
         "executive"
     else
         "staff"
     end
  end
end
employee = Employee.new("Augustus","Bondi","CFO")
employee.position = "CEO"
puts employee.etype    =>  executive
employee.position = "Engineer"
puts employee.etype    =>  staff

method_missing - une merveilleuse idée

(Dans la plupart des langues, lorsqu'une méthode est introuvable et qu'une erreur est générée et que votre programme s'arrête. Dans Ruby vous pouvez réellement détecter ces erreurs et peut-être faire quelque chose d'intelligent avec la situation)

class MathWiz
  def add(a,b) 
    return a+b
  end
  def method_missing(name, *args)
    puts "I don't know the method #{name}"
  end
end
mathwiz = MathWiz.new
puts mathwiz.add(1,4)
puts mathwiz.subtract(4,2)

5

Je ne connais pas la méthode soustraire

néant

5
Ramiz Uddin

Le conseil de James A. Rosen est cool ([* items] .each), mais je trouve qu'il détruit les hachages:

irb(main):001:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):002:0> [*h]
=> [[:name, "Bob"]]

Je préfère cette façon de traiter le cas lorsque j'accepte une liste de choses à traiter, mais je suis indulgente et je permets à l'appelant d'en fournir une:

irb(main):003:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):004:0> [h].flatten
=> [{:name=>"Bob"}]

Cela peut être combiné avec une signature de méthode comme si bien:

def process(*entries)
  [entries].flatten.each do |e|
    # do something with e
  end
end
4
minaguib

J'adore le mot-clé en ligne rescue comme ceci:
EXEMPLE MODIFIÉ:

@user #=> nil (but I did't know)
@user.name rescue "Unknown"
link_to( d.user.name, url_user( d.user.id, d.user.name)) rescue 'Account removed'

Cela évite de casser mon application et est bien meilleur que la fonctionnalité publiée à Rails . Try ()

4
Fabiano Soriani

Appel d'une méthode définie n'importe où dans la chaîne d'héritage, même en cas de substitution

Les objets d'ActiveSupport se font parfois passer pour des objets intégrés.

 nécessite 'support_actif' 
 jours = 5.jours 
 jours.classe # => Fixnum 
 jours.is_a? (Fixnum) # => true 
 Fixnum === jours # => faux (hein? Qu'est-ce que vous êtes vraiment?) 
 Object.instance_method (: classe) .bind (jours) .call # => ActiveSupport :: Duration (aha!) 
 ActiveSupport :: Durée === jours # => vrai 

Ce qui précède, bien sûr, repose sur le fait que active_support ne redéfinit pas Object # instance_method, auquel cas nous serions vraiment dans un ruisseau. Là encore, nous pourrions toujours enregistrer la valeur de retour de Object.instance_method (: class) avant le chargement d'une bibliothèque tierce.

Object.instance_method (...) renvoie un UnboundMethod que vous pouvez ensuite lier à une instance de cette classe. Dans ce cas, vous pouvez le lier à n'importe quelle instance d'Object (sous-classes incluses).

Si la classe d'un objet comprend des modules, vous pouvez également utiliser la méthode UnboundMethod à partir de ces modules.

 module Mod 
 def var_add (plus); @ var + plus; fin 
 fin 
 classe Cla 
 inclut Mod 
 def initialize (var); @ var = var; end 
 # override 
 def var_add (plus); @ var + plus + plus; fin 
 fin 
 cla = Cla.new ('abcdef') 
 cla.var_add ('ghi') # => "abcdefghighi" 
 Mod.instance_method ( : var_add) .bind (cla) .call ('ghi') # => "abcdefghi" 

Cela fonctionne même pour les méthodes singleton qui remplacent une méthode d'instance de la classe à laquelle appartient l'objet.

 classe Foo 
 def mymethod; 'original'; end 
 end 
 foo = Foo.new 
 foo.mymethod # => 'original' 
 def foo.mymethod; 'singleton'; fin 
 foo.mymethod # => 'singleton' 
 Foo.instance_method (: mymethod) .bind (foo) .call # => 'original' 
 
 # Vous pouvez également appeler la méthode #instance sur les classes singleton: 
 Class << foo; soi; end.instance_method (: mymethod) .bind (foo) .call # => 'singleton' 
4
Kelvin

Il y a certains aspects des littéraux de symboles que les gens devraient connaître. Un cas résolu par les littéraux de symboles spéciaux est lorsque vous devez créer un symbole dont le nom provoque une erreur de syntaxe pour une raison quelconque avec la syntaxe littérale de symbole normale:

:'class'

Vous pouvez également effectuer une interpolation de symboles. Dans le cadre d'un accesseur, par exemple:

define_method :"#{name}=" do |value|
  instance_variable_set :"@#{name}", value
end
3
Tom

each_with_index méthode pour tout objet énumérable (tableau, hachage, etc.) peut-être?

myarray = ["la", "li", "lu"]
myarray.each_with_index{|v,idx| puts "#{idx} -> #{v}"}

#result:
#0 -> la
#1 -> li
#2 -> lu

C'est peut-être plus connu que les autres réponses mais pas si bien connu de tous Ruby programmeurs :)

3
mhd
class A

  private

  def my_private_method
    puts 'private method called'
  end
end

a = A.new
a.my_private_method # Raises exception saying private method was called
a.send :my_private_method # Calls my_private_method and prints private method called'
2
Chirantan

Ruby a un mécanisme call/cc permettant de monter et descendre librement dans la pile.

Un exemple simple suit. Ce n'est certainement pas ainsi que l'on multiplierait une séquence dans Ruby, mais cela montre comment on pourrait utiliser call/cc pour atteindre la pile pour court-circuiter un algorithme. Dans ce cas, nous multiplions récursivement une liste de nombres jusqu'à ce que nous ayons vu chaque nombre ou que nous voyions zéro (les deux cas où nous connaissons la réponse). Dans le cas zéro, nous pouvons être arbitrairement profondément dans la liste et terminer.

#!/usr/bin/env Ruby

def rprod(k, rv, current, *nums)
  puts "#{rv} * #{current}"
  k.call(0) if current == 0 || rv == 0
  nums.empty? ? (rv * current) : rprod(k, rv * current, *nums)
end

def prod(first, *rest)
  callcc { |k| rprod(k, first, *rest) }
end

puts "Seq 1:  #{prod(1, 2, 3, 4, 5, 6)}"
puts ""
puts "Seq 2:  #{prod(1, 2, 0, 3, 4, 5, 6)}"

Vous pouvez voir la sortie ici:

http://codepad.org/Oh8ddh9e

Pour un exemple plus complexe avec des continuations se déplaçant dans l'autre sens sur la pile, lisez la source dans Generator .

2
Dustin

Je viens de lire toutes les réponses ... une omission notable a été la déstructuration de la mission:

> (a,b),c = [[1,2],3]
=> [[1,2],3]
> a
=> 1

Il fonctionne également pour les paramètres de bloc. Ceci est utile lorsque vous avez des tableaux imbriqués, dont chaque élément représente quelque chose de distinct. Au lieu d'écrire du code comme "tableau [0] [1]", vous pouvez décomposer ce tableau imbriqué et donner un nom descriptif à chaque élément, sur une seule ligne de code.

2
Alex D
@user #=> nil (but I did't know)
@user.name rescue "Unknown"
2
haoqi

Le raccourci sprintf

Mon préféré Ruby feature. La syntaxe est format_string % argument

"%04d"  % 1         # => "0001"
"%0.2f" % Math::PI  # => "3.14"

Fonctionne également pour les tableaux (format_string % array_of_arguments)

"%.2f %.3f %.4f" % ([Math::PI]*3) 
# => "3.14 3.142 3.1416"
1
iblue