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