Microsoft's Internet Explorer browser has no built-in vector graphics machinery required for "loss-free" gradient background themes.
Please upgrade to a better browser such as Firefox, Opera, Safari or others with built-in vector graphics machinery and much more. (Learn more or post questions or comments at the Slide Show (S9) project site. Thanks!)
Ruby è un linguaggio OOP General Purpose creato da Yukihiro “Matz” Matsumoto a metà degli anni 90.
L’obiettivo era quello di creare un liguaggio che fosse più ad oggetti di Python e con una sintassi per lo scripting più fluida di quella di Perl.
Le influenze di Ruby vanno ricercate in: Perl , Python , Smalltalk e Lisp .
Non esiste una specifica ufficiale del linguaggio, ma l’implementazione in C viene considerato lo standard de facto.
Altre implementazioni sono YARV , JRuby , Rubinius , IronRuby , e MacRuby .
Ruby 1.9 e Ruby 2.0 sono basate su YARV
From Wikipedia
Ruby consente la convivenza di diversi paradigmi di programmazione:
IRB è una Shell di comando Ruby completa di command line editing e command history.
La shell IRB è utile per sperimentazione, debugging e sviluppo iterativo.
rpl@ubik:~$ irb irb(main):001:0> puts "Hello World" Hello World => nil irb(main):002:0> def sum(a1,a2) irb(main):003:1> a1+a2 irb(main):004:1> end => nil irb(main):005:0> sum(5,6) => 11 irb(main):006:0>
Ruby fa uso di un ristretto numero di parole riservate:
alias and BEGIN begin break case class def defined do else elsif END end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield
Le variabili sono identificatori che iniziano con una lettera o un underscore (i successivi caratteri possono contenere anche i numeri da 0 a 9).
Le variabili possono essere dotate di un prefisso ($, @ o @@) che ne determina lo scope (visibilità).
$ARGV $1 $MY_GLOBAL @my_instance_var @filename @@my_class_var @@counter @@doc
Le costanti sono identificatori che iniziano con una lettera maiuscola.
Le costanti vengono utilizzate per identificare valori che non dovrebbero cambiare una volta assegnati.
I nome delle Classi e i dei Moduli sono identificati da costanti.
NOTA: Ruby non ne impedisce la modifica ma la segnala con un warning solo se ad essere modificata è la costante stessa e non un attributo dell’oggetto referenziato.
Kernel Object MyClass Array Fixnum
I numeri interi con segno (incapsulati nella classe Fixnum ) si rappresentano con le seguenti sintassi:
0 1234 -576 +3 0xabcd # Hex 0xab_cd # Hex with embedded underscore 0xABCD # Caps are ok -0xabcd # Negative hex 0177 # Octal 0_1_77 # Octal with embedded underscores -0177 # Negative octal 0b10101 # Binary -0b10101 # Negative binary ?a # character code for 'a' character
I numeri in virgola mobile (64-bit IEEE floating point numbers) sono incapsulati nella classe Float e rispettano la seguente sintassi:
123.456 3.141_592_653_589_793_238_462 -4.5 6.5e3 -.4_5_6e10
I Bignum rappresentano interi con segno di dimensione arbitraria (incapsulati nella classe Bignum) e rispettano la seguente sintassi:
112233445566778899112233445566778899 -999999999999999999999999999999999999 111_222_333_444_555_666_777_888_999_000 1_1_2_3_5_8_13_21_34_55_89_144_233_377 0xaaaaaaaaaaaaaaaaaaaaaaaaa 077777777777777777777777777777777777777777
Le stinghe rappresentano sequenze di caratteri (incapsule in classi String ) e rispettano le seguenti sintassi:
"Double quoted string" 'Single quoted string' "Double quoted can embed Ruby code using #{do something} notation" "Double quoted can even embed #{"double quoted strings"} inside the embedded code notation" %q(This is a single-quoted string) %Q(This is a double-quoted string)
x = <<END_OF_STRING All this content will be part of the string with newlines intact. HERE strings are double quoted by default. END_OF_STRING y = <<-'SINGLE_QUOTED' Specify single-quoted HERE strings in this way. SINGLE_QUOTED
I simboli ( Symbol ) sono rappresentati da sequenze di caratteri (per lo più alfanumerici ma con la possibilità di utilizzare alcuni caratteri speciali) preceduti dal carattere “:”
:this_is_a_symbol :"and so is this" :+ # some non-alphanumeric characters are allowed, # primarily for the purpose of defining overloaded operators
A runtime l’interprete garantisce l’unicità dei simboli assicurandoci che due simboli composti dallo stessi caratteri siano lo stesso oggetto.
I Range rappresentano gli estremi di una sequenza di numeri interi o stringhe e rispettano le seguenti sintassi:
1..5 'abb'..'abz' (1..5) ('abb'..'abz') 1...11 # equivalente a 1..10
I Regexp rappresentano una Regular Expression e rispettano le seguenti sintassi:
/^a.*b$/ %r{^a.*b$} /[a-zA-Z].*/ /^[a-z][0-9].*/
NOTA : Per approfondire l’argomento Regular Expression consultare la relativa pagina di Wikipedia
In Ruby tutto è un oggetto, quindi è lecito immaginare che tutti i tipi dati siano costituiti da classi che ereditano da Object.
Anche i numeri sono in realtà oggetti… e come tutti gli oggetti possono avere dei metodi:
10.class => "Fixnum" -10.abs => 10 # in molti linguaggi sarebbe stato abs(-10) 10.next => 11 10.even? => true 10.odd? => false 10.+(3) = 13 # o più semplicemente 10 + 3 = 13 10.times { puts "Hello" } 10.to_s => "10"
NOTA : Nelle classi standard Ruby vendono utilizzati i caratteri “?” e “!” nei nomi di alcuni metodi secondo la seguente convenzione:
Analogamente ai numeri anche le stringhe in realtà sono oggetti dotati dei propri metodi di utilità:
"Hello".length => 5 "Hello".upcase => "HELLO" "Hello".downcase => "hello" "1,2,3".split(",") => ["1", "2", "3"] "".empty? => true "1,2,3".include?("4") => false "1,2,3".+(",4") # o più semplicemente "1,2,3"+",4" "10".to_i => 10 "Hello".to_i => 0 "10H".to_i => 10 "H10".to_i => 0
I Range rappresentano degli intervalli in modo compatto e al tempo stesso orientato agli oggetti:
(1..5).to_a => [1, 2, 3, 4, 5] (1..5).max => 5 (1...5).max => 4 (4..12).min => 4 (10..100).include?(50) => true (10..100) === 5 => true (10..100) === 150 => false ('a'..'z') === c => true
Ruby è in grado di gestire anche sequenze di oggetti non nativi, a patto che siano comparabili (che implementino l’operatore <=> ) e che rispondano al metodo succ ritornando l’elemento successivo della sequenza
MyClass.new(1)..MyClass.new(100)
Le Regular Expression consentono di esprimere in maniera compatta regole di analisi del testo:
/[a-z]/ =~ "prova" => 0 /[a-z]/ =~ "1prova" => 1 /[a-z]/.match("prova") => #<MatchData "p"> /[a-z]/.match("1prova").to_s => 'p' /[a-z]/.match("1prova").post_match => 'rova' /[a-z]/.match("1prova").pre_match => '1' def show_regexp(a, re) if a =~ re "#{$`}<<#{$&}>>#{$'}" else "no match" end end
Gli array sono collezioni di oggetti con indice intero, a loro volta sono costituiti da istanze della classe Array:
a = [0, 1, 5] b = ['abc', 15, nil] c = %w{ dog cat tiger } => [ 'dog', 'cat', 'tiger' ] a[0] => 0 b[2] => nil a[5] => nil # ATT!!! indici fuori lunghezza ritornano nil a => [0, 1 5] [0, 1, 5].at(0) => 0 %w{ dog cat tiger }.member?('dog') => true c.member?('panther') => false c.sort! => ["cat", "dog", "tiger"] c.slice(1..2) => ["dog", "tiger"]
Gli hash (o dizionari) sono collezioni di oggetti indicizzati da una chiave di tipo arbitrario (un qualsiasi oggetto):
dict1 = { 'key1' => 'value1', 'key2' => 'value2' } dict2 = { :key1 => 'value1', :key2 => 'value2' } dict1['key1'] => 'value1' dict2[:key2] => 'value2' dict1[:key1] => nil dict1[:key1.to_s] => 'value1' dict2["key1".to_sym] => 'value1' dict1.size => 2 dict1.merge(dict2) => { :key1 => 'value1', :key2 => 'value2', 'key1' => 'value1', 'key2' => 'value2' } dict1.keys => [ "key1", "key2" ] dict1.each { |key, value| puts "#{key}: #{value}" }
In Ruby tutto è una espressione, cioè anche le strutture di controllo ( if , while , for , case ) ritornano un valore.
res = if condition1 then block1 elsif condition2 then block2 else block3 end action if condition1 mon, day, year = $1, $2, $3 if date =~ /(\d\d)-(\d\d)-(\d\d)/
res = unless condition1 then block1 else block2 end action unless condition1 print total unless total.zero? value = current > 100 ? true : false
str = case when year >= 2000: "maggiore/uguale di duemila" when year < 2000: "minore di duemila" end
str = case year when 1..2000: "minore/uguale di duemila" when 2001..65536: "maggiore di duemila" end
NOTA: In questa forma Ruby confronterà la variabile year con gli argomenti di when mediante l’operatore ===
case input_line when "help" puts "help blah blah..." when "cmd1" puts "elaborating cmd1..." puts "done" when /^info\s+(\w+)/ puts "info: #{$1}" when "quit", "exit" exit else puts "Unknown input: #{input_line}" end
while line = gets case line when /^help$/ puts "help..." when /^info$/ puts "info..." else puts "Unknown input: #{line}" end end
i = 0 until i == 10 puts i i += 1 end a = 1 a *= 2 while a < 100 a -= 10 until a < 100
NOTA : gets inserisce un \n alla fine di ogni stringa letta
for i in ['fee', 'fi', 'fo', 'fum'] print i, " " end for i in 1..3 print i, " " end for k,v in { :k1 => 10, :k2 => 20 } puts "#{k}: #{v}" end
i=0 loop do i += 1 next if i < 3 print i break if i > 4 end for i in 1..100 print "Now at #{i}. Restart? " retry if gets =~ /^y/i end
#!/bin/env ruby
puts "Hello, World!"
$ ruby hello.rb Hello, World! $ chmod a+x hello.rb $ ./hello.rb Hello, World!
def say_hello(word) puts "Hello, #{word}" end say_hello("World"); say_hello("Moon");
NOTA: il valore ritornato dall’ultima espressione contenuta in un metodo costituirà il valore di ritorno del metodo (il return esplicito è opzionale)
class MyClass def initialize puts "init" end end
class MyClass def initialize ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc) end def MyClass.finalize(id) puts "Object #{id} dying at #{Time.new}" end end # test code 3.times { MyClass.new } ObjectSpace.garbage_collect
class MyClass @@class_var = "class var value" attr_accessor :rw_instance_var attr_reader :ro_instance_var attr_writer :wo_instance_var def initialize @rw_instance_var = "test value" end end
class MyChildClass < MyClass end mcc = MyChildClass.new mcc.rw_instance_var
class MyClass def MyClass.test_class_method1 puts "test_class_method1" end def self.test_class_method2 puts "test_class_method2" end class << self def test_class_method3 puts "test_class_method3" end end end MyClass.test_class_method1 MyClass.test_class_method2 MyClass.test_class_method3 ...
class A protected def protected_method end private def private_method end end class B < A public def test_protected myA = A.new myA.protected_method end end b = B.new.test_protected
Il concetto di Closure (“chiusura”) deriva da Scheme e dalla programmazione funzionale in generale.
Consiste in una funzione (o blocco di codice) che porta con se le variabili raggiungibili dallo scope in cui è stata dichiarata oltre al codice che la compone.
La possibilità di definire Closure nei vari linguaggi di programmazione richiede che siano supportate le funzioni come First-class-object e viene spesso associato alla possibilità di definire funzioni anonime
From Wikipedia
L’uso delle Closure è molto simile a quello delle First class function in generale e vengono spesso utilizzate per:
Le Closure in Ruby sono utilizzate soprattutto per gli iteratori e sono alla base dell’implementazione in Ruby dei DSL (Domain Specific Language) interni come Ruby On Rails
[1,2,3,4].each do |i| puts i end {:p1 => "v1", :p2 => "v2"}.each do |k,v| puts "#{k}: #{v}" end ["a", "b", "c"].each { |i| puts i } [1,2,3,4].select { |i| i % 2 == 0 } [1,2,3,4].map { |i| i * 2 } def mult_forge(n) lambda { |i| i*n } end double = mult_forge(2) [1,2,3,4].map &double
class Array def each_odd self.each do |elem| yield elem if elem.odd? end end end [1,2,3].each_odd { |i| puts i }
class Array def each_odd(&blk) self.each do |elem| blk.call(elem) if elem.odd? end end end [1,2,3].each_odd { |i| puts i }
Ruby è dotato di una completissima libreria di classi standard:
Per includere una libreria si utilizza il metodo require
require 'fileutils' FileUtils.mkdir("/tmp/test") FileUtils.mkdir("/tmp/test/test1") tmp = Dir.open("/tmp/test").each { |i| puts i }
I Moduli in Ruby svolgono sia la funzione di Namespace che di Mixin per l’inclusione di blocchi di codice nel contesto dell’oggetto corrente.
module MyNamespace class MyClass end end MyClass # NameError: uninitialized constant Test MyNamespace MyNamespace::MyClass
module MyMixin def method_mm1 end end class MyClass include MyMixin def method1 end end class OtherClass extend MyMixin def method1 end end MyClass.instance_methods(false) MyClass.instance_methods() OtherClass.singleton_methods() OtherClass.instance_methods(false)
begin try_a_method rescue NameError => e puts e else puts "A different exception" ensure puts "ensure block" end def testmethod try_a_method raise "error" rescue NameError => e puts "try_a_method don't exist" end testmethod def try_a_method end testmethod
In Ruby, a differenze di linguaggi ad oggetti diffusi come C++ e Java, le classi non sono chiuse dopo la loro prima dichiarazione ma possono essere riaperte a Runtime in qualsiasi momento allo scopo di aggiungere del nuovo codice.
Questa caratteristica di Ruby affonda le radici nel passato: Smalltalk.
class MyClass @@class_var = "test_val" def MyClass.class_var @@class_var end end class MyClass def self.class_var=(new_value) @@class_var = new_value end end
Anche le classi contenute nella Ruby Standard Library (String, Fixnum, Range etc.) possono essere riaperte a Runtime.
class String def open File.open(self,"r") end end puts "/etc/lsb-release".open.read
If it walks like a duck and quacks like a duck, I would call it a duck.
In other words, don’t check whether it IS-a duck: check whether it QUACKS-like-a duck, WALKS-like-a duck, etc, etc, depending on exactly what subset of duck-like behaviour you need to play your language-games with.
Le tecniche di metaprogrammazione e le caratteristiche dei linguaggi che ne consentano l’implementazione sono diverse:
La Metaprogrammazione consiste nella possibilità di scrivere software che genera altro software, lo manipola come se fossero dati, o di eseguire a runtime task eseguiti di solito in compile time
Tecniche di metaprogrammazione avanzate erano presenti in linguaggi come Lisp/Scheme e Smalltalk .
From Wikipedia
ObjectSpace.each_object { |o| puts o if o.class == Class } ObjectSpace.each_object(Class) { |o| puts o } 10.methods 10.respond_to?(:to_s) 10.id 10.class => Fixnum 10.kind_of? Fixnum => true 10.kind_of? Numeric => true 10.instance_of? Fixnum => true 10.instance_of? Numeric => false Fixnum.class Fixnum.superclass Fixnum.ancestors Fixnum.included_modules Fixnum.include?(Comparable)
class MyClass A_CONST = "const value" @@a_var = "class var value" private def method1; puts "private method"; end protected def method2; puts "protected method"; end public def method3 @an_other_var = "instance var value" local1, local2 = 1, 2 local_variables end def self.method4 end end
MyClass.instance_methods MyClass.instance_methods(false) MyClass.public_instance_methods(false) MyClass.protected_instance_methods(false) MyClass.private_instance_methods(false) MyClass.singleton_methods(false) MyClass.class_variables MyClass.constants MyClass.method_defined?(:method3) MyClass.respond_to?(:method3) mc1 = MyClass.new mc1.respond_to?(:method3) mc1.instance_variables mc1.method3 mc1.instance_variables ...
10.send(:to_s) "10,20".send("split",",") split = "10,20".method("split") split.call(",") split.call("0") def double(x); 2*x; end dbl = method(:double) [1,2,3].collect(&dbl) def a_method local_val = "local value" binding end local_val = "different scope" method_binding = a_method eval("local_val", method_binding) eval("local_val")
# definizione di metodi di classe (espressione valutata nel contesto nell'oggetto singleton di tipo Class) # MyClass.instance_eval MyClass.instance_eval { def method1; end} MyClass.instance_methods(false) MyClass.singleton_methods # definizione di metodi di istanza metodi di istanza (espressione valutata nel contesto della Classe) # MyClass.class_eval | MyClass.module_eval MyClass.class_eval { def method2; end} MyClass.instance_methods(false) MyClass.singleton_methods class MyClass #metodi di istanza class << self #metodi di classe end end
# Definizione di una versione localizzata (e semplificata) di attr) # Module.class_eval do def attributo(name) define_method(name) do instance_variable_get('@'+name.to_s) end define_method(name.to_s+"=") do |value| instance_variable_set('@'+name.to_s,value) end end end class MyClass attributo :test end MyClass.instance_methods ...
class MyClass def method_missing(m, *args) puts "WARN: no method #{m}!!!" end end MyClass.new.everything_you_want ...