lib/moosex.rb in moosex-0.0.13 vs lib/moosex.rb in moosex-0.0.14
- old
+ new
@@ -32,10 +32,13 @@
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
end
end
@@ -44,10 +47,13 @@
meta = MooseX::Meta.new
unless c.respond_to? :__meta
c.class_exec do
define_singleton_method(:__meta) { meta }
+ define_singleton_method(:__meta_define_method) do |method_name, &proc|
+ define_method(method_name, proc)
+ end
end
end
def initialize(*args)
if self.respond_to? :BUILDARGS
@@ -72,15 +78,20 @@
end
end
class Meta
- attr_reader :attrs, :requires
+ attr_reader :attrs, :requires, :before, :after, :around
def initialize(old_meta=nil)
+ @initialized = false
@attrs = {}
@requires = []
+ @before = Hash.new { |hash, key| hash[key] = [] }
+ @after = Hash.new { |hash, key| hash[key] = [] }
+ @around = Hash.new { |hash, key| hash[key] = [] }
+
if old_meta
old_meta.attrs.each_pair do |key, value|
@attrs[key] = value.clone
end
@requires = old_meta.requires.clone
@@ -92,18 +103,70 @@
@attrs[key] = value.clone
end
@requires += other_meta.requires
end
+ def load_hooks(other_meta)
+ other_meta.before.each_pair do |m, b|
+ @before[m] += b.clone
+ end
+ other_meta.after.each_pair do |m, b|
+ @after[m] += b.clone
+ end
+ other_meta.around.each_pair do |m, b|
+ @around[m] += b.clone
+ end
+ end
+
def add(attr)
@attrs[attr.attr_symbol] = attr
end
def add_requires(method)
@requires << method
end
+ def add_before(method_name, block)
+ @before[method_name] << block.clone
+ end
+
+ def add_after(method_name, block)
+ @after[method_name] << block.clone
+ end
+
+ def add_around(method_name, block)
+ @around[method_name] << block.clone
+ 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
+
+ before = @before[method_name]
+ after = @after[method_name]
+ around = @around[method_name]
+
+ klass.__meta_define_method(method_name) do |*args|
+ before.each{|b| b.call(self,*args)}
+
+ original = lambda do |object, *args|
+ method.bind(object).call(*args)
+ end
+
+ result = around.inject(original) do |lambda1, lambda2|
+ lambda2.curry[lambda1]
+ end.call(self, *args)
+
+ after.each{|b| b.call(self,*args)}
+
+ result
+ end
+ end
+ 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?
@@ -116,44 +179,51 @@
end
end
module Core
def after(method_name, &block)
- method = instance_method 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
-
-# __meta.add_after(method_name, block)
+ 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
end
def before(method_name, &block)
- method = instance_method method_name
+ begin
+ method = instance_method method_name
- define_method method_name do |*args|
- block.call(self,*args)
- method.bind(self).call(*args)
- end
-
-# __meta.add_before(method_name, block)
+ 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
end
def around(method_name, &block)
- method = instance_method 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|
-
- block.call(code, self,*args)
-
- end
-# __meta.add_around(method, block)
+ define_method method_name do |*args|
+
+ block.call(code, self,*args)
+
+ end
+ rescue => e
+ __meta.add_around(method_name, block)
+ end
end
def requires(*methods)
methods.each do |method_name|
\ No newline at end of file