ctioga2 0.6.1 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +12 -0
- data/lib/ctioga2/commands/commands.rb +2 -1
- data/lib/ctioga2/commands/doc/help.rb +17 -7
- data/lib/ctioga2/commands/general-types.rb +8 -1
- data/lib/ctioga2/commands/interpreter.rb +3 -2
- data/lib/ctioga2/data/backends/backends/text.rb +13 -3
- data/lib/ctioga2/data/stack.rb +17 -2
- data/lib/ctioga2/graphics/elements/containers.rb +2 -1
- data/lib/ctioga2/graphics/elements/curve2d.rb +13 -19
- data/lib/ctioga2/graphics/elements/element.rb +51 -16
- data/lib/ctioga2/graphics/elements/parametric2d.rb +25 -31
- data/lib/ctioga2/graphics/elements/primitive.rb +20 -2
- data/lib/ctioga2/graphics/elements/subplot.rb +47 -9
- data/lib/ctioga2/graphics/elements/xyz-contour.rb +1 -10
- data/lib/ctioga2/graphics/elements/xyz-map.rb +2 -19
- data/lib/ctioga2/graphics/generator.rb +21 -4
- data/lib/ctioga2/graphics/styles/box.rb +63 -2
- data/lib/ctioga2/graphics/styles/colormap.rb +2 -2
- data/lib/ctioga2/graphics/styles/curve.rb +17 -1
- data/lib/ctioga2/graphics/styles/factory.rb +9 -2
- data/lib/ctioga2/graphics/styles/plot-types.rb +123 -0
- data/lib/ctioga2/graphics/styles/plot.rb +22 -4
- data/lib/ctioga2/graphics/types.rb +4 -2
- data/lib/ctioga2/log.rb +5 -2
- data/lib/ctioga2/metabuilder/type.rb +33 -9
- data/lib/ctioga2/plotmaker.rb +8 -2
- data/lib/ctioga2/postprocess.rb +39 -8
- data/lib/ctioga2/utils.rb +93 -3
- metadata +3 -2
@@ -0,0 +1,123 @@
|
|
1
|
+
# contour.rb: the style of a contour plot
|
2
|
+
# copyright (c) 2009 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
|
+
|
18
|
+
# This module contains all the classes used by ctioga
|
19
|
+
module CTioga2
|
20
|
+
|
21
|
+
Version::register_svn_info('$Revision$', '$Date$')
|
22
|
+
|
23
|
+
module Graphics
|
24
|
+
|
25
|
+
module Styles
|
26
|
+
|
27
|
+
StyleAspectRE = {
|
28
|
+
/^marker[_-]color$/i => :marker_color,
|
29
|
+
/^marker[_-](size|scale)$/i => :marker_scale,
|
30
|
+
}
|
31
|
+
|
32
|
+
StyleAspect =
|
33
|
+
CmdType.new('style-aspect', {:type => :re_list,
|
34
|
+
:list => StyleAspectRE}, <<EOD)
|
35
|
+
|
36
|
+
This type designs which aspect of the style of a
|
37
|
+
{command: xy-parametric} plot is controlled by a certain Z value.
|
38
|
+
It can take the following values:
|
39
|
+
* @marker_color@: the color for the markers
|
40
|
+
* @marker_size@/@marker_scale@: the size of the markers
|
41
|
+
EOD
|
42
|
+
|
43
|
+
# This class defines how the Z values are converted into
|
44
|
+
# stylistic information
|
45
|
+
class ParametricPlotStyle < BasicStyle
|
46
|
+
|
47
|
+
# What is the z1 axis
|
48
|
+
typed_attribute :z1, 'style-aspect'
|
49
|
+
|
50
|
+
# What is the z2 axis
|
51
|
+
typed_attribute :z2, 'style-aspect'
|
52
|
+
|
53
|
+
def initialize
|
54
|
+
@z1 = :marker_color
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare
|
58
|
+
@reversed = {}
|
59
|
+
|
60
|
+
2.times do |i|
|
61
|
+
val = self.send("z#{i+1}")
|
62
|
+
if val
|
63
|
+
@reversed[val] = i
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the marker style for the given Z values.
|
69
|
+
#
|
70
|
+
# This will only work if #prepare has been called first !
|
71
|
+
def marker_style(curve_style, zvalue, zmin, zmax)
|
72
|
+
|
73
|
+
style = curve_style.marker.dup
|
74
|
+
|
75
|
+
if @reversed[:marker_scale]
|
76
|
+
idx = @reversed[:marker_scale]
|
77
|
+
if idx < zvalue.size
|
78
|
+
max_scale = curve_style.marker.scale || 1.0
|
79
|
+
|
80
|
+
## @todo Later on, when a min_marker_scale is provided,
|
81
|
+
## then the scale will be constrained between the min
|
82
|
+
## and max. For now, it is simply proportionnal to the
|
83
|
+
## absolute value of the largest.
|
84
|
+
min_scale = curve_style.marker_min_scale
|
85
|
+
|
86
|
+
zm = zmin[idx]
|
87
|
+
zM = zmax[idx]
|
88
|
+
|
89
|
+
mm = zM.abs
|
90
|
+
m2 = zm.abs
|
91
|
+
mm = m2 if m2 > mm
|
92
|
+
|
93
|
+
z = zvalue[idx]
|
94
|
+
|
95
|
+
style.scale = if min_scale
|
96
|
+
min_scale + (max_scale - min_scale) *
|
97
|
+
(z - zm)/(zM - zm)
|
98
|
+
else
|
99
|
+
zvalue[idx].abs/mm * max_scale
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
if @reversed[:marker_color]
|
106
|
+
idx = @reversed[:marker_color]
|
107
|
+
if idx < zvalue.size
|
108
|
+
style.color = curve_style.marker_color_map.z_color(zvalue[idx],
|
109
|
+
zmin[idx],
|
110
|
+
zmax[idx])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
return style
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
@@ -19,7 +19,7 @@ require 'ctioga2/graphics/coordinates'
|
|
19
19
|
# This module contains all the classes used by ctioga
|
20
20
|
module CTioga2
|
21
21
|
|
22
|
-
Version::register_svn_info('$Revision:
|
22
|
+
Version::register_svn_info('$Revision: 521 $', '$Date: 2013-09-21 18:55:05 +0200 (Sat, 21 Sep 2013) $')
|
23
23
|
|
24
24
|
module Graphics
|
25
25
|
|
@@ -355,13 +355,27 @@ EOH
|
|
355
355
|
|
356
356
|
end
|
357
357
|
|
358
|
+
asco = AxisStyleOptions.dup
|
359
|
+
asco['also-axes'] = CmdArg.new('axis')
|
360
|
+
|
358
361
|
AxisStyleCommand =
|
359
362
|
Cmd.new("axis-style",nil,"--axis-style",
|
360
363
|
[
|
361
364
|
CmdArg.new('axis'),
|
362
|
-
],
|
363
|
-
|
364
|
-
|
365
|
+
], asco) do |plotmaker, which, opts|
|
366
|
+
axes = [which]
|
367
|
+
if opts['also-axes']
|
368
|
+
axes += opts['also-axes'].split(/\s*,\s*/)
|
369
|
+
end
|
370
|
+
|
371
|
+
for w in axes
|
372
|
+
begin
|
373
|
+
style = AxisStyle.current_axis_style(plotmaker, w)
|
374
|
+
style.set_from_hash(opts)
|
375
|
+
rescue Exception => e
|
376
|
+
error {"Error while setting style of axis: #{w} -- #{e}"}
|
377
|
+
end
|
378
|
+
end
|
365
379
|
end
|
366
380
|
AxisStyleCommand.
|
367
381
|
describe("Sets the style of the given axis",
|
@@ -370,6 +384,10 @@ This command can be used to set various aspects of the style of the
|
|
370
384
|
given axis, through its various options, which are documented in more details
|
371
385
|
in the {command: define-axis-style} command -- excepted for the @ticks@ bit
|
372
386
|
which are documented in the {command: ticks} command.
|
387
|
+
|
388
|
+
If the option @also-axes@ is specified, the style is also applied to
|
389
|
+
the comma-separated list of axes it contains.
|
390
|
+
|
373
391
|
EOH
|
374
392
|
|
375
393
|
ClearAxesCommand =
|
@@ -26,7 +26,7 @@ require 'ctioga2/graphics/types/grid'
|
|
26
26
|
# This module contains all the classes used by ctioga
|
27
27
|
module CTioga2
|
28
28
|
|
29
|
-
Version::register_svn_info('$Revision:
|
29
|
+
Version::register_svn_info('$Revision: 523 $', '$Date: 2013-09-22 15:31:16 +0200 (Sun, 22 Sep 2013) $')
|
30
30
|
|
31
31
|
module Graphics
|
32
32
|
|
@@ -49,6 +49,7 @@ module CTioga2
|
|
49
49
|
|
50
50
|
ColorType = CmdType.new('color', {
|
51
51
|
:type => :tioga_color,
|
52
|
+
:namespace => Tioga::ColorConstants,
|
52
53
|
}, <<EOD)
|
53
54
|
A color. It can take three forms:
|
54
55
|
* a named color, see
|
@@ -61,9 +62,10 @@ EOD
|
|
61
62
|
ColorOrFalseType =
|
62
63
|
CmdType.new('color-or-false', {
|
63
64
|
:type => :tioga_color,
|
65
|
+
:namespace => Tioga::ColorConstants,
|
64
66
|
:shortcuts => {'none' => false }
|
65
67
|
}, <<EOD)
|
66
|
-
A {type: color}, or
|
68
|
+
A {type: color}, or none to say that nothing should be drawn.
|
67
69
|
EOD
|
68
70
|
|
69
71
|
|
data/lib/ctioga2/log.rb
CHANGED
@@ -16,7 +16,7 @@ require 'logger'
|
|
16
16
|
|
17
17
|
module CTioga2
|
18
18
|
|
19
|
-
Version::register_svn_info('$Revision:
|
19
|
+
Version::register_svn_info('$Revision: 522 $', '$Date: 2013-09-22 12:02:48 +0200 (Sun, 22 Sep 2013) $')
|
20
20
|
|
21
21
|
# This module should be included (or extended) by every class that
|
22
22
|
# need logging/debugging facilities.
|
@@ -101,7 +101,10 @@ module CTioga2
|
|
101
101
|
|
102
102
|
# A logged replacement for system
|
103
103
|
def spawn(cmd, priority = :info)
|
104
|
-
|
104
|
+
if cmd.is_a? String
|
105
|
+
cmd = [cmd]
|
106
|
+
end
|
107
|
+
retval = system(*cmd)
|
105
108
|
self.send(priority) { "Spawned #{cmd} -> " +
|
106
109
|
if retval
|
107
110
|
"success"
|
@@ -20,7 +20,7 @@ require 'ctioga2/utils'
|
|
20
20
|
|
21
21
|
module CTioga2
|
22
22
|
|
23
|
-
Version::register_svn_info('$Revision:
|
23
|
+
Version::register_svn_info('$Revision: 523 $', '$Date: 2013-09-22 15:31:16 +0200 (Sun, 22 Sep 2013) $')
|
24
24
|
|
25
25
|
|
26
26
|
# The MetaBuilder module contains a framework to perform
|
@@ -104,6 +104,13 @@ module CTioga2
|
|
104
104
|
# passed through without further modification.
|
105
105
|
attr_accessor :passthrough
|
106
106
|
|
107
|
+
# An array of module whose constants can be used "as such"
|
108
|
+
attr_accessor :namespace
|
109
|
+
|
110
|
+
# When a :namespace option is provided, this hash provides a
|
111
|
+
# lookup 'lowercase name' => constant value.
|
112
|
+
attr_accessor :namespace_lookup
|
113
|
+
|
107
114
|
# A default constructor. It should be safe to use it directly for
|
108
115
|
# children, unless something more specific is needed. Any descendent
|
109
116
|
# should *always* register _type_ as @type - or, even better, call
|
@@ -128,6 +135,7 @@ module CTioga2
|
|
128
135
|
|
129
136
|
end
|
130
137
|
|
138
|
+
|
131
139
|
# This class function actually registers the current type
|
132
140
|
# to the Type ancestor. _name_ should be a symbol.
|
133
141
|
# Moreover, if the second argument is provided, it automatically
|
@@ -200,11 +208,12 @@ module CTioga2
|
|
200
208
|
end
|
201
209
|
end
|
202
210
|
end
|
211
|
+
|
203
212
|
# Then, constants lookup.
|
204
213
|
if @type.key?(:namespace)
|
205
214
|
begin
|
206
215
|
return stt_run_hook(lookup_const(string))
|
207
|
-
rescue
|
216
|
+
rescue IncorrectInput
|
208
217
|
end
|
209
218
|
end
|
210
219
|
return stt_run_hook(string_to_type_internal(string))
|
@@ -276,17 +285,32 @@ module CTioga2
|
|
276
285
|
|
277
286
|
protected
|
278
287
|
|
288
|
+
def build_namespace_lookup
|
289
|
+
if @type[:namespace]
|
290
|
+
@namespace = [@type[:namespace]].flatten
|
291
|
+
|
292
|
+
@namespace_lookup = {}
|
293
|
+
for m in @namespace
|
294
|
+
for c in m.constants
|
295
|
+
@namespace_lookup[c.to_s.downcase] = m.const_get(c)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
|
279
302
|
# Looks for the value as a constant specified in the :namespace
|
280
303
|
# modules. Raises IncorrectInput if not found.
|
281
304
|
def lookup_const(str)
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
305
|
+
str = str.downcase
|
306
|
+
if @type[:namespace] && (! @namespace_lookup)
|
307
|
+
build_namespace_lookup
|
308
|
+
end
|
309
|
+
if @namespace_lookup.key? str
|
310
|
+
return @namespace_lookup[str]
|
311
|
+
else
|
312
|
+
raise IncorrectInput, "Constant #{str} not found"
|
288
313
|
end
|
289
|
-
raise IncorrectInput, "Constant #{str} not found"
|
290
314
|
end
|
291
315
|
|
292
316
|
# The internal function for converting type to a string. Used by
|
data/lib/ctioga2/plotmaker.rb
CHANGED
@@ -158,7 +158,7 @@ require 'ctioga2/postprocess'
|
|
158
158
|
# displays of rate constants vs potentials)
|
159
159
|
module CTioga2
|
160
160
|
|
161
|
-
Version::register_svn_info('$Revision:
|
161
|
+
Version::register_svn_info('$Revision: 522 $', '$Date: 2013-09-22 12:02:48 +0200 (Sun, 22 Sep 2013) $')
|
162
162
|
|
163
163
|
# This class is the core of ctioga. It parses the command-line arguments,
|
164
164
|
# reads all necessary files and plots graphs. Most of its functionality
|
@@ -700,12 +700,18 @@ EOH
|
|
700
700
|
|
701
701
|
XpdfViewerCommand =
|
702
702
|
Cmd.new("xpdf",'-X',"--xpdf", [ ]) do |plotmaker|
|
703
|
-
plotmaker.postprocess.viewer =
|
703
|
+
plotmaker.postprocess.viewer = :auto
|
704
704
|
end
|
705
705
|
|
706
706
|
XpdfViewerCommand.describe('Uses xpdf to view the produced PDF files',
|
707
707
|
<<EOH, OutputSetupGroup)
|
708
708
|
Uses xpdf to view the PDF files produced by ctioga2.
|
709
|
+
|
710
|
+
If xpdf is not found, then it tries to guess which viewers are available:
|
711
|
+
* on windows, it uses the system file associations to open the PDF file
|
712
|
+
* on mac, it uses the open command
|
713
|
+
* on linux, it tries, mime-open, and if that is missing, falls back to
|
714
|
+
commonly available PDF viewers.
|
709
715
|
EOH
|
710
716
|
|
711
717
|
OpenViewerCommand =
|
data/lib/ctioga2/postprocess.rb
CHANGED
@@ -17,7 +17,7 @@ require 'ctioga2/log'
|
|
17
17
|
|
18
18
|
module CTioga2
|
19
19
|
|
20
|
-
Version::register_svn_info('$Revision:
|
20
|
+
Version::register_svn_info('$Revision: 522 $', '$Date: 2013-09-22 12:02:48 +0200 (Sun, 22 Sep 2013) $')
|
21
21
|
|
22
22
|
# What happens to generated PDF files ?
|
23
23
|
#
|
@@ -69,6 +69,33 @@ module CTioga2
|
|
69
69
|
end
|
70
70
|
|
71
71
|
|
72
|
+
# Try to open the file with xpdf, or fallback to system defaults
|
73
|
+
def view_pdf(pdf)
|
74
|
+
if Utils.which("xpdf")
|
75
|
+
spawn(["xpdf", "-z", "page", pdf])
|
76
|
+
else
|
77
|
+
case Utils.os
|
78
|
+
when :windows
|
79
|
+
# Use start
|
80
|
+
spawn(["start", "/B", pdf])
|
81
|
+
when :macosx
|
82
|
+
spawn(["open", pdf])
|
83
|
+
else
|
84
|
+
for w in %w{evince gv mimeopen}
|
85
|
+
if Utils.which(w)
|
86
|
+
if w == "mimeopen"
|
87
|
+
spawn(["mimeopen", "-n", pdf])
|
88
|
+
else
|
89
|
+
spawn([w, pdf])
|
90
|
+
end
|
91
|
+
break
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
72
99
|
# Process the given _file_. If _last_ is true, things that should
|
73
100
|
# only happen last happen.
|
74
101
|
def process_file(file, last = false)
|
@@ -96,15 +123,19 @@ module CTioga2
|
|
96
123
|
|
97
124
|
# View produced PDF or PNG files...
|
98
125
|
if (last || @view_all) && @viewer
|
99
|
-
if @
|
100
|
-
|
101
|
-
elsif @viewer =~ /%s/
|
102
|
-
cmd = @viewer % file
|
126
|
+
if @viewer == :auto
|
127
|
+
view_pdf(file)
|
103
128
|
else
|
104
|
-
|
129
|
+
if @png_res
|
130
|
+
cmd = "display #{target}"
|
131
|
+
elsif @viewer =~ /%s/
|
132
|
+
cmd = @viewer % file
|
133
|
+
else
|
134
|
+
cmd = "#{@viewer} #{file}"
|
135
|
+
end
|
136
|
+
info { "Spawning the viewer as requested for #{file}" }
|
137
|
+
spawn(cmd)
|
105
138
|
end
|
106
|
-
info { "Spawning the viewer as requested for #{file}" }
|
107
|
-
spawn(cmd)
|
108
139
|
end
|
109
140
|
end
|
110
141
|
|
data/lib/ctioga2/utils.rb
CHANGED
@@ -11,6 +11,9 @@
|
|
11
11
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
12
|
# GNU General Public License for more details (in the COPYING file).
|
13
13
|
|
14
|
+
# For platform detection
|
15
|
+
require 'rbconfig'
|
16
|
+
|
14
17
|
module CTioga2
|
15
18
|
|
16
19
|
# An exception to raise upon to-be-implemented-one-day features
|
@@ -35,7 +38,7 @@ module CTioga2
|
|
35
38
|
# arguments and have the Date and Revision svn:keyword:. Use this
|
36
39
|
# way:
|
37
40
|
#
|
38
|
-
# Version::register_svn_info('$Revision:
|
41
|
+
# Version::register_svn_info('$Revision: 532 $', '$Date: 2013-09-29 12:13:33 +0200 (Sun, 29 Sep 2013) $')
|
39
42
|
#
|
40
43
|
# To set the correct properties, the following command-line can be
|
41
44
|
# used:
|
@@ -75,7 +78,7 @@ module CTioga2
|
|
75
78
|
}
|
76
79
|
|
77
80
|
# The position of the URL, used for getting the version
|
78
|
-
SVN_URL = '$HeadURL: svn+ssh://rubyforge.org/var/svn/ctioga2/releases/ctioga2-0.
|
81
|
+
SVN_URL = '$HeadURL: svn+ssh://rubyforge.org/var/svn/ctioga2/releases/ctioga2-0.7/lib/ctioga2/utils.rb $'
|
79
82
|
|
80
83
|
# The version of ctioga2
|
81
84
|
CTIOGA_VERSION = if SVN_URL =~ /releases\/ctioga2-([^\/]+)/
|
@@ -84,7 +87,7 @@ module CTioga2
|
|
84
87
|
"SVN version"
|
85
88
|
end
|
86
89
|
|
87
|
-
register_svn_info('$Revision:
|
90
|
+
register_svn_info('$Revision: 532 $', '$Date: 2013-09-29 12:13:33 +0200 (Sun, 29 Sep 2013) $')
|
88
91
|
|
89
92
|
end
|
90
93
|
|
@@ -254,6 +257,93 @@ module CTioga2
|
|
254
257
|
end
|
255
258
|
return file # But that will fail later on.
|
256
259
|
end
|
260
|
+
|
261
|
+
|
262
|
+
|
263
|
+
# Cross-platform way of finding an executable in the $PATH.
|
264
|
+
#
|
265
|
+
# This is adapted from
|
266
|
+
# http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
267
|
+
def self.which(cmd)
|
268
|
+
return nil unless cmd
|
269
|
+
exts = ['']
|
270
|
+
if ENV['PATHEXT']
|
271
|
+
exts += ENV['PATHEXT'].split(';')
|
272
|
+
end
|
273
|
+
|
274
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
275
|
+
exts.each { |ext|
|
276
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
277
|
+
return exe if File.executable? exe
|
278
|
+
}
|
279
|
+
end
|
280
|
+
return nil
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
# Reliable OS detection, coming from:
|
285
|
+
#
|
286
|
+
# http://stackoverflow.com/questions/11784109/detecting-operating-systems-in-ruby
|
287
|
+
def self.os
|
288
|
+
host_os = RbConfig::CONFIG['host_os']
|
289
|
+
case host_os
|
290
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
291
|
+
:windows
|
292
|
+
when /darwin|mac os/
|
293
|
+
:macosx
|
294
|
+
when /linux/
|
295
|
+
:linux
|
296
|
+
when /solaris|bsd/
|
297
|
+
:unix
|
298
|
+
else
|
299
|
+
warn {"Unknown os: #{host_os.inspect}"}
|
300
|
+
:unknown
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
# Cluster a series of objects by the values returned by the given
|
306
|
+
# funcall. It returns an array of arrays where the elements are in
|
307
|
+
# the same order, and in each sub-array, the functions all return
|
308
|
+
# the same value
|
309
|
+
#
|
310
|
+
# @todo with block too ?
|
311
|
+
def self.cluster_by_value(list, funcall)
|
312
|
+
if list.size == 0
|
313
|
+
return []
|
314
|
+
end
|
315
|
+
ret = [ [list[0]] ]
|
316
|
+
cur = ret[0]
|
317
|
+
last = cur.first.send(funcall)
|
318
|
+
|
319
|
+
for o in list[1..-1]
|
320
|
+
val = o.send(funcall)
|
321
|
+
if last == val
|
322
|
+
cur << o
|
323
|
+
else
|
324
|
+
cur = [o]
|
325
|
+
ret << cur
|
326
|
+
last = val
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
return ret
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
# Returns a hash value -> [elements] in which the elements are in
|
335
|
+
# the same order
|
336
|
+
def self.sort_by_value(list, funcall)
|
337
|
+
ret = {}
|
338
|
+
|
339
|
+
for el in list
|
340
|
+
val = el.send(funcall)
|
341
|
+
ret[val] ||= []
|
342
|
+
|
343
|
+
ret[val] << el
|
344
|
+
end
|
345
|
+
return ret
|
346
|
+
end
|
257
347
|
end
|
258
348
|
|
259
349
|
|