SlideShare a Scribd company logo
1 of 43
Building A Gem From
                     Scratch
                                 Madison Ruby, 2011




twitter: bphogan
email: brianhogan at napcs.com
What's A Gem?



twitter: bphogan
email: brianhogan at napcs.com
The (normal) Process
           • Come up with an idea
           • write some code
           • Release a gem
           • Beg people to write tests for you

twitter: bphogan
email: brianhogan at napcs.com
Our process

           • Come up with an idea and write some code
           • Throw all that code away
           • Rewrite it with tests as we go
           • Release it as a Gem
           • Enjoy fame and fortune
twitter: bphogan
email: brianhogan at napcs.com
Grabatar
                        (a gem to grab Gravatar URLs)

                     http://www.gravatar.com/avatar/
                   6ef8cb7cd7cd58077f0b57e4fa49a969




twitter: bphogan
email: brianhogan at napcs.com
Step one: Build tested,
                 working code


twitter: bphogan
email: brianhogan at napcs.com
The basic structure of a
                   Gem
                                 gemname.gemspec
                                 lib/
                                        gemname
                                           version.rb
                                           anotherfile.rb
                                        gemname.rb

twitter: bphogan
email: brianhogan at napcs.com
Tests, Tests, Tests!




twitter: bphogan
email: brianhogan at napcs.com
Test::Unit
                                   test
                                          somefile_test.rb



twitter: bphogan
email: brianhogan at napcs.com
Write the test
   test/grabatar_test.rb

     require 'test/unit'
     require 'lib/grabatar'

     class GrabatarTest < Test::Unit::TestCase
       def test_displays_version
         assert Grabatar::VERSION
       end
     end




twitter: bphogan
email: brianhogan at napcs.com
Implement the code

   lib/grabatar/version.rb

      module Grabatar
        VERSION = "0.0.2"
      end




twitter: bphogan
email: brianhogan at napcs.com
Add to the main Ruby file:
   lib/grabatar.rb


     require 'grabatar/version'




twitter: bphogan
email: brianhogan at napcs.com
Repeat.



twitter: bphogan
email: brianhogan at napcs.com
Write the test first...
   test/gravatar_helper.rb

     require 'test/unit'
     require 'grabatar'

     class GravatarTest < Test::Unit::TestCase
       def test_builds_gravatar_url
         g = Grabatar::Gravatar.new("bphogan@gmail.com")
         assert_equal "http://www.gravatar.com/avatar/
                       6ef8cb7cd7cd58077f0b57e4fa49a969", g.avatar_url
       end
     end




twitter: bphogan
email: brianhogan at napcs.com
Then write the code
   lib/grabatar/gravatar.rb

      module Grabatar
        class Gravatar
          require 'digest/md5'

           def initialize(email)
             @email = email
           end

           def avatar_url
             hash = Digest::MD5.hexdigest(@email)
             "http://www.gravatar.com/avatar/#{hash}"
           end

        end
      end


twitter: bphogan
email: brianhogan at napcs.com
Then write the code
   lib/grabatar/gravatar.rb

      module Grabatar
        class Gravatar
          require 'digest/md5'

           def initialize(email)
             @email = email
           end

           def avatar_url
             hash = Digest::MD5.hexdigest(@email)
             "http://www.gravatar.com/avatar/#{hash}"
           end

        end
      end


twitter: bphogan
email: brianhogan at napcs.com
Then write the code
   lib/grabatar/gravatar.rb

      module Grabatar
        class Gravatar
          require 'digest/md5'

           def initialize(email)
             @email = email
           end

           def avatar_url
             hash = Digest::MD5.hexdigest(@email)
             "http://www.gravatar.com/avatar/#{hash}"
           end

        end
      end


twitter: bphogan
email: brianhogan at napcs.com
Then write the code
   lib/grabatar/gravatar.rb

      module Grabatar
        class Gravatar
          require 'digest/md5'

           def initialize(email)
             @email = email
           end

           def avatar_url
             hash = Digest::MD5.hexdigest(@email)
             "http://www.gravatar.com/avatar/#{hash}"
           end

        end
      end


twitter: bphogan
email: brianhogan at napcs.com
Step two: Make A
                         Gemspec


twitter: bphogan
email: brianhogan at napcs.com
Gemspecs are easy.
   grabatar.gemspec

     require 'lib/grabatar/version'
     Gem::Specification.new do |s|
       s.name = "grabatar"
       s.version = Grabatar::VERSION
       s.summary = "Fetch avatar image URLs from Gravatar"
       s.authors = ["Brian Hogan"]
       s.email = ["bphogan@gmail.com"]
       s.files = [
         "lib/grabatar.rb",
         "lib/grabatar/version.rb",
         "lib/grabatar/gravatar.rb",
         "lib/grabatar/railtie.rb",
         "lib/grabatar/view_helpers.rb"
       ]
     end


twitter: bphogan
email: brianhogan at napcs.com
Gemspecs are easy.
   grabatar.gemspec

     require 'lib/grabatar/version'
     Gem::Specification.new do |s|
       s.name = "grabatar"
       s.version = Grabatar::VERSION
       s.summary = "Fetch avatar image URLs from Gravatar"
       s.authors = ["Brian Hogan"]
       s.email = ["bphogan@gmail.com"]
       s.files = [
         "lib/grabatar.rb",
         "lib/grabatar/version.rb",
         "lib/grabatar/gravatar.rb",
         "lib/grabatar/railtie.rb",
         "lib/grabatar/view_helpers.rb"
       ]
     end


twitter: bphogan
email: brianhogan at napcs.com
Gemspecs are easy.
   grabatar.gemspec

     require 'lib/grabatar/version'
     Gem::Specification.new do |s|
       s.name = "grabatar"
       s.version = Grabatar::VERSION
       s.summary = "Fetch avatar image URLs from Gravatar"
       s.authors = ["Brian Hogan"]
       s.email = ["bphogan@gmail.com"]
       s.files = [
         "lib/grabatar.rb",
         "lib/grabatar/version.rb",
         "lib/grabatar/gravatar.rb",
         "lib/grabatar/railtie.rb",
         "lib/grabatar/view_helpers.rb"
       ]
     end


twitter: bphogan
email: brianhogan at napcs.com
Gemspecs are easy.
   grabatar.gemspec

     require 'lib/grabatar/version'
     Gem::Specification.new do |s|
       s.name = "grabatar"
       s.version = Grabatar::VERSION
       s.summary = "Fetch avatar image URLs from Gravatar"
       s.authors = ["Brian Hogan"]
       s.email = ["bphogan@gmail.com"]
       s.files = [
         "lib/grabatar.rb",
         "lib/grabatar/version.rb",
         "lib/grabatar/gravatar.rb",
         "lib/grabatar/railtie.rb",
         "lib/grabatar/view_helpers.rb"
       ]
     end


twitter: bphogan
email: brianhogan at napcs.com
The manifest




twitter: bphogan
email: brianhogan at napcs.com
bundle gem is bad for you
     s.files                = `git ls-files`.split("n")
     s.test_files           = `git ls-files --
                               {test,spec,features}/*`.split("n")
     s.executables          = `git ls-files -- bin/*`
                               .split("n").map{ |f| File.basename(f) }




twitter: bphogan
email: brianhogan at napcs.com
What lies beneath
           • .DS_Store
           • thumbs.db
           • ~whatever.rb
           • whatever.mine.rb
           • Step 3: Rake
           • Test::Unit tasks
twitter: bphogan
email: brianhogan at napcs.com
Craft your manifest by hand
    s.files = [
      "lib/grabatar.rb",
      "lib/grabatar/version.rb",
      "lib/grabatar/gravatar.rb",
      "lib/grabatar/railtie.rb",
      "lib/grabatar/view_helpers.rb"
    ]




twitter: bphogan
email: brianhogan at napcs.com
Build and install the gem
     $ gem build grabatar.gemspec
     $ gem install grabatar-0-0-1.gem




twitter: bphogan
email: brianhogan at napcs.com
Step 4: Rails gems



twitter: bphogan
email: brianhogan at napcs.com
Test first
   test/view_helpers_test.rb

     require 'test/unit'
     require 'grabatar/gravatar'
     require 'grabatar/view_helpers'

     class ViewHelpers < Test::Unit::TestCase
       include Grabatar::ViewHelpers
       def test_generates_avatar_url
         assert_equal
            "http://www.gravatar.com/avatar
             /6ef8cb7cd7cd58077f0b57e4fa49a969",
             gravatar_url_for("bphogan@gmail.com")
       end
     end




twitter: bphogan
email: brianhogan at napcs.com
Test first
   test/view_helpers_test.rb

     require 'test/unit'
     require 'grabatar/gravatar'
     require 'grabatar/view_helpers'

     class ViewHelpers < Test::Unit::TestCase
       include Grabatar::ViewHelpers
       def test_generates_avatar_url
         assert_equal
            "http://www.gravatar.com/avatar
             /6ef8cb7cd7cd58077f0b57e4fa49a969",
             gravatar_url_for("bphogan@gmail.com")
       end
     end




twitter: bphogan
email: brianhogan at napcs.com
Create a helper
   lib/grabatar/view_helpers.rb


      module Grabatar
        module ViewHelpers
          def gravatar_url_for(email)
            Grabatar::Gravatar.new(email).avatar_url
          end
        end
      end




twitter: bphogan
email: brianhogan at napcs.com
Railties



twitter: bphogan
email: brianhogan at napcs.com
Include the Helper
   lib/grabatar/railtie.rb


     module Grabatar
       class Railtie < Rails::Railtie
         initializer "grabatar.view_helpers" do
           ActionView::Base.send :include, ViewHelpers
         end
       end
     end




twitter: bphogan
email: brianhogan at napcs.com
Only load the Railtie if we have Rails
 lib/grabatar.rb


   require 'grabatar/railtie' if defined?(Rails)




twitter: bphogan
email: brianhogan at napcs.com
Making a CLI tool



twitter: bphogan
email: brianhogan at napcs.com
Add a bin folder with
                    the file!


twitter: bphogan
email: brianhogan at napcs.com
The CLI program
   bin/grabatar


     #!/usr/bin/env ruby
     require 'grabatar'

     puts "Grabatar v#{Grabatar::VERSION}"

     email = ARGV[0]

     if email.nil?
       puts "Usage: grabatar <youremail@server.com>"
     else
       g = Grabatar::Gravatar.new(email)
       puts g.avatar_url
     end




twitter: bphogan
email: brianhogan at napcs.com
The CLI program
   bin/grabatar


     #!/usr/bin/env ruby
     require 'grabatar'

     puts "Grabatar v#{Grabatar::VERSION}"

     email = ARGV[0]

     if email.nil?
       puts "Usage: grabatar <youremail@server.com>"
     else
       g = Grabatar::Gravatar.new(email)
       puts g.avatar_url
     end




twitter: bphogan
email: brianhogan at napcs.com
The CLI program
   bin/grabatar


     #!/usr/bin/env ruby
     require 'grabatar'

     puts "Grabatar v#{Grabatar::VERSION}"

     email = ARGV[0]

     if email.nil?
       puts "Usage: grabatar <youremail@server.com>"
     else
       g = Grabatar::Gravatar.new(email)
       puts g.avatar_url
     end




twitter: bphogan
email: brianhogan at napcs.com
Running it

     $ grabatar bphogan@gmail.com
     Grabatar v0.0.2
     http://www.gravatar.com/avatar/6ef8cb7cd7cd58077f0b57e4fa49a969




twitter: bphogan
email: brianhogan at napcs.com
Who wants code?
                     http://github.com/napcs/grabatar




twitter: bphogan
email: brianhogan at napcs.com
Thanks!
                                 http://spkr8.com/t/8181




twitter: bphogan
email: brianhogan at napcs.com

More Related Content

What's hot

Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
singingfish
 
Socket applications
Socket applicationsSocket applications
Socket applications
João Moura
 
Big data beyond the JVM - DDTX 2018
Big data beyond the JVM -  DDTX 2018Big data beyond the JVM -  DDTX 2018
Big data beyond the JVM - DDTX 2018
Holden Karau
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryBuilding a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 

What's hot (20)

Create responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJSCreate responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJS
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
 
Beware the potholes on the road to serverless
Beware the potholes on the road to serverlessBeware the potholes on the road to serverless
Beware the potholes on the road to serverless
 
High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax Applications
 
Looking Back to Move Forward: Building the Modern Web
Looking Back to Move Forward: Building the Modern WebLooking Back to Move Forward: Building the Modern Web
Looking Back to Move Forward: Building the Modern Web
 
HTML 5 & CSS 3
HTML 5 & CSS 3HTML 5 & CSS 3
HTML 5 & CSS 3
 
Opening up the Social Web - Standards that are bridging the Islands
Opening up the Social Web - Standards that are bridging the IslandsOpening up the Social Web - Standards that are bridging the Islands
Opening up the Social Web - Standards that are bridging the Islands
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
HTTP/2 BrightonSEO 2018
HTTP/2 BrightonSEO 2018HTTP/2 BrightonSEO 2018
HTTP/2 BrightonSEO 2018
 
Big data beyond the JVM - DDTX 2018
Big data beyond the JVM -  DDTX 2018Big data beyond the JVM -  DDTX 2018
Big data beyond the JVM - DDTX 2018
 
Writing Pluggable Software
Writing Pluggable SoftwareWriting Pluggable Software
Writing Pluggable Software
 
Ajax to the Moon
Ajax to the MoonAjax to the Moon
Ajax to the Moon
 
Web Development with Python and Django
Web Development with Python and DjangoWeb Development with Python and Django
Web Development with Python and Django
 
DEF CON 27 - BEN SADEGHIPOUR - owning the clout through ssrf and pdf generators
DEF CON 27 - BEN SADEGHIPOUR  - owning the clout through ssrf and pdf generatorsDEF CON 27 - BEN SADEGHIPOUR  - owning the clout through ssrf and pdf generators
DEF CON 27 - BEN SADEGHIPOUR - owning the clout through ssrf and pdf generators
 
Django a whirlwind tour
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tour
 
Ruby Isn't Just About Rails
Ruby Isn't Just About RailsRuby Isn't Just About Rails
Ruby Isn't Just About Rails
 
SearchLove San Diego 2018 | Tom Anthony | An Introduction to HTTP/2 & Service...
SearchLove San Diego 2018 | Tom Anthony | An Introduction to HTTP/2 & Service...SearchLove San Diego 2018 | Tom Anthony | An Introduction to HTTP/2 & Service...
SearchLove San Diego 2018 | Tom Anthony | An Introduction to HTTP/2 & Service...
 
How cgi scripting works
How cgi scripting worksHow cgi scripting works
How cgi scripting works
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQueryBuilding a desktop app with HTTP::Engine, SQLite and jQuery
Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Twig: Friendly Curly Braces Invade Your Templates!
Twig: Friendly Curly Braces Invade Your Templates!Twig: Friendly Curly Braces Invade Your Templates!
Twig: Friendly Curly Braces Invade Your Templates!
 

Similar to Building A Gem From Scratch

ChefConf 2012 Spiceweasel
ChefConf 2012 SpiceweaselChefConf 2012 Spiceweasel
ChefConf 2012 Spiceweasel
Matt Ray
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
Clinton Dreisbach
 

Similar to Building A Gem From Scratch (20)

Intro to Ruby
Intro to RubyIntro to Ruby
Intro to Ruby
 
Lightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClientLightweight Webservices with Sinatra and RestClient
Lightweight Webservices with Sinatra and RestClient
 
Merb Slices
Merb SlicesMerb Slices
Merb Slices
 
Djabot – Python Jabber Bot
Djabot – Python Jabber BotDjabot – Python Jabber Bot
Djabot – Python Jabber Bot
 
Freeing the cloud, one service at a time
Freeing the cloud, one service at a timeFreeing the cloud, one service at a time
Freeing the cloud, one service at a time
 
Django로 만든 웹 애플리케이션 도커라이징하기 + 도커 컴포즈로 개발 환경 구축하기
Django로 만든 웹 애플리케이션 도커라이징하기 + 도커 컴포즈로 개발 환경 구축하기Django로 만든 웹 애플리케이션 도커라이징하기 + 도커 컴포즈로 개발 환경 구축하기
Django로 만든 웹 애플리케이션 도커라이징하기 + 도커 컴포즈로 개발 환경 구축하기
 
Capistrano Overview
Capistrano OverviewCapistrano Overview
Capistrano Overview
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Sinatra for REST services
Sinatra for REST servicesSinatra for REST services
Sinatra for REST services
 
2018 the conf put git to work - increase the quality of your rails project...
2018 the conf   put git to work -  increase the quality of your rails project...2018 the conf   put git to work -  increase the quality of your rails project...
2018 the conf put git to work - increase the quality of your rails project...
 
ChefConf 2012 Spiceweasel
ChefConf 2012 SpiceweaselChefConf 2012 Spiceweasel
ChefConf 2012 Spiceweasel
 
Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3Migrating Legacy Rails Apps to Rails 3
Migrating Legacy Rails Apps to Rails 3
 
Life on the Edge
Life on the EdgeLife on the Edge
Life on the Edge
 
Capistrano
CapistranoCapistrano
Capistrano
 
Toolbox of a Ruby Team
Toolbox of a Ruby TeamToolbox of a Ruby Team
Toolbox of a Ruby Team
 
Writing Software not Code with Cucumber
Writing Software not Code with CucumberWriting Software not Code with Cucumber
Writing Software not Code with Cucumber
 
Sinatra Rack And Middleware
Sinatra Rack And MiddlewareSinatra Rack And Middleware
Sinatra Rack And Middleware
 
Agile Development With Hobo
Agile Development With HoboAgile Development With Hobo
Agile Development With Hobo
 
Capistrano
CapistranoCapistrano
Capistrano
 

More from Brian Hogan

FUD-Free Accessibility for Web Developers - Also, Cake.
FUD-Free Accessibility for Web Developers - Also, Cake.FUD-Free Accessibility for Web Developers - Also, Cake.
FUD-Free Accessibility for Web Developers - Also, Cake.
Brian Hogan
 
Responsive Web Design
Responsive Web DesignResponsive Web Design
Responsive Web Design
Brian Hogan
 
Turning Passion Into Words
Turning Passion Into WordsTurning Passion Into Words
Turning Passion Into Words
Brian Hogan
 

More from Brian Hogan (19)

Creating and Deploying Static Sites with Hugo
Creating and Deploying Static Sites with HugoCreating and Deploying Static Sites with Hugo
Creating and Deploying Static Sites with Hugo
 
Automating the Cloud with Terraform, and Ansible
Automating the Cloud with Terraform, and AnsibleAutomating the Cloud with Terraform, and Ansible
Automating the Cloud with Terraform, and Ansible
 
Create Development and Production Environments with Vagrant
Create Development and Production Environments with VagrantCreate Development and Production Environments with Vagrant
Create Development and Production Environments with Vagrant
 
Docker
DockerDocker
Docker
 
Getting Started Contributing To Open Source
Getting Started Contributing To Open SourceGetting Started Contributing To Open Source
Getting Started Contributing To Open Source
 
Rethink Frontend Development With Elm
Rethink Frontend Development With ElmRethink Frontend Development With Elm
Rethink Frontend Development With Elm
 
Testing Client-side Code with Jasmine and CoffeeScript
Testing Client-side Code with Jasmine and CoffeeScriptTesting Client-side Code with Jasmine and CoffeeScript
Testing Client-side Code with Jasmine and CoffeeScript
 
FUD-Free Accessibility for Web Developers - Also, Cake.
FUD-Free Accessibility for Web Developers - Also, Cake.FUD-Free Accessibility for Web Developers - Also, Cake.
FUD-Free Accessibility for Web Developers - Also, Cake.
 
Responsive Web Design
Responsive Web DesignResponsive Web Design
Responsive Web Design
 
Web Development with CoffeeScript and Sass
Web Development with CoffeeScript and SassWeb Development with CoffeeScript and Sass
Web Development with CoffeeScript and Sass
 
Turning Passion Into Words
Turning Passion Into WordsTurning Passion Into Words
Turning Passion Into Words
 
HTML5 and CSS3 Today
HTML5 and CSS3 TodayHTML5 and CSS3 Today
HTML5 and CSS3 Today
 
Web Development With Ruby - From Simple To Complex
Web Development With Ruby - From Simple To ComplexWeb Development With Ruby - From Simple To Complex
Web Development With Ruby - From Simple To Complex
 
Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7Intro to Ruby - Twin Cities Code Camp 7
Intro to Ruby - Twin Cities Code Camp 7
 
Make GUI Apps with Shoes
Make GUI Apps with ShoesMake GUI Apps with Shoes
Make GUI Apps with Shoes
 
The Why Of Ruby
The Why Of RubyThe Why Of Ruby
The Why Of Ruby
 
Story-driven Testing
Story-driven TestingStory-driven Testing
Story-driven Testing
 
Learning To Walk In Shoes
Learning To Walk In ShoesLearning To Walk In Shoes
Learning To Walk In Shoes
 
Rails and Legacy Databases - RailsConf 2009
Rails and Legacy Databases - RailsConf 2009Rails and Legacy Databases - RailsConf 2009
Rails and Legacy Databases - RailsConf 2009
 

Recently uploaded

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Recently uploaded (20)

Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 

Building A Gem From Scratch

  • 1. Building A Gem From Scratch Madison Ruby, 2011 twitter: bphogan email: brianhogan at napcs.com
  • 2. What's A Gem? twitter: bphogan email: brianhogan at napcs.com
  • 3. The (normal) Process • Come up with an idea • write some code • Release a gem • Beg people to write tests for you twitter: bphogan email: brianhogan at napcs.com
  • 4. Our process • Come up with an idea and write some code • Throw all that code away • Rewrite it with tests as we go • Release it as a Gem • Enjoy fame and fortune twitter: bphogan email: brianhogan at napcs.com
  • 5. Grabatar (a gem to grab Gravatar URLs) http://www.gravatar.com/avatar/ 6ef8cb7cd7cd58077f0b57e4fa49a969 twitter: bphogan email: brianhogan at napcs.com
  • 6. Step one: Build tested, working code twitter: bphogan email: brianhogan at napcs.com
  • 7. The basic structure of a Gem gemname.gemspec lib/ gemname version.rb anotherfile.rb gemname.rb twitter: bphogan email: brianhogan at napcs.com
  • 8. Tests, Tests, Tests! twitter: bphogan email: brianhogan at napcs.com
  • 9. Test::Unit test somefile_test.rb twitter: bphogan email: brianhogan at napcs.com
  • 10. Write the test test/grabatar_test.rb require 'test/unit' require 'lib/grabatar' class GrabatarTest < Test::Unit::TestCase def test_displays_version assert Grabatar::VERSION end end twitter: bphogan email: brianhogan at napcs.com
  • 11. Implement the code lib/grabatar/version.rb module Grabatar VERSION = "0.0.2" end twitter: bphogan email: brianhogan at napcs.com
  • 12. Add to the main Ruby file: lib/grabatar.rb require 'grabatar/version' twitter: bphogan email: brianhogan at napcs.com
  • 14. Write the test first... test/gravatar_helper.rb require 'test/unit' require 'grabatar' class GravatarTest < Test::Unit::TestCase def test_builds_gravatar_url g = Grabatar::Gravatar.new("bphogan@gmail.com") assert_equal "http://www.gravatar.com/avatar/ 6ef8cb7cd7cd58077f0b57e4fa49a969", g.avatar_url end end twitter: bphogan email: brianhogan at napcs.com
  • 15. Then write the code lib/grabatar/gravatar.rb module Grabatar class Gravatar require 'digest/md5' def initialize(email) @email = email end def avatar_url hash = Digest::MD5.hexdigest(@email) "http://www.gravatar.com/avatar/#{hash}" end end end twitter: bphogan email: brianhogan at napcs.com
  • 16. Then write the code lib/grabatar/gravatar.rb module Grabatar class Gravatar require 'digest/md5' def initialize(email) @email = email end def avatar_url hash = Digest::MD5.hexdigest(@email) "http://www.gravatar.com/avatar/#{hash}" end end end twitter: bphogan email: brianhogan at napcs.com
  • 17. Then write the code lib/grabatar/gravatar.rb module Grabatar class Gravatar require 'digest/md5' def initialize(email) @email = email end def avatar_url hash = Digest::MD5.hexdigest(@email) "http://www.gravatar.com/avatar/#{hash}" end end end twitter: bphogan email: brianhogan at napcs.com
  • 18. Then write the code lib/grabatar/gravatar.rb module Grabatar class Gravatar require 'digest/md5' def initialize(email) @email = email end def avatar_url hash = Digest::MD5.hexdigest(@email) "http://www.gravatar.com/avatar/#{hash}" end end end twitter: bphogan email: brianhogan at napcs.com
  • 19. Step two: Make A Gemspec twitter: bphogan email: brianhogan at napcs.com
  • 20. Gemspecs are easy. grabatar.gemspec require 'lib/grabatar/version' Gem::Specification.new do |s| s.name = "grabatar" s.version = Grabatar::VERSION s.summary = "Fetch avatar image URLs from Gravatar" s.authors = ["Brian Hogan"] s.email = ["bphogan@gmail.com"] s.files = [ "lib/grabatar.rb", "lib/grabatar/version.rb", "lib/grabatar/gravatar.rb", "lib/grabatar/railtie.rb", "lib/grabatar/view_helpers.rb" ] end twitter: bphogan email: brianhogan at napcs.com
  • 21. Gemspecs are easy. grabatar.gemspec require 'lib/grabatar/version' Gem::Specification.new do |s| s.name = "grabatar" s.version = Grabatar::VERSION s.summary = "Fetch avatar image URLs from Gravatar" s.authors = ["Brian Hogan"] s.email = ["bphogan@gmail.com"] s.files = [ "lib/grabatar.rb", "lib/grabatar/version.rb", "lib/grabatar/gravatar.rb", "lib/grabatar/railtie.rb", "lib/grabatar/view_helpers.rb" ] end twitter: bphogan email: brianhogan at napcs.com
  • 22. Gemspecs are easy. grabatar.gemspec require 'lib/grabatar/version' Gem::Specification.new do |s| s.name = "grabatar" s.version = Grabatar::VERSION s.summary = "Fetch avatar image URLs from Gravatar" s.authors = ["Brian Hogan"] s.email = ["bphogan@gmail.com"] s.files = [ "lib/grabatar.rb", "lib/grabatar/version.rb", "lib/grabatar/gravatar.rb", "lib/grabatar/railtie.rb", "lib/grabatar/view_helpers.rb" ] end twitter: bphogan email: brianhogan at napcs.com
  • 23. Gemspecs are easy. grabatar.gemspec require 'lib/grabatar/version' Gem::Specification.new do |s| s.name = "grabatar" s.version = Grabatar::VERSION s.summary = "Fetch avatar image URLs from Gravatar" s.authors = ["Brian Hogan"] s.email = ["bphogan@gmail.com"] s.files = [ "lib/grabatar.rb", "lib/grabatar/version.rb", "lib/grabatar/gravatar.rb", "lib/grabatar/railtie.rb", "lib/grabatar/view_helpers.rb" ] end twitter: bphogan email: brianhogan at napcs.com
  • 24. The manifest twitter: bphogan email: brianhogan at napcs.com
  • 25. bundle gem is bad for you s.files = `git ls-files`.split("n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("n") s.executables = `git ls-files -- bin/*` .split("n").map{ |f| File.basename(f) } twitter: bphogan email: brianhogan at napcs.com
  • 26. What lies beneath • .DS_Store • thumbs.db • ~whatever.rb • whatever.mine.rb • Step 3: Rake • Test::Unit tasks twitter: bphogan email: brianhogan at napcs.com
  • 27. Craft your manifest by hand s.files = [ "lib/grabatar.rb", "lib/grabatar/version.rb", "lib/grabatar/gravatar.rb", "lib/grabatar/railtie.rb", "lib/grabatar/view_helpers.rb" ] twitter: bphogan email: brianhogan at napcs.com
  • 28. Build and install the gem $ gem build grabatar.gemspec $ gem install grabatar-0-0-1.gem twitter: bphogan email: brianhogan at napcs.com
  • 29. Step 4: Rails gems twitter: bphogan email: brianhogan at napcs.com
  • 30. Test first test/view_helpers_test.rb require 'test/unit' require 'grabatar/gravatar' require 'grabatar/view_helpers' class ViewHelpers < Test::Unit::TestCase include Grabatar::ViewHelpers def test_generates_avatar_url assert_equal "http://www.gravatar.com/avatar /6ef8cb7cd7cd58077f0b57e4fa49a969", gravatar_url_for("bphogan@gmail.com") end end twitter: bphogan email: brianhogan at napcs.com
  • 31. Test first test/view_helpers_test.rb require 'test/unit' require 'grabatar/gravatar' require 'grabatar/view_helpers' class ViewHelpers < Test::Unit::TestCase include Grabatar::ViewHelpers def test_generates_avatar_url assert_equal "http://www.gravatar.com/avatar /6ef8cb7cd7cd58077f0b57e4fa49a969", gravatar_url_for("bphogan@gmail.com") end end twitter: bphogan email: brianhogan at napcs.com
  • 32. Create a helper lib/grabatar/view_helpers.rb module Grabatar module ViewHelpers def gravatar_url_for(email) Grabatar::Gravatar.new(email).avatar_url end end end twitter: bphogan email: brianhogan at napcs.com
  • 34. Include the Helper lib/grabatar/railtie.rb module Grabatar class Railtie < Rails::Railtie initializer "grabatar.view_helpers" do ActionView::Base.send :include, ViewHelpers end end end twitter: bphogan email: brianhogan at napcs.com
  • 35. Only load the Railtie if we have Rails lib/grabatar.rb require 'grabatar/railtie' if defined?(Rails) twitter: bphogan email: brianhogan at napcs.com
  • 36. Making a CLI tool twitter: bphogan email: brianhogan at napcs.com
  • 37. Add a bin folder with the file! twitter: bphogan email: brianhogan at napcs.com
  • 38. The CLI program bin/grabatar #!/usr/bin/env ruby require 'grabatar' puts "Grabatar v#{Grabatar::VERSION}" email = ARGV[0] if email.nil? puts "Usage: grabatar <youremail@server.com>" else g = Grabatar::Gravatar.new(email) puts g.avatar_url end twitter: bphogan email: brianhogan at napcs.com
  • 39. The CLI program bin/grabatar #!/usr/bin/env ruby require 'grabatar' puts "Grabatar v#{Grabatar::VERSION}" email = ARGV[0] if email.nil? puts "Usage: grabatar <youremail@server.com>" else g = Grabatar::Gravatar.new(email) puts g.avatar_url end twitter: bphogan email: brianhogan at napcs.com
  • 40. The CLI program bin/grabatar #!/usr/bin/env ruby require 'grabatar' puts "Grabatar v#{Grabatar::VERSION}" email = ARGV[0] if email.nil? puts "Usage: grabatar <youremail@server.com>" else g = Grabatar::Gravatar.new(email) puts g.avatar_url end twitter: bphogan email: brianhogan at napcs.com
  • 41. Running it $ grabatar bphogan@gmail.com Grabatar v0.0.2 http://www.gravatar.com/avatar/6ef8cb7cd7cd58077f0b57e4fa49a969 twitter: bphogan email: brianhogan at napcs.com
  • 42. Who wants code? http://github.com/napcs/grabatar twitter: bphogan email: brianhogan at napcs.com
  • 43. Thanks! http://spkr8.com/t/8181 twitter: bphogan email: brianhogan at napcs.com

Editor's Notes

  1. \n
  2. Who here knows what a Gem is? Who&apos;s built a gem?\n
  3. \n
  4. \n
  5. Simple gem that fetches the Gravatar URL based on the given email\n
  6. This is the easy part.\n
  7. a lib folder, a &quot;main&quot; file that includes our other files\n
  8. Because they make for good code.\n
  9. Because it&apos;s there. I think Gems should try to have as few dependencies as possible.\n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. By hand. \n
  21. \n
  22. \n
  23. \n
  24. Lists all the files you wish to release with your Gem.\n
  25. It sure is handy, but its generated manifest is overkill. It depends on git. Maybe it&amp;#x2019;s not bad for you, but it sure makes me uncomfortable. It also requires that I use Git. I can remove these lines trivially. But it&amp;#x2019;s still uncomfortable.\n
  26. Things that automatically build manifests can (and do) accidentally include things like this, and more. And you can&apos;t put exceptions in for every possible type of IDE backup file or hidden folder a contributor might have.\n
  27. This way, you ensure that what&apos;s in the Gem is what you want, and what your contributors want. \n
  28. \n
  29. We can make our gems work with Rails. Let&apos;s make a really simple Rails helper\n
  30. Our helper will be a module, so we write a test that includes the module and tests that it returns the right result.\n
  31. Our helper will be a module, so we write a test that includes the module and tests that it returns the right result.\n
  32. \n
  33. We create a new class that inherits from Railtie and then mix our module into the view helpers\n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n