Slideshow transcript
Slide 1: Dr Nic drnicwilliams.com DIY Syntax
Slide 2: $ irb >> $KCODE = \"u\" >> \"\\303\\274\" => \"ü\"
Slide 3: Isn’t this nicer? >> U00FC => \"ü\"
Slide 4: $ sudo gem install charesc $ irb >> $KCODE = \"u\" >> require 'rubygems' >> require 'charesc' >> \"charesc is made by Martin D#{U00FC}rst\" => \"charesc is made by Martin Dürst\" >> U00FC => \"ü\" >> \"\\303\\274\" => \"ü\" charesc
Slide 5: Active Records SELECT * FROM conferences WHERE (start_date > '2007-06-07') # But, much nicer is...
Slide 6: Active Records SELECT * FROM conferences WHERE (start_date > '2007-06-07') # But, much nicer is... Conference.find(:all, :conditions => [‘start_date > ?’,Date.today])
Slide 7: Active Records SELECT conferences.\"id\" AS t0_r0, conferences.\"name\" AS t0_r2, ..., conference_sessions.\"id\" AS t1_r0, conference_sessions.\"conference_id\" AS t1_r1, ... FROM conferences LEFT OUTER JOIN conference_sessions ON conference_sessions.conference_id = conferences.id WHERE (start_date < '2007-05-26') # But, definitely easier and nicer is...
Slide 8: Active Records SELECT conferences.\"id\" AS t0_r0, conferences.\"name\" AS t0_r2, ..., conference_sessions.\"id\" AS t1_r0, conference_sessions.\"conference_id\" AS t1_r1, ... FROM conferences LEFT OUTER JOIN conference_sessions ON conference_sessions.conference_id = conferences.id WHERE (start_date < '2007-05-26') # But, definitely easier and nicer is... Conference.find(:all, :conditions => ['start_date < ?', Date.today], :include => :conference_sessions)
Slide 9: Sexy Syntax ActiveRecords - no SQL ... + marshalling to objects
Slide 10: Sexy Syntax Convenient Code
Slide 11: Schemas create_table :conferences do |t| t.fkey :user t.string :name, :limit => 50 t.text :description t.date :start_date, :end_date t.auto_dates end # instead of... I can never remember SQL syntax
Slide 12: Schemas create_table :conferences do |t| t.fkey :user t.string :name, :limit => 50 t.text :description t.date :start_date, :end_date t.auto_dates end # instead of... Look up SQL on I can never remember SQL syntax
Slide 13: Composite Primary Keys ProductHistory.find(:first, :conditions => ['id = ? and start_date = ?', 56, Date.new(2000,5,5)]) # rather... What about Ruby syntax improving on other Ruby syntax?
Slide 14: Composite Primary Keys ProductHistory.find(:first, :conditions => ['id = ? and start_date = ?', 56, Date.new(2000,5,5)]) # rather... ProductHistory.find(56, Date.new(2000,5,5)) What about Ruby syntax class ProductHistory < ActiveRecord::Base improving on other Ruby set_primary_keys :id, :start_date syntax? end
Slide 15: What’s this do? #1 Nice syntax can quickly tell you want the code will does @user.conference_sessions_for(@conference)
Slide 16: What’s this do? #1 Nice syntax can quickly tell you want the code will does @user.conference_sessions_for(@conference) # Returns all ConferenceSessions # for a user at a conference
Slide 17: What’s this do? #2 @conference_attendees.map_id_and_login_and_full_name
Slide 18: What’s this do? #2 @conference_attendees.map_id_and_login_and_full_name # map {|att| [att.id, att.login, att.full_name]}
Slide 19: What’s this do? #3 User.find(params[:id])
Slide 20: What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id])
Slide 21: What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id]) @to_user.update(@from_db::User.find(params[:id]))
Slide 22: What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id]) @to_user.update(@from_db::User.find(params[:id])) # Copies a User from one database to another # see Magic Multi-Connection # http://magicmodels.rubyforge.org
Slide 23: Let’s see how they work...
Slide 24: What’s this do? #1 Nice syntax can quickly tell you want the code will does @user.conference_sessions_for(@conference)
Slide 25: What’s this do? #1 Nice syntax can quickly tell you want the code will does @user.conference_sessions_for(@conference) # Returns all ConferenceSessions # for a user at a conference
Slide 26: What’s this do? #1 class User < ActiveRecord::Base has_many :conference_sessions def conference_sessions_for(conference) conference_sessions.find(:all, :conditions => ['conference_id = ?', conference]) end end No meta-magic, but it gives nice syntax
Slide 27: What’s this do? #2 @attendees.map_by_id_and_login_and_full_name # map {|att| [att.id, att.login, att.full_name]}
Slide 28: Cute ways to use #map @users = User.find(:all) @users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh']
Slide 29: Cute ways to use #map @users = User.find(:all) @users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh'] @users.map &:login # => ['drnic', 'topfunky', 'dhh']
Slide 30: Cute ways to use #map @users = User.find(:all) @users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh'] @users.map &:login # => ['drnic', 'topfunky', 'dhh'] # but it gets ugly when you chain them... @users.map(&:login).map(&:size) # => [5, 8, 3]
Slide 31: Cute ways to use #map # So, instead of... @users.map(&:login).map(&:size) # We might like... @users.map_login.map_size
Slide 32: Remember find_by_xxx ? def method_missing(method_id, *arguments) pattern = /^find_(all_by|by)_([_a-zA-Z]\\w*)$/ if match = pattern.match(method_id.to_s) finder = determine_finder(match) # from active_record/base.rb, line 1190
Slide 33: Dissecting the request def method_missing(method, *args, &block) pattern = /(map|select|...)_by_([\\w\\_]+\\??)/ if (match = method.match(pattern)) iterator, callmethod = match[1], match[2] # changed ‘find’ to ‘map’ # or select, reject, each, collect...
Slide 34: Iterating the request # continued... iterator, callmethod = match[1], match[2] self.send(iterator) {|obj| obj.send callmethod } # @array.map_by_foo # callmethod => ‘foo’ # #foo invoked on each element of Array
Slide 35: Iterating many callmethods # continued... iterator, callmethod = match[1], match[2] callmethods = callmethod.split('_and_') callmethods.map do |callmethod| self.send(iterator) {|obj| obj.send callmethod } end # @array.map_by_foo_and_bar # callmethods => [‘foo’, ‘bar’] # #foo and #bar invoked on each element of Array
Slide 36: map_by_method gem # for complete source: $ gem install map_by_method $ mate $RUBYGEMS_PATH/map_by_method-0.6.0/lib/map_by_method.rb
Slide 37: map_by_method gem # for complete source: $ gem install map_by_method $ mate $RUBYGEMS_PATH/map_by_method-0.6.0/lib/map_by_method.rb # add the following to your ~/.irbrc require 'map_by_method'
Slide 38: What’s this do? #3 User.find(params[:id])
Slide 39: What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id])
Slide 40: What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id]) @to_user.update(@from_db::User.find(params[:id]))
Slide 41: What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id]) @to_user.update(@from_db::User.find(params[:id])) # Copies a User from one database to another # see Magic Multi-Connection # http://magicmodels.rubyforge.org
Slide 42: Magic Multi-Connections @db::User.find(params[:id])
Slide 43: MMC - alternate ideas @db::User.find(params[:id]) # but I would have preferred... User.find(params[:id]).from_db(@db)
Slide 44: MMC - alternate ideas @db::User.find(params[:id]) # but I would have preferred... User.find(params[:id]).from_db(@db) # but we’d need FindProxies # like AssociationProxies
Slide 45: But what does this mean? @db::User
Slide 46: class creator helper class Module def create_class(class_name, superclass = Object, &block) klass = Class.new superclass, &block self.const_set class_name, klass end end >> module Connection; end >> Connection.create_class 'User' => Connection::User
Slide 47: class creator helper class Module def create_class(class_name, superclass = Object, &block) klass = Class.new superclass, &block self.const_set class_name, klass end end >> module Connection; end >> Connection.create_class 'User' => Connection::User @db::User
Slide 48: But...the class... “when to create it?” When you ask for it!
Slide 49: const_missing class Module alias :old_const_missing :const_missing def const_missing(const_id) return old_const_missing(const_id) rescue nil target_class = \"::\\#{const_id}\".constantize rescue nil raise NameError.new(\"bad constant \\#{const_id}\") unless target_class create_class(const_id, target_class) end end
Slide 50: const_missing class Module alias :old_const_missing :const_missing def const_missing(const_id) return old_const_missing(const_id) rescue nil target_class = \"::\\#{const_id}\".constantize rescue nil raise NameError.new(\"bad constant \\#{const_id}\") unless target_class create_class(const_id, target_class) end end magic multi-connections
Slide 51: Picks up root classes class Person; end module Remote establish_connection :other end >> Remote::Person.superclass => Person
Slide 52: const_missing class Module def const_missing(const_id) return old_const_missing(class_id) rescue nil table_name = DrNicMagicModels::Schema.models[const_id] raise NameError.new(\"bad constant #{const_id}\") unless table_name create_class(class_id, ActiveRecord::Base) do set_table_name table_name end end end “Does the class name match to a table name?”
Slide 53: const_missing class Module def const_missing(const_id) return old_const_missing(class_id) rescue nil table_name = DrNicMagicModels::Schema.models[const_id] raise NameError.new(\"bad constant #{const_id}\") unless table_name create_class(class_id, ActiveRecord::Base) do set_table_name table_name end end dr nic’s magic models end “Does the class name match to a table name?”
Slide 54: const_missing >> U00FC => \"ü\"
Slide 55: const_missing def const_missing(const) if const.to_s =~ /^((U( [0-9ABCEF][0-9A-F]{3} # general BMP | D[0-7][0-9A-F]{2} # excluding surrogates | [1-9A-F][0-9A-F]{4} # planes 1-15 | 10 [0-9A-F]{4} # plane 16 ) )* ) $/ix unescaped = $1.split(/[Uu]/)[1..-1].collect do |hex| hex.to_i(16) end.pack('U*')
Slide 56: Sexy Syntax Convenient Code
Slide 57: Enjoy En ! drnicwilliams.com by Dr Nic



Add a comment on Slide 1
If you have a SlideShare account, login to comment; else you can comment as a guest- Favorites & Groups
Showing 1-50 of 4 (more)