Pro Yearly is on sale from $80 to $50! »

RedDotRubyConf

 RedDotRubyConf

F29327647a9cff5c69618bae420792ea?s=128

Aaron Patterson

June 07, 2013
Tweet

Transcript

  1. Hello!

  2. WELCOME!

  3. THANK YOU!

  4. I bought a Google Glass

  5. None
  6. None
  7. None
  8. None
  9. None
  10. I love food!

  11. Earth (top)

  12. Earth (top)

  13. Radius at Latitude R = radius of earth a =

    equatorial radius b = polar radius l = geodetic latitude
  14. Seattle Singapore Latitude 47.6097° N 1.3667° N Radius 6,373 km

    6,357 km
  15. None
  16. Aaron Patterson @tenderlove

  17. Ruby Core Team Rails Core Team

  18. Polymorphism Refactoring Caching Irresponsible Ruby

  19. WARNING!

  20. This talk is extremely technical

  21. Polymorphism

  22. Hide Complexity

  23. Decouple

  24. Driving a Car class Automatic def put_in_drive; end def gas;

    end end def drive(car) car.put_in_drive car.gas end car = Automatic.new drive(car)
  25. Manual Car class Manual def press_clutch; end def put_in_gear; end

    def release_clutch; end def gas; end end def drive(car) car.press_clutch car.put_in_gear car.release_clutch car.gas end car = Manual.new drive car
  26. Both Cars def drive(car) if car.is_a?(Automatic) car.put_in_drive car.gas else car.press_clutch

    car.put_in_gear car.release_clutch car.gas end end
  27. Polymorphic class Automatic def go put_in_drive gas end end class

    Manual def go press_clutch put_in_gear release_clutch gas end end
  28. Drive method def drive car car.go end

  29. rm Conditions def drive car if car.is_a? Automatic car.put_in_drive car.gas

    else car.press_clutch car.put_in_gear car.release_clutch car.gas end end
  30. Depends on Type def drive car car.go end

  31. Depends on Type def drive car car.go end

  32. Logic is removed from the caller

  33. “Caches” decision logic

  34. def drive car car.go end car = Automatic.new drive car

    “Cache”
  35. Refactoring

  36. Code is a graph

  37. if foo && bar do_something else do_something_else end Parse Tree

  38. Parse Tree if statement conditions positive negative

  39. Parse Tree: Structure, but no meaning

  40. if foo && bar do_something else do_something_else end Dependency Tree

  41. Dependency Tree if statement conditions positive negative foo bar

  42. Dependency Tree if statement conditions positive negative foo bar ????

  43. Active Support Callbacks API

  44. Callback Example class Hoge include ActiveSupport::Callbacks define_callbacks :save set_callback :save,

    :record set_callback :save, :record1 def record; puts __method__; end def record1; puts __method__; end end f = Hoge.new f.run_callbacks :save
  45. Results $ ruby test.rb record record1 $

  46. Active Record class Person < ActiveRecord::Base validates_presence_of :name validates_length_of :name,

    maximum:30 end
  47. Variations class Foo include ActiveSupport::Callbacks define_callbacks :save set_callback :save, :record

    set_callback :save, -> { p "lambda1" } set_callback :save, ->(o) { p "lambda2" } set_callback :save, ->(*a) { p "lambda3" } set_callback :save, "puts 'hello'" set_callback :save, SomeClass end call method call lambda eval call “before”
  48. 6 tests!

  49. Variations, :if class Foo set_callback :save, :record, if: :foo set_callback

    :save, :record, if: -> { p "lambda1" } set_callback :save, :record, if: ->(o) { p "lambda1" } set_callback :save, :record, if: ->(*a) { p "lambda1" } set_callback :save, :record, if: "true" set_callback :save, :record, if: SomeClass end call method call lambda eval call “before”
  50. 6 * 6 tests!

  51. Variations, :unless class Foo set_callback :save, :record, unless: :foo set_callback

    :save, :record, unless: -> { p "lambda1" } set_callback :save, :record, unless: ->(o) { p "lambda1" } set_callback :save, :record, unless: ->(*a) { p "lambda1" } set_callback :save, :record, unless: "true" set_callback :save, :record, unless: SomeClass end call method lambda eval call “before”
  52. 6 * 6 * 2 tests!

  53. Variations, location class Foo set_callback :save, :before, -> { "lambda"

    } set_callback :save, :after, -> { "lambda" } set_callback :save, :around, -> { "lambda" } end
  54. 6 * 6 * 2 * 3 tests!

  55. Variations, halt class Foo include ActiveSupport::Callbacks define_callbacks :save, terminator: "result

    == false" end
  56. 6 * 6 * 2 * 3 * tests

  57. Reality: 21 tests

  58. Callback Dependencies

  59. set_callback first

  60. set_callback first second third etc

  61. set_callback first second third etc

  62. set_callback first second third etc eval

  63. run_callback first second third etc

  64. run_callback first second third etc eval

  65. run_callbacks callbacks method callback method callback method conds callback conds

    callback
  66. Count Methods class Foo include ActiveSupport::Callbacks define_callbacks :save x =

    instance_methods.length 100.times do set_callback :save, -> { "lambda1" } end y = instance_methods.length - x p NEW_METHODS: y end
  67. Run It $ ruby test.rb {:NEW_METHODS=>100} $

  68. Count Methods f = Foo.new x = Foo.instance_methods.length f.run_callbacks :save

    y = Foo.instance_methods.length - x p NEW_METHODS: y
  69. Run It $ ruby test.rb {:NEW_METHODS=>1} $

  70. eval based when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result

    = result = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after
  71. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  72. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  73. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  74. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  75. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  76. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  77. when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result = result

    = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  78. value = nil halted = false if !halted && true

    result = result = _callback_before_1 halted = (xxx) if halted halted_callback_hook("#<Proc:>") end end if !halted && true result = result = _callback_before_2 halted = (xxx) if halted halted_callback_hook("#<Proc:>") end end value = !halted && (!block_given? || yield) value class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end User Code Eval’d Code
  79. Currently ❤ Hard to understand ❤ Hard to change ❤

    Memory Intensive ❤ Fast
  80. What we want ❤ Easy to understand ❤ Easy to

    change ❤ Low memory ❤ Fast
  81. ❤ Conditionals (:if, :unless) ❤ Callback body code ❤ Termination

    code Dependencies
  82. Leaf Nodes

  83. run_callbacks callbacks method callback method callback method conds callback conds

    callback
  84. run_callbacks callbacks method callback method callback method conds callback conds

    callback
  85. def _compile_filter(filter) case filter when Symbol filter when String "(#{filter})"

    when Proc method_name = "_callback_#{@kind}_#{next_id}" @klass.send(:define_method, method_name, &filter) return method_name if filter.arity <= 0 method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ") else @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{method_name}(&blk) #{method_name}_object.send(:#{method_to_call}, self, &blk) end RUBY_EVAL method_name end end Conversion Method
  86. compile_filter

  87. compile_filter Object

  88. compile_filter String

  89. compile_filter

  90. String contains ❤ A method name ❤ Some code to

    eval ❤ A method that changes depending on the arity of the proc
  91. We need CONSISTENCY

  92. Return a lambda!

  93. if object.is_a?(Symbol) lambda { |target,object| object.send target } end Handle

    Symbols
  94. Handle Lambdas if object.is_a?(Proc) object end

  95. Handle Objects if object.is_a?(Object) lambda { |target, object| object.before_filter(target) }

    end
  96. Etc...

  97. def make_lambda(filter) case filter when Symbol lambda { |target, _,

    &blk| target.send filter, &blk } when String l = eval "lambda { |value| #{filter} }" lambda { |target, value| target.instance_exec(value, &l) } when ::Proc if filter.arity > 1 return lambda { |target, _, &block| raise ArgumentError unless block target.instance_exec(target, block, &filter) } end if filter.arity <= 0 lambda { |target, _| target.instance_exec(&filter) } else lambda { |target, _| target.instance_exec(target, &filter) } end else lambda { |target, _, &blk| filter.public_send method_to_call, target, &blk } end end Conversion Method
  98. Move Up

  99. run_callbacks callbacks method callback method callback method conds callback conds

    callback
  100. run_callbacks callbacks method callback method callback method conds callback conds

    callback
  101. Conversion Method when :before <<-RUBY_EVAL if !halted && #{@compiled_options} result

    = result = #{@source} halted = (#{chain.config[:terminator]}) if halted halted_callback_hook(#{@raw_filter}) end end #{code} RUBY_EVAL when :after
  102. compile_method

  103. compile_method conditions, callback, next callback

  104. compile_method

  105. Return a lambda!

  106. if filter_type == :before lambda { halting = halted.call conds

    = conditionals.all? { |c| c.call } if !halting && conds callback_lambda.call end next_callback.call } end “Before” Callback
  107. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  108. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  109. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  110. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  111. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  112. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  113. when :before lambda { |env| target = env.target value =

    env.value halted = env.halted if !halted && user_conditions.all? { |c| c.call(target, value) } result = user_callback.call target, value env.halted = halted_lambda.call result if env.halted target.send :halted_callback_hook, @filter end end next_callback.call env } when :after class Foo define_callbacks :save, :terminator => 'xxx' set_callback :save, :before, -> { "lambda" } set_callback :save, -> { "lambda1" } end
  114. if filter_type == :after lambda { next_callback.call halting = halted.call

    conds = conditionals.all? { |c| c.call } if !halting && conds callback_lambda.call end } end “After” Callback
  115. lambda Linked List

  116. lambda lambda lambda Linked List

  117. Generate Lambda when :before # The “before” callback lambda when

    :after # The “after” callback lambda when :around # The “around” callback lambda else # ... end
  118. Switch lambdas based on type. (polymorphism)

  119. What we want ❤ Easy to understand ❤ Easy to

    change ❤ Low memory? ❤ Fast?
  120. Benchmark!

  121. require 'active_support/callbacks' class Foo include ActiveSupport::Callbacks define_callbacks :save 100_000.times {

    set_callback :save, :before, -> { "lambda" } } end puts "DONE!" GC.start sleep
  122. Memory

  123. What we want ❤ Easy to understand ❤ Easy to

    change ❤ Low memory ❤ Fast?
  124. Speed [aaron@higgins rails (4-0-stable)]$ time bundle exec ruby rawr.rb DONE!

    real 0m54.925s user 0m53.928s sys 0m0.498s [aaron@higgins rails (4-0-stable)]$ git checkout 73aefee [aaron@higgins rails (73aefee...)]$ time bundle exec ruby rawr.rb DONE! real 0m17.619s user 0m17.385s sys 0m0.176s [aaron@higgins rails (73aefee...)]$
  125. Speed [aaron@higgins rails (4-0-stable)]$ time bundle exec ruby rawr.rb DONE!

    real 0m54.925s user 0m53.928s sys 0m0.498s [aaron@higgins rails (4-0-stable)]$ git checkout 73aefee [aaron@higgins rails (73aefee...)]$ time bundle exec ruby rawr.rb DONE! real 0m17.619s user 0m17.385s sys 0m0.176s [aaron@higgins rails (73aefee...)]$ 54s 18s
  126. Runtime Speed class User < ActiveRecord::Base validates_presence_of :name end user

    = User.new(name: 'Aaron') user.valid? Benchmark.ips do |x| x.report("valid") { user.valid? } end
  127. Runtime Speed [aaron@higgins rails (4-0-stable)]$ bundle exec ruby test.rb Calculating

    ------------------------------------- valid 3902 i/100ms ------------------------------------------------- valid 51094.4 (±14.0%) i/s - 253630 in 5.059460s [aaron@higgins rails (4-0-stable)]$ [aaron@higgins rails (73aefee...)]$ bundle exec ruby test.rb Calculating ------------------------------------- valid 3726 i/100ms ------------------------------------------------- valid 49397.5 (±12.1%) i/s - 245916 in 5.047747s [aaron@higgins rails (73aefee...)]$ 51k / s 49k / s
  128. Slower. (T_T)

  129. More Polymorphism!

  130. lambda { |env| if user_conditions.all? { |c| c.call(target, value) }

    # ... result = user_callback.call target, value # ... end next_callback.call env }
  131. irb(main):001:0> [].all? => true irb(main):002:0> No conditions

  132. if user_conditions.empty? lambda { |env| # ... result = user_callback.call

    target, value # ... next_callback.call env } else lambda { |env| if user_conditions.all? { |c| c.call(target, value) } # ... result = user_callback.call target, value # ... end next_callback.call env } end
  133. Runtime Speed [aaron@higgins rails (4-0-stable)]$ bundle exec ruby test.rb Calculating

    ------------------------------------- valid 3902 i/100ms ------------------------------------------------- valid 51094.4 (±14.0%) i/s - 253630 in 5.059460s [aaron@higgins rails (4-0-stable)]$ [aaron@higgins rails (master)]$ bundle exec ruby test.rb Calculating ------------------------------------- valid 3953 i/100ms ------------------------------------------------- valid 52240.9 (±10.8%) i/s - 260898 in 5.051079s [aaron@higgins rails (master)]$ 51k / s 52k / s
  134. What we want ❤ Easy to understand ❤ Easy to

    change ❤ Low memory ❤ Fast
  135. Caching

  136. Active Record

  137. Architecture

  138. Person.where(...).where(...)

  139. AR::Relation AR::Relation AR::Base Person.where(...).where(...) Person .where(...) .where(...)

  140. AR::Relation AR::Relation AR::Base Person.where(...).where(...).to_a

  141. AR::Relation AR::Relation AR::Base Person.where(...).where(...).to_a Arel::Manager SQL AST WHERE ...

  142. AR::Relation AR::Relation AR::Base Person.where(...).where(...).to_a Arel::Manager SQL AST WHERE ... ...

  143. AR::Relation AR::Relation AR::Base Person.where(...).where(...).to_a Arel::Manager SQL AST WHERE ... ...

    FROM people SELECT *
  144. AST to SQL SELECT * FROM people WHERE ... AND

    ...
  145. AST to SQL SQL AST WHERE ... ... FROM people

    SELECT * SELECT * FROM people WHERE ... AND ...
  146. 3 Transformations 1. Code to AR::Relation 2. AR::Relation to SQL

    AST 3. SQL AST to SQL statement
  147. Bind Params R ails >= 3.2

  148. SELECT * FROM people WHERE id = ?

  149. Database Query Database Rails Application

  150. Database Query Database Rails Application SQL Binds

  151. Database Query Database Rails Application Records

  152. Database Work ❤ Parse SQL ❤ Plan Query ❤ Execute

    Query ❤ Return Results
  153. Database Work ❤ Parse SQL ❤ Plan Query ❤ Execute

    Query ❤ Return Results
  154. Query Plan is cached

  155. Parsed SQL is cached

  156. Better Caching

  157. Student Work

  158. Find Records Person.where(:id => 10).first Person.where(:id => 15).first Person.where(:id =>

    3).first
  159. Post.where(:id => params[:id]).first Generated Query Bind Parameters SELECT * FROM

    people WHERE id = ? [id, 10] SELECT * FROM people WHERE id = ? [id, 15] SELECT * FROM people WHERE id = ? [id, 3]
  160. Only bind parameters change

  161. class MyController def index person = Person.where(:id => params[:id]).first end

    end
  162. class MyController def index person = Person.where(:id => params[:id]).first end

    end Only dynamic value
  163. 1. Generate AR::Relation chain 2. Generate SQL AST 3. Generate

    SQL String 4. Query the database On Every Request
  164. Cache Invariants

  165. relation = Post.where(:id => 10) loop do relation.set_binds([rand(100)]) relation.to_a end

    R ails >= 4.1
  166. Benchmarks

  167. class NoCache def initialize(&blk) @block = blk end def call(*args)

    @block.call(*args).to_a end end nocache = NoCache.new do |name, age| User.where(:name => name).where(:age => age) end No Cache
  168. class Cache def initialize(&blk) @block = blk @relation = nil

    end def call *args @relation ||= @block.call(*args) @relation.set_binds args @relation.to_a end end nocache = Cache.new do |name, age| User.where(:name => name).where(:age => age) end Cache
  169. class Cache def initialize(&blk) @block = blk @relation = nil

    end def call *args @relation ||= @block.call(*args) @relation.set_binds args @relation.to_a end end nocache = Cache.new do |name, age| User.where(:name => name).where(:age => age) end Cache Cache Relation
  170. class Cache def initialize(&blk) @block = blk @relation = nil

    end def call *args @relation ||= @block.call(*args) @relation.set_binds args @relation.to_a end end nocache = Cache.new do |name, age| User.where(:name => name).where(:age => age) end Cache Reset Binds
  171. Benchmark cache = Cache.new do |name, age| User.where(:name => name).where(:age

    => age) end nocache = NoCache.new do |name, age| User.where(:name => name).where(:age => age) end name = names.first Benchmark.ips do |x| x.report("cache") { cache.call(name, 32) } x.report("nocache") { nocache.call(name, 32) } end
  172. Result $ bundle exec ruby qcache.rb Calculating ------------------------------------- cache 456

    i/100ms nocache 278 i/100ms ------------------------------------------------- cache 4754.9 (±8.0%) i/s - 23712 in 5.018513s nocache 2820.4 (±5.9%) i/s - 14178 in 5.046598s
  173. 0 1250 2500 3750 5000 Queries per second Cached Not

    Cached
  174. 1.68 times faster!

  175. 1. Generate AR::Relation chain 2. Generate SQL AST 3. Generate

    SQL String 4. Query the database On Every Request Cached! Cached!
  176. Invalidation

  177. Record Cache x = Post.where(:name => ‘xxx’) x.to_a x.to_a x.to_a

  178. Invalidation def set_binds(list) @loaded = nil @records = [] list.zip(values[:bind]).each

    do |val, bv| bv[1] = val end end
  179. Record Cache x = Post.where(:name => ‘xxx’) x.to_a x.set_binds(...) #

    cache is invalidated x.to_a x.to_a
  180. We can go even faster!

  181. Refactoring is the gateway to speed

  182. Use polymorphism

  183. Cache Invariants

  184. Irresponsible Ruby

  185. Ruby Values ❤ Immediate ❤ Regular

  186. Immediate Values ❤ nil ❤ true ❤ false ❤ Fixnum

    (2 ** (0.size * 8 - 2) - 1)
  187. 10.object_id >> 1 # => 10 14.object_id >> 1 #

    => 14 Fixnum Trick
  188. Regular Values

  189. >> o = Object.new => #<Object:0x007fab5b38bbd0> >> o.object_id.to_s(16) => "3fd5ad9c5de8"

    >> (o.object_id << 1).to_s(16) => "7fab5b38bbd0" >>
  190. fiddle with memory

  191. Get a pointer require ‘fiddle’ pointer = Fiddle::Pointer.new(offset) pointer[0] #

    => get the char * val pointer[0] = x # => set the val
  192. Fiddle with Ruby require ‘fiddle’ o = Object.new offset =

    o.object_id << 1 pointer = Fiddle::Pointer.new(offset)
  193. RObject Layout struct RObject { struct RBasic basic; union {

    struct { long numiv; VALUE *ivptr; struct st_table *iv_index_tbl; } heap; VALUE ary[ROBJECT_EMBED_LEN_MAX]; } as; };
  194. RBasic struct RBasic { VALUE flags; const VALUE klass; }

  195. What is VALUE? typedef uintptr_t VALUE; >> require 'fiddle' =>

    false >> Fiddle::SIZEOF_UINTPTR_T => 8
  196. Read Flags >> require 'fiddle' >> o = Object.new >>

    offset = o.object_id << 1 >> pointer = Fiddle::Pointer.new(offset) >> 8.times.map { |i| pointer[i] } => [33, 0, 0, 0, 0, 0, 0, 0] >>
  197. Read klass >> 8.times.map { |i| pointer[i+8] } => [-64,

    55, -114, -40, -88, 127, 0, 0] >>
  198. Get klass >> 8.times.map { |i| pointer[i+8] } => [-64,

    55, -114, -40, -88, 127, 0, 0] >> addr = _.pack('C8').unpack('Q') => [140363164432320] >> Fiddle::Pointer.new(addr.first).to_value => Object >>
  199. Lets set the class!

  200. Set klass o = Object.new offset = o.object_id << 1

    pointer = Fiddle::Pointer.new(offset) klass_offset = String.object_id << 1 [klass_offset].pack('Q').unpack('C8').each_with_index { |n,i| pointer[i + 8] = n } o.class # => String
  201. None
  202. Have Fun at RedDotRubyConf!

  203. None