rubyenrails2007 - dr nic williams - diy syntax

57
Dr Nic drnicwilliams.com DIY Syntax

Upload: dr-nic-williams

Post on 05-Dec-2014

7.874 views

Category:

Business


0 download

DESCRIPTION

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

TRANSCRIPT

Page 1: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Dr Nicdrnicwilliams.com

DIY Syntax

Page 2: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

$ irb>> $KCODE = "u" >> "\303\274"=> "ü"

Page 3: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Isn’t this nicer?

>> U00FC=> "ü"

Page 4: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

$ 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

Page 5: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

ActiveRecords

SELECT * FROM conferences WHERE (start_date > '2007-06-07')

# But, much nicer is...

Page 6: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

ActiveRecords

SELECT * FROM conferences WHERE (start_date > '2007-06-07')

# But, much nicer is...

Conference.find(:all, :conditions => [‘start_date > ?’,Date.today])

Page 7: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Active RecordsSELECT 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...

Page 8: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Active RecordsSELECT 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)

Page 9: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

ActiveRecords - no SQL ... + marshalling to objects

SexySyntax

Page 10: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

SexySyntax

Convenient Code

Page 11: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Schemascreate_table :conferences do |t| t.fkey :user t.string :name, :limit => 50 t.text :description t.date :start_date, :end_date t.auto_datesend

# instead of...

I can never remember SQL syntax

Page 12: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Schemascreate_table :conferences do |t| t.fkey :user t.string :name, :limit => 50 t.text :description t.date :start_date, :end_date t.auto_datesend

# instead of...

Look up SQL onI can never remember SQL syntax

Page 13: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

CompositePrimary 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?

Page 14: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

CompositePrimary 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?

ProductHistory.find(56, Date.new(2000,5,5))

class ProductHistory < ActiveRecord::Base set_primary_keys :id, :start_dateend

Page 15: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #1Nice syntax can quickly tell you want the code will does

@user.conference_sessions_for(@conference)

Page 16: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #1Nice syntax can quickly tell you want the code will does

@user.conference_sessions_for(@conference)# Returns all ConferenceSessions# for a user at a conference

Page 17: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #2

@conference_attendees.map_id_and_login_and_full_name

Page 18: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #2

@conference_attendees.map_id_and_login_and_full_name

# map {|att| [att.id, att.login, att.full_name]}

Page 19: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

Page 20: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

@to_user = @target_db::User.find(params[:id])

Page 21: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

@to_user = @target_db::User.find(params[:id])@to_user.update(@from_db::User.find(params[:id]))

Page 22: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

@to_user = @target_db::User.find(params[:id])

# Copies a User from one database to another

# see Magic Multi-Connection# http://magicmodels.rubyforge.org

@to_user.update(@from_db::User.find(params[:id]))

Page 23: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Let’s see how they work...

Page 24: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #1Nice syntax can quickly tell you want the code will does

@user.conference_sessions_for(@conference)

Page 25: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #1Nice syntax can quickly tell you want the code will does

@user.conference_sessions_for(@conference)# Returns all ConferenceSessions# for a user at a conference

Page 26: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

class User < ActiveRecord::Base has_many :conference_sessions

def conference_sessions_for(conference) conference_sessions.find(:all, :conditions => ['conference_id = ?', conference]) endend

What’s this do? #1

No meta-magic, but it gives nice syntax

Page 27: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

What’s this do? #2

@attendees.map_by_id_and_login_and_full_name

# map {|att| [att.id, att.login, att.full_name]}

Page 28: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

@users = User.find(:all)@users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh']

Cute ways to use #map

Page 29: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

@users = User.find(:all)@users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh']

Cute ways to use #map

@users.map &:login# => ['drnic', 'topfunky', 'dhh']

Page 30: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

@users = User.find(:all)@users.map {|user| user.login} # => ['drnic', 'topfunky', 'dhh']

Cute ways to use #map

@users.map &:login# => ['drnic', 'topfunky', 'dhh']

# but it gets ugly when you chain them...

@users.map(&:login).map(&:size) # => [5, 8, 3]

Page 31: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

# So, instead [email protected](&:login).map(&:size)

# We might [email protected]_login.map_size

Cute ways to use #map

Page 32: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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

Remember find_by_xxx ?

Page 33: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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...

Dissecting the request

Page 34: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

# 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 the request

Page 35: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

# 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

Iterating many callmethods

Page 36: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

# 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

Page 37: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

# 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

# add the following to your ~/.irbrcrequire 'map_by_method'

Page 38: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

Page 39: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

@to_user = @target_db::User.find(params[:id])

Page 40: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

@to_user = @target_db::User.find(params[:id])@to_user.update(@from_db::User.find(params[:id]))

Page 41: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

User.find(params[:id])

What’s this do? #3

@to_user = @target_db::User.find(params[:id])

# Copies a User from one database to another

# see Magic Multi-Connection# http://magicmodels.rubyforge.org

@to_user.update(@from_db::User.find(params[:id]))

Page 42: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

MagicMulti-Connections

@db::User.find(params[:id])

Page 43: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

@db::User.find(params[:id])

# but I would have preferred...

User.find(params[:id]).from_db(@db)

MMC - alternate ideas

Page 44: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

@db::User.find(params[:id])

# but I would have preferred...

User.find(params[:id]).from_db(@db)

MMC - alternate ideas

# but we’d need FindProxies # like AssociationProxies

Page 45: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

But what does this mean?

@db::User

Page 46: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

class creator helperclass Module def create_class(class_name, superclass = Object, &block) klass = Class.new superclass, &block self.const_set class_name, klass endend

>> module Connection; end>> Connection.create_class 'User'=> Connection::User

Page 47: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

class creator helperclass Module def create_class(class_name, superclass = Object, &block) klass = Class.new superclass, &block self.const_set class_name, klass endend

>> module Connection; end>> Connection.create_class 'User'=> Connection::User

@db::User

Page 48: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

But...the class...“when to create it?”

When you ask for it!

Page 49: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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) endend

Page 50: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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) endend

magic multi-connections

Page 51: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Picks up root classesclass Person; end

module Remote establish_connection :otherend

>> Remote::Person.superclass=> Person

Page 52: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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 endend

const_missing

“Does the class name match to a table name?”

Page 53: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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 endend

const_missing

dr nic’s magic models

“Does the class name match to a table name?”

Page 54: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

const_missing

>> U00FC=> "ü"

Page 55: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

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*')

Page 56: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

Convenient Code

SexySyntax

Page 57: RubyEnRails2007 - Dr Nic Williams - DIY Syntax

drnicwilliams.com

by Dr Nic

Enjoy En !