Ruby Gems são ferramentas amplamente utilizadas no desenvolvimento de aplicações, oferecendo soluções prontas para resolver problemas comuns em muitos projetos. Neste tutorial vamos mostrar passo a passo como criar sua própria Ruby Gem.
Antes de começar
A seguir, alguns conceitos importantes que serão necessários para compreender esse tutorial: - Resumidamente, uma gem é uma biblioteca de código Ruby (conjunto de classes/módulos e métodos) reutilizável, ou seja, pode ser aproveitada em diferentes partes das aplicações para realizar uma determinada função. - Rubygems é a plataforma mais conhecida e utilizada pela comunidade, oferecendo hospedagem dos códigos publicados por usuários. - Bundler é o gerenciador de gems e dependências do ruby.
Construindo a gem
O próprio Bundler possui um comando para criar o repositório e a estrutura com os arquivos padrão recomendados para a gem, mas também é possível construir os arquivos individualmente ou adicionar o gemspec (vamos falar sobre ele mais pra frente) a um projeto já existente. Neste tutorial utilizaremos o inicializador do bundle para criar uma gem chamada “example”. Para evitar a criação de uma gem cujo nome já existe, recomenda-se utilizar a pesquisa no RubyGems com nome desejado para verificar a pré-existência de alguma gem com este nome. Este tutorial utiliza a versão 2.7.0 do Ruby.
Dica: O Rubygems possui algumas recomendações em relação ao nome da gem. A tabela a seguir demonstra as diferenças da estrutura e referenciação no código em relação ao seu nome.
Nome da gem (não utilizar maiúsculas) | Referência no código | Classe/Módulo principal |
---|---|---|
test_gem | require ‘test_gem’ | TestGem |
test-gem | require ‘test/gem’ | Test::Gem |
Além disso, /
é utilizado sua gem esteja adicionando funcionalidades a outra gem. Para mais informações, veja esse guia.
1° passo - Criando o projeto
Execute o comando bundle gem example
, substituindo example
com o nome da sua gem:
$ bundle gem example ruby-2.7.0
Creating gem 'example'...
create example/Gemfile
create example/lib/example.rb
create example/lib/example/version.rb
create example/example.gemspec
create example/Rakefile
create example/README.md
create example/bin/console
create example/bin/setup
create example/.gitignore
create example/.travis.yml
create example/test/test_helper.rb
create example/test/example_test.rb
Initializing git repo in /home/icaro/Workspace/rebase/example
Gem 'example' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
Os arquivos são criados com a seguinte estrutura:
2° passo - Criação do gemspec
Para construir uma gem é necessário possuir o arquivo gemspec na raíz da aplicação. Este arquivo é um manual de instruções da gem para o Ruby, nele estão contidos dados e metadados da gem como nome, versão, autores, entre outras. Além disso, as dependências externas como outras gems são declaradas no gemspec (add_development_dependency
e add_runtime_dependency
dependendo da função da dependência, ou apenas add_dependency
). Atualizaremos nosso gemspec padrão para o seguinte:
require_relative 'lib/example/version'
Gem::Specification.new do |spec|
spec.name = "example"
spec.version = Example::VERSION
spec.authors = ["Your User"]
spec.email = ["your@user.com.br"]
spec.summary = %q{Write a short summary, because RubyGems requires one.}
spec.description = %q{Write a longer description or delete this line.}
spec.homepage = "https://homepage.com.br"
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.metadata["allowed_push_host"] = "Set to 'http://mygemserver.com'"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "https://github.com/User/your_repository"
spec.metadata["changelog_uri"] = "https://github.com/User/your_repository/changelog.md"
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_development_dependency 'bundler', '~> 2.0'
spec.add_development_dependency 'minitest', '~> 2.1.0'
spec.add_development_dependency 'mocha', '~> 1.11.2'
end
Neste exemplo, foram inseridas as informações de contato e adicionadas as dependências que serão utilizadas pela aplicação.
3° passo - Criação da base do código
Recomenda-se que todos os arquivos de classes e/ou módulos estejam na pasta lib
e os testes na pasta test
ou spec
. Para este exemplo, iremos construir um simples selecionador de nomes aleatório (como a gem Faker), uma formatação do nome no formato de e-mail e seus respectivos testes:
Arquivo: example/lib/example.rb
.
class Example
NAMES = ['Bilbo Baggins',
'Samwise Gangee',
'Meriadoc Brandebuque',
'Frodo Baggins',
'Peregrin Took']
def self.random_name
NAMES.sample
end
def self.random_email
name = NAMES.sample
"#{name.gsub(' ', '.').downcase}@shire.com.me"
end
end
Arquivo: example/test/example_test.rb
.
require 'minitest/autorun'
require './lib/example'
require 'mocha/minitest' # gem utilizada para fazer o mock do resultado no teste
class ExampleTest < Minitest::Test
def test_random_name
Array.any_instance.stubs(:sample).returns('Samwise Gangee')
assert Example.random_name == 'Samwise Gangee'
end
def test_random_email
Array.any_instance.stubs(:sample).returns('Samwise Gangee')
assert Example.random_email == 'samwise.gangee@shire.com.me'
end
end
Para executar os testes rode bundle install
e, então, ruby test/*
.
$ ruby test/* ruby-2.7.0 master
Run options: --seed 60160
# Running:
..
Finished in 0.001388s, 1441.1890 runs/s, 1441.1890 assertions/s.
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
Dica: Acesse os repositórios das gems que costuma utilizar no dia a dia e veja a estruturação do código e os testes, isso pode ajudar a identificar boas práticas e aplicá-las em seu código.
4° passo - Documentação
A documentação é de extrema importância, pois uma gem muitas vezes é uma dependência utilizada por terceiros. Logo, sua utilização correta depende do entendimento por quem for utilizá-la. A documentação padrão que foi inicializada pelo bundler já possui uma estrutura que pode ser seguida como base, nesse caso será substituída por uma simples documentação da app:
5° passo - Construindo a gem (example.gem)
Para criar o .gem
basta executar o comando gem build
passando o gemspec. O bundler utilizará o gemspec e criará o arquivo example-0.1.0.gem
, que contém o código “empacotado” já no seu formato instalável pelo bundler, ou seja, a gem propriamente dita.
$ gem build example.gemspec ruby-2.7.0 master
WARNING: licenses is empty, but is recommended. Use a license identifier from
http://spdx.org/licenses or 'Nonstandard' for a nonstandard license.
WARNING: See http://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: example
Version: 0.1.0
File: example-0.1.0.gem
Feito isso, já temos a gem pronta para ser instalada e utilizada!
Podemos instalá-la localmente com o comando gem install
passando o arquivo .gem
criado no passo anterior como opção:
$ gem install example-0.1.0.gem ruby-2.7.0 master ✗
Successfully installed example-0.1.0
1 gem installed
Podemos verificar se a gem foi instalada corretamente e sua versão através do comando gem list
:
gem list grep example ruby-2.7.0 master ✗
*** LOCAL GEMS ***
*** LOCAL GEMS ***
example (0.1.0)
Agora, com a gem instalada, vamos testá-la no IRB:
irb ruby-2.7.0 master ✗
2.7.0 :001 > require 'example'
=> true
2.7.0 :002 > Example.random_name
=> "Frodo Baggins"
2.7.0 :003 > Example.random_name
=> "Peregrin Took"
2.7.0 :004 > Example.random_email
=> "bilbo.baggins@shire.com.me"
2.7.0 :005 > Example.random_email
=> "samwise.gangee@shire.com.me"
Agora a gem está instalada e pronta para ser utilizada, como podemos ver se os métodos são chamados e funcionam corretamente.
6° passo - Publicando a gem
Para disponibilizar a gem no site RubyGems e torná-la disponível para ser utilizada pela comunidade, é necessário criar uma conta no RubyGems (caso ainda não tenha) para configurar a autenticação.
Agora já podemos enviar a gem ao repositório remoto com o comando gem push nome-da-gem.gem
e, em seguida, inserir o e-mail e senha correspondente à sua conta do RubyGems:
$ gem push nome-da-sua-gem.gem
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at https://rubygems.org/sign_up
Email: gem_author@example
Password:
Signed in.
Pushing gem to RubyGems.org...
Successfully registered gem: nome-da-sua-gem (versão)
Pronto! Sua Ruby Gem está disponível para ser utilizada pela comunidade. :D