require 'set' Module.class_eval do def alias name = nil if name name.must_be.a String name.must_not_be.blank @alias = name.to_s else @alias ||= self.name.split('::').last end end def is?(base) ancestors.include?(base) end def wrap_method( sym, prefix = "old_", &blk ) old_method = "#{prefix}_#{sym}".to_sym alias_method old_method, sym define_method(sym) do |*args| instance_exec(old_method, *args, &blk) end end def namespace if @module_namespace_defined @module_namespace else @module_namespace_defined = true @module_namespace = Module.namespace_for name end end def each_namespace &block current = namespace while current do block.call current current = current.namespace end end def each_ancestor include_standard = false, &block if include_standard ancestors.each{|a| block.call a unless a == self} else exclude = [self, Object, Kernel] ancestors.each do |a| block.call a unless exclude.include? a end end end def self_ancestors_and_namespaces &b b.call self each_ancestor &b each_namespace &b end # TODO cache it? def self.namespace_for class_name list = class_name.split("::") if list.size > 1 list.pop return eval(list.join("::"), TOPLEVEL_BINDING, __FILE__, __LINE__) else return nil end end def inheritable_accessor attribute_name, default_value raise "Can be used only for Class and Module" unless self.class.is? Module # raise "Default value can't be nil!" unless default_value iv_name = "@#{attribute_name}" iv_defined = "@#{attribute_name}_defined" define_method attribute_name do unless instance_variable_get(iv_defined) iv = nil ancestors[1..-1].each do |a| if a.respond_to?(attribute_name) and (value = a.send(attribute_name)) iv = value.deep_clone break end end iv ||= default_value.deep_clone instance_variable_set iv_name, iv instance_variable_set iv_defined, true iv else instance_variable_get iv_name end end define_method "#{attribute_name}=" do |value| # raise "Value can't be nil!" unless value instance_variable_set iv_name, value instance_variable_set iv_defined, true end end raise "Internal error, it shouldn't be loaded twice!" if defined? ESCAPE_METHOD_SYMBOLS # some tricky error when runing spec with rake ESCAPE_METHOD_SYMBOLS = [ ['==', 'assign'], ['>', 'gt'], ['<', 'lt'], ['>=', 'gte'], ['<=', 'lte'], ['?', 'qst'], ['!', 'imp'], ['<=>', 'lorg'], ['*', 'mp'], ['+', 'add'], ['-', 'sub'], ['=', 'assign'], ['**', 'pw'], ['=~', 'sim'], ['[]', 'sb'], ] def escape_method method m = method.to_s.clone ESCAPE_METHOD_SYMBOLS.each{|from, to| m.gsub! from, to} raise "Invalid method name '#{method}'!" unless m =~ /^[_a-zA-Z0-9]+$/ m.to_sym end def attr_required *attrs attrs.each do |attr| define_method(attr){instance_variable_get(:"@#{attr}") || raise("attribute :#{attr} not defined!")} end end public :include, :define_method end