lib/immutable.rb in up_the_irons-immutable-0.2 vs lib/immutable.rb in up_the_irons-immutable-0.3
- old
+ new
@@ -1,38 +1,52 @@
module Immutable
class CannotOverrideMethod < StandardError; end
+ # Random ID changed at each interpreter load
+ UNIQ = "_#{object_id.abs}"
+
def self.included(mod)
mod.extend(ClassMethods)
end
module ClassMethods
def immutable_method(*args)
+ # Initialize variables
+ @immutable_methods = [] if @immutable_methods.nil?
+ @silent_immutable_methods = [] if @silent_immutable_methods.nil?
+ instance_variable_set("@#{UNIQ}_in_method_added", false)
+
opts = args.last.is_a?(Hash) ? args.pop : {}
args.each do |method|
- alias_method "orig_#{method}", method
+ alias_method "#{UNIQ}_old_#{method}", method
end
+
+ # Build list of immutable methods
+ @immutable_methods += args
+ @silent_immutable_methods += args if opts[:silent]
- @args = args; @opts = opts
+ @opts = opts
module_eval do
def self.method_added(sym)
- if @args
- @args.each do |method|
- if method && sym == method.to_sym && !called_by_method_added
- unless @opts[:silent]
+ if @immutable_methods
+ @immutable_methods.each do |method|
+ if method && sym == method.to_sym && !in_method_added?
+ unless @silent_immutable_methods.include?(method)
raise CannotOverrideMethod, "Cannot override the immutable method: #{sym}"
end
-
- self.module_eval <<-"end;"
- def #{method.to_s}(*args, &block)
- orig_#{method.to_s}(*args, &block)
- end
- end;
+
+ allow_method_override do
+ self.module_eval <<-"end;"
+ def #{method}(*args, &block)
+ #{UNIQ}_old_#{method}(*args, &block)
+ end
+ end;
+ end
end
end # @args.each
- end # @args
+ end # @immutable_methods
end # def self.method_added()
def self.method_undefined(sym)
method_added(sym)
end
@@ -40,12 +54,18 @@
def self.method_removed(sym)
method_added(sym)
end
end # module_eval
- def self.called_by_method_added
- # This is a little brittle, suggestions?
- caller[3] =~ /eval.*in.*method_added/
+ def self.allow_method_override
+ instance_variable_set("@#{UNIQ}_in_method_added", true)
+ yield
+ ensure
+ instance_variable_set("@#{UNIQ}_in_method_added", false)
+ end
+
+ def self.in_method_added?
+ instance_variable_get("@#{UNIQ}_in_method_added")
end
end # def immutable_method()
alias immutable_methods immutable_method