lib/moosex.rb in moosex-0.0.16 vs lib/moosex.rb in moosex-0.0.17
- old
+ new
@@ -5,646 +5,672 @@
# Copyright:: Copyright (c) 2014 Tiago Peczenyj
# License:: MIT
#
require "moosex/version"
require "moosex/types"
+require "weakref"
module MooseX
- @@MOOSEX_WARNINGS = true
- @@MOOSEX_FATAL = false
-
- class FatalError < StandardError
- end
-
- def self.warn(x, *c)
- raise FatalError, "[MooseX] exception: #{x}",*c if @@MOOSEX_FATAL
+ @@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 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
- class RequiredMethodNotFoundError < NameError
- end
+ class RequiredMethodNotFoundError < NameError
+ end
- def MooseX.included(c)
-
- c.extend(MooseX::Core)
+ 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)
+
+ def c.included(x)
+
+ MooseX.included(x)
+ x.__meta.load_from(self.__meta)
- return unless x.is_a? Class
+ return unless x.is_a? Class
- x.__meta.load_hooks(self.__meta)
- self.__meta.init_klass(x)
+ x.__meta.load_hooks(self.__meta)
+ self.__meta.init_klass(x)
- x.__meta.requires.each do |method|
- unless x.public_instance_methods.include? method
- MooseX.warn "you must implement method '#{method}' in #{x} #{x.class}: required"# if $MOOSEX_DEBUG
- end
- end
- end
+ x.__meta.requires.each do |method|
+ unless x.public_instance_methods.include? method
+ MooseX.warn "you must implement method '#{method}' in #{x} #{x.class}: required"# if $MOOSEX_DEBUG
+ end
+ end
+ end
- meta = MooseX::Meta.new
+ 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
- args = self.BUILDARGS(*args)
- else
- args = args[0]
- end
-
- self.class.__meta().init(self, args || {})
+ 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
+ args = self.BUILDARGS(*args)
+ else
+ args = args[0]
+ end
+
+ self.class.__meta().init(self, args || {})
- self.BUILD() if self.respond_to? :BUILD
- end
+ self.BUILD() if self.respond_to? :BUILD
+ end
- def c.inherited(subclass)
- subclass.class_exec do
- old_meta = subclass.__meta
+ def c.inherited(subclass)
+ subclass.class_exec do
+ old_meta = subclass.__meta
- meta = MooseX::Meta.new(old_meta)
+ meta = MooseX::Meta.new(old_meta)
- define_singleton_method(:__meta) { meta }
- end
- end
-
- end
-
- class Meta
- attr_reader :attrs, :requires, :before, :after, :around, :roles
+ define_singleton_method(:__meta) { meta }
+ end
+ end
+
+ end
+
+ class Meta
+ 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] = [] }
+ 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
- old_meta.attrs.each_pair do |key, value|
- @attrs[key] = value.clone
- end
- @requires = old_meta.requires.clone
- end
- end
+ if old_meta
+ old_meta.attrs.each_pair do |key, value|
+ @attrs[key] = value.clone
+ end
+ @requires = old_meta.requires.clone
+ end
+ end
- def load_from(other_meta)
- other_meta.attrs.each_pair do |key, value|
- @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 load_from(other_meta)
+ other_meta.attrs.each_pair do |key, value|
+ @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(attr)
+ if @attrs.has_key?(attr.attr_symbol) && ! attr.override
+ raise FatalError, "#{attr.attr_symbol} already exists, you should specify override: true"
+ end
+ @attrs[attr.attr_symbol] = attr
+ end
- def add_requires(method)
- @requires << method
- end
+ def add_requires(method)
+ @requires << method
+ end
- def add_before(method_name, block)
- @before[method_name] << block.clone
- 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_after(method_name, block)
+ @after[method_name] << block.clone
+ end
- def add_around(method_name, block)
- @around[method_name] << block.clone
- end
-
- def add_role(block)
- @roles << block
+ 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
+ def init_klass(klass)
+ #return if @initialized
- [@before.keys + @after.keys + @around.keys].flatten.uniq.each do |method_name|
- begin
- method = klass.instance_method method_name
+ [@before.keys + @after.keys + @around.keys].flatten.uniq.each do |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]
+ before = @before[method_name]
+ after = @after[method_name]
+ around = @around[method_name]
- klass.__meta_define_method(method_name) do |*args, &proc|
- before.each{|b| b.call(self,*args, &proc)}
-
- original = lambda do |object, *args, &proc|
- method.bind(object).call(*args, &proc)
- end
+ klass.__meta_define_method(method_name) do |*args, &proc|
+ before.each{|b| b.call(self,*args, &proc)}
+
+ original = lambda do |object, *args, &proc|
+ method.bind(object).call(*args, &proc)
+ end
- result = around.inject(original) do |lambda1, lambda2|
- lambda2.curry[lambda1]
- end.call(self, *args, &proc)
+ result = around.inject(original) do |lambda1, lambda2|
+ lambda2.curry[lambda1]
+ end.call(self, *args, &proc)
- after.each{|b| b.call(self,*args, &proc)}
-
- result
- end
- end
- end
+ after.each{|b| b.call(self,*args, &proc)}
+
+ result
+ end
+ end
+ end
- def init(object, args)
- @attrs.each_pair{ |symbol, attr| attr.init(object, args) }
+ def init(object, args)
+ @attrs.each_pair{ |symbol, attr| attr.init(object, args) }
- MooseX.warn "unused attributes #{args} for #{object.class}", caller unless 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"
- end
- end
- end
- end
+ @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 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
+ module Core
+ 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, &proc|
- result = method.bind(self).call(*args, &proc)
- block.call(self,*args,&proc)
- 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
+ define_method method_name do |*args, &proc|
+ result = method.bind(self).call(*args, &proc)
+ block.call(self,*args,&proc)
+ 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(*methods_name, &block)
- methods_name.each do |method_name|
- 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, &proc|
- block.call(self,*args, &proc)
- method.bind(self).call(*args, &proc)
- 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
+ define_method method_name do |*args, &proc|
+ block.call(self,*args, &proc)
+ method.bind(self).call(*args, &proc)
+ 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(*methods_name, &block)
- methods_name.each do |method_name|
- 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, &proc|
- method.bind(o).call(*a,&proc)
- end
+ code = Proc.new do | o, *a, &proc|
+ method.bind(o).call(*a,&proc)
+ end
- define_method method_name do |*args, &proc|
- block.call(code, self,*args, &proc)
- 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
+ define_method method_name do |*args, &proc|
+ block.call(code, self,*args, &proc)
+ 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)
+ def requires(*methods)
- methods.each do |method_name|
- __meta.add_requires(method_name)
- end
- end
+ 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
- elsif attr_name.is_a? Hash
- attr_name.each_pair do |attr, options |
- has(attr, options)
- end
- else
+ def has(attr_name, attr_options = {})
+ if attr_name.is_a? Array
+ attr_name.each do |attr|
+ has(attr, attr_options)
+ end
+ elsif attr_name.is_a? Hash
+ attr_name.each_pair do |attr, options |
+ has(attr, options)
+ end
+ else
+ attr = MooseX::Attribute.new(attr_name, attr_options, self)
- attr = MooseX::Attribute.new(attr_name, attr_options, self)
+ __meta.add(attr)
- attr.methods.each_pair do |method, proc|
- define_method method, &proc
- end
+ attr.methods.each_pair do |method, proc|
+ define_method method, &proc
+ end
- if attr.is.eql?(:rwp)
- private attr.writter
- elsif attr.is.eql?(:private)
- private attr.writter
- private attr.reader
- end
+ if attr.is.eql?(:rwp)
+ private attr.writter
+ elsif attr.is.eql?(:private)
+ private attr.writter
+ private attr.reader
+ end
+ end
+ end
+ end
+
+ class InvalidAttributeError < TypeError
- __meta.add(attr)
- end
- end
- end
-
- class InvalidAttributeError < TypeError
+ end
- end
+ class Attribute
+ include MooseX::Types
- class Attribute
- include MooseX::Types
+ attr_reader :attr_symbol, :is, :reader, :writter, :lazy, :builder, :methods, :override
+ DEFAULTS= {
+ is: :rw,
+ weak: false,
+ lazy: false,
+ clearer: false,
+ required: false,
+ predicate: false,
+ isa: isAny,
+ handles: {},
+ trigger: lambda {|object,value|}, # TODO: implement
+ coerce: lambda {|object| object}, # TODO: implement
+ doc: nil,
+ override: false,
+ }
- attr_reader :attr_symbol, :is, :reader, :writter, :lazy, :builder, :methods
- DEFAULTS= {
- lazy: false,
- clearer: false,
- required: false,
- predicate: false,
- isa: isAny,
- handles: {},
- trigger: lambda {|object,value|}, # TODO: implement
- coerce: lambda {|object| object}, # TODO: implement
- }
+ REQUIRED = []
- REQUIRED = [ :is ]
+ VALIDATE = {
+ is: lambda do |is, field_name|
+ unless [:rw, :rwp, :ro, :lazy, :private].include?(is)
+ raise InvalidAttributeError, "invalid value for field '#{field_name}' is '#{is}', must be one of :private, :rw, :rwp, :ro or :lazy"
+ end
+ end,
+ };
- VALIDATE = {
- is: lambda do |is, field_name|
- unless [:rw, :rwp, :ro, :lazy, :private].include?(is)
- raise InvalidAttributeError, "invalid value for field '#{field_name}' is '#{is}', must be one of :private, :rw, :rwp, :ro or :lazy"
- end
- end,
- };
+ COERCE = {
+ is: lambda do |is, field_name|
+ is.to_sym
+ end,
+ isa: lambda do |isa, field_name|
+ isType(isa)
+ end,
+ default: lambda do |default, field_name|
+ return default if default.is_a? Proc
- COERCE = {
- is: lambda do |is, field_name|
- is.to_sym
- end,
- isa: lambda do |isa, field_name|
- isType(isa)
- end,
- default: lambda do |default, field_name|
- return default if default.is_a? Proc
+ return lambda { default }
+ end,
+ required: lambda do |required, field_name|
+ !!required
+ end,
+ lazy: lambda do |lazy, field_name|
+ !!lazy
+ end,
+ predicate: lambda do |predicate, field_name|
+ if ! predicate
+ return false
+ elsif predicate.is_a? TrueClass
+ return "has_#{field_name}?".to_sym
+ end
- return lambda { default }
- end,
- required: lambda do |required, field_name|
- !!required
- end,
- lazy: lambda do |lazy, field_name|
- !!lazy
- end,
- predicate: lambda do |predicate, field_name|
- if ! predicate
- return false
- elsif predicate.is_a? TrueClass
- return "has_#{field_name}?".to_sym
- end
+ begin
+ predicate.to_sym
+ rescue => e
+ # create a nested exception here
+ raise InvalidAttributeError, "cannot coerce field predicate to a symbol for #{field_name}: #{e}"
+ end
+ end,
+ clearer: lambda do|clearer, field_name|
+ if ! clearer
+ return false
+ elsif clearer.is_a? TrueClass
+ return "clear_#{field_name}!".to_sym
+ end
+
+ begin
+ clearer.to_sym
+ rescue => e
+ # create a nested exception here
+ raise InvalidAttributeError, "cannot coerce field clearer to a symbol for #{field_name}: #{e}"
+ end
+ end,
+ handles: lambda do |handles, field_name|
+
+ unless handles.is_a? Hash
- begin
- predicate.to_sym
- rescue => e
- # create a nested exception here
- raise InvalidAttributeError, "cannot coerce field predicate to a symbol for #{field_name}: #{e}"
- end
- end,
- clearer: lambda do|clearer, field_name|
- if ! clearer
- return false
- elsif clearer.is_a? TrueClass
- return "clear_#{field_name}!".to_sym
- end
-
- begin
- clearer.to_sym
- rescue => e
- # create a nested exception here
- raise InvalidAttributeError, "cannot coerce field clearer to a symbol for #{field_name}: #{e}"
- end
- end,
- handles: lambda do |handles, field_name|
-
- unless handles.is_a? Hash
+ array_of_handles = handles
- array_of_handles = handles
+ unless array_of_handles.is_a? Array
+ array_of_handles = [ array_of_handles ]
+ end
- unless array_of_handles.is_a? Array
- array_of_handles = [ array_of_handles ]
- end
+ handles = array_of_handles.map do |handle|
- handles = array_of_handles.map do |handle|
+ if handle == BasicObject
+
+ raise InvalidAttributeError, "ops, should not use BasicObject for handles in #{field_name}"
+
+ elsif handle.is_a? Class
- if handle == BasicObject
-
- raise InvalidAttributeError, "ops, should not use BasicObject for handles in #{field_name}"
-
- elsif handle.is_a? Class
+ handle = handle.public_instance_methods - handle.superclass.public_instance_methods
+
+ elsif handle.is_a? Module
+
+ handle = handle.public_instance_methods
- handle = handle.public_instance_methods - handle.superclass.public_instance_methods
-
- elsif handle.is_a? Module
-
- handle = handle.public_instance_methods
+ end
+
+ handle
- end
-
- handle
+ end.flatten.reduce({}) do |hash, method_name|
+ hash.merge({ method_name => method_name })
+ end
+ end
- end.flatten.reduce({}) do |hash, method_name|
- hash.merge({ method_name => method_name })
- end
- end
-
- handles.map do |key,value|
+ handles.map do |key,value|
if value.is_a? Hash
raise "ops! Handle should accept only one map / currying" unless value.count == 1
original, currying = value.shift
{ key.to_sym => [original.to_sym, currying] }
else
- { key.to_sym => value.to_sym }
+ { key.to_sym => value.to_sym }
end
- end.reduce({}) do |hash,e|
- hash.merge(e)
- end
- end,
- reader: lambda do |reader, field_name|
- reader.to_sym
- end,
- writter: lambda do |writter, field_name|
- writter.to_sym
- end,
- builder: lambda do |builder, field_name|
- unless builder.is_a? Proc
- builder_method_name = builder.to_sym
- builder = lambda do |object|
- object.send(builder_method_name)
- end
- end
+ end.reduce({}) do |hash,e|
+ hash.merge(e)
+ end
+ end,
+ reader: lambda do |reader, field_name|
+ reader.to_sym
+ end,
+ writter: lambda do |writter, field_name|
+ writter.to_sym
+ end,
+ builder: lambda do |builder, field_name|
+ unless builder.is_a? Proc
+ builder_method_name = builder.to_sym
+ builder = lambda do |object|
+ object.send(builder_method_name)
+ end
+ end
- builder
- end,
- init_arg: lambda do |init_arg, field_name|
- init_arg.to_sym
- end,
- trigger: lambda do |trigger, field_name|
- unless trigger.is_a? Proc
- trigger_method_name = trigger.to_sym
- trigger = lambda do |object, value|
- object.send(trigger_method_name,value)
- end
- end
+ builder
+ end,
+ init_arg: lambda do |init_arg, field_name|
+ init_arg.to_sym
+ end,
+ trigger: lambda do |trigger, field_name|
+ unless trigger.is_a? Proc
+ trigger_method_name = trigger.to_sym
+ trigger = lambda do |object, value|
+ object.send(trigger_method_name,value)
+ end
+ end
- trigger
- end,
- coerce: lambda do |coerce, field_name|
- unless coerce.is_a? Proc
- coerce_method_name = coerce.to_sym
- coerce = lambda do |object|
- object.send(coerce_method_name)
- end
- end
+ trigger
+ end,
+ coerce: lambda do |coerce, field_name|
+ unless coerce.is_a? Proc
+ coerce_method_name = coerce.to_sym
+ coerce = lambda do |object|
+ object.send(coerce_method_name)
+ end
+ end
- coerce
- end,
- };
+ coerce
+ end,
+ weak: lambda do |weak, field_name|
+ !! weak
+ end,
+ doc: lambda do |doc, field_name|
+ doc.to_s
+ end,
+ override: lambda do |override, field_name|
+ !! override
+ end,
+ };
- 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,
- builder: "build_#{a}".to_sym,
- init_arg: a,
- }).merge(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,
+ builder: "build_#{a}".to_sym,
+ init_arg: a,
+ }).merge(o)
- REQUIRED.each { |field|
- unless o.has_key?(field)
- raise InvalidAttributeError, "field #{field} is required for Attribute #{a}"
- end
- }
- COERCE.each_pair do |field, coerce|
- if o.has_key? field
- o[field] = coerce.call(o[field], a)
- end
- end
- VALIDATE.each_pair do |field, validate|
- return if ! o.has_key? field
+ REQUIRED.each { |field|
+ unless o.has_key?(field)
+ raise InvalidAttributeError, "field #{field} is required for Attribute #{a}"
+ end
+ }
+ COERCE.each_pair do |field, coerce|
+ if o.has_key? field
+ o[field] = coerce.call(o[field], a)
+ end
+ end
+ VALIDATE.each_pair do |field, validate|
+ return if ! o.has_key? field
- validate.call(o[field], a)
- end
+ validate.call(o[field], a)
+ end
- if o[:is].eql? :ro
- o[:writter] = nil
- elsif o[:is].eql? :lazy
- o[:lazy] = true
- o[:writter] = nil
- end
+ if o[:is].eql? :ro
+ o[:writter] = nil
+ elsif o[:is].eql? :lazy
+ o[:lazy] = true
+ o[:writter] = nil
+ end
- unless o[:lazy]
- o[:builder] = nil
- end
+ unless o[:lazy]
+ o[:builder] = nil
+ end
- @attr_symbol = a
- @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 = {}
+ if o[:weak]
+ old_coerce = o[:coerce]
+ o[:coerce] = lambda do |value|
+ WeakRef.new old_coerce.call(value)
+ end
+ end
- MooseX.warn "Unused attributes #{o} for attribute #{a} @ #{x} #{x.class}",caller() if ! o.empty?
+ @attr_symbol = a
+ @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)
+ @weak = o.delete(:weak)
+ @documentation = o.delete(:doc)
+ @override = o.delete(:override)
+ @methods = {}
- if @reader
- @methods[@reader] = generate_reader
- end
-
- if @writter
- @methods[@writter] = generate_writter
- end
- inst_variable_name = "@#{@attr_symbol}".to_sym
- if @predicate
- @methods[@predicate] = Proc.new do
- instance_variable_defined? inst_variable_name
- end
- end
+ MooseX.warn "Unused attributes #{o} for attribute #{a} @ #{x} #{x.class}",caller() if ! o.empty?
- if @clearer
- @methods[@clearer] = Proc.new do
- if instance_variable_defined? inst_variable_name
- remove_instance_variable inst_variable_name
- end
- end
- end
-
- attr_symbol = @attr_symbol
- @handles.each_pair do | method, target_method |
- if target_method.is_a? Array
- original, currying = target_method
+ if @reader
+ @methods[@reader] = generate_reader
+ end
+
+ if @writter
+ @methods[@writter] = generate_writter
+ end
+ inst_variable_name = "@#{@attr_symbol}".to_sym
+ if @predicate
+ @methods[@predicate] = Proc.new do
+ instance_variable_defined? inst_variable_name
+ end
+ end
- @methods[method] = Proc.new do |*args, &proc|
-
- a1 = [ currying ]
-
- if currying.is_a?Proc
- a1 = currying.call()
- elsif currying.is_a? Array
- a1 = currying.map{|c| (c.is_a?(Proc)) ? c.call : c }
- end
-
- self.send(attr_symbol).send(original, *a1, *args, &proc)
- end
- else
- @methods[method] = Proc.new do |*args, &proc|
- self.send(attr_symbol).send(target_method, *args, &proc)
- end
- end
- end
- end
-
- def init(object, args)
- value = nil
- value_from_default = false
-
- if args.has_key? @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"
- else
- return
- end
+ if @clearer
+ @methods[@clearer] = Proc.new do
+ if instance_variable_defined? inst_variable_name
+ remove_instance_variable inst_variable_name
+ end
+ end
+ end
+
+ attr_symbol = @attr_symbol
+ @handles.each_pair do | method, target_method |
+ if target_method.is_a? Array
+ original, currying = target_method
- value = @coerce.call(value)
- begin
- @isa.call( value )
- rescue MooseX::Types::TypeCheckError => e
- raise MooseX::Types::TypeCheckError, "isa check for field #{attr_symbol}: #{e}"
- end
- unless value_from_default
- @trigger.call(object, value)
- end
- inst_variable_name = "@#{@attr_symbol}".to_sym
- object.instance_variable_set inst_variable_name, value
- end
+ @methods[method] = Proc.new do |*args, &proc|
+
+ a1 = [ currying ]
+
+ if currying.is_a?Proc
+ a1 = currying.call()
+ elsif currying.is_a? Array
+ a1 = currying.map{|c| (c.is_a?(Proc)) ? c.call : c }
+ end
+
+ self.send(attr_symbol).send(original, *a1, *args, &proc)
+ end
+ else
+ @methods[method] = Proc.new do |*args, &proc|
+ self.send(attr_symbol).send(target_method, *args, &proc)
+ end
+ end
+ end
+ end
+
+ def init(object, args)
+ value = nil
+ value_from_default = false
+
+ if args.has_key? @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"
+ else
+ return
+ end
- private
- def generate_reader
- inst_variable_name = "@#{@attr_symbol}".to_sym
-
- builder = @builder
- before_get = lambda {|object| }
+ value = @coerce.call(value)
+ begin
+ @isa.call( value )
+ rescue MooseX::Types::TypeCheckError => e
+ raise MooseX::Types::TypeCheckError, "isa check for field #{attr_symbol}: #{e}"
+ end
+ unless value_from_default
+ @trigger.call(object, value)
+ end
+ inst_variable_name = "@#{@attr_symbol}".to_sym
+ object.instance_variable_set inst_variable_name, value
+ end
- if @lazy
- type_check = @isa
- coerce = @coerce
- trigger = @trigger
- before_get = lambda do |object|
- return if object.instance_variable_defined? inst_variable_name
+ private
+ def generate_reader
+ inst_variable_name = "@#{@attr_symbol}".to_sym
+
+ builder = @builder
+ before_get = lambda {|object| }
- value = builder.call(object)
- value = coerce.call(value)
- begin
- type_check.call( value )
- rescue MooseX::Types::TypeCheckError => e
- raise MooseX::Types::TypeCheckError, "isa check for #{inst_variable_name} from builder: #{e}"
- end
+ if @lazy
+ type_check = @isa
+ coerce = @coerce
+ trigger = @trigger
+ before_get = lambda do |object|
+ return if object.instance_variable_defined? inst_variable_name
- trigger.call(object, value)
- object.instance_variable_set(inst_variable_name, value)
- end
- end
+ value = builder.call(object)
+ value = coerce.call(value)
+ begin
+ type_check.call( value )
+ rescue MooseX::Types::TypeCheckError => e
+ raise MooseX::Types::TypeCheckError, "isa check for #{inst_variable_name} from builder: #{e}"
+ end
- Proc.new do
- before_get.call(self)
- instance_variable_get inst_variable_name
- end
- end
-
- def generate_writter
- writter_name = @writter
- inst_variable_name = "@#{@attr_symbol}".to_sym
- coerce = @coerce
- type_check = @isa
- trigger = @trigger
- Proc.new do |value|
- value = coerce.call(value)
- begin
- type_check.call( value )
- rescue MooseX::Types::TypeCheckError => e
- raise MooseX::Types::TypeCheckError, "isa check for #{writter_name}: #{e}"
- end
- trigger.call(self,value)
- instance_variable_set inst_variable_name, value
- end
- end
- end
-end
\ No newline at end of file
+ trigger.call(object, value)
+ object.instance_variable_set(inst_variable_name, value)
+ end
+ end
+
+ Proc.new do
+ before_get.call(self)
+ instance_variable_get inst_variable_name
+ end
+ end
+
+ def generate_writter
+ writter_name = @writter
+ inst_variable_name = "@#{@attr_symbol}".to_sym
+ coerce = @coerce
+ type_check = @isa
+ trigger = @trigger
+ Proc.new do |value|
+ value = coerce.call(value)
+ begin
+ type_check.call( value )
+ rescue MooseX::Types::TypeCheckError => e
+ raise MooseX::Types::TypeCheckError, "isa check for #{writter_name}: #{e}"
+ end
+ trigger.call(self,value)
+ instance_variable_set inst_variable_name, value
+ end
+ end
+ end
+end