Skip to content

Instantly share code, notes, and snippets.

@yosevu
Last active March 5, 2018 18:13
Show Gist options
  • Select an option

  • Save yosevu/15d59d368ed9ed92e53e1146f8bc7fb0 to your computer and use it in GitHub Desktop.

Select an option

Save yosevu/15d59d368ed9ed92e53e1146f8bc7fb0 to your computer and use it in GitHub Desktop.
Ruby Koans Notes

Ruby Koans Notes

about_classes.rb

  assert_equal 'STRING', "STRING".to_s
  assert_equal '"STRING"', "STRING".inspect
  • open class: a class that is re-declared to add funcitonality

about_inheritance.rb

class BullDog < Dog
  def bark
    super + ", GROWL"
  end
end

def test_subclasses_can_invoke_parent_behavior_via_super
  ralph = BullDog.new("Ralph")
  assert_equal 'WOOF, GROWL', ralph.bark
end
  • super calls parent method of same name
class GreatDane < Dog
  def growl
    super.bark + ", GROWL"
  end
end

def test_super_does_not_work_cross_method
  george = GreatDane.new("George")
  assert_raise(NoMethodError) do
    george.growl
  end
end
  • <NoMethodError: super: no superclass method `growl' for #<AboutInheritance::GreatDane:0x007ffa6b3648c8 @name="George">>
  • super does not call parent method from another method

about_modules.rb

about_scope.rb

class String
end

def test_bare_bones_class_names_assume_the_current_scope
  assert_equal true, AboutScope::String == String
end

def test_nested_string_is_not_the_same_as_the_system_string
  assert_equal false, String == "HI".class
end

def test_use_the_prefix_scope_operator_to_force_the_global_scope
  assert_equal true, ::String == "HI".class
end

about_methods.rb

  • singleton:
def test_you_can_define_methods_on_individual_objects
  fido = Dog.new
  def fido.wag
    :fidos_wag
  end
  assert_equal :fidos_wag, fido.wag
end

def test_other_objects_are_not_affected_by_these_singleton_methods
  fido = Dog.new
  rover = Dog.new
  def fido.wag
    :fidos_wag
  end

  assert_raise(NoMethodError) do
    rover.wag
  end
end

about_class_methods.rb

class Dog
  class << self
    def another_class_method
      :still_another_way
    end
  end
end

def test_heres_still_another_way_to_write_class_methods
  assert_equal :still_another_way, Dog.another_class_method
end

# THINK ABOUT IT:
#
# The two major ways to write class methods are:
#   class Demo
#     def self.method
#     end
#
#     class << self
#       def class_methods
#       end
#     end
#   end
#
# Which do you prefer and why?
# Are there times you might prefer one over the other?
def test_heres_an_easy_way_to_call_class_methods_from_instance_methods
  fido = Dog.new
  assert_equal :still_another_way, fido.class.another_class_method
end
  • When would you call a class method this way?

about_message_passing.rb

def test_send_with_underscores_will_also_send_messages
  mc = MessageCatcher.new

  assert_equal true, mc.__send__(:caught?)

  # THINK ABOUT IT:
  #
  # Why does Ruby provide both send and __send__ ?
end
class MessageCatcher
  def add_a_payload(*args)
    args
  end
end

def test_sending_a_message_with_arguments
  mc = MessageCatcher.new

  assert_equal [], mc.add_a_payload
  assert_equal __, mc.send(:add_a_payload)

  assert_equal [3, 4, nil, 6], mc.add_a_payload(3, 4, nil, 6)
  assert_equal __,  mc.send(:add_a_payload, 3, 4, nil, 6)
end

# NOTE:
#
# Both obj.msg and obj.send(:msg) sends the message named :msg to
# the object. We use "send" when the name of the message can vary
# dynamically (e.g. calculated at run time), but by far the most
# common way of sending a message is just to say: obj.msg.
  • Why isn't the :add_a_payload symbol not sent?
def test_calling_method_missing_causes_the_no_method_error
  typical = TypicalObject.new

  exception = assert_raise(NoMethodError) do
    typical.method_missing(:foobar)
  end
  assert_match(/foobar/, exception.message)

  # THINK ABOUT IT:
  #
  # If the method :method_missing causes the NoMethodError, then
  # what would happen if we redefine method_missing?
  #
  # NOTE:
  #
  # In Ruby 1.8 the method_missing method is public and can be
  # called as shown above. However, in Ruby 1.9 (and later versions)
  # the method_missing method is private. We explicitly made it
  # public in the testing framework so this example works in both
  # versions of Ruby. Just keep in mind you can't call
  # method_missing like that after Ruby 1.9 normally.
  #
  # Thanks.  We now return you to your regularly scheduled Ruby
  # Koans.
end
class AllMessageCatcher
  def method_missing(method_name, *args, &block)
    "Someone called #{method_name} with <#{args.join(", ")}>"
  end
end

def test_all_messages_are_caught
  catcher = AllMessageCatcher.new

  assert_equal 'Someone called foobar with <>', catcher.foobar
  assert_equal 'Someone called foobaz with <1>', catcher.foobaz(1)
  assert_equal 'Someone called sum with <1, 2, 3, 4, 5, 6>', catcher.sum(1,2,3,4,5,6)
end

def test_catching_messages_makes_respond_to_lie
  catcher = AllMessageCatcher.new

  assert_nothing_raised do
    catcher.any_method
  end
  assert_equal false, catcher.respond_to?(:any_method)
end
  • How does catcher make respond_to? lie?

about_to_str.rb

  • to_str vs. to_s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment