• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
 

RubyEnRails2007 - Dr Nic Williams - DIY Syntax

on

  • 7,719 views

Many features of rails give you beautiful syntax - here's some ideas to create your own

Many features of rails give you beautiful syntax - here's some ideas to create your own

Statistics

Views

Total Views
7,719
Views on SlideShare
7,554
Embed Views
165

Actions

Likes
4
Downloads
276
Comments
0

7 Embeds 165

http://coderwall.com 135
http://drnicwilliams.com 14
http://2007.rubyenrails.nl 11
http://www.slideshare.net 2
http://jisi.dreamblog.jp 1
http://localhost:3000 1
http://www.linkedin.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    RubyEnRails2007 - Dr Nic Williams - DIY Syntax RubyEnRails2007 - Dr Nic Williams - DIY Syntax Presentation Transcript

    • Dr Nic drnicwilliams.com DIY Syntax
    • $ irb >> $KCODE = quot;uquot; >> quot;303274quot; => quot;üquot;
    • Isn’t this nicer? >> U00FC => quot;üquot;
    • $ sudo gem install charesc $ irb >> $KCODE = quot;uquot; >> require 'rubygems' >> require 'charesc' >> quot;charesc is made by Martin D#{U00FC}rstquot; => quot;charesc is made by Martin Dürstquot; >> U00FC => quot;üquot; >> quot;303274quot; => quot;üquot; charesc
    • Active Records SELECT * FROM conferences WHERE (start_date > '2007-06-07') # But, much nicer is...
    • Active Records SELECT * FROM conferences WHERE (start_date > '2007-06-07') # But, much nicer is... Conference.find(:all, :conditions => [‘start_date > ?’,Date.today])
    • Active Records SELECT conferences.quot;idquot; AS t0_r0, conferences.quot;namequot; AS t0_r2, ..., conference_sessions.quot;idquot; AS t1_r0, conference_sessions.quot;conference_idquot; 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...
    • Active Records SELECT conferences.quot;idquot; AS t0_r0, conferences.quot;namequot; AS t0_r2, ..., conference_sessions.quot;idquot; AS t1_r0, conference_sessions.quot;conference_idquot; 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)
    • Sexy Syntax ActiveRecords - no SQL ... + marshalling to objects
    • Sexy Syntax Convenient Code
    • 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
    • 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
    • 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?
    • 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
    • What’s this do? #1 Nice syntax can quickly tell you want the code will does @user.conference_sessions_for(@conference)
    • 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
    • What’s this do? #2 @conference_attendees.map_id_and_login_and_full_name
    • What’s this do? #2 @conference_attendees.map_id_and_login_and_full_name # map {|att| [att.id, att.login, att.full_name]}
    • What’s this do? #3 User.find(params[:id])
    • What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id])
    • 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]))
    • 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
    • Let’s see how they work...
    • What’s this do? #1 Nice syntax can quickly tell you want the code will does @user.conference_sessions_for(@conference)
    • 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
    • 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
    • What’s this do? #2 @attendees.map_by_id_and_login_and_full_name # map {|att| [att.id, att.login, att.full_name]}
    • Cute ways to use #map @users = User.find(:all) @users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh']
    • Cute ways to use #map @users = User.find(:all) @users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh'] @users.map &:login # => ['drnic', 'topfunky', 'dhh']
    • 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]
    • Cute ways to use #map # So, instead of... @users.map(&:login).map(&:size) # We might like... @users.map_login.map_size
    • 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
    • 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...
    • 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
    • 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
    • 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
    • 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'
    • What’s this do? #3 User.find(params[:id])
    • What’s this do? #3 @to_user = @target_db::User.find(params[:id]) User.find(params[:id])
    • 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]))
    • 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
    • Magic Multi-Connections @db::User.find(params[:id])
    • MMC - alternate ideas @db::User.find(params[:id]) # but I would have preferred... User.find(params[:id]).from_db(@db)
    • 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
    • But what does this mean? @db::User
    • 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
    • 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
    • But...the class... “when to create it?” When you ask for it!
    • 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 = quot;::#{const_id}quot;.constantize rescue nil raise NameError.new(quot;bad constant #{const_id}quot;) unless target_class create_class(const_id, target_class) end end
    • 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 = quot;::#{const_id}quot;.constantize rescue nil raise NameError.new(quot;bad constant #{const_id}quot;) unless target_class create_class(const_id, target_class) end end magic multi-connections
    • Picks up root classes class Person; end module Remote establish_connection :other end >> Remote::Person.superclass => Person
    • 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(quot;bad constant #{const_id}quot;) 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?”
    • 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(quot;bad constant #{const_id}quot;) 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?”
    • const_missing >> U00FC => quot;üquot;
    • 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*')
    • Sexy Syntax Convenient Code
    • Enjoy En ! drnicwilliams.com by Dr Nic