Closed cstrap closed 7 years ago
Ok, credo di aver capito il perché non avevo capito. Il concetto equivalente alla directory site-package è praticamente scomparso in Ruby.
In sviluppo si usano i version manager come rvm per gestire più versioni dell'interprete (indispensabile perché si hanno clienti con progetti su versioni diverse). L'equivalente Python è virtualenv.
Per ogni versione di Ruby si installa il package manager (sempre bundler ma possono volerci versioni diverse) con cui gestire insiemi diversi di gemme per progetto. Si può fare switch a mano o usare i gemset. Tipicamente le gemme finiscono da qualche parte dentro a ~/.rvm
, separate per interprete e per gemset. Credo che virtualenv faccia anche questo.
In produzione si fa un deploy con bundle nella directory del progetto, circa come fa npm.
L'equivalente Ruby del package Python sembra essere la gemma, che però richiede un po' più di lavoro di packaging. Il file singolo Ruby non è niente, ma se ne può fare require ed usarne il contenuto. Se il suo contenuto è racchiuso in module end
equivale ad un modulo Python ed ha un suo namespace. Non solo bisogna farne require, ma anche import. Qui è dove aiuta Rails, che fa da solo tutte le require e le import per i file in certe directory.
Per distribuire i package e poterli scaricare con pip si usa il formato wheel?
Per i package si può usare sia wheel che zip. I setuptools
aiuta a pacchettizzare il tutto grazie ad un file chiamato setup.py
. La differenza tra wheel e zip è che il nuovo formato wheel contiene i compilati C, quindi non si ha più la necessità di avere librerie esterne (es. il driver di postgres in psycopg)
Nelle ultime versioni di pip prevale wheel.
Tra l'altro non serve pip per installare un package, potrebbe essere banalmente scompattato, per poi essere installato con python setup.py install
Nulla vieta di avere un package non pacchettizzato (zip o wheel), ma installabile dai sorgenti, l'importante è la presenza di setup.py
.
Si può far benissimo pip install https://github.com/nomepacchetto
, pip install local/path
... ci sono un po' di opzioni.
Una interessante è la -e
che permette di installare il package in editing, ma sto andando OT, troppe informazioni.
Gli ambienti con virtualenv e rvm necessitano di una sezione a parte.
Comunque sì, grazie al file requirements.txt
(che può chiamarsi anche pippo o qualsivoglia, è solo convenzione) vengono riportati tutti i package, con versione, del progetto.
Molto semplicemente un package e' solo un gruppo di moduli python. Dentro uno stesso progetto posso definere piu' package e o moduli. Ad esempio se dovessi scrivere "Quake" in python farei un package "client", un package "server" e un package "Network" usato dagli altri 2. E' una astrazione che rinforza la modularizzazione. Per marcare una directory come package e' stato scelto di usare il file init.py, invece di dichiarare il package in ogni file di una certa directory, come fa Java.
E come fa anche Ruby, ma limitatamente ai file che contengono module ... end
Java ha i package
(la sua keyword è quella) là dove Python ha i moduli e sta introducendo i moduli come collezioni di package (Java 9).
Ruby ha solo moduli e li si usa per creare quelle astrazioni client, server, network nel modo che descrivevo, con un modulo che fa le veci del file __init__.py
Aggiungo che un modulo, può utilizzare il famigerato:
if __name__ == '__main__':
# do something
Utilizzando __name__
si fa in modo che il modulo venga azionato come script nel caso che venga invocato via interprete, ad esempio, python mymodule.py
eseguirà il codice dentro l'if __name__...
, mentre all'interno dell'interprete (o di altro modulo), ad esempio con un import mymodule
, il codice all'interno dell'if __name__...
non sarà eseguito, poiché __name__
non avrà il valore __main__
(riassumendo molto).
In Ruby un file di cui si fa il require viene eseguito dall'inizio alla fine. Se definisce un modulo si può includervi la callback included
che viene eseguita quando poi dell'altro codice farà include QuelModulo
module Foo
def self.included(klass)
puts "Foo has been included in class #{klass}"
end
end
Googlando ho trovato l'equivalente di
if __name__ == '__main__':
# do something
ed è l'orribile
if __FILE__== $0
puts "sei il main!"
end
Di solito si organizzano i programmi in modo che non si debbano scrivere queste __brutture__
: i moduli fanno i moduli e i main fanno i main.
Riassumendo
$ cat a.rb
module A
def self.included(k)
puts "included"
end
end
if __FILE__== $0
puts "sei il main!"
end
$ irb
2.3.0 :001 > require "./a.rb"
=> true
2.3.0 :002 > include A
included
=> Object
$ ruby a.rb
sei il main!
In breve Modulo: qualsiasi script python che contiene classi e funzioni. L'import del modulo deve essere aggiunto al PYHONPATH, oppure risiedere nella directory corrente o ancora in un namespace (senza init) Package: il modo per creare un modulo importabile usando la notazione a punti. Si installa nella directory site-packages e viene esposto a tutto l'interprete, utilizzando la forma
import module
ofrom module import something
.Documentazione: https://docs.python.org/3.6/tutorial/modules.html
il vantaggio di utilizzare uno o l'altro rende il tuo script portabile, con la sola necessità dell'interprete. Es: bottle (una sorta di sinatra), rocket (web server)