lib/moosex.rb in moosex-0.0.7 vs lib/moosex.rb in moosex-0.0.8

- old
+ new

@@ -65,32 +65,32 @@ attr = MooseX::Attribute.new(attr_name, attr_options) g = attr.generate_getter - define_method attr.attr_symbol, &g + define_method attr.reader, &g s = attr.generate_setter case attr.is when :rw - define_method "#{attr.attr_symbol}=", &s + define_method attr.writter, &s when :rwp - define_method "#{attr.attr_symbol}=", &s + define_method attr.writter, &s - private "#{attr.attr_symbol}=" + private attr.writter end __meta.add(attr) end end end class Attribute - attr_reader :attr_symbol, :is + attr_reader :attr_symbol, :is, :reader, :writter, :lazy, :builder DEFAULTS= { lazy: false, clearer: false, required: false, predicate: false, @@ -104,11 +104,10 @@ is: lambda do |is, field_name| unless [:rw, :rwp, :ro, :lazy].include?(is) raise "invalid value for field '#{field_name}' is '#{is}', must be one of :rw, :rwp, :ro or :lazy" end end, - handles: lambda {|handles, field_name| true }, # TODO: add implementation }; COERCE = { is: lambda do |is, field_name| is.to_sym @@ -197,17 +196,42 @@ handles.map do |key,value| { key.to_sym => value.to_sym } end.reduce({}) do |hash,e| hash.merge(e) end - 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, }; def initialize(a, o) # todo extract this to a framework, see issue #21 on facebook - o = DEFAULTS.merge(o) + 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 "field #{field} is required for Attribute #{a}" end } @@ -218,10 +242,18 @@ end VALIDATE.each_pair do |field, validate| return if ! o.has_key? field validate.call(o[field], a) + end + + if o[:is].eql? :lazy + o[:lazy] = true + end + + unless o[:lazy] + o[:builder] = nil end @attr_symbol = a @is = o[:is] @isa = o[:isa] @@ -229,16 +261,19 @@ @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] end def init(object, args) inst_variable_name = "@#{@attr_symbol}".to_sym - setter = @attr_symbol.to_s.concat("=").to_sym value = nil attr_symbol = @attr_symbol @handles.each_pair do | method, target_method | object.define_singleton_method method do |*args| @@ -258,50 +293,66 @@ remove_instance_variable inst_variable_name end end end - if args.has_key? @attr_symbol - value = args[ @attr_symbol ] + if args.has_key? @init_arg + value = args[ @init_arg ] elsif @default value = @default.call elsif @required raise "attr \"#{@attr_symbol}\" is required" else return end - if @is.eql? :ro + if @is.eql?(:ro) || @is.eql?(:lazy) # TODO: remove redundancy - type_check = generate_type_check + type_check = @isa type_check.call(value) + object.instance_variable_set inst_variable_name, value else - object.send( setter, value ) + object.send( @writter, value ) end end def generate_getter inst_variable_name = "@#{@attr_symbol}".to_sym - Proc.new { instance_variable_get inst_variable_name } + + builder = @builder + before_get = lambda {|object| } + + if @lazy + type_check = @isa + + before_get = lambda do |object| + return if object.instance_variable_defined? inst_variable_name + + value = builder.call(object) + type_check.call(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_setter inst_variable_name = "@#{@attr_symbol}".to_sym - type_check = generate_type_check + type_check = @isa Proc.new do |value| type_check.call(value) instance_variable_set inst_variable_name, value end - end - - def generate_type_check - - return @isa - end + end end end \ No newline at end of file