Date Once

Post on 21-Jan-2015

865 views 1 download

Tags:

description

Explanation of the method Date::once in the ruby core classes. This talk was originally given at the TSOT Ruby on Rails Project Night

transcript

Inside Date.once Understanding some of the more interesting

code in the Ruby core

The Problem

The Problem

Instances of Date are immutable

The Problem

Instances of Date are immutable

Many methods involve complex calculations

The Problem

Instances of Date are immutable

Many methods involve complex calculations

Caching of results is desirable

The Problem

Instances of Date are immutable

Many methods involve complex calculations

Caching of results is desirable

Want to keep the code clean and uncluttered with caching related code

def jd_to_civil(jd, sg=GREGORIAN) if os?(jd, sg) a = jd else x = ((jd - 1867216.25) / 36524.25).floor a = jd + 1 + x - (x / 4.0).floor end b = a + 1524 c = ((b - 122.1) / 365.25).floor d = (365.25 * c).floor e = ((b - d) / 30.6001).floor dom = b - d - (30.6001 * e).floor if e <= 13 m = e - 1 y = c - 4716 else m = e - 13 y = c - 4715 end return y, m, domend

The Solution

The Solution

Write the individual methods as if they would not be cached

The Solution

Write the individual methods as if they would not be cached

Use some meta-programming magic to add caching support after the fact

def jd_to_civil ...end

once :jd_to_civil

class << self def once(*ids) # :nodoc: for id in ids module_eval <<-"end;", __FILE__, __LINE__ alias_method :__#{id.to_i}__, :#{id.to_s} private :__#{id.to_i}__ def #{id.to_s}(*args, &block) if defined? @__#{id.to_i}__ @__#{id.to_i}__ elsif ! self.frozen? @__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block) else __#{id.to_i}__(*args, &block) end end end; end end

private :onceend

class << self def once(*ids) # :nodoc: for id in ids module_eval <<-"end;", __FILE__, __LINE__ alias_method :__#{id.to_i}__, :#{id.to_s} private :__#{id.to_i}__ def #{id.to_s}(*args, &block) if defined? @__#{id.to_i}__ @__#{id.to_i}__ elsif ! self.frozen? @__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block) else __#{id.to_i}__(*args, &block) end end end; end end

private :onceend

class << self def once(*ids) # :nodoc: for id in ids module_eval <<-"end;", __FILE__, __LINE__ alias_method :__#{id.to_i}__, :#{id.to_s} private :__#{id.to_i}__ def #{id.to_s}(*args, &block) if defined? @__#{id.to_i}__ @__#{id.to_i}__ elsif ! self.frozen? @__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block) else __#{id.to_i}__(*args, &block) end end end; end end

private :onceend

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

alias_method

puts 'cat'

class Example

def one

puts 'cat'

end

end

one

Message

class Example

alias_methodclass Example

def one

puts 'cat'

end

alias_method :two, :one

endputs 'cat'

two

one

Message

class Example

alias_methodclass Example

def one

puts 'cat'

end

alias_method :two, :one

def one

puts 'dog'

end

end

puts 'cat'twoone

Message

class Example

puts 'dog'

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

Frozen objects

Object.freeze

“Prevents further modifications to obj. A TypeError will be raised if modification is attempted. There is no way to unfreeze a frozen object.”

Object.frozen?

“Returns the freeze status of obj“

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

alias_method :__14369__, :jd_to_civilprivate :__14369__def jd_to_civil(*args, &block) if defined? @__14369__ @__14369__ elsif ! self.frozen? @__14369__ ||= __14369__(*args, &block) else __14369__(*args, &block) endend

once :jd_to_civil

class << self def once(*ids) # :nodoc: for id in ids module_eval <<-"end;", __FILE__, __LINE__ alias_method :__#{id.to_i}__, :#{id.to_s} private :__#{id.to_i}__ def #{id.to_s}(*args, &block) if defined? @__#{id.to_i}__ @__#{id.to_i}__ elsif ! self.frozen? @__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block) else __#{id.to_i}__(*args, &block) end end end; end end

private :onceend

Shameless Plug

I can help you with your Ruby and/or Rails projects. Ask me how.

Mike Bowlermbowler@GargoyleSoftware.comwww.GargoyleSoftware.com (company)www.SphericalImprovement.com (blog)