Continuando il meme "Funzioni nascoste di ...", condividiamo le funzionalità meno note ma utili del linguaggio di programmazione Ruby.
Cerca di limitare questa discussione con il core Ruby, senza alcun Ruby on Rails cose.
Guarda anche:
(Per favore, solo una funzione nascosta per risposta.)
Grazie
From Ruby 1.9 Proc # === è un alias per Proc # call, il che significa che gli oggetti Proc possono essere usati in questi casi:
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 ha una buona lista di Ruby. Forse il mio preferito è quello di consentire l'enumerazione di singoli oggetti e collezioni. (Cioè, trattare un non- oggetto di raccolta come una raccolta contenente solo quell'oggetto.) È simile al seguente:
[*items].each do |item|
# ...
end
Non so quanto sia nascosto, ma l'ho trovato utile quando è necessario creare un hash da un array unidimensionale:
fruit = ["Apple","red","banana","yellow"]
=> ["Apple", "red", "banana", "yellow"]
Hash[*fruit]
=> {"Apple"=>"red", "banana"=>"yellow"}
Un trucco che mi piace è usare lo splat (*
) espansore su oggetti diversi dalle matrici. Ecco un esempio di una corrispondenza di espressioni regolari:
match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)
Altri esempi includono:
a, b, c = *('A'..'Z')
Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
Wow, nessuno ha menzionato l'operatore di infradito:
1.upto(100) do |i|
puts i if (i == 3)..(i == 15)
end
Una delle cose interessanti di Ruby è che puoi chiamare metodi ed eseguire il codice in luoghi in cui altre lingue non si accorgerebbero, come nelle definizioni di metodi o classi.
Ad esempio, per creare una classe che ha una superclasse sconosciuta fino al runtime, ovvero è casuale, è possibile effettuare le seguenti operazioni:
class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample
end
RandomSubclass.superclass # could output one of 6 different classes.
Questo utilizza il metodo 1.9 Array#sample
(Solo in 1.8.7, vedi Array#choice
), E l'esempio è abbastanza elaborato ma puoi vedere il potere qui.
Un altro esempio interessante è la possibilità di inserire valori di parametri predefiniti non fissi (come spesso richiedono altre lingue):
def do_something_at(something, at = Time.now)
# ...
end
Naturalmente il problema con il primo esempio è che viene valutato al momento della definizione, non al momento della chiamata. Quindi, una volta che una superclasse è stata scelta, rimane quella superclasse per il resto del programma.
Tuttavia, nel secondo esempio, ogni volta che chiami do_something_at
, La variabile at
sarà il momento in cui è stato chiamato il metodo (beh, molto molto vicino ad esso)
Un'altra piccola funzione: convertire un Fixnum
in qualsiasi base fino a 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"
E come ha commentato Huw Walters, convertire dall'altra parte è altrettanto semplice:
>> "kf12oi".to_i(36)
=> 1234567890
Hash con valori predefiniti! Un array in questo caso.
parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []
parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"
Molto utile nella metaprogrammazione.
Scarica Ruby 1.9 e problema make golf
, quindi puoi fare cose del genere:
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"
Leggi il golf_prelude.c
per nascondere altre cose pulite.
Un'altra aggiunta divertente nella funzionalità Proc 1.9 è il curry Proc # che consente di trasformare un Proc che accetta n argomenti in uno che accetta n-1. Qui è combinato con il suggerimento Proc # === che ho menzionato sopra:
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
Operatori booleani su valori non booleani.
&&
e ||
Entrambi restituiscono il valore dell'ultima espressione valutata.
Ecco perché il ||=
aggiornerà la variabile con il valore restituito espressione sul lato destro se la variabile non è definita. Questo non è esplicitamente documentato, ma conoscenza comune.
Comunque, il &&=
non è abbastanza conosciuto.
string &&= string + "suffix"
è equivalente a
if string
string = string + "suffix"
end
È molto utile per operazioni distruttive che non dovrebbero procedere se la variabile non è definita.
La funzione Symbol # to_proc che Rails fornisce è davvero interessante.
Invece di
Employee.collect { |emp| emp.name }
Tu puoi scrivere:
Employee.collect(&:name)
Un ultimo - in Ruby puoi usare qualsiasi carattere che desideri delimitare le stringhe. Prendi il seguente codice:
message = "My message"
contrived_example = "<div id=\"contrived\">#{message}</div>"
Se non vuoi sfuggire alle doppie virgolette all'interno della stringa, puoi semplicemente usare un delimitatore diverso:
contrived_example = %{<div id="contrived-example">#{message}</div>}
contrived_example = %[<div id="contrived-example">#{message}</div>]
Oltre a evitare di dover sfuggire ai delimitatori, puoi utilizzare questi delimitatori per stringhe multilinea più belle:
sql = %{
SELECT strings
FROM complicated_table
WHERE complicated_condition = '1'
}
Trovo che usare il comando define_method per generare dinamicamente metodi sia abbastanza interessante e non così noto. Per esempio:
((0..9).each do |n|
define_method "press_#{n}" do
@number = @number.to_i * 10 + n
end
end
Il codice sopra usa il comando 'define_method' per creare dinamicamente i metodi da "press1" a "press9". Invece di digitare tutti i 10 metodi che contengono essenzialmente lo stesso codice, il comando define method viene utilizzato per generare questi metodi al volo, se necessario.
Utilizzare un oggetto Range come un elenco pigro infinito:
Inf = 1.0 / 0
(1..Inf).take(5) #=> [1, 2, 3, 4, 5]
Maggiori informazioni qui: http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-Ruby/
I metodi del modulo dichiarati come module_function creeranno copie di se stessi come private metodi di istanza nella classe che include il Modulo:
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>
Se si utilizza module_function senza argomenti, tutti i metodi del modulo che seguono la dichiarazione module_function diventeranno automaticamente module_functions stessi.
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!'
Attenzione: questo articolo è stato votato # 1 Hack più orrendo del 2008, quindi usalo con cura. In realtà, evitatelo come la peste, ma è certamente nascosto Ruby.
Hai mai desiderato un operatore di stretta di mano super-segreto per alcune operazioni uniche nel tuo codice? Ti piace giocare a code golf? Prova operatori come - ~ + ~ - o <--- Quest'ultimo è usato negli esempi per invertire l'ordine di un articolo.
Non ho nulla a che fare con Superators Project oltre ad ammirarlo.
Sono in ritardo alla festa, ma:
Puoi facilmente prendere due array di uguale lunghezza e trasformarli in un hash con un array che fornisce le chiavi e l'altro i valori:
a = [:x, :y, :z]
b = [123, 456, 789]
Hash[a.Zip(b)]
# => { :x => 123, :y => 456, :z => 789 }
(Funziona perché Array # Zip "comprime" i valori dei due array:
a.Zip(b) # => [[:x, 123], [:y, 456], [:z, 789]]
E Hash [] può prendere proprio un tale array. Ho visto persone fare anche questo:
Hash[*a.Zip(b).flatten] # unnecessary!
Il che produce lo stesso risultato, ma lo splat e l'appiattimento sono totalmente inutili - forse non lo erano in passato?)
Hash auto-vivificanti in 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 } } }
Questo può essere dannatamente utile.
Destructuring an Array
(a, b), c, d = [ [:a, :b ], :c, [:d1, :d2] ]
Dove:
a #=> :a
b #=> :b
c #=> :c
d #=> [:d1, :d2]
Usando questa tecnica possiamo usare un semplice incarico per ottenere i valori esatti che vogliamo dall'array nidificato di qualsiasi profondità.
Class.new()
Crea una nuova classe in fase di esecuzione. L'argomento può essere una classe da cui derivare e il blocco è il corpo della classe. Potresti anche voler guardare const_set/const_get/const_defined?
per registrare correttamente la tua nuova classe, in modo che inspect
stampi un nome anziché un numero.
Non qualcosa di cui hai bisogno ogni giorno, ma abbastanza utile quando lo fai.
creare una matrice di numeri consecutivi:
x = [*0..5]
imposta x su [0, 1, 2, 3, 4, 5]
Molta della magia che vedi in Rubyland ha a che fare con la metaprogrammazione, che è semplicemente scrivere codice che scrive codice per te. Ruby attr_accessor
, attr_reader
, e attr_writer
sono tutte semplici metaprogrammazioni, in quanto creano due metodi in una riga, seguendo uno schema standard. Rails esegue molte metaprogrammazioni con i loro metodi di gestione delle relazioni come has_one
e belongs_to
.
Ma è abbastanza semplice creare i tuoi trucchi di metaprogrammazione usando class_eval
per eseguire codice scritto dinamicamente.
L'esempio seguente consente a un oggetto wrapper di inoltrare determinati metodi insieme a un oggetto interno:
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"]
Il metodo Wrapper.forwards
accetta i simboli per i nomi dei metodi e li memorizza nell'array methods
. Quindi, per ognuno di quelli indicati, usiamo define_method
per creare un nuovo metodo il cui compito è inviare il messaggio, inclusi tutti gli argomenti e i blocchi.
Una grande risorsa per i problemi di metaprogrammazione è Why "Lucky Seeing Metaprogramming Clearing" .
usa tutto ciò che risponde a ===(obj)
per i confronti di casi:
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
(e quindi Class
), Regexp
, Date
e molte altre classi definiscono un metodo di istanza: === (altro), e tutti possono essere utilizzato.
Grazie a Farrel per il promemoria di Proc#call
essendo alias come Proc#===
in Ruby 1.9.
Il binario "Ruby" (almeno la risonanza magnetica) supporta molti degli switch che hanno reso molto popolare la battuta del Perl.
Significativi:
put
s automatico alla fine di ogni iterazione di loopQualche esempio:
# 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
Sentiti libero di utilizzare Google "Ruby one-liner" e "Perl one-liner" per tonnellate di esempi più utilizzabili e pratici. In sostanza ti permette di usare Ruby come sostituto abbastanza potente di awk e sed.
Il metodo send () è un metodo generico che può essere utilizzato su qualsiasi classe o oggetto in Ruby. Se non sovrascritto, send () accetta una stringa e chiama il nome del metodo di cui viene passata la stringa. Ad esempio, se l'utente fa clic sul pulsante "Clr", la stringa "press_clear" verrà inviata al metodo send () e verrà chiamato il metodo "press_clear". Il metodo send () consente un modo divertente e dinamico di chiamare funzioni in 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
Parlo di più di questa funzione in Scarpe da blog: l'applicazione Simple-Calc
private unless Rails.env == 'test'
# e.g. a bundle of methods you want to test directly
Sembra un fantastico e (in alcuni casi) bello/utile hack/funzionalità di Ruby.
Fixnum#to_s(base)
può essere davvero utile in alcuni casi. Uno di questi casi sta generando token univoci casuali (pseudo) convertendo un numero casuale in stringa usando una base di 36.
Token di lunghezza 8:
Rand(36**8).to_s(36) => "fmhpjfao"
Rand(36**8).to_s(36) => "gcer9ecu"
Rand(36**8).to_s(36) => "krpm0h9r"
Token di lunghezza 6:
Rand(36**6).to_s(36) => "bvhl8d"
Rand(36**6).to_s(36) => "lb7tis"
Rand(36**6).to_s(36) => "ibwgeh"
Imbrogliamo qualche classe o modulo dicendo che ha richiesto qualcosa che in realtà non ha richiesto:
$" << "something"
Questo è utile ad esempio quando si richiede A che a sua volta richiede B ma non abbiamo bisogno di B nel nostro codice (e A non lo userà nemmeno attraverso il nostro codice):
Ad esempio, bdrb_test_helper requires
'test/spec'
, ma non lo usi affatto, quindi nel tuo codice:
$" << "test/spec"
require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
Definizione di un metodo che accetta un numero qualsiasi di parametri e li scarta tutti
def hello(*)
super
puts "hello!"
end
Il precedente metodo hello
deve solo puts
"hello"
sullo schermo e chiama super
- ma poiché la superclasse hello
definisce anche i parametri, anche se non ha bisogno di utilizzare i parametri in sé - non lo fa dare loro un nome.
Per combinare più regex con |
, Puoi usare
Regexp.union /Ruby\d/, /test/i, "cheat"
per creare un Regexp simile a:
/(Ruby\d|[tT][eE][sS][tT]|cheat)/
Lo trovo utile in alcuni script. Consente di utilizzare direttamente le variabili di ambiente, come negli script Shell e nei Makefile. Le variabili di ambiente vengono utilizzate come fallback per costanti non definite 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
Che ne dici di aprire un file basato su ARGV [0]?
readfile.rb:
$<.each_line{|l| puts l}
Ruby readfile.rb testfile.txt
È un'ottima scorciatoia per scrivere script unici. C'è un sacco di variabili predefinite che molte persone non conoscono. Usali con saggezza (leggi: non sporcare una base di codice che intendi mantenere con loro, può diventare disordinata).
Sono un fan di:
%w{An Array of strings} #=> ["An", "Array", "of", "Strings"]
È abbastanza divertente quanto spesso sia 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
(Nella maggior parte delle lingue quando non è possibile trovare un metodo e viene generato un errore e il programma si arresta. In Ruby puoi effettivamente rilevare quegli errori e forse fare qualcosa di intelligente con la situazione)
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
Non conosco il metodo sottrarre
zero
La punta di James A. Rosen è interessante ([* items] .each), ma trovo che distrugga gli hash:
irb(main):001:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):002:0> [*h]
=> [[:name, "Bob"]]
Preferisco questo modo di gestire il caso quando accetto un elenco di cose da elaborare ma sono indulgente e consento al chiamante di fornirne uno:
irb(main):003:0> h = {:name => "Bob"}
=> {:name=>"Bob"}
irb(main):004:0> [h].flatten
=> [{:name=>"Bob"}]
Questo può essere combinato con una firma del metodo così bene:
def process(*entries)
[entries].flatten.each do |e|
# do something with e
end
end
Adoro amo la parola chiave incorporata salvataggio in questo modo:
ESEMPIO MODIFICATO:
@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'
Questo evita di interrompere la mia app ed è molto meglio della funzione rilasciata a Rails . Try ()
Chiamare un metodo definito in qualsiasi punto della catena di ereditarietà, anche se sottoposto a override
Gli oggetti di ActiveSupport talvolta si mascherano come oggetti incorporati.
richiedono 'active_support' giorni = 5.days days.class # => Fixnum days.is_a? (Fixnum) # => true Fixnum === giorni # => false (eh? Che cosa sei veramente?) Object.instance_method (: class) .bind (days) .call # => ActiveSupport :: Duration (aha!) ActiveSupport :: Durata === giorni # => vero
Quanto sopra, ovviamente, si basa sul fatto che active_support non ridefinisce l'Oggetto # istanza_metodo, nel qual caso saremmo davvero su un ruscello. Quindi, potremmo sempre salvare il valore restituito di Object.instance_method (: class) prima che venga caricata una libreria di terze parti.
Object.instance_method (...) restituisce un UnboundMethod che puoi quindi associare a un'istanza di quella classe. In questo caso, è possibile associarlo a qualsiasi istanza di Object (sottoclassi incluse).
Se la classe di un oggetto include moduli, è anche possibile utilizzare UnboundMethod da tali moduli.
modulo Mod def var_add (altro); @ Var + più; end end class Cla include Mod def inizializza (var); @ Var = var; end # override def var_add (altro); @ Var + più + di più; end end cla = Cla.new ('abcdef') cla.var_add ('ghi') # => "abcdefghighi" Mod.instance_method ( : var_add) .bind (cla) .call ('ghi') # => "abcdefghi"
Questo funziona anche con metodi singleton che sovrascrivono un metodo di istanza della classe a cui appartiene l'oggetto.
classe Foo def mymethod; 'originale'; end end foo = Foo.new foo.mymethod # => 'original' def foo.mymethod; 'singleton'; end foo.mymethod # => 'singleton' Foo.instance_method (: mymethod) .bind (foo) .call # => 'original' # Puoi anche chiamare il metodo #instance su classi singleton: Class << pippo; se stesso; end.instance_method (: mymethod) .bind (foo) .call # => 'singleton'
Ci sono alcuni aspetti dei simboli letterali che le persone dovrebbero conoscere. Un caso risolto da letterali di simboli speciali è quando è necessario creare un simbolo il cui nome causa un errore di sintassi per qualche motivo con la normale sintassi letterale di simboli:
:'class'
Puoi anche eseguire l'interpolazione dei simboli. Nel contesto di un accessorio, ad esempio:
define_method :"#{name}=" do |value|
instance_variable_set :"@#{name}", value
end
each_with_index metodo per qualsiasi oggetto enumarabile (array, hash, ecc.) forse?
myarray = ["la", "li", "lu"]
myarray.each_with_index{|v,idx| puts "#{idx} -> #{v}"}
#result:
#0 -> la
#1 -> li
#2 -> lu
Forse è più noto di altre risposte ma non così noto per tutti Ruby :)
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 ha un meccanismo call/cc che consente di salire e scendere liberamente dallo stack.
Segue un semplice esempio. Questo non è certamente il modo in cui si moltiplicherebbe una sequenza in Ruby, ma dimostra come si potrebbe usare call/cc per raggiungere lo stack per cortocircuitare un algoritmo. In questo caso, stiamo moltiplicando ricorsivamente un elenco di numeri fino a quando non abbiamo visto tutti i numeri o non vediamo zero (i due casi in cui conosciamo la risposta). Nel caso zero, possiamo essere arbitrariamente in profondità nell'elenco e terminare.
#!/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)}"
Puoi vedere l'output qui:
Per un esempio più complesso con continuazioni che si muovono nell'altra direzione nello stack, leggi l'origine su Generatore .
Ho appena letto tutte le risposte ... una notevole omissione è stata la distruzione del compito:
> (a,b),c = [[1,2],3]
=> [[1,2],3]
> a
=> 1
Funziona anche per i parametri di blocco. Ciò è utile quando si hanno array nidificati, ciascun elemento rappresenta qualcosa di distinto. Invece di scrivere codice come "array [0] [1]", puoi suddividere quell'array nidificato e assegnare un nome descrittivo a ciascun elemento, in una singola riga di codice.
@user #=> nil (but I did't know)
@user.name rescue "Unknown"
Il mio preferito Ruby. La sintassi è format_string % argument
"%04d" % 1 # => "0001"
"%0.2f" % Math::PI # => "3.14"
Funziona anche con array (format_string % array_of_arguments
)
"%.2f %.3f %.4f" % ([Math::PI]*3)
# => "3.14 3.142 3.1416"