SlideShare ist ein Scribd-Unternehmen logo
1 von 20
REUSABLE RUBY
     ROUTE 9 RUBY GROUP – JUNE 20, 2012



                BLAKE CARLSON
     BLAKE@COIN-OPERATED.NET   • @SKINANDBONES
GITHUB.COM/SKINANDBONES • LINKEDIN.COM/IN/BLAKECARLSON
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
OUR REUSABLE RUBY
          TOOLBOX*
            * this list is not everything, okay




‣ Inheritance
‣ Modules
‣ Composition
‣ Gems & Bundler
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?)
WE ♥ MODULES
‣ Namespaces
‣ Inject a bucket o’ instance methods into
  something else
‣ The included callback
‣ ActiveSupport::Concern
‣ Testing
‣ Pitfalls
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
MODULES: METHOD INJECTION

module Sluggable

 def generate_slug(str)
  str.to_s.strip.downcase.gsub(/[^a-z0-9s]/, '').gsub(/s+/, '-')
 end

end

class Post < ActiveRecord::Base
 include Sluggable

 before_validation :update_slug

 private

 def update_slug
  self.slug = generate_slug(title)
 end

end

# Note (1): this is a super naive solution
# Note (2): check out the stringex gem for things like String#to_url.
MODULES: THE BASICS

Let’s make generate_slug available to all AR models

Put this code into a file like lib/sluggable.rb ...

         module Sluggable
          # ...
         end

         ActiveRecord::Base.send :include, Sluggable



Somewhere, like in config/initializers ...

         require 'sluggable'
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
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
                       end


https://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
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
           end



https://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
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
       end



https://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
MODULES: TESTING
Test 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
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.
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.
COMPOSITION:
WRANGLE THOSE MODULES



‣ A.K.A. aggregation
‣ A class is composed of several other
  classes, use delegation
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.
 end




http://37signals.com/svn/posts/1553-models-vs-modules
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
THE END
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

Weitere ähnliche Inhalte

Was ist angesagt?

Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
Nerd Tzanetopoulos
 
13 java beans
13 java beans13 java beans
13 java beans
snopteck
 
Migrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsMigrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain Points
Steven Evatt
 

Was ist angesagt? (19)

Android Bootstrap
Android BootstrapAndroid Bootstrap
Android Bootstrap
 
(5) c sharp introduction_object_orientation_part_ii
(5) c sharp introduction_object_orientation_part_ii(5) c sharp introduction_object_orientation_part_ii
(5) c sharp introduction_object_orientation_part_ii
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
 
Introduction Php
Introduction PhpIntroduction Php
Introduction Php
 
Asset management with Zend Framework 2
Asset management with Zend Framework 2Asset management with Zend Framework 2
Asset management with Zend Framework 2
 
Basic Oops concept of PHP
Basic Oops concept of PHPBasic Oops concept of PHP
Basic Oops concept of PHP
 
13 java beans
13 java beans13 java beans
13 java beans
 
Migrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsMigrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain Points
 
Symfony internals [english]
Symfony internals [english]Symfony internals [english]
Symfony internals [english]
 
14 mvc
14 mvc14 mvc
14 mvc
 
Sf2 wtf
Sf2 wtfSf2 wtf
Sf2 wtf
 
Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
 
O que há de novo no Rails 3
O que há de novo no Rails 3O que há de novo no Rails 3
O que há de novo no Rails 3
 
Intro to Joomla Development
Intro to Joomla DevelopmentIntro to Joomla Development
Intro to Joomla Development
 
Java Course 14: Beans, Applets, GUI
Java Course 14: Beans, Applets, GUIJava Course 14: Beans, Applets, GUI
Java Course 14: Beans, Applets, GUI
 
Adapter 2pp
Adapter 2ppAdapter 2pp
Adapter 2pp
 
Debugging on rails
Debugging on railsDebugging on rails
Debugging on rails
 
Introduction To Web Beans
Introduction To Web BeansIntroduction To Web Beans
Introduction To Web Beans
 

Ähnlich wie Reusable Ruby • Rt 9 Ruby Group • Jun 2012

Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methodsClassboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Shugo Maeda
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
Puppet
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
旻琦 潘
 

Ähnlich wie Reusable Ruby • Rt 9 Ruby Group • Jun 2012 (20)

The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014
 
The Dark Art of Rails Plugins (2008)
The Dark Art of Rails Plugins (2008)The Dark Art of Rails Plugins (2008)
The Dark Art of Rails Plugins (2008)
 
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methodsClassboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
 
Creational pattern 2
Creational pattern 2Creational pattern 2
Creational pattern 2
 
Metaprogramming Rails
Metaprogramming RailsMetaprogramming Rails
Metaprogramming Rails
 
Ruby on Rails at PROMPT ISEL '11
Ruby on Rails at PROMPT ISEL '11Ruby on Rails at PROMPT ISEL '11
Ruby on Rails at PROMPT ISEL '11
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
Dependency injection in scala
Dependency injection in scalaDependency injection in scala
Dependency injection in scala
 
Webpack: your final module bundler
Webpack: your final module bundlerWebpack: your final module bundler
Webpack: your final module bundler
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
Advanced Node.JS Meetup
Advanced Node.JS MeetupAdvanced Node.JS Meetup
Advanced Node.JS Meetup
 
Introduction to OSGi
Introduction to OSGiIntroduction to OSGi
Introduction to OSGi
 
Objective-C Is Not Java
Objective-C Is Not JavaObjective-C Is Not Java
Objective-C Is Not Java
 
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
 
Git submodule
Git submoduleGit submodule
Git submodule
 
Only oop
Only oopOnly oop
Only oop
 
Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.
 
Dependency Injection for PHP
Dependency Injection for PHPDependency Injection for PHP
Dependency Injection for PHP
 
Ruby for C# Developers
Ruby for C# DevelopersRuby for C# Developers
Ruby for C# Developers
 

Kürzlich hochgeladen

Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
UXDXConf
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
panagenda
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
FIDO Alliance
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
FIDO Alliance
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
FIDO Alliance
 
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
UK Journal
 

Kürzlich hochgeladen (20)

Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdfIntroduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
Introduction to FDO and How It works Applications _ Richard at FIDO Alliance.pdf
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
 
The Metaverse: Are We There Yet?
The  Metaverse:    Are   We  There  Yet?The  Metaverse:    Are   We  There  Yet?
The Metaverse: Are We There Yet?
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform Engineering
 
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
 
Structuring Teams and Portfolios for Success
Structuring Teams and Portfolios for SuccessStructuring Teams and Portfolios for Success
Structuring Teams and Portfolios for Success
 
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
Easier, Faster, and More Powerful – Alles Neu macht der Mai -Wir durchleuchte...
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
 
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...Hyatt driving innovation and exceptional customer experiences with FIDO passw...
Hyatt driving innovation and exceptional customer experiences with FIDO passw...
 
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdfLinux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
 
ERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage Intacct
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch Tuesday
 
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
 
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
 
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
 
Intro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджераIntro in Product Management - Коротко про професію продакт менеджера
Intro in Product Management - Коротко про професію продакт менеджера
 

Reusable Ruby • Rt 9 Ruby Group • Jun 2012

  • 1. REUSABLE RUBY ROUTE 9 RUBY GROUP – JUNE 20, 2012 BLAKE CARLSON BLAKE@COIN-OPERATED.NET • @SKINANDBONES GITHUB.COM/SKINANDBONES • LINKEDIN.COM/IN/BLAKECARLSON
  • 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. OUR REUSABLE RUBY TOOLBOX* * this list is not everything, okay ‣ Inheritance ‣ Modules ‣ Composition ‣ Gems & Bundler
  • 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. WE ♥ MODULES ‣ Namespaces ‣ Inject a bucket o’ instance methods into something else ‣ The included callback ‣ ActiveSupport::Concern ‣ Testing ‣ Pitfalls
  • 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. MODULES: METHOD INJECTION module Sluggable def generate_slug(str) str.to_s.strip.downcase.gsub(/[^a-z0-9s]/, '').gsub(/s+/, '-') end end class Post < ActiveRecord::Base include Sluggable before_validation :update_slug private def update_slug self.slug = generate_slug(title) end end # Note (1): this is a super naive solution # Note (2): check out the stringex gem for things like String#to_url.
  • 8. MODULES: THE BASICS Let’s make generate_slug available to all AR models Put this code into a file like lib/sluggable.rb ... module Sluggable # ... end ActiveRecord::Base.send :include, Sluggable Somewhere, like in config/initializers ... require 'sluggable'
  • 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. 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 end https://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
  • 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 end https://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
  • 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 end https://github.com/rails/rails/blob/master/activesupport/lib/active_support/concern.rb
  • 13. MODULES: TESTING Test 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. 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. 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. COMPOSITION: WRANGLE THOSE MODULES ‣ A.K.A. aggregation ‣ A class is composed of several other classes, use delegation
  • 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. end http://37signals.com/svn/posts/1553-models-vs-modules
  • 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
  • 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

Hinweis der Redaktion

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n