lib/moosex.rb in moosex-0.0.11 vs lib/moosex.rb in moosex-0.0.12

- old
+ new

@@ -7,36 +7,62 @@ # require "moosex/version" require "moosex/types" module MooseX + $MOOSEX_DEBUG = true + 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) - - c.class_exec do - meta = MooseX::Meta.new + + def c.included(x) + MooseX.included(x) + x.__meta.load_from(self.__meta) - define_singleton_method(:__meta) { meta } + return unless x.is_a? Class + + 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 end + meta = MooseX::Meta.new + + unless c.respond_to? :__meta + c.class_exec do + define_singleton_method(:__meta) { meta } + end + end + def initialize(*args) - args = BUILDARGS(*args) + if self.respond_to? :BUILDARGS + args = self.BUILDARGS(*args) + else + args = args[0] + end self.class.__meta().init(self, args || {}) - BUILD() + self.BUILD() if self.respond_to? :BUILD end - def BUILDARGS(*args) - args[0] - end - - def BUILD - end - def c.inherited(subclass) subclass.class_exec do old_meta = subclass.__meta meta = MooseX::Meta.new(old_meta) @@ -46,44 +72,49 @@ end end class Meta - attr_reader :attrs, :after, :before, :around + attr_reader :attrs, :requires def initialize(old_meta=nil) - @attrs = [] - @after = Hash.new {|hash, key| hash[key] = []} - @before= Hash.new {|hash, key| hash[key] = []} - @around= Hash.new {|hash, key| hash[key] = []} - + @attrs = {} + @requires = [] if old_meta - @attrs = old_meta.attrs.map{|att| att.clone } - @after.merge! old_meta.after.clone - @before.merge! old_meta.before.clone - @around.merge! old_meta.around.clone + old_meta.attrs.each_pair do |key, value| + @attrs[key] = value.clone + end + @requires = old_meta.requires.clone end end - - def add(attr) - @attrs << attr - end - def add_after(method, block) - @after[method] << MooseX::Hook::After.new(method, block) + def load_from(other_meta) + other_meta.attrs.each_pair do |key, value| + @attrs[key] = value.clone + end + @requires += other_meta.requires end - def add_before(method, block) - @before[method] << MooseX::Hook::Before.new(method, block) + def add(attr) + @attrs[attr.attr_symbol] = attr end - def add_around(method, block) - @around[method] << MooseX::Hook::Around.new(method, block) + def add_requires(method) + @requires << method end def init(object, args) - @attrs.each{ |attr| attr.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? + + @requires.each do |method| + unless object.respond_to? method + raise RequiredMethodNotFoundError, + "you must implement method '#{method}' in #{object.class}: required" + end + end end end module Core def after(method_name, &block) @@ -93,35 +124,42 @@ result = method.bind(self).call(*args) block.call(self,*args) result end - __meta.add_after(method_name, block) +# __meta.add_after(method_name, block) end def before(method_name, &block) 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) +# __meta.add_before(method_name, block) end def around(method_name, &block) method = instance_method method_name define_method method_name do |*args| block.call(method, self,*args) end - __meta.add_around(method, block) +# __meta.add_around(method, block) end + def requires(*methods) + + methods.each do |method_name| + __meta.add_requires(method_name) + end + end + def has(attr_name, attr_options = {}) if attr_name.is_a? Array attr_name.each do |attr| has(attr, attr_options) end @@ -129,11 +167,11 @@ attr_name.each_pair do |attr, options | has(attr, options) end else - attr = MooseX::Attribute.new(attr_name, attr_options) + attr = MooseX::Attribute.new(attr_name, attr_options, self) attr.methods.each_pair do |method, proc| define_method method, &proc end @@ -147,29 +185,10 @@ __meta.add(attr) end end end - module Hook - class Base - attr_reader :method, :block - def initialize(method, block) - @method= method - @block = block - end - end - - class After < Base - end - - class Before < Base - end - - class Around < Base - end - end - class InvalidAttributeError < TypeError end class Attribute @@ -321,11 +340,11 @@ coerce end, }; - def initialize(a, o) + 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, @@ -359,26 +378,28 @@ unless o[:lazy] o[:builder] = nil end @attr_symbol = a - @is = o[:is] - @isa = o[:isa] - @default = o[:default] - @required = o[:required] - @predicate = o[:predicate] - @clearer = o[:clearer] - @handles = o[:handles] - @lazy = o[:lazy] - @reader = o[:reader] - @writter = o[:writter] - @builder = o[:builder] - @init_arg = o[:init_arg] - @trigger = o[:trigger] - @coerce = o[:coerce] + @is = o.delete(:is) + @isa = o.delete(:isa) + @default = o.delete(:default) + @required = o.delete(:required) + @predicate = o.delete(:predicate) + @clearer = o.delete(:clearer) + @handles = o.delete(:handles) + @lazy = o.delete(:lazy) + @reader = o.delete(:reader) + @writter = o.delete(:writter) + @builder = o.delete(:builder) + @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? + if @reader @methods[@reader] = generate_reader end if @writter @@ -410,10 +431,10 @@ def init(object, args) value = nil value_from_default = false if args.has_key? @init_arg - value = args[ @init_arg ] + value = args.delete(@init_arg) elsif @default value = @default.call value_from_default = true elsif @required raise InvalidAttributeError, "attr \"#{@attr_symbol}\" is required" \ No newline at end of file