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