ROR lab. DD-1
   - The 1st round -



Active Support
Core Extensions
     March 16, 2013

     Hyoseong Choi
Active Support

• Ruby on Rails components
 • actionmailer
 • actionpack
 • activerecord
 • activesupport ...
Active Support

• Ruby on Rails components
 • actionmailer
 • actionpack
 • activerecord
 • activesupport ...
Active Support

• Ruby language extensions
• Utility classes
• Other transversal stuff
Core Extensions
  Stand-Alone Active Support
   require 'active_support'


  “blank?” method
  Cherry-picking
  require 'active_support/core_ext/object/blank'


  Grouped Core Extensions
  require 'active_support/core_ext/object'


  All Core Extensions
  require 'active_support/core_ext'


  All Active Support
  require 'active_support/all'
Core Extensions
  Active Support within ROR Application

   Default
   require 'active_support/all'




   Barebone setting with Cherry-pickings
   config.active_support.bare = true
Ext. to All Objects
• blank?
    ‣ nil and false                         0 and 0.0

    ‣ whitespaces : spaces, tabs, newlines
    ‣ empty arrays and hashes                  !
                                            blank
    ‣ empty? true

• present?
                        active_support/core_ext/object/
    ‣ !blank?                      blank.rb
Ext. to All Objects
• presence
  host = config[:host].presence || 'localhost'




                             active_support/core_ext/object/
                                        blank.rb
Ext. to All Objects
• duplicable?
  "".duplicable?     # => true
  false.duplicable?  # => false



 Singletons : nil, false, true, symobls, numbers,
 and class and module objects



                             active_support/core_ext/object/
                                      duplicable.rb
Ext. to All Objects
• try
  def log_info(sql, name, ms)
    if @logger.try(:debug?)
      name = '%s (%.1fms)' % [name || 'SQL', ms]
      @logger.debug(format_log_entry(name, sql.squeeze(' ')))
    end
  end


  @person.try { |p| "#{p.first_name} #{p.last_name}" }



• try!
                          active_support/core_ext/object/try.rb
Ext. to All Objects
• singleton_class
  nil => NilClass
  true => TrueClass
  false => FalseClass




                        active_support/core_ext/kernel/
                              singleton_class.rb
o us
    ym s


             Singleton Class?
  on as
an cl




       •     When you add a method to a specific object, Ruby inserts
             a new anonymous class into the inheritance hierarchy as
             a container to hold these types of methods.



                                                               foobar = [ ]
                                                               def foobar.say
                                                                 “Hello”
                                                               end




      http://www.devalot.com/articles/2008/09/ruby-singleton
o us
    ym s


             Singleton Class?
  on as
an cl




      foobar = Array.new                           module Foo
                                                     def foo
      def foobar.size                                  "Hello World!"
        "Hello World!"                               end
      end                                          end
      foobar.size # => "Hello World!"
      foobar.class # => Array                      foobar = []
      bizbat = Array.new                           foobar.extend(Foo)
      bizbat.size # => 0                           foobar.singleton_methods # => ["foo"]




      foobar = []                                  foobar = []

      class << foobar                              foobar.instance_eval <<EOT
        def foo                                      def foo
          "Hello World!"                               "Hello World!"
        end                                          end
      end                                          EOT

      foobar.singleton_methods # => ["foo"]        foobar.singleton_methods # => ["foo"]




      http://www.devalot.com/articles/2008/09/ruby-singleton
o us
    ym s


             Singleton Class?
  on as
an cl




      • Practical Uses of Singleton Classes
             class Foo
                                                class
               def self.one () 1 end
                                                method
               class << self
                 def two () 2 end               class
               end                              method

               def three () 3 end

               self.singleton_methods # => ["two", "one"]
               self.class             # => Class
               self                   # => Foo
             end




      http://www.devalot.com/articles/2008/09/ruby-singleton
Ext. to All Objects
• class_eval(*args, &block)
 class Proc
   def bind(object)
     block, time = self, Time.now
     object.class_eval do
       method_name = "__bind_#{time.to_i}_#{time.usec}"
       define_method(method_name, &block)
       method = instance_method(method_name)
       remove_method(method_name)
       method
     end.bind(object)
   end
 end



                              active_support/core_ext/kernel/
                                    singleton_class.rb
Ext. to All Objects
    •   acts_like?(duck)           same interface?




      def acts_like_string?
      end



      some_klass.acts_like?(:string)


  or ple
f m
e xa     acts_like_date? (Date class)
      acts_like_time? (Time class)


                                        active_support/core_ext/object/
                                                 acts_likes.rb
Ext. to All Objects
    • to_param(=> to_s)             a value for :id placeholder



     class User
                      overwriting
       def to_param
         "#{id}-#{name.parameterize}"
       end
     end




➧    user_path(@user) # => "/users/357-john-smith"



    => The return value should not be escaped!
                                  active_support/core_ext/object/
                                            to_param.rb
Ext. to All Objects
    •   to_query              a value for :id placeholder



    class User
      def to_param
        "#{id}-#{name.parameterize}"
      end
    end




➧   current_user.to_query('user') # => user=357-john-smith



    => escaped!
                                 active_support/core_ext/object/
                                           to_query.rb
Ext. to All Objects
               es
                    ca

•
                         pe
    to_query                  d



account.to_query('company[name]')
# => "company%5Bname%5D=Johnson+%26+Johnson"


[3.4, -45.6].to_query('sample')
# => "sample%5B%5D=3.4&sample%5B%5D=-45.6"


{:c => 3, :b => 2, :a => 1}.to_query
# => "a=1&b=2&c=3"


{:id => 89, :name => "John Smith"}.to_query('user')
# => "user%5Bid%5D=89&user%5Bname%5D=John+Smith"


         active_support/core_ext/object/
                   to_query.rb
Ext. to All Objects
• with_options
 class Account < ActiveRecord::Base
   has_many :customers, :dependent =>   :destroy
   has_many :products,  :dependent =>   :destroy
   has_many :invoices,  :dependent =>   :destroy
   has_many :expenses,  :dependent =>   :destroy
 end


 class Account < ActiveRecord::Base
   with_options :dependent => :destroy do |assoc|
     assoc.has_many :customers
     assoc.has_many :products
     assoc.has_many :invoices
     assoc.has_many :expenses
   end
 end


          active_support/core_ext/object/
                  with_options.rb
Ext. to All Objects
     • with_options
I18n.with_options locale: user.locale, scope: "newsletter" do |i18n|
  subject i18n.t(:subject)
  body    i18n.t(:body, user_name: user.name)
end
                      interpolation
                           key


# app/views/home/index.html.erb
<%=t 'greet_username', :user => "Bill", :message => "Goodbye" %>
 
# config/locales/en.yml
en:
  greet_username: "%{message}, %{user}!"


             http://guides.rubyonrails.org/i18n.html

                active_support/core_ext/object/
                        with_options.rb
Ext. to All Objects
 • with_options
en:
                     scope of
  activerecord:        i18n
    models:
      user: Dude
    attributes:
      user:
        login: "Handle"
      # will translate User attribute "login" as "Handle"

                                       config/locales/en.yml



          http://guides.rubyonrails.org/i18n.html

             active_support/core_ext/object/
                     with_options.rb
Ext. to All Objects
• Instance Variables
 class C
   def initialize(x, y)
     @x, @y = x, y
   end
 end
  
 C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}




          active_support/core_ext/object/
               instance_variable.rb
E
                      Ext. to All Objects
                      • Silencing Warnings, Streams, and Exceptions
           B OS
   E   R
$V


  silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
                                                                         si
                                                                            le
                                                                         st nc
                                                                           re in
                       silence_stream(STDOUT) do                              am g
                                                                                s
                         # STDOUT is silent here
                       end
                                                        su ev
                                                          bp en
                                                            ro i
                                                              ce n
                                                                ss
                       quietly { system 'bundle install' }         es
                                                                                    si
                                                                                  ex le
                                                                                    ce nc
                                                                                       pt in
                       # If the user is locked the increment is lost, no big deal.       io g
                       suppress(ActiveRecord::StaleObjectError) do                         ns
                         current_user.increment! :visits
                       end

                                 active_support/core_ext/kernel/
                                          reporting.rb
Ext. to All Objects
• in?
 1.in?(1,2)            #   =>   true
 1.in?([1,2])          #   =>   true
 "lo".in?("hello")     #   =>   true
 25.in?(30..50)        #   =>   false
 1.in?(1)              #   =>   ArgumentError




• include? (array method)
 [1,2].include? 1         # => true
 "hello".include? "lo"    # => true
 (30..50).include? 25     # => false



          active_support/core_ext/object/
                   inclusion.rb
ROR Lab.

Active Support Core Extensions (1)

  • 1.
    ROR lab. DD-1 - The 1st round - Active Support Core Extensions March 16, 2013 Hyoseong Choi
  • 2.
    Active Support • Rubyon Rails components • actionmailer • actionpack • activerecord • activesupport ...
  • 3.
    Active Support • Rubyon Rails components • actionmailer • actionpack • activerecord • activesupport ...
  • 4.
    Active Support • Rubylanguage extensions • Utility classes • Other transversal stuff
  • 5.
    Core Extensions Stand-Alone Active Support require 'active_support' “blank?” method Cherry-picking require 'active_support/core_ext/object/blank' Grouped Core Extensions require 'active_support/core_ext/object' All Core Extensions require 'active_support/core_ext' All Active Support require 'active_support/all'
  • 6.
    Core Extensions Active Support within ROR Application Default require 'active_support/all' Barebone setting with Cherry-pickings config.active_support.bare = true
  • 7.
    Ext. to AllObjects • blank? ‣ nil and false 0 and 0.0 ‣ whitespaces : spaces, tabs, newlines ‣ empty arrays and hashes ! blank ‣ empty? true • present? active_support/core_ext/object/ ‣ !blank? blank.rb
  • 8.
    Ext. to AllObjects • presence host = config[:host].presence || 'localhost' active_support/core_ext/object/ blank.rb
  • 9.
    Ext. to AllObjects • duplicable? "".duplicable?     # => true false.duplicable?  # => false Singletons : nil, false, true, symobls, numbers, and class and module objects active_support/core_ext/object/ duplicable.rb
  • 10.
    Ext. to AllObjects • try def log_info(sql, name, ms)   if @logger.try(:debug?)     name = '%s (%.1fms)' % [name || 'SQL', ms]     @logger.debug(format_log_entry(name, sql.squeeze(' ')))   end end @person.try { |p| "#{p.first_name} #{p.last_name}" } • try! active_support/core_ext/object/try.rb
  • 11.
    Ext. to AllObjects • singleton_class nil => NilClass true => TrueClass false => FalseClass active_support/core_ext/kernel/ singleton_class.rb
  • 12.
    o us ym s Singleton Class? on as an cl • When you add a method to a specific object, Ruby inserts a new anonymous class into the inheritance hierarchy as a container to hold these types of methods. foobar = [ ] def foobar.say “Hello” end http://www.devalot.com/articles/2008/09/ruby-singleton
  • 13.
    o us ym s Singleton Class? on as an cl foobar = Array.new module Foo def foo def foobar.size "Hello World!" "Hello World!" end end end foobar.size # => "Hello World!" foobar.class # => Array foobar = [] bizbat = Array.new foobar.extend(Foo) bizbat.size # => 0 foobar.singleton_methods # => ["foo"] foobar = [] foobar = [] class << foobar foobar.instance_eval <<EOT def foo def foo "Hello World!" "Hello World!" end end end EOT foobar.singleton_methods # => ["foo"] foobar.singleton_methods # => ["foo"] http://www.devalot.com/articles/2008/09/ruby-singleton
  • 14.
    o us ym s Singleton Class? on as an cl • Practical Uses of Singleton Classes class Foo class def self.one () 1 end method class << self def two () 2 end class end method def three () 3 end self.singleton_methods # => ["two", "one"] self.class # => Class self # => Foo end http://www.devalot.com/articles/2008/09/ruby-singleton
  • 15.
    Ext. to AllObjects • class_eval(*args, &block) class Proc   def bind(object)     block, time = self, Time.now     object.class_eval do       method_name = "__bind_#{time.to_i}_#{time.usec}"       define_method(method_name, &block)       method = instance_method(method_name)       remove_method(method_name)       method     end.bind(object)   end end active_support/core_ext/kernel/ singleton_class.rb
  • 16.
    Ext. to AllObjects • acts_like?(duck) same interface? def acts_like_string? end some_klass.acts_like?(:string) or ple f m e xa acts_like_date? (Date class) acts_like_time? (Time class) active_support/core_ext/object/ acts_likes.rb
  • 17.
    Ext. to AllObjects • to_param(=> to_s) a value for :id placeholder class User overwriting   def to_param     "#{id}-#{name.parameterize}"   end end ➧ user_path(@user) # => "/users/357-john-smith" => The return value should not be escaped! active_support/core_ext/object/ to_param.rb
  • 18.
    Ext. to AllObjects • to_query a value for :id placeholder class User   def to_param     "#{id}-#{name.parameterize}"   end end ➧ current_user.to_query('user') # => user=357-john-smith => escaped! active_support/core_ext/object/ to_query.rb
  • 19.
    Ext. to AllObjects es ca • pe to_query d account.to_query('company[name]') # => "company%5Bname%5D=Johnson+%26+Johnson" [3.4, -45.6].to_query('sample') # => "sample%5B%5D=3.4&sample%5B%5D=-45.6" {:c => 3, :b => 2, :a => 1}.to_query # => "a=1&b=2&c=3" {:id => 89, :name => "John Smith"}.to_query('user') # => "user%5Bid%5D=89&user%5Bname%5D=John+Smith" active_support/core_ext/object/ to_query.rb
  • 20.
    Ext. to AllObjects • with_options class Account < ActiveRecord::Base   has_many :customers, :dependent => :destroy   has_many :products,  :dependent => :destroy   has_many :invoices,  :dependent => :destroy   has_many :expenses,  :dependent => :destroy end class Account < ActiveRecord::Base   with_options :dependent => :destroy do |assoc|     assoc.has_many :customers     assoc.has_many :products     assoc.has_many :invoices     assoc.has_many :expenses   end end active_support/core_ext/object/ with_options.rb
  • 21.
    Ext. to AllObjects • with_options I18n.with_options locale: user.locale, scope: "newsletter" do |i18n|   subject i18n.t(:subject)   body    i18n.t(:body, user_name: user.name) end interpolation key # app/views/home/index.html.erb <%=t 'greet_username', :user => "Bill", :message => "Goodbye" %>   # config/locales/en.yml en:   greet_username: "%{message}, %{user}!" http://guides.rubyonrails.org/i18n.html active_support/core_ext/object/ with_options.rb
  • 22.
    Ext. to AllObjects • with_options en: scope of   activerecord: i18n     models:       user: Dude     attributes:       user:         login: "Handle"       # will translate User attribute "login" as "Handle" config/locales/en.yml http://guides.rubyonrails.org/i18n.html active_support/core_ext/object/ with_options.rb
  • 23.
    Ext. to AllObjects • Instance Variables class C   def initialize(x, y)     @x, @y = x, y   end end   C.new(0, 1).instance_values # => {"x" => 0, "y" => 1} active_support/core_ext/object/ instance_variable.rb
  • 24.
    E Ext. to All Objects • Silencing Warnings, Streams, and Exceptions B OS E R $V silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger } si le st nc re in silence_stream(STDOUT) do am g s   # STDOUT is silent here end su ev bp en ro i ce n ss quietly { system 'bundle install' } es si ex le ce nc pt in # If the user is locked the increment is lost, no big deal. io g suppress(ActiveRecord::StaleObjectError) do ns   current_user.increment! :visits end active_support/core_ext/kernel/ reporting.rb
  • 25.
    Ext. to AllObjects • in? 1.in?(1,2)          # => true 1.in?([1,2])        # => true "lo".in?("hello")   # => true 25.in?(30..50)      # => false 1.in?(1)            # => ArgumentError • include? (array method) [1,2].include? 1         # => true "hello".include? "lo"    # => true (30..50).include? 25     # => false active_support/core_ext/object/ inclusion.rb
  • 26.