
Nel post precedente ho tralasciato parecchie cose su come gestire file e directory con Ruby. Ne è nata una discussione, credo sia il caso di approfondire l’argomento. Anche perché non ci sono cose nuove, non ancora affrontate nel corso.
Una cosa che ho dato per scontata e forse non lo è: in Ruby ci sono sempre diverse vie per fare una cosa, non so se è un bene o no, ma è la filosofia di Matz. Ancora: ci sono istruzioni che nel tempo cambiano; quello che era OK con la revisione x.y
non vale più dalla z.0
in poi. Non proprio l’ideale, ma dobbiamo conviverci.
require
e load
Le due istruzioni sembrano uguali, consentono entrambe di usare nello script corrente le risorse (oggetti, in Ruby tutto è un oggetto) definite al loro interno come se fossero nel file corrente. C’è però una grossa differenza: require
va usato una sola volta gli oggetti vengono memorizzati mentre load
è solo un modo per evitare il copia-incolla da un file a quello corrente, evitando di doverlo rifare quando si modifica l’originale; quindi può essere usato più volte nello stesso script (se uno è pasticcione, altrimenti non credo sia necessario).
Ecco un esempio minimo che usa sia require
che load
(loreq.rb):
#!/usr/bin/ruby
# encoding: UTF-8
# loreq.rb
load 'lo-0.rb'
puts "sono nel main: #{__FILE__}"
require './req.rb'
puts "v = #{$v}"
load 'lo-1.rb'
puts "v2 = #{$v2}"
ci servono 3 file, 2 per load
e 1 per require
, eccoli:
#!/usr/bin/ruby
# encoding: UTF-8
# lo-0.rb
puts "sono nel file: #{__FILE__}"
#!/usr/bin/ruby
# encoding: UTF-8
# rec.rb
$v = 8
#!/usr/bin/ruby
# encoding: UTF-8
# lo-1.rb
$v2 = 42
Inoltre nella variabile di sistema __FILE__
viene memorizzato il nome del file corrente. Altre cose sulle directories verranno raccontate in seguito, per adesso vediamo cosa succede se lo eseguiamo:

Tutto come previsto, anche le variabili definite nei file secondari sono visibili in quello principale. Sappiamo già che quelle il cui nome inizia con $
sono globali, vero?
Ma se questo è logico per require
con load
la variabile dev’essere globale? Uh… ehmm, io penso che …, dai proviamo (testload.rb e incload.rb):
#!/usr/bin/ruby
# encoding: UTF-8
# testload.rb
load 'incload.rb'
puts "nel main: prova = #{prova}"
# incload.rb
prova = 42
puts "nel file incluso: prova = #{prova}"

OPS! no! load
non si comporta come dovrebbe; la variabile dichiarata al suo interno non viene vista nel main. Quindi, se non è un bug che verrà corretto, non usare load
ma require
.
Accedere a file e directory
Non sempre i file e le risorse che ci servono sono nella stessa directory (cartella). Nessun problema, Ruby è in grado di gestire benissimo la cosa (quasi), ecco un primo esempio (path.rb):
#!/usr/bin/ruby
# encoding: UTF-8
# path.rb
nomefile = __FILE__
puts "nomefile = #{nomefile}"
pathname = File.expand_path(nomefile)
puts "pathname = #{pathname}"
dirname = File.expand_path('../', pathname)
puts "dirname = #{dirname}"
t = dirname + '/'
puts "inutile ma dirname + '/' = #{t}"
home = File.expand_path('~')
puts "home = #{home}"

Tutto come previsto, il modulo File
fa parte di quelli predefiniti, immediatamente disponibili, senza usare require.
L’operatore +
concatena le stringhe, come già visto. Per trattare i pathnames in realtà non serve ma volendo c’è. Ovviamente ~
è definita solo per Linux. Per Windows si può usare ENV
, un hash che mappa le variabili di ambiente (environment), così (hvs.rb):
#!/usr/bin/ruby
# encoding: UTF-8
# hvs.rb
home = ENV['HOME']
puts "home = #{home}"

Attenzione: è un hash, le parentesi sono quadre 😉
FileUtils
Ci sono ancora tante cose da vedere; per esempio c’è tutto il modulo FileUtils
. Che (almeno da me) non è che funzioni proprio come dovrebbe. Eccone un assaggio, maggiori informazioni, forse, in futuro (fu-pwd.rb):
#!/usr/bin/ruby
# encoding: UTF-8
# fu-pwd.rb
require 'fileutils.rb'
fdir = FileUtils.pwd
puts "directory corrente = #{fdir}"
questo = File.join(fdir, __FILE__)
puts "questo = #{questo}"
f = File.file?(questo)
d = File.directory?(questo)
print f, " ", d, "\n"

Notare che il modulo dev’essere inserito con require
(riga 6) e che il nome del file è tutto minuscolo. Le funzioni contenute sono elencate qui.
Non tutte funzionano, anche perché il modulo si riferisce a una versione diversa da quella che sto utilizzando. resta indispensabile il modulo File
.
Notare alla riga 11 il modo sicuro per concatenare i path e i predicati file?
e directory?
(righe 14 e 15). Ne esistono parecchi altri, tra i quali exists?
Per oggi basta 😀 e per un po’ basta Ruby, ci sono altre cose in coda 😉