Skip to content

Instantly share code, notes, and snippets.

@haroldrandom
Created February 24, 2018 17:02
Show Gist options
  • Save haroldrandom/d53f76d16b6908b2b9f216ac48daef02 to your computer and use it in GitHub Desktop.
Save haroldrandom/d53f76d16b6908b2b9f216ac48daef02 to your computer and use it in GitHub Desktop.
Difference between instance_eval and class_eval
#!/usr/bin/env ruby
# encoding: UTF-8
class RackServer
def options
#puts "RackServer: #{self} #{__LINE__}"
@options ||= parse_options(ARGV)
end
def start
p options
end
private
def parse_options(args)
#puts "RackServer: #{self} #{__LINE__}"
options = default_options
options
end
def default_options
#puts "RackServer: #{self} #{__LINE__}"
{
:environment => 'development',
:pid => nil,
:config =>'config.ru'
}
end
end
class RailsServer < RackServer
def default_options
#puts "RailsServer: #{self} #{__LINE__}"
super.merge({
:config => File.expand_path(__FILE__)
})
end
def start
super
end
def demo_show
'rails class demo show'
end
def config
@config ||= {}
end
puts "#{__LINE__}, #{self}" # class
class << self
def instance
@instance ||= new
end
def configure(&blk)
instance.configure(&blk)
end
end
def configure(&blk)
puts "#{__LINE__}, #{self}" # instance
instance_eval(&blk)
#instance_eval do
# puts "#{__LINE__}, #{self}" # instance, same as line 61
# # implicitly means that demo_show get invoked by an instance of RailsServer
# p demo_show
# blk.call() if block_given?
#end
end
end
RailsServer.class_eval do
# bar is defined within the context of class RailsServer
# So, bar become a instance method
def bar
puts "#{__LINE__}, #{self} call bar by class_eval"
end
end
RailsServer.instance_eval do
# instance_eval invoked like this way will open the singleton class of RailsServer, called #RailsServer.
# Because RailsServer has to be someone's instance, instance_eval can finally be worthy of the name.
# So #RailsServer get created.
# That's an unconsipicuous difference between instance_eval and class_eval,
# if there is no singleton class of current instance, instance_eval will create one for it, but class_eval don't
#
# You can do this by doing
# class << self
# ...
# end
# within the class definition.
# Actually, Module#extend works like that.
def bar
# bar is defined witin the context of class #RailsServer (metaclass of RailsServer),
# So, bar become a class method
# Note that, class method is nothing but a singleton method of a class, which is #RailsServer in this case
# An instance method of a singleton class
puts "#{__LINE__}, #{self} call bar by instance_eval"
end
end
server = RailsServer.new
server.start
server.bar
RailsServer.bar
puts "#{__LINE__}, #{server} within ousider" # instance
# Demo
RailsServer.configure do
puts "Start to RailsServer.configure...config: #{config}"
config[:r] = 'Ruby'
config[:p] = 'Python'
config[:c] = 'C++'
config[:g] = 'golang'
puts "After to RailsServer.configure...config: #{config}"
end
# instance_eval invoked like this way will also open the singleton class of server instance,
# which is the metaclass of server instance, called #server
#server.instance_eval do
# puts "#{__LINE__}, #{self}"
#end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment