Creazione di gemme con Bundler

Costruire una gemma era un compito complesso che richiedeva una conoscenza precisa del formato della gemma, di se stesso o di alcuni strumenti dedicati per generare una piastra adatta. In questi giorni, possiamo usare l'eccellente Bundler per rimuovere questa complessità e mantenere al minimo la quantità di codice generato.


Cosa stiamo costruendo

La gemma di prova che stiamo per costruire è un generatore di contenuto fittizio che potresti utilizzare durante lo sviluppo. Invece di generare frasi "lorem ipsum", usa Dracula di Bram Stoker per generare una quantità arbitraria di frasi prese dal libro. Il nostro flusso di lavoro inizierà generando la gemma, testando e implementando la quantità minima di codice necessaria per ottenere la nostra gemma pronta e quindi pubblicandola su RubyGems.


Generare uno scheletro

Presumo che tu abbia già installato un ambiente Ruby. Per questo tutorial, useremo Ruby 1.9.3 come base di riferimento. Se si prevede, tuttavia, di sviluppare un vero gioiello, potrebbe essere utile testarlo anche su Ruby 1.8 e altri interpreti. A tale scopo, uno strumento come Travis CI è una manna dal cielo; Con una solida suite di test, Travis ti permetterà di testare la tua gemma contro un'ampia varietà di piattaforme senza problemi. Iniziamo generando lo scheletro:

bundle gem bramipsum

Mi dispiace davvero se non ti piace il nome che ho scelto, infatti uno dei compiti più difficili nello sviluppo di un gioiello è trovare il nome giusto. Il comando creerà una directory, chiamata bramipsum con pochi file:

Gemfile

Il Gemfile è molto minimale:

source 'http://rubygems.org' # Specifica le dipendenze della tua gemma in bramipsum.gemspec gemspec

Nota che ti dice chiaramente di spostare le tue dipendenze gem bramipsum.gemspec, per avere tutti i dati rilevanti per la tua gemma nel file che verrà utilizzato per popolare i metadati su Rubygems.

bramipsum.gemspec

Il gemspec il file contiene una buona quantità di informazioni sulla nostra gemma; possiamo vedere che dipende molto Idiota per assegnare i giusti valori a tutte le variabili che coinvolgono l'elenco dei file.

# - * - encoding: utf-8 - * - richiede File.expand_path ('... / lib / bramipsum / version', __FILE__) Gem :: Specification.new do | gem | gem.authors = ["Claudio Ortolina"] gem.email = ["[email protected]"] gem.description =% q TODO: Scrivi una descrizione della gemma gem.summary =% q TODO: Scrivi un sommario della gemma  gem.homepage = "" gem.executables = 'git ls-files - bin / *'. split ("\ n"). map | f | File.basename (f) gem.files = 'git ls-files'.split ("\ n") gem.test_files =' git ls-files - test, specifiche, caratteristiche / * '. Split (" \ n ") gem.name =" bramipsum "gem.require_paths = [" lib "] gem.version = Bramipsum :: VERSIONE gem.add_development_dependency" rastrello "fine

Successivamente, possiamo correre fascio installare Rake. Dato che è stato aggiunto come dipendenza di sviluppo, non sarà installato da Bundler quando qualcuno usa la nostra gemma.

Alcune note interessanti sul file:

  • Include il commento di apertura di Ruby 1.9 che specifica la codifica del file. Questo è importante, dal momento che alcuni dati nel file (come l'e-mail o il nome dell'autore) possono essere un carattere non-ascii.
  • descrizione e sommario devono essere cambiati per essere visualizzati correttamente su Rubygems.
  • La versione è definita all'interno del lib / bramipsum / versione file, richiesto in alto. Definisce il VERSIONE costante, chiamato subito prima della fine del file.

La cartella lib

Il lib la cartella contiene un generico bramipsum.rb file che richiede il versione modulo. Anche se il commento nel file suggerisce di aggiungere codice direttamente al file stesso, lo useremo solo per richiedere classi separate che formeranno la nostra piccola gemma.


Aggiornamento dei dati di base e aggiunta di un framework di test

Iniziamo aggiornando i dati in bramipsum.gemspec:

... gem.description =% q Frasi a caso da Dracula di Bram Stoker gem.summary =% q Genera una o più frasi fittizie prese da Dracula di Bram Stoker ... 

Roba molto semplice Successivamente, aggiungiamo il supporto per il test corretto. Noi useremo Minitest, come è incluso di default in Ruby 1.9. Aggiungiamo a test directory:

test di mkdir

Successivamente, abbiamo bisogno di a test_helper.rb file e un test per la presenza del Bramipsum :: VERSIONE costante.

touch test / test_helper.rb mkdir -p test / lib / bramipsum touch test / lib / bramipsum / version_test.rb

Apriamo il test_helper.rb file e aggiungi alcune righe:

richiedere 'minitest / autorun' richiede 'minitest / pride' richiede File.expand_path ('... / ... /lib/bramipsum.rb', __FILE__)

Richiede sia Minitest che Pride per l'output colorato; quindi richiede il file bramipsum principale.

Il version_test.rb il file deve essere aggiornato con il seguente codice:

require_relative '... / ... / test_helper' descrive Bramipsum fallo "deve essere definito" fai Bramipsum :: VERSION.wont_be_nil end end

Usiamo il formato di aspettativa per i nostri test. Il test stesso è abbastanza autoesplicativo e può essere facilmente eseguito digitando:

ruby test / lib / bramipsum / version_test.rb

Dovresti fare un test di passaggio!

Aggiungiamo ora il Rakefile avere un modo più comodo per eseguire i nostri test. Cancella tutto e incolla il seguente codice:

#! / usr / bin / env rake richiede "bundler / gem_tasks" richiede 'rake / testtask' Rake :: TestTask.new do | t | t.libs << 'lib/bramipsum' t.test_files = FileList['test/lib/bramipsum/*_test.rb'] t.verbose = true end task :default => :test

Questo ci consentirà di eseguire i nostri test digitando rastrello dalla cartella gem root.


Aggiunta di funzionalità

Poiché il focus di questo tutorial è la creazione di un gioiello, limiteremo la quantità di funzionalità che aggiungeremo.


Classe Base

Il bramipsum è ancora un guscio vuoto. Siccome vogliamo usare il libro di Dracula per generare frasi, è il momento di aggiungerlo al repository. Ho preparato una versione del libro in cui ho rimosso qualsiasi contenuto, tranne la storia stessa: aggiungiamola al progetto.

mkdir -p book curl https://raw.github.com/cloud8421/bundler-gem-tutorial/master/book/dracula.txt -o book / dracula.txt

Creiamo ora un Base classe, dove si aggiungeranno tutti i metodi necessari per estrarre i dati dal libro.

touch lib / bramipsum / base.rb touch test / lib / bramipsum / base_test.rb

Il file di test avrà solo alcune aspettative:

require_relative '... / ... / test_helper' descrive Bramipsum :: Base do subject Bramipsum :: Base descrive "lettura da file" fallo "deve avere un'origine" do subject.must_respond_to (: source) termina "deve avere il dracula file come sorgente "do subject.source.must_be_instance_of (String) end end descrive" splitting in lines "fallo" deve dividere correttamente il file in linee "do subject.processed_source.must_be_instance_of (Array) e termina" deve rimuovere correttamente le linee vuote "do subject.processed_source.wont_include (nil) end end end

In esecuzione rastrello ora mostrerà un'eccezione, come il base.rb il file è ancora vuoto. Base leggerà semplicemente il contenuto del file e restituirà una serie di linee (rimuovendo quelle vuote).

L'implementazione è molto semplice:

module Classe Bramipsum Base def self.source @source || = self.read end def self.processed_source @processed_source || = self.source.split ("\ n"). uniq end private def self.read File.read (File .expand_path ('book / dracula.txt')) end end end

Definiamo una serie di metodi di classe che contengono il testo originale e una versione elaborata, memorizzando nella cache i risultati dopo la prima esecuzione.

Abbiamo quindi bisogno di aprire lib / bramipsum.rb e aggiungi la dichiarazione di richiesta giusta:

require_relative "./bramipsum/base"

Se salvi e corri rastrello ora dovresti vedere passare tutti i test.


Frase di classe

Successivamente, abbiamo bisogno di aggiungere una nuova classe per generare frasi. Lo chiameremo Condanna, frase.

touch lib / bramipsum / sentence.rb touch test / lib / bramipsum / sentence_test.rb

Come prima, dobbiamo aprire lib / bramipsum.rb e richiede il file appena creato:

require_relative "./bramipsum/base" require_relative "./bramipsum/sentence"

Da questa classe erediterà Base, quindi possiamo mantenere l'implementazione minima. Il test richiederà solo tre aspettative:

require_relative '... / ... / test_helper' descrive Bramipsum :: Frase del soggetto Bramipsum :: Frase "deve restituire una frase casuale" do subject.sentence.must_be_instance_of (String) termina "deve restituire 5 frasi per impostazione predefinita" fai oggetto .sentences.size.must_equal (5) terminare "deve restituire la quantità specificata di frasi" do subject.sentences (10) .size.must_equal (10) end end

L'idea è che possiamo chiamare Bramipsum :: Sentence.sentence o Bramipsum :: Sentence.sentences (10) per generare ciò di cui abbiamo bisogno.

Il contenuto per sentence.rb è anche molto conciso:

modulo Bramipsum classe Frase < Base def self.sentence self.processed_source.sample end def self.sentences(n=5) self.processed_source.sample(n) end end end

Dato che siamo su Ruby 1.9, possiamo usare il campione metodo per restituire un elemento casuale da una matrice.

Ancora una volta, correndo rastrello dovrebbe mostrare tutti i test che passano.


Costruire e distribuire la gemma

Se corri build gemma dalla riga di comando, una copia locale della gemma verrà costruita e confezionata per te. Se non hai bisogno di distribuirlo, o se devi mantenerlo privato, puoi fermarti qui. Ma se si tratta di un progetto che puoi open source, ti incoraggio a farlo.

Il passo ovvio è aggiungere il nostro nuovo gioiello a RubyGems.org.

Dopo aver creato un account sul sito, visita il tuo profilo. Troverai un comando che devi eseguire per autorizzare il tuo computer. Nel mio caso è stato:

curl -u cloud8421 https://rubygems.org/api/v1/api_key.yaml> ~ / .gem / credentials

Ora sei a un solo passo per pubblicare la gemma su Rubygems, tuttavia non farlo a meno che tu non lo voglia. Il comando che avresti eseguito è:

gemma spingere bramipsum-0.0.1.gem

Conclusione

Congratulazioni! Ora sai come creare una gemma da zero usando semplicemente Bundler. Tuttavia, ci sono altre cose da tenere in considerazione:

  • Compatibilità: potresti voler supportare anche Ruby 1.8. Ciò richiederà il refactoring di tutto il require_relative le chiamate; inoltre, sarà necessario utilizzare il Minitest gem come non è incluso di default in Ruby 1.8
  • Integrazione continua: puoi aggiungere supporto a Travis CI e il tuo gioi verrà testato nel cloud contro tutte le principali versioni di Ruby. Ciò renderà semplice accertarsi che non vi siano problemi con le modifiche al comportamento specifiche della piattaforma.
  • Documentazione: questo è importante, è bello avere commenti RDoc che possono aiutare a generare documenti automatici e un buon file README con esempi e linee guida.

Grazie per aver letto! Qualsiasi domanda?