Becoming a Ruby Gemcutter

Becoming a Ruby Gemcutter

Welcome to the world of Ruby: where the gems are deep, rough, and rarely documented! No need to fear though, in this presentation you'll learn what a RubyGem is, how they're used in Rails and Ruby applications, and of course, how to make your own. You'll see just how easy it is to share your code with others in the Ruby universe, and why creating packages is a joy instead of a burden thanks to the tools and ecosystem of RubyGems.

Given at CodeMash 2012. http://codemash.org

Eb8975af8e49e19e3dd6b6b84a542e26?s=128

Nick Quaranto

January 12, 2012
Tweet

Transcript

  1. BECOMING A RUBY GEMCUTTER

  2. i’m @qrush this is @qrush’s dog

  3. @ i live here

  4. i work at 37signals

  5. OMG FIRST CODEMASH!!!

  6. RUBY i mostly write

  7. RUBY RAILS i mostly write with

  8. RUBY GEMS i mostly write inside of

  9. RAILS GEMS in fact, is made of

  10. GEMS EASY and are

  11. EASY!

  12. YOU MUST BE THIS CODER TO RIDE THE TALK KNOW

    A BIT OF RUBY LOVE YOUR CODE WILLING TO LEARN!
  13. COVERING: WHAT? HOW? WHY?

  14. GEMS GEMS GEMS GEMS GEMS

  15. GEMS contain a packaged Ruby library or application.

  16. RUBYGEMS helps you download, install, and manipulate gems.

  17. RUBYGEMS gives you the gem command

  18. RUBYGEMS.ORG is a community repository of gems available for use.

  19. RUBYGEMS CLIENT RUBYGEMS.ORG

  20. RUBYGEMS CLIENT RUBYGEMS.ORG

  21. RUBYGEMS CLIENT RUBYGEMS.ORG .gem .gem

  22. http://rubygems.org/pages/download

  23. GEM WHAT’S IN A

  24. Docs Code Gemspec

  25. % tree freewill freewill/ |-- bin/ | `-- freewill |--

    lib/ | `-- freewill.rb |-- test/ | `-- test_freewill.rb |-- README |-- Rakefile `-- freewill.gemspec
  26. % tree freewill freewill/ |-- bin/ | `-- freewill |--

    lib/ | `-- freewill.rb |-- test/ | `-- test_freewill.rb |-- README |-- Rakefile `-- freewill.gemspec DOCS!
  27. % tree freewill freewill/ |-- bin/ | `-- freewill |--

    lib/ | `-- freewill.rb |-- test/ | `-- test_freewill.rb |-- README |-- Rakefile `-- freewill.gemspec CODE!
  28. % tree freewill freewill/ |-- bin/ | `-- freewill |--

    lib/ | `-- freewill.rb |-- test/ | `-- test_freewill.rb |-- README |-- Rakefile `-- freewill.gemspec GEMSPEC!
  29. .GEM RAILS ?

  30. Ruby looks on your $LOAD_PATH when you call Kernel#require

  31. RubyGems manages your $LOAD_PATH

  32. % irb -rpp >> pp $LOAD_PATH [".../lib/ruby/site_ruby/1.8", ".../lib/ruby/site_ruby", ".../lib/ruby/vendor_ruby/1.8", ".../lib/ruby/vendor_ruby",

    ".../lib/ruby/1.8", "."]
  33. % irb -rpp >> require 'rake' LoadError: no such file

    to load -- rake from (irb):2:in `require' from (irb):2
  34. >> require 'rubygems' => true >> require 'rake' => true

    >> pp $LOAD_PATH[0..1] [".../gems/rake-0.8.7/bin", ".../gems/rake-0.8.7/lib"]
  35. RubyGems overrides Kernel#require RubyGems puts bin/ and lib/ on your

    $LOAD_PATH
  36. RubyGems manages your external Ruby code.

  37. The Gemspec holds metadata & info about the gem

  38. % cat freewill.gemspec Gem::Specification.new do |s| s.name = 'freewill' s.version

    = '1.0.0' s.date = '2012-01-03' s.summary = "Freewill!" s.description = "I will choose Freewill!" s.authors = ["Nick Quaranto"] s.email = 'nick@quaran.to' s.homepage = 'http://example.com' s.files = ["lib/freewill.rb"] end
  39. A .gem is just a tarball of tarballs

  40. % gem fetch rake Downloaded rake-0.8.7 % tar zxvf rake-0.8.7.gem

    x data.tar.gz x metadata.gz
  41. A GEM IS A TARBALL WITHIN A TARBALL

  42. WHY CAN’T I USE MY LINUX PACKAGE MANAGER THEN

  43. None
  44. LOL, WHAT’S A TARBALL

  45. WHY? WHY? WHY? ? WH W HY?

  46. Why did you make a RubyGem?

  47. REUSE

  48. INVENTION

  49. AUTOMATION

  50. IMPROVEMENT

  51. FIX HUGE PROBLEMS

  52. GOOD LUCK WITH THAT

  53. NO REALLY WHY SHOULD I BOTHER WITH THIS, I’M BUSY!

    REUSE YOUR CODE EASY TO INSTALL EASY TO SHARE
  54. GEM! MAKE YOUR OWN!

  55. FIRST GEM EXECUTABLE TESTING DOCS

  56. FIRST GEM EXECUTABLE TESTING DOCS

  57. % tree . !"" hola.gemspec #"" lib #"" hola.rb

  58. % cat lib/hola.rb class Hola def self.hi(msg = "world") puts

    "Hello #{msg}!" end end
  59. require ‘hola’ % tree . !"" hola.gemspec #"" lib #""

    hola.rb
  60. % cat hola.gemspec Gem::Specification.new do |s| s.name = 'hola' s.version

    = '0.0.0' s.date = '2011-01-03' s.summary = "Hola!" s.description = "A simple hello world gem" s.authors = ["Nick Quaranto"] s.email = 'nick@quaran.to' s.files = ["lib/hola.rb"] s.homepage = 'http://rubygems.org/gems/hola' end
  61. build install push

  62. build install push LOCAL REMOTE

  63. % gem build hola.gemspec Successfully built RubyGem Name: hola Version:

    0.0.0 File: hola-0.0.0.gem % gem install ./hola-0.0.0.gem Successfully installed hola-0.0.0 1 gem installed
  64. SHIP IT!

  65. OOPS. bad push?

  66. Try your gem out before pushing!

  67. % irb -rubygems >> require 'hola' => true >> Hola.hi

    Hello world!
  68. At least run your tests first! ...You wrote tests, right?

  69. SHIP IT!

  70. % gem push hola-0.0.0.gem Enter your RubyGems.org credentials. Don't have

    an account yet? Create one at http://rubygems.org/sign_up Email: nick@quaran.to Password: Signed in. Pushing gem to RubyGems.org... Successfully registered gem: hola (0.0.0)
  71. REMOTE LOCAL install build push list -r install

  72. % gem list -r hola *** REMOTE GEMS *** hola

    (0.0.0) % gem install hola Successfully installed hola-0.0.0 1 gem installed
  73. FIRST GEM EXECUTABLE TESTING DOCS

  74. gems are awesome command line tools

  75. % curl -s http://jsonip.com/ | \ prettify_json.rb { "ip": "69.204.109.48"

    }
  76. % mkdir bin % touch bin/hola % chmod a+x bin/hola

  77. % cat bin/hola #!/usr/bin/env ruby require 'hola' puts Hola.hi(ARGV[0])

  78. % cat bin/hola #!/usr/bin/env ruby require 'hola' puts Hola.hi(ARGV[0]) (shə-băng')

  79. % cat bin/hola #!/usr/bin/env ruby require 'hola' puts Hola.hi(ARGV[0]) “Probably

    derived from “shell bang” under the influence of American slang “the whole shebang” (everything, the works)” http://www.retrologic.com/jargon/S/shebang.html (shə-băng')
  80. % cat bin/hola #!/usr/bin/env ruby require 'hola' puts Hola.hi(ARGV[0]) (shə-băng')

    “Probably derived from “shell bang” under the influence of American slang “the whole shebang” (everything, the works)” http://www.retrologic.com/jargon/S/shebang.html
  81. % ruby -Ilib ./bin/hola Hello world! % ruby -Ilib ./bin/hola

    CodeMash Hello CodeMash!
  82. % ruby -Ilib ./bin/hola Hello world! % ruby -Ilib ./bin/hola

    CodeMash Hello CodeMash! $LOAD_PATH.unshift(“lib”)
  83. % hola Hello world! % hola CodeMash Hello CodeMash!

  84. % head -4 hola.gemspec Gem::Specification.new do |s| s.name = 'hola'

    s.version = '0.0.1' s.executables << 'hola'
  85. FIRST GEM EXECUTABLE TESTING DOCS

  86. outsource your automation and framework

  87. automation framework

  88. automation framework rake thor

  89. automation framework rake thor Test::Unit rspec bacon context matchy shoulda

    riot testy shindo zebra lemon dfect cucumber steak
  90. Test your gem. Use whatever. Please test it.

  91. You will be tested: http://test.rubygems.org

  92. % cat Rakefile require 'rake/testtask' Rake::TestTask.new do |t| t.libs <<

    'test' end desc "Run tests" task :default => :test
  93. % cat test/test_hola.rb require 'test/unit' require 'hola' class HolaTest <

    Test::Unit::TestCase def test_default_hello assert_equal "Hello world!", Hola.hi end def test_custom_hello assert_equal "Hello Boston!", Hola.hi("Boston") end end
  94. % rake test (in /Users/qrush/Dev/ruby/hola) Loaded suite Started .. Finished

    in 0.000736 seconds. 2 tests, 2 assertions, 0 failures, 0 errors, 0 skips Test run options: --seed 15331
  95. FIRST GEM EXECUTABLE TESTING DOCS

  96. Meh.

  97. push gem webhook tweet on @rubygems

  98. push gem webhook tweet on @rubygems ON EVERY PUSH

  99. push gem webhook tweet on @rubygems ON EVERY PUSH ~200+

    TIMES DAILY
  100. Say hi, your gem will!

  101. guides inline

  102. guides inline nokogiri yard

  103. guides inline nokogiri yard rails datamapper

  104. # The main Hola driver class Hola # Say hi

    to the world! # # Example: # >> Hola.hi("Buffalo") # => Hello Buffalo! # # Arguments: # message: (String) def self.hi(message = "world") puts "Hello #{message}!" end end
  105. Learn how to document your code: http://yardoc.org

  106. 10TIPS AWESOME FOR MAKING YOUR GEM

  107. Write a README. 1.

  108. WHAT SHOULD GO IN A README WHAT IT IS INSTALL

    INSTRUCTIONS HOW TO USE IT
  109. Use a LICENSE 2.

  110. Code with no LICENSE is COPYRIGHTED.

  111. Pick a license BEFORE pushing your gem.

  112. Name your gem properly. 3.

  113. DO NOT CALL IT: [rR].* rials cheezburger kitty dicks

  114. Have a memorable name, not a stupid one.

  115. Have a sane versioning scheme. 4.

  116. http://www.flickr.com/photos/ioerror/3014911710/lightbox/

  117. 3 3.1 3.141 3.1415 3.14159 3.141592 3.14159256

  118. http://semver.org Semantic Versioning

  119. 1.2.3 MAJOR.MINOR.PATCH

  120. 0.0.X PATCH implementation details small bug fixes

  121. 0.X.0 MINOR backwards compatible API changes

  122. X.0.0 MAJOR backwards incompatible API changes

  123. Have one top-level file 5.

  124. . #"" lib !"" foo.rb #"" set.rb

  125. . #"" lib !"" foo.rb #"" set.rb require ‘set’

  126. . #"" lib !"" foo.rb #"" set.rb require ‘set’

  127. . #"" lib !"" foo % #"" set.rb #"" foo.rb

    require ‘foo/set’
  128. Don’t mess with $LOAD_PATH 6.

  129. . #"" lib !"" hola % #"" translator.rb #"" hola.rb

  130. . #"" lib !"" hola % #"" translator.rb #"" hola.rb

    BAD: require File.join(File.dirname( __FILE__), "hola", "translator")
  131. . #"" lib !"" hola % #"" translator.rb #"" hola.rb

    WORSE: $LOAD_PATH.unshift "lib/hola" require "translator"
  132. . #"" lib !"" hola % #"" translator.rb #"" hola.rb

    GOOD: require "hola/translator"
  133. Specify dependencies 7.

  134. http://www.slideshare.net/copiousfreetime/gemology

  135. runtime development

  136. runtime development what your gem needs to work

  137. runtime development what your gem needs to work what your

    tests need to work
  138. Gem::Specification.new do |s| s.name = "hola" s.version = "2.0.0" s.add_runtime_dependency(

    "daemons", [">= 1.1.0"]) s.add_development_dependency( "rspec", ["= 2.2.0"])
  139. Be pessimistic (with dependencies) 8.

  140. Gem::Specification.new do |s| s.name = "hola" s.version = "2.0.0" s.add_runtime_dependency(

    "thor", [">= 0.14.5"]) s.add_development_dependency( "rspec", ["= 2.2.0"]) Only this one works for me! EXACT
  141. Gem::Specification.new do |s| s.name = "hola" s.version = "2.0.0" s.add_runtime_dependency(

    "thor", [">= 0.14.5"]) s.add_development_dependency( "rspec", ["= 2.2.0"]) It will always work! OPTIMISTIC
  142. Avoid >=

  143. Gem::Specification.new do |s| s.name = "hola" s.version = "2.0.0" s.add_runtime_dependency(

    "thor", [">= 0.14.5", "< 1.0.0"]) s.add_development_dependency( "rspec", ["= 2.2.0"]) Lock to a range instead PESSIMISTIC
  144. Gem::Specification.new do |s| s.name = "hola" s.version = "2.0.0" s.add_runtime_dependency(

    "thor", ["~> 0.14"]) s.add_development_dependency( "rspec", ["= 2.2.0"]) Use the twiddle-wakka! PESSIMISTIC
  145. Cut prereleases 9.

  146. % head -4 hola.gemspec Gem::Specification.new do |s| s.name = 'hola'

    s.version = '1.0.0.pre'
  147. % head -4 hola.gemspec Gem::Specification.new do |s| s.name = 'hola'

    s.version = '1.0.0.pre' ANY LETTER(S)
  148. % gem install hola --pre Fetching: hola-1.0.0.pre.gem (100%) Successfully installed

    hola-1.0.0.pre 1 gem installed
  149. Build on Travis-CI 10.

  150. No configuration, totally free CI. http://travis-ci.org

  151. None
  152. GO PUSH A GEM TODAY

  153. GO PUSH A GEM TODAY @qrush Thanks!