lib/ctioga2/graphics/styles/base.rb in ctioga2-0.10.1 vs lib/ctioga2/graphics/styles/base.rb in ctioga2-0.11
- old
+ new
@@ -21,17 +21,57 @@
# All the styles
module Styles
# This style is the base class of a series of style objects that
# share one common feature: all their attributes can be set
- # using the set_from_hash function.
+ # using the #set_from_hash function.
class BasicStyle
OldAttrAccessor = method(:attr_accessor)
AllStyles = []
+ # Returns the list of valid aliases, including those defined
+ # in parent classes.
+ def self.aliases
+ ret = if superclass.respond_to? :aliases
+ superclass.aliases
+ else
+ {}
+ end
+ if @aliases
+ ret.merge!(@aliases)
+ end
+ return ret
+ end
+
+ def self.normalize_in(name, fmt = "%s")
+ name = name.to_s.downcase.gsub('-', '_')
+ als = self.aliases
+ if als
+ for k, v in als
+ if fmt % k == name
+ name = fmt % v
+ break
+ end
+ end
+ end
+ return name
+ end
+
+ def self.normalize_out(name)
+ return name.gsub('_', '-')
+ end
+
+ def self.normalize_hash(hsh, fmt = "%s")
+ ret = {}
+ for k,v in hsh
+ ret[normalize_in(k, fmt)] = v
+ end
+ return ret
+ end
+
def self.inherited(cls)
AllStyles << cls
end
# This redefinition of attr_accessor allows to track for the
@@ -55,10 +95,14 @@
else
[]
end
end
+ def self.defined_aliases
+ return @aliases || {}
+ end
+
# Returns the type of all attributes (chaining to the parent
# when applicable)
def self.attribute_types
return ( @attribute_types || {} ).
merge(
@@ -82,33 +126,35 @@
# for instance to have halign and valign as aliases for the
# less intuitive alignment and justification.
def self.typed_attribute(symbol, type)
sym = symbol.to_sym
self.attr_accessor(sym)
- type = CmdArg.new(type) unless type.respond_to? :string_to_type
+ # The unless type.respond_to? :string_to_type seems
+ type = CmdArg.new(type) # unless type.respond_to? :string_to_type
@attribute_types ||= {}
@attribute_types[sym] = type
return type
end
# Define an attribute to be the alias for something else.
- def self.alias_for(symbol, target)
- target = target.to_sym
- if ! @attribute_types[target]
- raise "Declaring alias #{symbol} for unexisting target #{target}"
+ #
+ # @todo Maybe make multiple aliases ?
+ def self.alias_for(what, target, define_methods = false)
+ target = self.normalize_in(target)
+ what = self.normalize_in(what)
+ @aliases ||= {}
+ @aliases[what] = target
+ if define_methods
+ alias_method what.to_sym, target.to_sym
+ alias_method "#{what}=".to_sym, "#{target}=".to_sym
end
- symbol = symbol.to_sym
- @attribute_types[symbol] = @attribute_types[target]
- @attributes << symbol
- alias_method symbol, target
- alias_method "#{symbol}=".to_sym, "#{target}=".to_sym
end
# Returns the type of an attribute, or _nil_ if there is no
# attribute of that name. Handles sub-styles correctly.
def self.attribute_type(symbol, fmt = "%s")
- name = symbol.to_s
+ name = self.normalize_in(symbol.to_s, fmt)
for k,v in attribute_types
if (fmt % k.to_s) == name
if v.respond_to? :type
return v.type
@@ -120,11 +166,11 @@
if @sub_styles # Not always present too
for sub in @sub_styles
sym, cls, fmt2, fc = *sub
f = fmt % fmt2
- ret = cls.attribute_type(symbol, f)
+ ret = cls.attribute_type(name, f)
return ret if ret
end
end
return nil
end
@@ -177,10 +223,20 @@
fmt = key % fmt
ret.merge!(cls.options_hash(fmt))
end
end
+ # And now we expand options
+ if @aliases
+ for k, v in @aliases
+ v = key % v
+ if ret.key?(v)
+ ret[key % k] = ret[v]
+ end
+ end
+ end
+
return ret
end
def self.sub_styles
return @sub_styles
@@ -199,10 +255,11 @@
# @todo Maybe there should be a way to detect extra attributes ?
#
# This function returns the number of properties that were
# effectively set (including those set in sub-styles)
def set_from_hash(hash, name = "%s")
+ hash = self.class.normalize_hash(hash, name)
nb_set = 0
for key_name in self.class.attributes
hash_key = name % key_name
if hash.key? hash_key
self.send("#{key_name}=", hash[hash_key])
@@ -254,24 +311,48 @@
end
end
end
# Converts to a hash. Does the reverse of #set_from_hash.
+ #
+ # _nil_ values get stripped off (but not false values, of course).
def to_hash(name = "%s")
retval = {}
for attr in self.class.attributes
if instance_variable_defined?("@#{attr}")
- retval[name % attr] = instance_variable_get("@#{attr}")
+ val = instance_variable_get("@#{attr}")
+ if ! val.nil?
+ retval[name % attr] = val
+ end
end
end
return retval
end
# Updates information from another object.
def update_from_other(other_object)
set_from_hash(other_object.to_hash)
end
+ # Converts a hash in text format into a format suitable for
+ # feeding to #set_from_hash. Only relevant keys are
+ # converted. Keys that exist in the options hash but are not
+ # Strings are left untouched
+ def self.convert_string_hash(opts, key = "%s")
+ cnv = self.options_hash(key)
+
+ ret = {}
+ for k,v in opts
+ if cnv.key? k
+ if v.is_a? String
+ ret[k] = cnv[k].type.string_to_type(v)
+ else
+ ret[k] = v
+ end
+ end
+ end
+ return ret
+ end
end
end
end
end