lib/moosex.rb in moosex-0.0.14 vs lib/moosex.rb in moosex-0.0.15

- old
+ new

@@ -7,41 +7,59 @@ # require "moosex/version" require "moosex/types" module MooseX - $MOOSEX_DEBUG = true + @@MOOSEX_WARNINGS = true + @@MOOSEX_FATAL = false + + class FatalError < StandardError + end + + def self.warn(x, *c) + raise FatalError, "[MooseX] exception: #{x}",*c if @@MOOSEX_FATAL + Kernel.warn("[MooseX] warning: #{x}") if @@MOOSEX_WARNINGS + end + + def self.init(args={}) + if args.has_key? :warnings + @@MOOSEX_WARNINGS = !! args[:warnings] + end + + if args.has_key? :fatal + @@MOOSEX_FATAL = !! args[:fatal] + end + + self + end - def MooseX.enable_warnings() - $MOOSEX_DEBUG = false - MooseX - end - - def MooseX.disable_warnings() - $MOOSEX_DEBUG = false - MooseX - end - class RequiredMethodNotFoundError < NameError end def MooseX.included(c) c.extend(MooseX::Core) + + def c.init(*args) + __meta.roles.each{|role| role.call(*args)} + + self + end def c.included(x) + MooseX.included(x) x.__meta.load_from(self.__meta) return unless x.is_a? Class x.__meta.load_hooks(self.__meta) self.__meta.init_klass(x) x.__meta.requires.each do |method| unless x.public_instance_methods.include? method - warn "[MooseX] you must implement method '#{method}' in #{x} #{x.class}: required" if $MOOSEX_DEBUG + MooseX.warn "you must implement method '#{method}' in #{x} #{x.class}: required"# if $MOOSEX_DEBUG end end end meta = MooseX::Meta.new @@ -78,16 +96,17 @@ end end class Meta - attr_reader :attrs, :requires, :before, :after, :around + attr_reader :attrs, :requires, :before, :after, :around, :roles def initialize(old_meta=nil) @initialized = false @attrs = {} @requires = [] + @roles = [] @before = Hash.new { |hash, key| hash[key] = [] } @after = Hash.new { |hash, key| hash[key] = [] } @around = Hash.new { |hash, key| hash[key] = [] } if old_meta @@ -134,17 +153,26 @@ end def add_around(method_name, block) @around[method_name] << block.clone end + + def add_role(block) + @roles << block + end def init_klass(klass) #return if @initialized [@before.keys + @after.keys + @around.keys].flatten.uniq.each do |method_name| - method = klass.instance_method method_name - + begin + method = klass.instance_method method_name + rescue => e + MooseX.warn "Unable to apply hooks (after/before/around) in #{klass}::#{method_name} : #{e}" # if $MOOSEX_DEBUG + next + end + before = @before[method_name] after = @after[method_name] around = @around[method_name] klass.__meta_define_method(method_name) do |*args| @@ -166,11 +194,11 @@ end def init(object, args) @attrs.each_pair{ |symbol, attr| attr.init(object, args) } - warn "[MooseX] unused attributes #{args} for #{object.class}" if $MOOSEX_DEBUG && ! args.empty? + MooseX.warn "unused attributes #{args} for #{object.class}", caller unless args.empty? @requires.each do |method| unless object.respond_to? method raise RequiredMethodNotFoundError, "you must implement method '#{method}' in #{object.class}: required" @@ -178,53 +206,66 @@ end end end module Core - def after(method_name, &block) - begin - method = instance_method method_name + def on_init(&block) + __meta.add_role(block) + end + + def after(*methods_name, &block) + methods_name.each do |method_name| + begin + method = instance_method method_name - define_method method_name do |*args| - result = method.bind(self).call(*args) - block.call(self,*args) - result - end - rescue => e - __meta.add_after(method_name, block) - end + define_method method_name do |*args| + result = method.bind(self).call(*args) + block.call(self,*args) + result + end + rescue => e + MooseX.warn "unable to apply hook after in #{method_name} @ #{self}: #{e}", caller() if self.is_a?(Class) + __meta.add_after(method_name, block) + end + end end - def before(method_name, &block) - begin - method = instance_method method_name + def before(*methods_name, &block) + methods_name.each do |method_name| + begin + method = instance_method method_name - define_method method_name do |*args| - block.call(self,*args) - method.bind(self).call(*args) - end - rescue => e - __meta.add_before(method_name, block) - end + define_method method_name do |*args| + block.call(self,*args) + method.bind(self).call(*args) + end + rescue => e + MooseX.warn "unable to apply hook before in #{method_name} @ #{self}: #{e}", caller() if self.is_a?(Class) + __meta.add_before(method_name, block) + end + end end - def around(method_name, &block) - begin - method = instance_method method_name + def around(*methods_name, &block) + methods_name.each do |method_name| + begin + method = instance_method method_name - code = Proc.new do | o, *a| - method.bind(o).call(*a) - end + code = Proc.new do | o, *a| + method.bind(o).call(*a) + end - define_method method_name do |*args| + define_method method_name do |*args| - block.call(code, self,*args) + block.call(code, self,*args) - end - rescue => e - __meta.add_around(method_name, block) - end + end + rescue => e + MooseX.warn "unable to apply hook around in #{method_name} @ #{self}: #{e}", caller() if self.is_a?(Class) + __meta.add_around(method_name, block) + end + end end def requires(*methods) methods.each do |method_name| @@ -414,11 +455,11 @@ coerce end, }; - def initialize(a, o, x) + def initialize(a, o ,x) #o ||= {} # todo extract this to a framework, see issue #21 on facebook o = DEFAULTS.merge({ reader: a, writter: a.to_s.concat("=").to_sym, @@ -468,10 +509,10 @@ @init_arg = o.delete(:init_arg) @trigger = o.delete(:trigger) @coerce = o.delete(:coerce) @methods = {} - warn "[MooseX] unused attributes #{o} for attribute #{a} @ #{x} #{x.class}" if $MOOSEX_DEBUG && ! o.empty? + MooseX.warn "Unused attributes #{o} for attribute #{a} @ #{x} #{x.class}",caller() if ! o.empty? if @reader @methods[@reader] = generate_reader end \ No newline at end of file