Reusable Ruby • Rt 9 Ruby Group • Jun 2012

604 views
509 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
604
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Reusable Ruby • Rt 9 Ruby Group • Jun 2012

    1. 1. REUSABLE RUBY ROUTE 9 RUBY GROUP – JUNE 20, 2012 BLAKE CARLSON BLAKE@COIN-OPERATED.NET • @SKINANDBONESGITHUB.COM/SKINANDBONES • LINKEDIN.COM/IN/BLAKECARLSON
    2. 2. WHY GO REUSABLE? sloth love reusable ruby‣ D-R-Y‣ Maintainability‣ Leads to better solutions‣ Make large projects adaptable to change‣ Your co-workers will love you‣ Make gems, share code
    3. 3. OUR REUSABLE RUBY TOOLBOX* * this list is not everything, okay‣ Inheritance‣ Modules‣ Composition‣ Gems & Bundler
    4. 4. STAY CLASSY RUBY‣ Class inheritance‣ ActiveRecord, ActionController, etc.‣ Meant for things that can be instantiated or inherited‣ Sorry, NO Interfaces or Abstract Classes in Ruby (sad face?)
    5. 5. WE ♥ MODULES‣ Namespaces‣ Inject a bucket o’ instance methods into something else‣ The included callback‣ ActiveSupport::Concern‣ Testing‣ Pitfalls
    6. 6. MODULES: NAMESPACES # Namespaces module Foo class Widget # ... one thing ... end end module Bar class Widget # ... something else ... end end x = Foo::Widget.new y = Bar::Widget.new
    7. 7. MODULES: METHOD INJECTIONmodule Sluggable def generate_slug(str) str.to_s.strip.downcase.gsub(/[^a-z0-9s]/, ).gsub(/s+/, -) endendclass Post < ActiveRecord::Base include Sluggable before_validation :update_slug private def update_slug self.slug = generate_slug(title) endend# Note (1): this is a super naive solution# Note (2): check out the stringex gem for things like String#to_url.
    8. 8. MODULES: THE BASICSLet’s make generate_slug available to all AR modelsPut this code into a file like lib/sluggable.rb ... module Sluggable # ... end ActiveRecord::Base.send :include, SluggableSomewhere, like in config/initializers ... require sluggable
    9. 9. MODULES: COMMON IDIOMS module Sluggable module ClassMethods def find_by_slug(str) # ... end end module InstanceMethods def generate_slug(str) # ... end private def update_slug # ... end end def self.included(base) base.extend ClassMethods base.send :include, InstanceMethods base.before_validation :update_slug end end
    10. 10. ACTIVESUPPORT::CONCERN Bring THE PRETTY require active_support/concern module Sluggable extend ActiveSupport::Concern included do before_validation :update_slug end module ClassMethods def find_by_slug(str) # ... end end private def update_slug # ... end endhttps://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
    11. 11. ACTIVESUPPORT::CONCERN What about module dependencies? module Foo def self.included(base) base.class_eval do def self.method_injected_by_foo # ... end end end end module Bar def self.included(base) base.method_injected_by_foo end end class Host include Foo # We need to include this dependency for Bar include Bar # Bar is the module that Host really needs endhttps://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
    12. 12. ACTIVESUPPORT::CONCERN require active_support/concern module Foo extend ActiveSupport::Concern included do class_eval do def self.method_injected_by_foo # ... end end end end module Bar extend ActiveSupport::Concern include Foo included do self.method_injected_by_foo end end class Host include Bar # works, Bar takes care now of its dependencies endhttps://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
    13. 13. MODULES: TESTINGTest just the module, stub aggressively, use a Dummy class # sluggable_test.rb require spec_helper class Dummy include ActiveModel::Validations extend ActiveModel::Callbacks include Sluggable define_model_callbacks :validation attr_accessor :title, :slug def initialize(title) self.title = title end end describe Sluggable do let(:dummy) { Dummy.new(a special title) } it "should update the slug when validated" do dummy.valid? dummy.slug.should eq(a-special-title) end end
    14. 14. MODULES: THE DARK SIDE Classes that use too many modules can become a handful. 1. Which module defined which method? 2. What methods are defined in the class? 3. Method name collisions when including modules 4. You can’t reference a modularized entity, you must pass around the object that contains it.
    15. 15. MODULES: THE DARK SIDE‣ Over-engineering / pre-awesome-ization‣ Which module defined which method?‣ What methods are defined in the class?‣ Method name collisions when including modules‣ You can’t reference a modularized entity, you must pass around the object that contains it.
    16. 16. COMPOSITION:WRANGLE THOSE MODULES‣ A.K.A. aggregation‣ A class is composed of several other classes, use delegation
    17. 17. Example: Composition class Avatar class Person < ActiveRecord::Base attr_reader :master # ... def initialize(master) def avatar @master = master @avatar ||= Avatar.new(self) end end def exists? def avatar_exists? master.has_avatar? avatar.exists? end end def create(file) end master.update_attribute :has_avatar, true # thumbnail and install the given avatar end def destroy master.update_attribute :has_avatar, false # delete avatar file end # etc. endhttp://37signals.com/svn/posts/1553-models-vs-modules
    18. 18. GEMS & BUNDLER‣ NO FEAR, make private gems to share code between projects‣ Use Bundler to bootstrap gem creation https://github.com/radar/guides/blob/master/ gem-development.md‣ Use :git in your Gemfile to use gems directly from git repositories http://gembundler.com/git.html
    19. 19. THE END
    20. 20. RESOURCES‣ http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active- support-concern/‣ http://yehudakatz.com/2009/11/12/better-ruby-idioms/‣ http://metabates.com/2011/02/07/building-interfaces-and-abstract-classes-in-ruby/‣ http://37signals.com/svn/posts/1553-models-vs-modules‣ http://andrzejonsoftware.blogspot.com/2011/01/code-reuse-in-ruby-why- composition-is.html‣ https://github.com/rails/rails/blob/master/activesupport/lib/active_support/ concern.rb‣ https://github.com/rails/rails/tree/master/activemodel

    ×