Initial shot of "new" rake-based builder
Based on SVN https://swing.fit.cvut.cz/svn/stx/goodies/builder/trunk/rake@592
module Rake
end
module Rake::StX
end
class Object
def self.new_property_value(*args, &block)
if self == Object
return args[0]
else
return self.new(*args, &block)
end
end
end
class Proc
def self.new_property_value(*args, &block)
# TODO: add check
return args[0]
end
end
class Fixnum
def self.new_property_value(*args, &block)
# TODO: add check
return args[0]
end
end
class Symbol
def self.new_property_value(*args, &block)
# TODO: add check
return args[0].to_sym
end
end
module Rake::StX::DSL
# Base class for DSL object that may have properties
class Object
# Class-instance variable to hold property definitions
@property_definitions = {}
attr_accessor :properties
def self.property(name, properties = {})
@property_definitions ||= {}
if @property_definitions.include? name
raise Exception.new("Property #{name} already defined in class #{self.name}")
else
prop_def_class = properties[:property_definition_class] || PropertyDefinition
@property_definitions[name] = prop_def_class.new(name, self, properties)
end
end
def self.property_defined?(name)
@property_definitions ||= {}
if @property_definitions.include? name
return @property_definitions[name]
else
if self == Rake::StX::DSL::Object
return nil
else
return self.superclass.property_defined?(name)
end
end
end
def self.property_definition(name)
prop_def = self.property_defined?(name)
if not prop_def
raise Exception.new("Property #{name} not defined in class #{self.class.name}")
end
return prop_def
end
def _get_property(name)
@properties ||= {}
prop = @properties[name]
if prop
return prop.value
else
return self.class.property_definition(name).default
end
end
def _set_property(name, source = '<unknown source>', *args, &block)
@properties ||= {}
prop_def = self.class.property_definition(name)
prop = prop_def.instantiate(name, source, @properties[name], args, &block)
@properties[name] = prop
end
def property_defined?(name)
return false if not self.class.property_defined? name
return false if @properties == nil
return @properties.has_key? name
end
def _set_property_value(name, value, source = '<unknown source>')
@properties ||= {}
self.class.property_definition(name).validate(value)
prop = Property.new(name, value, source, @properties[name])
@properties[name] = prop
end
def clone()
c = super()
c.properties = {}
@properties.each do | name, prop |
c.properties[name] = prop.clone()
end
return c
end
def merge(other)
_merge_properties(other)
return self
end
def _merge_properties(other)
other.properties.each do | name, prop |
if not @properties.key? name
@properties[name] = prop.clone()
end
end
end
end # Object
class PropertyDefinition < Object
attr_accessor :name, :default
def initialize(name, owning_class, properties = {})
@name = name
@owning_class = owning_class
@values = properties[:values]
@klass = @values ? nil : (properties[:class] || String)
@type = properties[:type] || :scalar
if properties.include? :default
@default = properties[:default]
else
@default = nil
end
define_getter()
define_setter()
end
def default
return @default
end
def valid?(value)
#return true
if @values
return @values.include? value
else
return value.kind_of? @klass
end
end
def validate(value)
if not valid? value
raise Exception.new("Invalid value (#{value.inspect}) for property :'#{@name}' defined in #{@owning_class.name}")
end
end
def instantiate(name, source, previous, args, &block)
begin
if @values
if not @values.include? args[0]
raise Exception.new("Value #{args[0]} not allowed (not one of: #{@values.join(", ")})")
else
value = args[0]
end
else
value = @klass.new_property_value(*args, &block)
end
return Property.new(name, value, source, previous)
rescue => e
puts e.backtrace.join("\n")
raise e.exception("Error when instantiating property :'#{name}' in class #{@owning_class.name}: #{e.message}")
end
end
def define_getter()
name = @name
@owning_class.send(:define_method, name) do | *args, &block |
if (args.empty? and not block_given?)
return self._get_property(name)
else
return self._set_property(name, caller()[1], *args, &block)
end
end
end
def define_setter()
name = @name
@owning_class.send(:define_method, "#{@name}=") do | value |
self._set_property_value(name, value, caller()[1])
end
end
end # PropertyDefinition
class Property
attr_reader :name, :value, :source, :overridden
def initialize(name, value, source = '<unknown source>' , overridden = nil)
@name = name
@value = value
@source = source || caller(4).first
@overridden = overridden
end
def clone()
if (@value.class == Symbol)
value = @value
elsif @value.class == NilClass
value = nil
elsif @value == true || @value == false
value = @value
else
value = @value.clone
end
overriden = @overriden == nil ? nil : @overridden.clone()
return self.class.new(@name, value, @source, overridden)
end
end # class Property
class PropertyException < Exception
end
class PropertyNotFoundException < PropertyException
end
class InvalidPropertyValueException < PropertyException
end
end