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
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
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
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"}
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
Wow, personne n'a mentionné l'opérateur de bascule:
1.upto(100) do |i|
puts i if (i == 3)..(i == 15)
end
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)
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
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.
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.
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
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.
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)
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'
}
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.
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/
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!'
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.
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.
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é?)
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.
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.
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.
créer un tableau de nombres consécutifs:
x = [*0..5]
définit x sur [0, 1, 2, 3, 4, 5]
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 .
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.
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:
put
s automatique à la fin de chaque itération de boucleQuelques 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.
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
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.
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"
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")
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.
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)/
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
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é).
Je suis fan de:
%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]
C'est assez drôle combien de fois c'est utile.
def getCostAndMpg
cost = 30000 # some fancy db calls go here
mpg = 30
return cost,mpg
end
AltimaCost, AltimaMpg = getCostAndMpg
puts "AltimaCost = #{AltimaCost}, AltimaMpg = #{AltimaMpg}"
i = 0
j = 1
puts "i = #{i}, j=#{j}"
i,j = j,i
puts "i = #{i}, j=#{j}"
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
(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
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
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 ()
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'
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
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 :)
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'
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:
Pour un exemple plus complexe avec des continuations se déplaçant dans l'autre sens sur la pile, lisez la source dans Generator .
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.
@user #=> nil (but I did't know)
@user.name rescue "Unknown"
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"