Skip to content

Instantly share code, notes, and snippets.

@johnlane
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnlane/9079353 to your computer and use it in GitHub Desktop.
Save johnlane/9079353 to your computer and use it in GitHub Desktop.
The One Module (TOM) is an example Ruby module that demonstrates setting of module, class, class instance and instance variables for classes that include or extend the module.
# TOM : The One Module
#
# An example Ruby module that demonstrates setting of module, class, class instance
# and instance variables for classes that include or extend the module
#
# (c) John Lane 20140218
#
module Tom
extend self # makes module methods available as class and instance methods.
@moduleinstvar = "mv1" # this sets the module instance variable (unique to the module)
@@classvar = "cv1" # this sets the class variable (common to module and all classes)
# Callback when a class includes the module (which defines instance methods).
# It extends the same module so that class methods are defined
# It defines the class instance variable in the new class (an instance of 'Class')
def included(c)
c.instance_eval do
@classinstvar ||= "civ1" # define class instance variable in including class
end
c.extend self # make module (instance) methods also exist as class methods
# self.classvar = "cv2" # this sets the class variable
attr_accessor :instvar
end
# Callback when a class extends the module (which defines class methods).
# It includes the same module so that instance methods are defined
# It defines the class instance variable in the new class (an instance of 'Class')
def extended(c)
m = self # need to refer to module (self) inside block below
# executes inside the class being extended into (self = c)
unless included_modules.include? m
c.instance_eval do
@classinstvar ||= "civ2" # define class instance variable in extending class
include m unless included_modules.include? m # include is a private method of c
end
# self.classvar = "cv3" # alternate place to set the class variable (see note)
end
end
# Callback when a class that includes/extends the module is instantiated
# It defines the instance variable within the instance.
def initialize
@instvar = "iv1" # this sets @cv, the instance variable
end
# Callback when a class that includes/extends the module is inherited
# It defines the class instance variable within the inherited class
def inherited(c)
c.instance_eval do
@classinstvar ||= "civ3" # define class instance variable in inheriting class
end
end
# The methods below are accessors that can be used as both class and instance methods.
# (due to the "extend" at the top of the module. They can be used on a class that
# includes/extends the module or on an instance of such a class.
#
# Accessors for the class variable
def classvar=(v)
@@classvar = v
end
def classvar
@@classvar
end
# Accessors for the class instance variables
def classinstvar=(v)
if defined?(@classinstvar)
@classinstvar = v
elsif self.class.respond_to? :classinstvar=
self.class.classinstvar = v
else
@classinstvar = v
end
end
def classinstvar
if defined?(@classinstvar)
@classinstvar
elsif self.class.respond_to? :classinstvar
self.class.classinstvar
else
nil
end
end
end
# Notes ##############################################################################
#
# Module Instance Variable
# this is an instance variable in the scope of the module. It does not exist in any
# classes (they have class instance varaibles instead) or instances (they have
# instane variables instead)
# mv1 : Default value. Set when the module is first defined
#
# Class Variable
# this is shared between the module and all classes that include the module
# the default value is reset at every include/extend
# cv1 : Default value. Set when the module is first defined
# cv2 : Changes current value whenever module is included into a class. Commented out
# cv3 : Changes current value whenever module is extended into a class. Commented out
#
# Class Instance Variable
# this is defined when the module is included/extended into a class
# each class that includes/extends the module gets its own class instance variable
# each class that inherits such a class also gets its own class instance variable
# civ1 : set when module is included into class.
# civ2 : set when module is extended into class.
# civ3 : set when class inherits a class that includes/extends the module
#
# Instance Variable
# this is defined with a class that included/extends the module is instantiated
# iv1 : set when the instance is created.
#
#######################################################################JL20140218#####
# TOM : The One Module
#
# An example Ruby module that demonstrates setting of module, class, class instance
# and instance variables for classes that include or extend the module
#
# rspec test suite
#
# (c) John Lane 20140218
#
require_relative 'tom'
class TomIncluded; include Tom; end
class TomExtended; extend Tom; end
class InheritedA < TomIncluded; end
class InheritedB < TomIncluded; end
class InheritedC < TomExtended; end
class InheritedD < TomExtended; end
describe Tom do
it "is a module" do
Tom.class.should == Module
end
it "has a module instance variable called @moduleinstvar" do
Tom.instance_variables.should include(:@moduleinstvar)
Tom.instance_variable_get(:@moduleinstvar).should == "mv1"
end
it "has a class variable called @@classvar" do
Tom.class_variables.should include(:@@classvar)
Tom.class_variable_get(:@@classvar).should == "cv1"
end
describe "when included in a class" do
it "includes the module" do
TomIncluded.included_modules.include? Tom.should be_true
InheritedA.included_modules.include? Tom.should be_true
InheritedB.included_modules.include? Tom.should be_true
end
it "does not have an instance variable called @moduleinstvar" do
TomIncluded.instance_variables.should_not include(:@moduleinstvar)
TomIncluded.class.instance_variables.should_not include(:@moduleinstvar)
InheritedA.instance_variables.should_not include(:@moduleinstvar)
InheritedA.class.instance_variables.should_not include(:@moduleinstvar)
InheritedB.instance_variables.should_not include(:@moduleinstvar)
InheritedB.class.instance_variables.should_not include(:@moduleinstvar)
end
it "has a class variable called @@classvar" do
TomIncluded.class_variables.should include(:@@classvar)
TomIncluded.class_variable_get(:@@classvar).should == "cv1"
TomIncluded.class_variable_get(:@@classvar).should == Tom.class_variable_get(:@@classvar)
InheritedA.class_variables.should include(:@@classvar)
InheritedA.class_variable_get(:@@classvar).should == "cv1"
InheritedA.class_variable_get(:@@classvar).should == Tom.class_variable_get(:@@classvar)
InheritedB.class_variables.should include(:@@classvar)
InheritedB.class_variable_get(:@@classvar).should == "cv1"
InheritedB.class_variable_get(:@@classvar).should == Tom.class_variable_get(:@@classvar)
end
it "has a class instance varaible called @classinstvar" do
TomIncluded.instance_variables.should include(:@classinstvar)
TomIncluded.instance_variable_get(:@classinstvar).should == "civ1"
InheritedA.instance_variables.should include(:@classinstvar)
InheritedA.instance_variable_get(:@classinstvar).should == "civ3"
InheritedB.instance_variables.should include(:@classinstvar)
InheritedB.instance_variable_get(:@classinstvar).should == "civ3"
end
it "doesn't change the module variable's value" do
Tom.instance_variable_get(:@moduleinstvar).should == "mv1"
end
it "has a class variable accessor called classvar" do
TomIncluded.methods.should include(:classvar)
TomIncluded.classvar.should == "cv1"
InheritedA.methods.should include(:classvar)
InheritedA.classvar.should == "cv1"
InheritedB.methods.should include(:classvar)
InheritedB.classvar.should == "cv1"
end
it "has a class variable accessor called classvar=" do
TomIncluded.methods.should include(:'classvar=')
InheritedA.methods.should include(:'classvar=')
InheritedB.methods.should include(:'classvar=')
end
it "has a class instance variable accessor called classinstvar" do
TomIncluded.methods.should include(:classinstvar)
TomIncluded.classinstvar.should == "civ1"
InheritedA.methods.should include(:classinstvar)
InheritedA.classinstvar.should == "civ3"
InheritedB.methods.should include(:classinstvar)
InheritedB.classinstvar.should == "civ3"
end
it "has a class instance variable accessor called classinstvar=" do
TomIncluded.methods.should include(:'classinstvar=')
InheritedA.methods.should include(:'classinstvar=')
InheritedB.methods.should include(:'classinstvar=')
end
end
describe "when extended in a class" do
it "includes the module" do
TomExtended.included_modules.include? Tom.should be_true
InheritedC.included_modules.include? Tom.should be_true
InheritedD.included_modules.include? Tom.should be_true
end
it "does not have an instance variable called @moduleinstvar" do
TomExtended.instance_variables.should_not include(:@moduleinstvar)
TomExtended.class.instance_variables.should_not include(:@moduleinstvar)
InheritedC.instance_variables.should_not include(:@moduleinstvar)
InheritedC.class.instance_variables.should_not include(:@moduleinstvar)
InheritedD.instance_variables.should_not include(:@moduleinstvar)
InheritedD.class.instance_variables.should_not include(:@moduleinstvar)
end
it "has a class variable called @@classvar" do
TomExtended.class_variables.should include(:@@classvar)
TomExtended.class_variable_get(:@@classvar).should == "cv1"
TomExtended.class_variable_get(:@@classvar).should == Tom.class_variable_get(:@@classvar)
InheritedC.class_variables.should include(:@@classvar)
InheritedC.class_variable_get(:@@classvar).should == "cv1"
InheritedC.class_variable_get(:@@classvar).should == Tom.class_variable_get(:@@classvar)
InheritedD.class_variables.should include(:@@classvar)
InheritedD.class_variable_get(:@@classvar).should == "cv1"
InheritedD.class_variable_get(:@@classvar).should == Tom.class_variable_get(:@@classvar)
end
it "has a class instance varaible called @classinstvar" do
TomExtended.instance_variables.should include(:@classinstvar)
TomExtended.instance_variable_get(:@classinstvar).should == "civ2"
InheritedC.instance_variables.should include(:@classinstvar)
InheritedC.instance_variable_get(:@classinstvar).should == "civ3"
InheritedD.instance_variables.should include(:@classinstvar)
InheritedD.instance_variable_get(:@classinstvar).should == "civ3"
end
it "doesn't change the module variable's value" do
Tom.instance_variable_get(:@moduleinstvar).should == "mv1"
end
it "has a class variable accessor called classvar" do
TomExtended.methods.should include(:classvar)
TomExtended.classvar.should == "cv1"
InheritedC.methods.should include(:classvar)
InheritedC.classvar.should == "cv1"
InheritedD.methods.should include(:classvar)
InheritedD.classvar.should == "cv1"
end
it "has a class variable accessor called classvar=" do
TomExtended.methods.should include(:'classvar=')
InheritedC.methods.should include(:'classvar=')
InheritedD.methods.should include(:'classvar=')
end
it "has a class instance variable accessor called classinstvar" do
TomExtended.methods.should include(:classinstvar)
TomExtended.classinstvar.should == "civ2"
InheritedC.methods.should include(:classinstvar)
InheritedC.classinstvar.should == "civ3"
InheritedD.methods.should include(:classinstvar)
InheritedD.classinstvar.should == "civ3"
end
it "has a class instance variable accessor called classinstvar=" do
TomExtended.methods.should include(:'classinstvar=')
InheritedC.methods.should include(:'classinstvar=')
InheritedD.methods.should include(:'classinstvar=')
end
end
describe "when instantiated" do
@ci = TomIncluded.new
@ce = TomExtended.new
instances = [@ci, @ce]
instances.each do |i|
it "has a class instance varaible called @classinstvar" do
i.class.instance_variables.should include(:@classinstvar)
end
it "has an instance varaible @instvar" do
i.instance_variables.should include(:@instvar)
end
it "has a class variable accessor called classvar" do
i.methods.should include(:classvar)
end
it "has a class variable accessor called classvar=" do
i.methods.should include(:'classvar=')
end
it "has a class instance variable accessor called classinstvar" do
i.methods.should include(:classinstvar)
end
it "has a class instance variable accessor called classinstvar=" do
i.methods.should include(:'classinstvar=')
end
it "has an instance variable accessor called instvar" do
i.methods.should include(:instvar)
end
it "has an instance variable accessor called instvar=" do
i.methods.should include(:'instvar=')
end
end
end
describe "changing the module instace variable" do
it "can be changed" do
Tom.instance_variable_set('@moduleinstvar','woohoo')
Tom.instance_variable_get('@moduleinstvar').should == 'woohoo'
Tom::instance_variable_set('@moduleinstvar','woohoo')
Tom::instance_variable_get('@moduleinstvar').should == 'woohoo'
end
end
describe "changing variable values" do
instances = [
TomIncluded.new,
TomExtended.new,
InheritedA.new,
InheritedA.new,
InheritedB.new,
InheritedB.new,
InheritedC.new,
InheritedC.new,
InheritedD.new,
InheritedD.new,
TomIncluded.new,
TomExtended.new,
InheritedA.new,
InheritedA.new,
InheritedB.new,
InheritedB.new,
InheritedC.new,
InheritedC.new,
InheritedD.new,
InheritedD.new
]
describe "changing the class variable" do
instances.each do |i|
it "can be changed" do
i.classvar = 'changed value'
i.classvar.should == 'changed value'
Tom.classvar.should == 'changed value'
TomIncluded.classvar.should == 'changed value'
TomExtended.classvar.should == 'changed value'
InheritedA.classvar.should == 'changed value'
InheritedB.classvar.should == 'changed value'
InheritedC.classvar.should == 'changed value'
InheritedD.classvar.should == 'changed value'
end
it "is the same in all classes and instances" do
Tom.classvar = 'class value'
Tom.classvar.should == 'class value'
TomIncluded.classvar.should == 'class value'
TomExtended.classvar.should == 'class value'
InheritedA.classvar.should == 'class value'
InheritedB.classvar.should == 'class value'
InheritedC.classvar.should == 'class value'
InheritedD.classvar.should == 'class value'
instances[0].classvar.should == 'class value'
instances[1].classvar.should == 'class value'
instances[2].classvar.should == 'class value'
instances[3].classvar.should == 'class value'
instances[4].classvar.should == 'class value'
instances[5].classvar.should == 'class value'
instances[6].classvar.should == 'class value'
instances[7].classvar.should == 'class value'
instances[8].classvar.should == 'class value'
instances[9].classvar.should == 'class value'
instances[10].classvar.should == 'class value'
instances[11].classvar.should == 'class value'
instances[12].classvar.should == 'class value'
instances[13].classvar.should == 'class value'
instances[14].classvar.should == 'class value'
instances[15].classvar.should == 'class value'
instances[16].classvar.should == 'class value'
instances[17].classvar.should == 'class value'
instances[18].classvar.should == 'class value'
instances[19].classvar.should == 'class value'
end
end
end
describe "changing the class instance variable" do
instances.each do |i|
it "can be changed" do
i.classinstvar = 'changed value'
i.classinstvar.should == 'changed value'
end
end
it "is unique per class" do
instances[0].classinstvar = "value TomIncluded"
instances[1].classinstvar = "value TomExtended"
instances[2].classinstvar = "value InheritedA"
instances[4].classinstvar = "value InheritedB"
instances[6].classinstvar = "value InheritedC"
instances[8].classinstvar = "value InheritedD"
instances[0].classinstvar.should == "value TomIncluded"
instances[1].classinstvar.should == "value TomExtended"
instances[2].classinstvar.should == "value InheritedA"
instances[3].classinstvar.should == "value InheritedA"
instances[4].classinstvar.should == "value InheritedB"
instances[5].classinstvar.should == "value InheritedB"
instances[6].classinstvar.should == "value InheritedC"
instances[7].classinstvar.should == "value InheritedC"
instances[8].classinstvar.should == "value InheritedD"
instances[9].classinstvar.should == "value InheritedD"
instances[10].classinstvar.should == "value TomIncluded"
instances[11].classinstvar.should == "value TomExtended"
instances[12].classinstvar.should == "value InheritedA"
instances[13].classinstvar.should == "value InheritedA"
instances[14].classinstvar.should == "value InheritedB"
instances[15].classinstvar.should == "value InheritedB"
instances[16].classinstvar.should == "value InheritedC"
instances[17].classinstvar.should == "value InheritedC"
instances[18].classinstvar.should == "value InheritedD"
instances[19].classinstvar.should == "value InheritedD"
end
end
describe "changing the instance variable" do
instances.each do |i|
it "can be changed" do
i.instvar = 'changed value'
i.instvar.should == 'changed value'
end
end
it "is unique per instance" do
(0..19).each { |i| instances[i].instvar = "value #{i}" }
(0..19).each { |i| instances[i].instvar.should == "value #{i}" }
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment