ctioga2 0.10.1 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Changelog +18 -0
- data/bin/ctioga2 +28 -0
- data/lib/ctioga2/commands/commands.rb +1 -0
- data/lib/ctioga2/commands/doc/documentation-commands.rb +13 -0
- data/lib/ctioga2/commands/doc/help.rb +3 -2
- data/lib/ctioga2/commands/doc/html.rb +48 -0
- data/lib/ctioga2/commands/doc/introspection.rb +2 -2
- data/lib/ctioga2/commands/general-types.rb +10 -0
- data/lib/ctioga2/commands/parsers/file.rb +23 -2
- data/lib/ctioga2/data/backends/backends.rb +1 -2
- data/lib/ctioga2/data/backends/backends/smath.rb +129 -0
- data/lib/ctioga2/data/backends/backends/text.rb +1 -0
- data/lib/ctioga2/data/dataset.rb +1 -1
- data/lib/ctioga2/data/stack.rb +13 -3
- data/lib/ctioga2/graphics/elements.rb +2 -0
- data/lib/ctioga2/graphics/elements/containers.rb +3 -1
- data/lib/ctioga2/graphics/elements/element.rb +194 -5
- data/lib/ctioga2/graphics/elements/gradient-region.rb +5 -2
- data/lib/ctioga2/graphics/elements/histogram.rb +7 -2
- data/lib/ctioga2/graphics/elements/plot-elements.rb +88 -0
- data/lib/ctioga2/graphics/elements/primitive.rb +28 -12
- data/lib/ctioga2/graphics/elements/region.rb +6 -1
- data/lib/ctioga2/graphics/elements/style-lists.rb +2 -2
- data/lib/ctioga2/graphics/elements/subplot.rb +3 -3
- data/lib/ctioga2/graphics/elements/tangent.rb +5 -8
- data/lib/ctioga2/graphics/generator.rb +10 -0
- data/lib/ctioga2/graphics/geometry.rb +96 -0
- data/lib/ctioga2/graphics/legends.rb +4 -2
- data/lib/ctioga2/graphics/legends/area.rb +12 -4
- data/lib/ctioga2/graphics/root.rb +16 -14
- data/lib/ctioga2/graphics/styles.rb +5 -2
- data/lib/ctioga2/graphics/styles/arrows.rb +5 -0
- data/lib/ctioga2/graphics/styles/axes.rb +1 -1
- data/lib/ctioga2/graphics/styles/base.rb +95 -14
- data/lib/ctioga2/graphics/styles/curve.rb +8 -0
- data/lib/ctioga2/graphics/styles/drawable.rb +35 -48
- data/lib/ctioga2/graphics/styles/factory.rb +23 -23
- data/lib/ctioga2/graphics/styles/fill.rb +268 -0
- data/lib/ctioga2/graphics/styles/plot.rb +90 -46
- data/lib/ctioga2/graphics/styles/sets.rb +3 -0
- data/lib/ctioga2/graphics/styles/{sheet.rb → styles.rb} +70 -160
- data/lib/ctioga2/graphics/styles/stylesheet.rb +355 -0
- data/lib/ctioga2/graphics/styles/texts.rb +4 -2
- data/lib/ctioga2/graphics/styles/ticks.rb +44 -4
- data/lib/ctioga2/graphics/subplot-commands.rb +84 -9
- data/lib/ctioga2/graphics/types.rb +1 -1
- data/lib/ctioga2/graphics/types/dimensions.rb +40 -0
- data/lib/ctioga2/graphics/types/grid.rb +21 -5
- data/lib/ctioga2/graphics/types/point.rb +2 -1
- data/lib/ctioga2/log.rb +5 -1
- data/lib/ctioga2/metabuilder/types/styles.rb +11 -7
- data/lib/ctioga2/plotmaker.rb +2 -0
- data/lib/ctioga2/utils.rb +21 -6
- data/lib/ctioga2/version.rb +2 -2
- metadata +105 -108
@@ -29,6 +29,8 @@ module CTioga2
|
|
29
29
|
undef :elements
|
30
30
|
undef :subframe
|
31
31
|
|
32
|
+
define_style 'region'
|
33
|
+
|
32
34
|
# The curves which delimit the region
|
33
35
|
attr_accessor :curves
|
34
36
|
|
@@ -39,7 +41,10 @@ module CTioga2
|
|
39
41
|
attr_accessor :reversed_fill_style
|
40
42
|
|
41
43
|
# Creates a new empty region
|
42
|
-
def initialize(parent
|
44
|
+
def initialize(parent, root, opts)
|
45
|
+
setup_style(parent, opts)
|
46
|
+
# A reason why we don't use the superclass constructor ?
|
47
|
+
|
43
48
|
@parent = parent
|
44
49
|
@clipped = true # clipped by default !
|
45
50
|
|
@@ -241,7 +241,7 @@ module CTioga2
|
|
241
241
|
|
242
242
|
tdy = txt_dy + box_dy
|
243
243
|
|
244
|
-
sets = Styles::CurveStyleFactory::parameters['
|
244
|
+
sets = Styles::CurveStyleFactory::parameters['color'].sets
|
245
245
|
|
246
246
|
set_names = sets.keys.sort
|
247
247
|
|
@@ -306,7 +306,7 @@ module CTioga2
|
|
306
306
|
|
307
307
|
tdy = txt_dy + box_dy
|
308
308
|
|
309
|
-
sets = Styles::CurveStyleFactory::parameters['
|
309
|
+
sets = Styles::CurveStyleFactory::parameters['marker'].sets
|
310
310
|
|
311
311
|
set_names = sets.keys.sort
|
312
312
|
|
@@ -46,8 +46,8 @@ module CTioga2
|
|
46
46
|
# as #real_do hasn't been entered into.
|
47
47
|
attr_accessor :computed_boundaries
|
48
48
|
|
49
|
-
def initialize(parent, root,
|
50
|
-
super(parent, root)
|
49
|
+
def initialize(parent, root, opts)
|
50
|
+
super(parent, root, opts)
|
51
51
|
|
52
52
|
@subframe = Types::MarginsBox.new("2.8dy", "2.8dy",
|
53
53
|
"2.8dy", "2.8dy")
|
@@ -56,7 +56,7 @@ module CTioga2
|
|
56
56
|
|
57
57
|
@prev_subframe = nil
|
58
58
|
|
59
|
-
@style =
|
59
|
+
@style = Styles::PlotStyle.new(self)
|
60
60
|
|
61
61
|
@user_boundaries = {}
|
62
62
|
|
@@ -30,12 +30,13 @@ module CTioga2
|
|
30
30
|
'xextent' => 'float',
|
31
31
|
'yextent' => 'float',
|
32
32
|
'nbavg' => 'integer',
|
33
|
-
|
34
|
-
}.update(Styles::ArrowStyle::options_hash)
|
33
|
+
} # .update(Styles::ArrowStyle::options_hash)
|
35
34
|
|
36
35
|
TiogaPrimitiveCall.
|
37
|
-
|
38
|
-
|
36
|
+
styled_primitive("tangent", "tangent", [ 'data-point'],
|
37
|
+
Styles::ArrowStyle,
|
38
|
+
'arrow', [],
|
39
|
+
TangentOptions) do |t, point,style,options|
|
39
40
|
options ||= {}
|
40
41
|
nb = options['nbavg'] || 7
|
41
42
|
x = point.x_val(nb)
|
@@ -81,10 +82,6 @@ module CTioga2
|
|
81
82
|
options['color'] = $last_curve_style.line.color
|
82
83
|
end
|
83
84
|
|
84
|
-
st_name = options['base-style'] || "base"
|
85
|
-
style = Styles::StyleSheet.style_for(Styles::ArrowStyle ,st_name)
|
86
|
-
style.set_from_hash(options)
|
87
|
-
|
88
85
|
coords = options['tail'] + options['head']
|
89
86
|
style.draw_arrow(t, *coords)
|
90
87
|
end
|
@@ -85,6 +85,7 @@ module CTioga2
|
|
85
85
|
plot.style.apply_transforms!(dataset)
|
86
86
|
end
|
87
87
|
|
88
|
+
old_opts = options.dup
|
88
89
|
# Now, we trim options unrelated to the plotting
|
89
90
|
options.delete_if { |k,v|
|
90
91
|
! Graphics::Styles::
|
@@ -99,6 +100,15 @@ module CTioga2
|
|
99
100
|
# over the one specified by
|
100
101
|
# --legend.
|
101
102
|
curve = send(@current_curves, dataset, style)
|
103
|
+
|
104
|
+
# Here, we update the style from the stylesheet and then
|
105
|
+
# again from the options, so that the options provided on
|
106
|
+
# the command-line take precedence.
|
107
|
+
curve.setup_style(plot, old_opts)
|
108
|
+
curve.update_style(curve.curve_style)
|
109
|
+
curve.curve_style.
|
110
|
+
set_from_hash(@style_factory.hash_name_to_target(options))
|
111
|
+
|
102
112
|
curve.curve_style.target = curve
|
103
113
|
end
|
104
114
|
return curve
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# geometry.rb: various geometry-related utility classes
|
2
|
+
# copyright (c) 2014 by Vincent Fourmond
|
3
|
+
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details (in the COPYING file).
|
13
|
+
|
14
|
+
require 'ctioga2/utils'
|
15
|
+
require 'ctioga2/log'
|
16
|
+
|
17
|
+
module CTioga2
|
18
|
+
|
19
|
+
# This module contains all graphical elements of CTioga2
|
20
|
+
module Graphics
|
21
|
+
|
22
|
+
|
23
|
+
# A geometry line, ie something that has a starting point and a
|
24
|
+
# direction. It is infinite
|
25
|
+
class Line
|
26
|
+
|
27
|
+
# Checks if within the bounds of the line (but not necessarily
|
28
|
+
# ON the line)
|
29
|
+
def within_bounds?(x, y)
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_accessor :x, :y, :dx, :dy
|
34
|
+
|
35
|
+
def initialize(x, y, dx, dy)
|
36
|
+
@x = x.to_f
|
37
|
+
@y = y.to_f
|
38
|
+
@dx = dx.to_f
|
39
|
+
@dy = dy.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the X and Y positions of the intersection with the
|
43
|
+
# given Line, or false should there be none.
|
44
|
+
def intersection(line)
|
45
|
+
fact = @dx * line.dy - line.dx * @dy
|
46
|
+
rhs = @dy * (line.x - @x) - @dx * (line.y - @y)
|
47
|
+
if fact != 0 # There is a unique intersection
|
48
|
+
beta = rhs/fact
|
49
|
+
nx = line.x + beta * line.dx
|
50
|
+
ny = line.y + beta * line.dy
|
51
|
+
# elsif rhs == 0
|
52
|
+
# # Infinite, we return
|
53
|
+
# return
|
54
|
+
else
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
return [nx, ny] if (within_bounds?(nx, ny) and
|
58
|
+
line.within_bounds?(nx, ny))
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Same as line, but with a beginning and an end
|
64
|
+
class Segment < Line
|
65
|
+
|
66
|
+
attr_accessor :x2, :y2
|
67
|
+
|
68
|
+
def initialize(x1, y1, x2, y2)
|
69
|
+
@x2 = x2
|
70
|
+
@y2 = y2
|
71
|
+
super(x1, y1, x2 - x1, y2 - y1)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def within_bounds?(x, y)
|
76
|
+
return (
|
77
|
+
(
|
78
|
+
(x - @x) * (x - @x2) <= 0 or
|
79
|
+
(x - @x).abs < 1e-15 or
|
80
|
+
(x - @x2).abs < 1e-15
|
81
|
+
) and
|
82
|
+
((y - @y) * (y - @y2) <= 0 or
|
83
|
+
(y - @y).abs < 1e-15 or
|
84
|
+
(y - @y2).abs < 1e-15
|
85
|
+
)
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_line()
|
90
|
+
return Line.new(@x, @y, @dx, @dy)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
@@ -96,11 +96,13 @@ they have the same meaning as corresponding ones of
|
|
96
96
|
{command: define-box-style} with the @frame-@ bit dropped.
|
97
97
|
EOH
|
98
98
|
|
99
|
+
opts = LegendStyleOptions
|
100
|
+
opts.merge!(Elements::TiogaElement::StyleBaseOptions)
|
99
101
|
LegendInsideCommand =
|
100
102
|
Cmd.new("legend-inside", nil, "--legend-inside",
|
101
103
|
[ CmdArg.new('aligned-point')],
|
102
|
-
|
103
|
-
l = Legends::LegendArea.new(:inside)
|
104
|
+
opts) do |plotmaker, point, options|
|
105
|
+
l = Legends::LegendArea.new(:inside, plotmaker.root_object.current_plot, options)
|
104
106
|
l.legend_position = point
|
105
107
|
plotmaker.root_object.current_plot.legend_area = l
|
106
108
|
l.legend_style.set_from_hash(options)
|
@@ -35,8 +35,11 @@ module CTioga2
|
|
35
35
|
# @legend_area for the current Elements::Container, with the
|
36
36
|
# given position.
|
37
37
|
#
|
38
|
-
# \todo make a subclass for a top-level area ????
|
39
|
-
|
38
|
+
# \todo make a subclass for a top-level area ????
|
39
|
+
#
|
40
|
+
# This class is a subclass of Elements::TiogaElement so that it
|
41
|
+
# can be styled just like the rest.
|
42
|
+
class LegendArea < Elements::TiogaElement
|
40
43
|
|
41
44
|
# The style of the LegendStorage, a Styles::LegendStorageStyle
|
42
45
|
# object (of course)
|
@@ -44,14 +47,19 @@ module CTioga2
|
|
44
47
|
|
45
48
|
# The type of the legend. Can be :left, :right, :top, :bottom
|
46
49
|
# or :inside
|
50
|
+
#
|
51
|
+
# @todo Should this move inside the style ?
|
47
52
|
attr_accessor :legend_type
|
48
53
|
|
49
54
|
# The position of the LegendArea. Only significant when the
|
50
55
|
# type is :inside. A Types::AlignedPoint instance.
|
51
56
|
attr_accessor :legend_position
|
52
57
|
|
53
|
-
|
54
|
-
|
58
|
+
define_style 'legend', Styles::LegendStorageStyle
|
59
|
+
|
60
|
+
def initialize(type = :right, parent = nil, opts = {})
|
61
|
+
setup_style(parent, opts)
|
62
|
+
@legend_style = get_style()
|
55
63
|
@legend_type = type
|
56
64
|
@legend_position = Types::AlignedPoint.new(0.5,0.5,:frame)
|
57
65
|
end
|
@@ -48,7 +48,7 @@ module CTioga2
|
|
48
48
|
|
49
49
|
@container_stack = []
|
50
50
|
|
51
|
-
@legend_area = Legends::LegendArea.new
|
51
|
+
@legend_area = Legends::LegendArea.new(:right, nil, {'class' => 'root'})
|
52
52
|
|
53
53
|
@count_legend_in_page = false
|
54
54
|
# @count_legend_in_page = true
|
@@ -67,15 +67,17 @@ module CTioga2
|
|
67
67
|
if @current_container
|
68
68
|
return @current_container
|
69
69
|
else
|
70
|
-
subplot = Elements::Subplot.new(nil, self,
|
70
|
+
subplot = Elements::Subplot.new(nil, self,
|
71
|
+
{'id' => 'root' })
|
71
72
|
enter_subobject(subplot)
|
72
73
|
return subplot
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
76
|
-
# Enters into a new Elements::Container, _new_object_
|
77
|
-
|
78
|
-
|
77
|
+
# Enters into a new Elements::Container, _new_object_, and adds
|
78
|
+
# it to the current container, unless _add_ is false.
|
79
|
+
def enter_subobject(new_object, add = true)
|
80
|
+
if @current_container && add
|
79
81
|
@current_container.add_element(new_object)
|
80
82
|
end
|
81
83
|
@current_container = new_object
|
@@ -135,33 +137,33 @@ module CTioga2
|
|
135
137
|
#
|
136
138
|
# For the sake of convenience, returns the newly created
|
137
139
|
# Elements::Subplot
|
138
|
-
def subplot()
|
140
|
+
def subplot(opts)
|
139
141
|
if ! @current_container
|
140
|
-
enter_subobject(Elements::Container.new(nil, self))
|
142
|
+
enter_subobject(Elements::Container.new(nil, self, {}))
|
141
143
|
end
|
142
|
-
subplot = Elements::Subplot.new(@current_container, self,
|
144
|
+
subplot = Elements::Subplot.new(@current_container, self, opts)
|
143
145
|
enter_subobject(subplot)
|
144
146
|
return subplot
|
145
147
|
end
|
146
148
|
|
147
149
|
# This function is the companion of #subplot, but for Region
|
148
150
|
# objects. Returns the newly created Region.
|
149
|
-
def enter_region
|
151
|
+
def enter_region(opts)
|
150
152
|
if ! @current_container
|
151
|
-
subplot
|
153
|
+
subplot({})
|
152
154
|
end
|
153
|
-
region = Elements::Region.new(@current_container, self)
|
155
|
+
region = Elements::Region.new(@current_container, self, opts)
|
154
156
|
enter_subobject(region)
|
155
157
|
return region
|
156
158
|
end
|
157
159
|
|
158
160
|
# This function is the companion of #subplot, but for GradientRegion
|
159
161
|
# objects. Returns the newly created GradientRegion
|
160
|
-
def enter_gradient
|
162
|
+
def enter_gradient(opts)
|
161
163
|
if ! @current_container
|
162
|
-
subplot
|
164
|
+
subplot({})
|
163
165
|
end
|
164
|
-
region = Elements::GradientRegion.new(@current_container, self)
|
166
|
+
region = Elements::GradientRegion.new(@current_container, self, opts)
|
165
167
|
enter_subobject(region)
|
166
168
|
return region
|
167
169
|
end
|
@@ -14,6 +14,7 @@
|
|
14
14
|
require 'ctioga2/graphics/styles/base'
|
15
15
|
|
16
16
|
require 'ctioga2/graphics/styles/drawable'
|
17
|
+
require 'ctioga2/graphics/styles/fill'
|
17
18
|
require 'ctioga2/graphics/styles/arrows'
|
18
19
|
require 'ctioga2/graphics/styles/box'
|
19
20
|
require 'ctioga2/graphics/styles/location'
|
@@ -31,6 +32,8 @@ require 'ctioga2/graphics/styles/errorbar'
|
|
31
32
|
require 'ctioga2/graphics/styles/sets'
|
32
33
|
require 'ctioga2/graphics/styles/ticks'
|
33
34
|
|
35
|
+
require 'ctioga2/graphics/styles/curve'
|
36
|
+
|
34
37
|
require 'ctioga2/graphics/styles/axes'
|
35
38
|
require 'ctioga2/graphics/styles/map-axes'
|
36
39
|
require 'ctioga2/graphics/styles/background'
|
@@ -39,9 +42,9 @@ require 'ctioga2/graphics/styles/plot'
|
|
39
42
|
require 'ctioga2/graphics/styles/legend'
|
40
43
|
|
41
44
|
|
42
|
-
require 'ctioga2/graphics/styles/curve'
|
43
45
|
|
44
46
|
require 'ctioga2/graphics/styles/factory'
|
45
47
|
|
46
48
|
# Style sheets
|
47
|
-
require 'ctioga2/graphics/styles/
|
49
|
+
require 'ctioga2/graphics/styles/stylesheet'
|
50
|
+
require 'ctioga2/graphics/styles/styles'
|
@@ -146,7 +146,7 @@ minor_tick_length minor_tick_width)
|
|
146
146
|
end
|
147
147
|
t.show_axis(spec)
|
148
148
|
# Now, we draw axis ticks
|
149
|
-
if type == Tioga::FigureConstants::AXIS_WITH_MAJOR_TICKS_AND_NUMERIC_LABELS || type == Tioga::FigureConstants::AXIS_WITH_TICKS_AND_NUMERIC_LABELS
|
149
|
+
if (type == Tioga::FigureConstants::AXIS_WITH_MAJOR_TICKS_AND_NUMERIC_LABELS) || (type == Tioga::FigureConstants::AXIS_WITH_TICKS_AND_NUMERIC_LABELS)
|
150
150
|
|
151
151
|
fnc = info['vertical'] ? :convert_figure_to_frame_y : :convert_figure_to_frame_x
|
152
152
|
stl = @tick_label_style.dup
|
@@ -23,13 +23,53 @@ module CTioga2
|
|
23
23
|
|
24
24
|
# This style is the base class of a series of style objects that
|
25
25
|
# share one common feature: all their attributes can be set
|
26
|
-
# using the set_from_hash function.
|
26
|
+
# using the #set_from_hash function.
|
27
27
|
class BasicStyle
|
28
28
|
|
29
29
|
OldAttrAccessor = method(:attr_accessor)
|
30
30
|
|
31
31
|
AllStyles = []
|
32
32
|
|
33
|
+
# Returns the list of valid aliases, including those defined
|
34
|
+
# in parent classes.
|
35
|
+
def self.aliases
|
36
|
+
ret = if superclass.respond_to? :aliases
|
37
|
+
superclass.aliases
|
38
|
+
else
|
39
|
+
{}
|
40
|
+
end
|
41
|
+
if @aliases
|
42
|
+
ret.merge!(@aliases)
|
43
|
+
end
|
44
|
+
return ret
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.normalize_in(name, fmt = "%s")
|
48
|
+
name = name.to_s.downcase.gsub('-', '_')
|
49
|
+
als = self.aliases
|
50
|
+
if als
|
51
|
+
for k, v in als
|
52
|
+
if fmt % k == name
|
53
|
+
name = fmt % v
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
return name
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.normalize_out(name)
|
62
|
+
return name.gsub('_', '-')
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.normalize_hash(hsh, fmt = "%s")
|
66
|
+
ret = {}
|
67
|
+
for k,v in hsh
|
68
|
+
ret[normalize_in(k, fmt)] = v
|
69
|
+
end
|
70
|
+
return ret
|
71
|
+
end
|
72
|
+
|
33
73
|
def self.inherited(cls)
|
34
74
|
AllStyles << cls
|
35
75
|
end
|
@@ -57,6 +97,10 @@ module CTioga2
|
|
57
97
|
end
|
58
98
|
end
|
59
99
|
|
100
|
+
def self.defined_aliases
|
101
|
+
return @aliases || {}
|
102
|
+
end
|
103
|
+
|
60
104
|
# Returns the type of all attributes (chaining to the parent
|
61
105
|
# when applicable)
|
62
106
|
def self.attribute_types
|
@@ -84,29 +128,31 @@ module CTioga2
|
|
84
128
|
def self.typed_attribute(symbol, type)
|
85
129
|
sym = symbol.to_sym
|
86
130
|
self.attr_accessor(sym)
|
87
|
-
|
131
|
+
# The unless type.respond_to? :string_to_type seems
|
132
|
+
type = CmdArg.new(type) # unless type.respond_to? :string_to_type
|
88
133
|
@attribute_types ||= {}
|
89
134
|
@attribute_types[sym] = type
|
90
135
|
return type
|
91
136
|
end
|
92
137
|
|
93
138
|
# Define an attribute to be the alias for something else.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
139
|
+
#
|
140
|
+
# @todo Maybe make multiple aliases ?
|
141
|
+
def self.alias_for(what, target, define_methods = false)
|
142
|
+
target = self.normalize_in(target)
|
143
|
+
what = self.normalize_in(what)
|
144
|
+
@aliases ||= {}
|
145
|
+
@aliases[what] = target
|
146
|
+
if define_methods
|
147
|
+
alias_method what.to_sym, target.to_sym
|
148
|
+
alias_method "#{what}=".to_sym, "#{target}=".to_sym
|
98
149
|
end
|
99
|
-
symbol = symbol.to_sym
|
100
|
-
@attribute_types[symbol] = @attribute_types[target]
|
101
|
-
@attributes << symbol
|
102
|
-
alias_method symbol, target
|
103
|
-
alias_method "#{symbol}=".to_sym, "#{target}=".to_sym
|
104
150
|
end
|
105
151
|
|
106
152
|
# Returns the type of an attribute, or _nil_ if there is no
|
107
153
|
# attribute of that name. Handles sub-styles correctly.
|
108
154
|
def self.attribute_type(symbol, fmt = "%s")
|
109
|
-
name = symbol.to_s
|
155
|
+
name = self.normalize_in(symbol.to_s, fmt)
|
110
156
|
|
111
157
|
for k,v in attribute_types
|
112
158
|
if (fmt % k.to_s) == name
|
@@ -122,7 +168,7 @@ module CTioga2
|
|
122
168
|
for sub in @sub_styles
|
123
169
|
sym, cls, fmt2, fc = *sub
|
124
170
|
f = fmt % fmt2
|
125
|
-
ret = cls.attribute_type(
|
171
|
+
ret = cls.attribute_type(name, f)
|
126
172
|
return ret if ret
|
127
173
|
end
|
128
174
|
end
|
@@ -179,6 +225,16 @@ module CTioga2
|
|
179
225
|
end
|
180
226
|
end
|
181
227
|
|
228
|
+
# And now we expand options
|
229
|
+
if @aliases
|
230
|
+
for k, v in @aliases
|
231
|
+
v = key % v
|
232
|
+
if ret.key?(v)
|
233
|
+
ret[key % k] = ret[v]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
182
238
|
return ret
|
183
239
|
end
|
184
240
|
|
@@ -201,6 +257,7 @@ module CTioga2
|
|
201
257
|
# This function returns the number of properties that were
|
202
258
|
# effectively set (including those set in sub-styles)
|
203
259
|
def set_from_hash(hash, name = "%s")
|
260
|
+
hash = self.class.normalize_hash(hash, name)
|
204
261
|
nb_set = 0
|
205
262
|
for key_name in self.class.attributes
|
206
263
|
hash_key = name % key_name
|
@@ -256,11 +313,16 @@ module CTioga2
|
|
256
313
|
end
|
257
314
|
|
258
315
|
# Converts to a hash. Does the reverse of #set_from_hash.
|
316
|
+
#
|
317
|
+
# _nil_ values get stripped off (but not false values, of course).
|
259
318
|
def to_hash(name = "%s")
|
260
319
|
retval = {}
|
261
320
|
for attr in self.class.attributes
|
262
321
|
if instance_variable_defined?("@#{attr}")
|
263
|
-
|
322
|
+
val = instance_variable_get("@#{attr}")
|
323
|
+
if ! val.nil?
|
324
|
+
retval[name % attr] = val
|
325
|
+
end
|
264
326
|
end
|
265
327
|
end
|
266
328
|
return retval
|
@@ -271,6 +333,25 @@ module CTioga2
|
|
271
333
|
set_from_hash(other_object.to_hash)
|
272
334
|
end
|
273
335
|
|
336
|
+
# Converts a hash in text format into a format suitable for
|
337
|
+
# feeding to #set_from_hash. Only relevant keys are
|
338
|
+
# converted. Keys that exist in the options hash but are not
|
339
|
+
# Strings are left untouched
|
340
|
+
def self.convert_string_hash(opts, key = "%s")
|
341
|
+
cnv = self.options_hash(key)
|
342
|
+
|
343
|
+
ret = {}
|
344
|
+
for k,v in opts
|
345
|
+
if cnv.key? k
|
346
|
+
if v.is_a? String
|
347
|
+
ret[k] = cnv[k].type.string_to_type(v)
|
348
|
+
else
|
349
|
+
ret[k] = v
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
return ret
|
354
|
+
end
|
274
355
|
end
|
275
356
|
end
|
276
357
|
end
|