Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby's Inner Beauty 2.0

Ruby's Inner Beauty 2.0

Presented at Codemash 2016.

Avatar for Alex Burkhart

Alex Burkhart

January 08, 2016
Tweet

More Decks by Alex Burkhart

Other Decks in Programming

Transcript

  1. PARSE A LINE 2 + 5 * 10 2 +

    (5 * 10) (2 + (5 * 10))
  2. WALK THE TREE 2 + 5 * 10 2 +

    (5 * 10) (2 + (5 * 10)) (2 + (50)) (2 + 50)
  3. EVALUATE THE TREE 2 + 5 * 10 2 +

    (5 * 10) (2 + (5 * 10)) (2 + (50)) (2 + 50) (52) 52
  4. HUMAN READABLE NUMBERS error_prone = 1000000000 super_easy = 1_000_000_000 if

    error_prone != super_easy raise ProgrammerError.new("Looks like you made a typo!") end
  5. STRING SYNTAX s1 = "syntactic sugar" s2 = 'syntactic sugar'

    s3 = String.new("syntactic sugar") [s1, s2, s3].uniq.one? # => true
  6. ARRAY OF WORDS SYNTAX words1 = %w| array of strings

    | words2 = ["array", "of", "strings"] sym1 = %i( array of symbols ) sym2 = [:array, :of, :symbols]
  7. ESCAPING STRING SYNTAX s1 = "\"Don't forget to escape your

    quotes\" -Alex" s2 = '"Don\'t forget to escape your quotes -Alex' s3 = %Q{"Don't forget to escape your quotes" -Alex} s4 = %q{"Don't forget to escape your quotes" -Alex} [s1, s2, s3, s4].uniq.one? # => true
  8. ESCAPING REGEXP r1 = /^(\/foo\/|\/bar\/)/ r2 = Regexp.new("^(/foo/|/bar/)") r3 =

    %r_^(/foo/|/bar/)_ [r1, r2, r3].uniq.one? # => true
  9. SHORTHAND SYNTAX square = Proc.new { |x| x * x

    } square.call(2) # => 4 cube = ->(y){ y * y * y } cube.call(2) # => 8 cube.class == Proc # => true
  10. HASH SYNTAX h1 = { a: 10 } h2 =

    { :a => 10 } h3 = Hash.new h3[:a] = 10 h1 == h2 == h3 # => true
  11. FAKE SYNTAX params = { category: 'ruby' } params[:category] #

    => 'ruby' class Hash def [](key) fetch(key, nil) end end
  12. INSTANCE VARIABLE ACCESS class Coffee def initialize(size, roast) @size =

    size @roast = roast end def to_s "#{@size} cup of #{@roast} roast" end end pry> Coffee.new('large', 'light').to_s => "large cup of light roast"
  13. INSTANCE VARIABLE ACCESS class Coffee def initialize(size, roast) instance_variable_set(:@size, size)

    instance_variable_set(:@roast, roast) end def to_s size = instance_variable_get(:@size) roast = instance_variable_get(:@roast) "#{size} cup of #{roast} roast" end end pry> Coffee.new('large', 'light').to_s => "large cup of light roast"
  14. EVERYTHING IS A MESSAGE 12 + 8 12.send(:+, 8) operators

    = [:+, :-, :/] operators.send(:<<, :*)
  15. ASSIGNMENT class Todo attr_accessor :state def initialize(title) @title = title

    @state = :pending end end ruby_talk = Todo.new("Present Ruby's Inner Beauty at Codemash") ruby_talk.state = :in_progress
  16. ASSIGNMENT METHODS class Todo attr_reader :state def initialize(title) @title =

    title @state = :pending end def state=(state) @state = state end end ruby_talk = Todo.new("Present Ruby's Inner Beauty at Codemash") ruby_talk.state = :in_progress
  17. ASSIGNMENT METHODS class Todo attr_reader :state def initialize(title) @title =

    title @state = :pending end def state=(state) @state = state end end ruby_talk = Todo.new("Present Ruby's Inner Beauty at Codemash") ruby_talk.state=(:in_progress)
  18. ASSIGNMENT VIA MESSAGES class Todo attr_reader :state def initialize(title) @title

    = title @state = :pending end def state=(state) @state = state end end ruby_talk = Todo.new("Present Ruby's Inner Beauty at Codemash") ruby_talk.send(:state=, :in_progress)
  19. ABSOLUTELY EVERYTHING IS A MESSAGE class Todo attr_reader :state def

    initialize(title) @title = title @state = :pending end def state=(state) @state = state end end ruby_talk = Todo.send(:new, "Present Ruby's Inner Beauty at Codemash") ruby_talk.send(:state=, :in_progress)
  20. Class#new class Class def new(*args) instance = allocate instance.initialize(*args) instance

    end def allocate Heap.malloc(self) # gross simplification end end Coffee.send(:new, 'medium', 'dark')
  21. include Celluloid # Class methods added to classes which include

    Celluloid module ClassMethods # Create a new actor def new(*args, &block) proxy = Cell.new(allocate, behavior_options, actor_options).proxy proxy._send_(:initialize, *args, &block) proxy end end
  22. ASYNC MESSAGE PASSING class AsyncSpammer include Celluloid def deliver_spam(address) sleep(1)

    puts "spamming #{address.inspect}" end end worker = AsyncSpammer.new # => #<Celluloid::CellProxy(AsyncSpammer:0x3fd351810484)> worker.async.deliver_spam('[email protected]') # => nil # => spamming "[email protected]"
  23. class KEYWORD class Todo def initialize(title) @title = title @state

    = :pending end def to_s "#{@state}: #{@title}" end end Todo.new('Introduce class Keyword')
  24. Class::new Todo = Class.new(Object) do def to_s "#{@state}: #{@title}" end

    end Todo.send(:new, "Reveal the `new` class method on Class")
  25. REOPENING CLASSES Todo ||= Class.new(Object) Todo.class_eval do def state=(state) instance_variable_set(@:state,

    state) end end t2 = Todo.send(:new, 'Reopen Todo Class') t2.send(:state=, :in_progress)
  26. def DEMYSTIFIED class Todo define_method(:state=) do |new_state| @state = new_state

    end end t2 = Todo.new('Breakdown def keyword') t2.state = :in_pieces
  27. def DEMYSTIFIED Todo ||= Class.new Todo.class_eval do define_method :state= do

    |new_state| instance_variable_set(:@state, new_state) end end t2 = Todo.send(:new, 'Breakdown def keyword') t2.send(:state=, :in_pieces)
  28. A BETTER METHOD MAKING MACHINE Class.class_eval do define_method(:better_reader) do |name|

    define_method(name) do instance_variable_get("@#{name}") end end end Todo.class_eval { better_reader :title } t = Todo.new("Reimplement attr_reader") t.title # => "Reimplement attr_reader"
  29. PRACTICALLY A MONEY MAKING MACHINE Class.class_eval do define_method(:better_writer) do |name|

    define_method("#{name}=") do |val| instance_variable_set("@#{name}", val) end end end Todo.class_eval { better_writer :title } t = Todo.new("Reimplement attr_writer") t.title = "A much better writer..." t.title # => "A much better writer..."
  30. LOCAL VARIABLES class Todo def state=(new_state) previous_state = @state puts

    "Transitioning from #{previous_state} to #{new_state}" @state = new_state end end
  31. Kernel#binding class Todo def state=(new_state) previous_state = @state binding.local_variables #

    => [:new_state, :previous_state] puts "Transitioning from #{previous_state} to #{new_state}" binding.eval('new_state') == new_state # => true @state = new_state end end
  32. SELF class Todo def get_binding binding end def get_self binding.eval('self')

    end end t = Todo.new t.get_binding # => #<Binding:0x007fa6a485df20> t.get_self # => #<Todo:0x007fa6a485df20>
  33. CHANGE SELF Todo.class_eval do # self == Todo class end

    t2 = Todo.new("Change execution contexts") t2.instance_eval do # self == instance of Todo end
  34. EVAL + BINDING => SUPERMETA class SuperMeta def initialize(data) @data

    = data end def instanze_eval(str) eval(str, self.send(:binding)) end end sm = SuperMeta.new(too_far: true) sm.instanze_eval('puts "Too far? #{self.instance_variable_get(:@data)}"') # => Too far? {:too_far=>true}