A class plays two roles in an OO program:
- It provides a container for behavior that's shared by many objects.
- It acts as an object factory, manufacturing new instances and ensuring they are initialized correctly.
class Enum | |
def self.new | |
Class.new do | |
def initialize(name) | |
@name = name | |
end | |
def to_s | |
"#{self.class.name}: #{@name}" |
module TraceCalls | |
def self.included(including_class) | |
class << including_class | |
def methods | |
@methods ||= [] | |
end | |
def method_added(name) | |
unless methods.include?(name) |
module TraceCalls | |
def self.included(including_class) | |
def including_class.method_added(name) | |
return if @_adding_a_method | |
@_adding_a_method = true | |
TraceCalls.wrap_method(self, name) | |
@_adding_a_method = false | |
end | |
end |
#!/usr/bin/env ruby | |
# Taken from https://github.com/dbrady/scoped_attr_accessor | |
# This module adds scoped accessor methods to a Ruby Class. For | |
# example: | |
# | |
# class Foo | |
# extend ScopedAttrAccessor | |
# private_attr_reader :thing1, :thing2, :thing3 | |
# protected_attr_writer :counter |
module TraceCalls | |
def self.included(klass) | |
suppress_tracing do | |
klass.instance_methods(false).each do |existing_method| | |
wrap(klass, existing_method) | |
end | |
end | |
def klass.method_added(method) # note: nested definition | |
unless @trace_calls_internal | |
@trace_calls_internal = true |
# | |
# A hand-rolled singleton behaviour | |
# | |
class SnowFlake | |
class << self | |
private :new | |
end | |
def self.instance | |
@instance ||= new |
A class plays two roles in an OO program:
LIVE_CELL = Object.new | |
class << LIVE_CELL | |
def to_s() puts 'o' end | |
def next_generation(x, y, board) | |
case board.neighbors(x, y).count(LIVE_CELL) | |
when 2..3 then self | |
else DEAD_CELL | |
end | |
end |
http://gmoeck.github.io/2011/09/20/why-you-should-care-about-encapsulation.html
...when I say encapsulation, I mean "the behavior of an object can only be affected through its API". Or to put it negatively, an object is not well encapsulated when its behavior can be affected without calling its API. Or another way to think about it is that a well encapsulated object draws a solid boundry or wall around itself, and ensures that all the code that changes its behavior is contained within the object itself.
We want to be careful with the distinction between “encapsulation” and “information hiding.” The terms are often used interchangeably but actually refer to two separate, and largely orthogonal, qualities:
Ensures that the behavior of an object can only be affected through its API. It lets us control how much a change to one object will impact other parts of the system by ensuring that there a
require 'minitest/spec' | |
require 'minitest/autorun' | |
# Any live cell with < 2 live neighbours dies, as if caused by under-population. | |
# Any live cell with 2..3 live neighbours lives on to the next generation. | |
# Any live cell with > 3 live neighbours dies, as if by overcrowding. | |
# Any dead cell with == 3 live neighbours becomes a live cell, as if by reproduction. | |
class GameOfLife | |
def initialize(width, height) |