Skip to content

Instantly share code, notes, and snippets.

@ryanking
Created December 6, 2013 01:03
Show Gist options
  • Save ryanking/7817001 to your computer and use it in GitHub Desktop.
Save ryanking/7817001 to your computer and use it in GitHub Desktop.
I just stumbled on this bit of ruby code from a long time ago. Matt Knox and I were trying to solve the question of "can you selectively prevent monkey-patching in ruby?" I think this is the best we could do at the time.
# Ever get tired of people messing with your ruby classes?
# now you can put the hammer down and stop them. Just
# include this module and no one will be able to modify the
# class implementation or any instance implementations.
module Stop
module CantTouchThis
def self.included(mod)
%w[instance_variable_get instance_variable_set].each do |m|
send(:protected, m)
end
eigenclass = class << mod; self; end
%w[const_set class_variable_get class_variable_set public_class_method attr attr_reader attr_writer].each do |m|
eigenclass.send(:protected, m)
end
mod.send(:define_method, :instance_eval) do
raise NoMethodError, "do do do, uh uh, duh duh. can't touch this"
end
%w[class_eval class_exec module_eval module_exec include extend alias_method unfreeze remove_const remove_method undef_method define_method].each do |m|
mod.class.send(:define_method, m) do
raise NoMethodError, "do do do, uh uh, duh duh. can't touch this"
end
end
mod.send(:protected, :send)
eigenclass.send(:protected, :send)
mod.freeze
end
end
end
# simplest possible testing framework
def r
yield
puts "fail"
rescue => e
p e
end
# some simple tests
module B
def self.included(_)
puts "fail"
end
end
class A
include Stop::CantTouchThis
r{class_eval '' }
r{class_exec {} }
r{module_eval '' }
r{include B }
r{extend B }
r{alias_method :class, :id }
r{define_method(:foo) {} }
r{ remove_const(:FOO) }
r{ remove_method(:id) }
end
r{ A.new.instance_eval '' }
r{ A.new.instance_variable_get(:@foo) }
r{ A.new.instance_variable_set(:@foo, :foo) }
r{ A.class_variable_get(:@foo) }
r{ A.new.class_variable_get(:@foo) }
r{ A.class_variable_set(:@foo, :bar) }
r{ A.new.class_variable_set(:@foo, :bar) }
r{ A.const_set(:B, :foo) }
r{ A.public_class_method(:send) }
r{ A.const_set(:FOO, :bar) }
r{ A.attr(:foo) }
r{ A.attr_reader(:foo) }
r{ A.attr_writer(:foo) }
r{ A.new.send(:id)}
r{ A.send(:id)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment