Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing Ruby Gems

Writing Ruby Gems

An introduction to how to write Ruby gems - particularly focusing on the gemspec, naming files, managing dependencies, publishing gems, and some bonus tips for writing gems that integrate with Rails.

If you want a version with speaker notes - or the video - visit https://freelancing-gods.com/slides/gems.html

29f82ebe1801087f04de6aaae92e19ea?s=128

Pat Allan

March 25, 2020
Tweet

More Decks by Pat Allan

Other Decks in Technology

Transcript

  1. Womenjika

  2. Writing Ruby Gems Pat Allan - @pat
 https://freelancing-gods.com

  3. What is a gem?

  4. gem |jem| noun a precious or semiprecious stone, esp. when

    cut and polished or engraved.
  5. gem |jem| noun a packaged code library written in the

    Ruby programming language.
  6. gem |jem| noun a command line executable distributed with the

    RubyGems package manager.
  7. rubygems |ˈro ͞ obējemz| noun a package manager for Ruby

    libraries.
  8. rubygems |ˈro ͞ obējemz| noun a website that stores published

    versions of Ruby gems.
  9. Why write a gem?

  10. To re-use code Why write a gem?

  11. To re-use code To make code easy to install Why

    write a gem?
  12. To re-use code Why write a gem? To make code

    easy to install To make code easy to share
  13. How do I write a gem?

  14. gemspec

  15. melb_ruby.gemspec

  16. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  17. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  18. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  19. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  20. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  21. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  22. Gem::Specification.new do |spec| spec.name = "melb_ruby" spec.version = "0.0.1" spec.authors

    = ["Pat Allan"] spec.email = ["pat@freelancing-gods.com"] spec.summary = "A gem that does something" spec.homepage = "https://github.com/pat/melb_ruby" spec.license = "MIT" # ... end
  23. Where do I put files?

  24. melb_ruby/lib # code goes here melb_ruby/exe # executables melb_ruby/bin #

    development commands melb_ruby/spec # or melb_ruby/test melb_ruby/README.markdown melb_ruby/CHANGELOG.markdown
  25. melb_ruby/lib # code goes here melb_ruby/exe # executables melb_ruby/bin #

    development commands melb_ruby/spec # or melb_ruby/test melb_ruby/README.markdown melb_ruby/CHANGELOG.markdown
  26. melb_ruby/lib # code goes here melb_ruby/exe # executables melb_ruby/bin #

    development commands melb_ruby/spec # or melb_ruby/test melb_ruby/README.markdown melb_ruby/CHANGELOG.markdown
  27. melb_ruby/lib # code goes here melb_ruby/exe # executables melb_ruby/bin #

    development commands melb_ruby/spec # or melb_ruby/test melb_ruby/README.markdown melb_ruby/CHANGELOG.markdown
  28. melb_ruby/lib # code goes here melb_ruby/exe # executables melb_ruby/bin #

    development commands melb_ruby/spec # or melb_ruby/test melb_ruby/README.markdown melb_ruby/CHANGELOG.markdown
  29. melb_ruby/lib # code goes here melb_ruby/exe # executables melb_ruby/bin #

    development commands melb_ruby/spec # or melb_ruby/test melb_ruby/README.markdown melb_ruby/CHANGELOG.markdown
  30. # A list of all files in the gem: spec.files

    = ["lib/melb_ruby.rb"] # This is the default: spec.require_paths = ["lib"] # This is *not* the default, but maybe should be: spec.bindir = "exe" # And then you need to explicitly list each # executable: spec.executables = ["melburnian"]
  31. # A list of all files in the gem: spec.files

    = ["lib/melb_ruby.rb"] # This is the default: spec.require_paths = ["lib"] # This is *not* the default, but maybe should be: spec.bindir = "exe" # And then you need to explicitly list each # executable: spec.executables = ["melburnian"]
  32. # A list of all files in the gem: spec.files

    = ["lib/melb_ruby.rb"] # This is the default: spec.require_paths = ["lib"] # This is *not* the default, but maybe should be: spec.bindir = "exe" # And then you need to explicitly list each # executable: spec.executables = ["melburnian"]
  33. # A list of all files in the gem: spec.files

    = ["lib/melb_ruby.rb"] # This is the default: spec.require_paths = ["lib"] # This is *not* the default, but maybe should be: spec.bindir = "exe" # And then you need to explicitly list each # executable: spec.executables = ["melburnian"]
  34. spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do `git ls-files -z`.split("\x0").reject { |f|

    f.match(%r{^(test|spec|features)/}) } end
  35. spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }

  36. Naming is hard

  37. Naming is hard Use underscores between words

  38. MelbRuby

  39. melb_ruby

  40. Naming is hard Use underscores between words Use dashes for

    namespacing
  41. RSpec::Rails

  42. rspec-rails

  43. MelbRuby::Burgers

  44. melb_ruby-burgers

  45. File structure should match the gem name Naming is hard

    Use underscores between words Use dashes for namespacing
  46. # contains MelbRuby: lib/melb_ruby.rb # contains MelbRuby::Burgers lib/melb_ruby/burgers.rb # contains

    MelbRuby::HackNight lib/melb_ruby/hack_night.rb
  47. # contains MelbRuby: lib/melb_ruby.rb # contains MelbRuby::Burgers lib/melb_ruby/burgers.rb # contains

    MelbRuby::HackNight lib/melb_ruby/hack_night.rb
  48. # contains MelbRuby: lib/melb_ruby.rb # contains MelbRuby::Burgers lib/melb_ruby/burgers.rb # contains

    MelbRuby::HackNight lib/melb_ruby/hack_night.rb
  49. # contains MelbRuby: lib/melb_ruby.rb # contains MelbRuby::Burgers lib/melb_ruby/burgers.rb # contains

    MelbRuby::HackNight lib/melb_ruby/hack_night.rb
  50. # don't put MelbRuby::Burgers in lib/burgers.rb # because a gem

    called Burgers # probably has this file too, and # Ruby will get confused.
  51. #!/usr/bin/env ruby require "melb_ruby/cli" MelbRuby::CLI.call

  52. #!/usr/bin/env ruby require "melb_ruby/cli" MelbRuby::CLI.call

  53. exe/melburnian

  54. chmod +x exe/melburnian

  55. Dependencies

  56. Runtime Dependencies

  57. Development Dependencies

  58. spec.add_runtime_dependency "thor", ">= 0.14" spec.add_development_dependency "rspec", "~> 3.0"

  59. Building a gem

  60. melb_ruby-0.0.1.gem

  61. gem build melb_ruby.gemspec

  62. gem install melb_ruby-0.0.1.gem

  63. Publishing a gem

  64. Get an account on rubygems.org

  65. gem push melb_ruby-0.0.1.gem

  66. Published gem versions cannot be changed

  67. Published gem versions can be removed… but probably shouldn't be.

  68. Okay, take a breath.

  69. Use Bundler to generate a gem

  70. bundle gem melb_ruby

  71. rake release

  72. # Gemfile source "https://rubygems.org" gemspec

  73. Code of Conduct

  74. Support

  75. Support GitHub Issues

  76. Stack Overflow GitHub Issues Support

  77. README Support Stack Overflow GitHub Issues

  78. Versioning

  79. Semantic Versioning

  80. 6.0.1

  81. 6.0.1 Major

  82. 6.0.1 Minor

  83. 6.0.1 Patch

  84. New Patch Versions Patch 6.0.2

  85. New Minor Versions Minor 6.1.0

  86. Major Versions Major 7.0.0

  87. Looking for examples?

  88. Most gems are on GitHub

  89. bundle open rspec

  90. Gems that use Rails

  91. Rails Engines

  92. melb_ruby/app/models/post.rb melb_ruby/db/migrate/1_create_posts.rb

  93. # lib/melb_ruby/engine.rb class MelbRuby::Engine < Rails::Engine engine_name :melb_ruby end

  94. # within lib/melb_ruby.rb require "melb_ruby/engine"

  95. Railties

  96. # lib/melb_ruby/railtie.rb class MelbRuby::Railtie < Rails::Railtie config.to_prepare do MelbRuby::Prepare.call end

    initializer 'melb_ruby.initialisation' do # ... end rake_tasks do load File.expand_path('../tasks.rb', __FILE__) end end
  97. # within lib/melb_ruby.rb require "melb_ruby/railtie"

  98. Other General Advice

  99. Don't Monkeypatch Core Ruby

  100. Don't Monkeypatch Rails

  101. Use fewer modules

  102. Use Appraisal

  103. Use CI

  104. Use Combustion (for Rails engines)

  105. And that's it…