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

Ruby's Inner Beauty

Ruby's Inner Beauty

My presentation for the March Columbus Ruby Brigade meeting on Ruby syntax & semantics.

Alex Burkhart

March 16, 2015
Tweet

More Decks by Alex Burkhart

Other Decks in Technology

Transcript

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

    (5 * 10) (2 + (5 * 10))
  2. EVALUATE THE EXPRESSION TREE 2 + 5 * 10 2

    + (5 * 10) (2 + (5 * 10)) (2 + (50)) (2 + 50) (52) 52
  3. 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
  4. 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
  5. HASH SYNTAX h1 = { a: 10 } h2 =

    { :a => 10 } h3 = Hash.new h3[:a] = 10 h1 == h2 == h3 # => true
  6. STRING SYNTAX s1 = "syntactic" s2 = 'syntactic' s3 =

    String.new("syntactic") s1 == s2 == s3 # => true
  7. ARRAY OF * SYNTAX words1 = %w| array of strings

    | words2 = ["array", "of", "strings"] sym1 = %i( array of symbols ) sym2 = [:array, :of, :symbols]
  8. FAKE SYNTAX params = { category: 'ruby' } params[:category] #

    => 'ruby' class Hash def [](key) fetch(key, nil) end end
  9. 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"
  10. 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"
  11. EVERYTHING IS A MESSAGE 12 + 8 12.send(:+, 8) operators

    = [:+, :-, :/] operators.send(:<<, :*)
  12. 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 CRB") ruby_talk.state = :in_progress
  13. 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 CRB") ruby_talk.state = :in_progress
  14. 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 CRB") ruby_talk.state=(:in_progress)
  15. 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 CRB") ruby_talk.send(:state=, :in_progress)
  16. 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 CRB") ruby_talk.send(:state=, :in_progress)
  17. 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')
  18. 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
  19. 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]"
  20. class KEYWORD class Todo def initialize(title) @title = title @state

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

    end Todo.send(:new, "Reveal the `new` class method on Class")
  22. 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)
  23. 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
  24. 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)
  25. A BETTER METHOD MAKING MACHINE Class.class_eval do define_method(:bttr_reader) do |name|

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

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

    "Transitioning from #{previous_state} to #{new_state}" @state = new_state end end
  28. 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
  29. 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>
  30. 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