Class: CTioga2::Graphics::Styles::BasicStyle

Inherits:
Object
  • Object
show all
Defined in:
lib/ctioga2/graphics/styles/base.rb

Overview

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.

Constant Summary collapse

OldAttrAccessor =
method(:attr_accessor)
AllStyles =
[]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.alias_for(what, target, define_methods = false) ⇒ Object

TODO:

Maybe make multiple aliases ?

Define an attribute to be the alias for something else.



141
142
143
144
145
146
147
148
149
150
# File 'lib/ctioga2/graphics/styles/base.rb', line 141

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
end

.aliasesObject

Returns the list of valid aliases, including those defined in parent classes.



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/ctioga2/graphics/styles/base.rb', line 35

def self.aliases
  ret = if superclass.respond_to? :aliases
          superclass.aliases
        else
          {}
        end
  if @aliases
    ret.merge!(@aliases)
  end
  return ret
end

.attr_accessor(symbol) ⇒ Object

This redefinition of attr_accessor allows to track for the names of the attributes, while still showing them up properly documented in rdoc.



80
81
82
83
84
85
86
87
88
# File 'lib/ctioga2/graphics/styles/base.rb', line 80

def self.attr_accessor(symbol)
  cal = caller
  # if ! (caller[0] =~ /typed_attribute/)
  #   puts "Deprecated use at #{caller[0]}"
  # end
  @attributes ||= []
  @attributes << symbol
  OldAttrAccessor.call(symbol)
end

.attribute_type(symbol, fmt = "%s") ⇒ Object

Returns the type of an attribute, or nil if there is no attribute of that name. Handles sub-styles correctly.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/ctioga2/graphics/styles/base.rb', line 154

def self.attribute_type(symbol, fmt = "%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
      else
        return v
      end
    end
  end

  if @sub_styles        # Not always present too
    for sub in @sub_styles
      sym, cls, fmt2, fc = *sub
      f = fmt % fmt2
      ret = cls.attribute_type(name, f)
      return ret if ret
    end
  end
  return nil
end

.attribute_typesObject

Returns the type of all attributes (chaining to the parent when applicable)



106
107
108
109
110
111
112
113
114
115
# File 'lib/ctioga2/graphics/styles/base.rb', line 106

def self.attribute_types
  return ( @attribute_types || {} ).
    merge(
          if superclass.respond_to?(:attribute_types)
            superclass.attribute_types
          else
            {}
          end
          )
end

.attributesObject

Returns the list of attributes.



91
92
93
94
95
96
97
98
# File 'lib/ctioga2/graphics/styles/base.rb', line 91

def self.attributes
  return ( @attributes || [] ) + 
    if superclass.respond_to?(:attributes)
      superclass.attributes
    else
      []
    end
end

.convert_string_hash(opts, key = "%s") ⇒ Object

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



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/ctioga2/graphics/styles/base.rb', line 379

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

.defined_aliasesObject



100
101
102
# File 'lib/ctioga2/graphics/styles/base.rb', line 100

def self.defined_aliases
  return @aliases || {}
end

.deprecated_attribute(symbol, type, message = true) ⇒ Object

Adds a deprecated typed attribute



179
180
181
182
# File 'lib/ctioga2/graphics/styles/base.rb', line 179

def self.deprecated_attribute(symbol, type, message = true)
  type = self.typed_attribute(symbol, type)
  type.option_deprecated = message
end

.from_hash(hash, name = "%s") ⇒ Object

Creates a new object from a hash specification, just as in #set_from_hash.



308
309
310
311
312
# File 'lib/ctioga2/graphics/styles/base.rb', line 308

def self.from_hash(hash, name = "%s")
  obj = self.new
  obj.set_from_hash(hash, name)
  return obj
end

.inherited(cls) ⇒ Object



73
74
75
# File 'lib/ctioga2/graphics/styles/base.rb', line 73

def self.inherited(cls)
  AllStyles << cls
end

.normalize_hash(hsh, fmt = "%s") ⇒ Object



65
66
67
68
69
70
71
# File 'lib/ctioga2/graphics/styles/base.rb', line 65

def self.normalize_hash(hsh, fmt = "%s")
  ret = {}
  for k,v in hsh
    ret[normalize_in(k, fmt)] = v
  end
  return ret
end

.normalize_in(name, fmt = "%s") ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/ctioga2/graphics/styles/base.rb', line 47

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

.normalize_out(name) ⇒ Object



61
62
63
# File 'lib/ctioga2/graphics/styles/base.rb', line 61

def self.normalize_out(name)
  return name.gsub('_', '-')
end

.options_hash(key = "%s") ⇒ Object

Returns a hash suitable for using as an options hash.

key provides tuning of the key names.



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/ctioga2/graphics/styles/base.rb', line 207

def self.options_hash(key = "%s")
  ret = if superclass.respond_to?(:options_hash)
          superclass.options_hash(key)
        else
          {}
        end

  if @attribute_types   # Not always present
    for k, v in @attribute_types
      ret[key % k] = v
    end
  end

  if @sub_styles        # Not always present too
    for sub in @sub_styles
      sym, cls, fmt, fc = *sub
      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

.sub_style(symbol, cls, fmt = nil, force_create = false) ⇒ Object

Defines an accessor for an attribute which is a BasicStyle subclass in itself.

fmt is the thing fed to the subclass for the from_hash function.

if force_create is on, then the corresponding sub-object is created even if no property we set within.



192
193
194
195
196
197
198
199
200
201
202
# File 'lib/ctioga2/graphics/styles/base.rb', line 192

def self.sub_style(symbol, cls, fmt = nil, force_create = false)
  @sub_styles ||= []    # A list of [symbol, cls, fmt]
  
  if ! fmt
    fmt = "#{symbol.to_s}_%s"
  end
  
  @sub_styles << [symbol, cls, fmt, force_create]
  # Define the accessor
  OldAttrAccessor.call(symbol)
end

.sub_stylesObject



241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/ctioga2/graphics/styles/base.rb', line 241

def self.sub_styles
  # p [:ss, self]
  rv = if self.superclass.respond_to?(:sub_styles)
         self.superclass.sub_styles
       else
         []
       end
  # p [:sparents, self, rv]
  if @sub_styles
    rv += @sub_styles
  end
  # p [:sparents_own, self, rv]
  return rv
end

.typed_attribute(symbol, type) ⇒ Object

TODO:

There may be a reason to make some of the attributes

TODO:

Provide a function to make attributes “aliases” of

This function should be the main way now of declaring attributes, as it allows one to automatically generate an options hash for Command

private to some extent ?

others (but just on the hash side of the things), in order for instance to have halign and valign as aliases for the less intuitive alignment and justification.



128
129
130
131
132
133
134
135
136
# File 'lib/ctioga2/graphics/styles/base.rb', line 128

def self.typed_attribute(symbol, type)
  sym = symbol.to_sym
  self.attr_accessor(sym)
  # 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

Instance Method Details

#instance_variable_defined?(iv) ⇒ Boolean

Returns:

  • (Boolean)


318
319
320
321
322
323
324
325
# File 'lib/ctioga2/graphics/styles/base.rb', line 318

def instance_variable_defined?(iv)
  a = instance_variables.index(iv)
  if a && a >= 0 
    return true
  else
    return false
  end
end

#set_from_hash(hash, name = "%s") ⇒ Object

TODO:

Maybe there should be a way to detect extra attributes ?

Sets the values of the attributes from the given hash. Keys are looked under the form of

name % key_name

where key_name takes all the values of the attributes.

Unspecified attributes are not removed from the object. Extra keys are silently ignored.

This function returns the number of properties that were effectively set (including those set in sub-styles)



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/ctioga2/graphics/styles/base.rb', line 270

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])
      nb_set += 1
    end
  end

  if self.class.sub_styles
    for sub in self.class.sub_styles
      sym, cls, fmt, fc = *sub
      cur_var = self.send(sym)
      if ! cur_var        # Create if not present
        cur_var = cls.new
        set_after = true
      end
      # p :bef, fmt
      fmt = name % fmt
      # p :aft, fmt
      nb = cur_var.set_from_hash(hash, fmt)

      # Here, this means that missing attributes do not get
      # created.
      if (nb > 0 or fc)  and set_after
        self.send("#{sym}=", cur_var)
      end
      nb_set += nb
    end
  end
  return nb_set
    
end

#to_hash(name = "%s") ⇒ Object

Converts to a hash. Does the reverse of #set_from_hash.

nil values get stripped off (but not false values, of course).



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/ctioga2/graphics/styles/base.rb', line 331

def to_hash(name = "%s")
  retval = {}
  for attr in self.class.attributes
    if instance_variable_defined?("@#{attr}")
      val = instance_variable_get("@#{attr}")
      if ! val.nil?
        retval[name % attr] = val
      end
    end
  end

  # Now, substyles
  for sb in self.class.sub_styles
    symb, cls, fmt, fc = *sb
    if instance_variable_defined?("@#{symb.to_s}")
      sub = instance_variable_get("@#{symb.to_s}")
      fmt = name % fmt
      if ! sub.nil?
        retval.update(sub.to_hash(fmt))
      end
    end
  end
  return retval
end

#update_from_other(other_object) ⇒ Object

Updates information from another object.



357
358
359
# File 'lib/ctioga2/graphics/styles/base.rb', line 357

def update_from_other(other_object)
  set_from_hash(other_object.to_hash)
end

#use_defaults_from(hsh) ⇒ Object

Sets the style from the given hash or other object, if the style is not present yet.



363
364
365
366
367
368
369
370
371
372
373
# File 'lib/ctioga2/graphics/styles/base.rb', line 363

def use_defaults_from(hsh)
  if hsh.is_a? BasicStyle
    hsh = hsh.to_hash
  end
  at = self.class.attribute_types
  for k, v in hsh
    if at.key?(k.to_sym) and ! instance_variable_defined?("@#{k}".to_sym)
      self.send("#{k}=", v)
    end
  end
end