cdo 1.2.7 → 1.3.0
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.
- data/gemspec +2 -2
- data/lib/cdo.rb +204 -279
- data/lib/cdo_lib.rb +415 -0
- data/test/test_cdo.rb +180 -181
- metadata +3 -3
- data/lib/cdo_oo.rb +0 -301
data/gemspec
CHANGED
@@ -3,9 +3,9 @@ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
|
3
3
|
|
4
4
|
spec = Gem::Specification.new do |s|
|
5
5
|
s.name = "cdo"
|
6
|
-
s.version = '1.
|
6
|
+
s.version = '1.3.0'
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
|
-
s.files = ["lib/cdo.rb","lib/
|
8
|
+
s.files = ["lib/cdo.rb","lib/cdo_lib.rb"] + ["gemspec","LICENSE"]
|
9
9
|
s.test_file = "test/test_cdo.rb"
|
10
10
|
s.description = "Easy access to the Climate Data operators"
|
11
11
|
s.summary = "Easy access to the Climate Data operators"
|
data/lib/cdo.rb
CHANGED
@@ -3,116 +3,97 @@ require 'open3'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'stringio'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
6
|
+
class Cdo
|
7
|
+
OutputOperatorsPattern = /(diff|info|output|griddes|zaxisdes|show|ncode|ndate|nlevel|nmon|nvar|nyear|ntime|npar|gradsdes|pardes)/
|
8
|
+
|
9
|
+
attr_accessor :cdo, :returnCdf, :forceOutput, :env, :debug, :logging, :logFile
|
10
|
+
attr_reader :operators, :filetypes
|
11
|
+
|
12
|
+
def initialize(cdo: 'cdo',
|
13
|
+
returnCdf: false,
|
14
|
+
returnFalseOnError: false,
|
15
|
+
forceOutput: true,
|
16
|
+
env: {},
|
17
|
+
logging: false,
|
18
|
+
logFile: StringIO.new,
|
19
|
+
debug: false,
|
20
|
+
returnNilOnError: false)
|
21
|
+
|
22
|
+
# setup path to cdo executable
|
23
|
+
@cdo = ENV.has_key?('CDO') ? ENV['CDO'] : cdo
|
24
|
+
|
25
|
+
@operators = getOperators(binary=@cdo)
|
26
|
+
@returnCdf = returnCdf
|
27
|
+
@forceOutput = forceOutput
|
28
|
+
@env = env
|
29
|
+
@debug = ENV.has_key?('DEBUG') ? true : debug
|
30
|
+
@returnNilOnError = returnNilOnError
|
31
|
+
|
32
|
+
@filetypes = getFiletypes
|
33
|
+
@returnFalseOnError = returnFalseOnError
|
34
|
+
|
35
|
+
@logging = logging
|
36
|
+
@logFile = logFile
|
37
|
+
@logger = Logger.new(@logFile,'a')
|
38
|
+
@logger.level = Logger::INFO
|
37
39
|
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
intgridtraj intpoint isosurface lmavg lmean lmmean lmstd log lsmean
|
53
|
-
meandiff2test mergegrid mod moncount monlogs mrotuv mrotuvb mulcoslat ncode
|
54
|
-
ncopy nmltest normal nvar outputbounds outputboundscpt outputcenter
|
55
|
-
outputcenter2 outputcentercpt outputkey outputtri outputvector outputvrml
|
56
|
-
pardup parmul pinfo pinfov pressure_fl pressure_hl read_e5ml remapcon1
|
57
|
-
remapdis1 retocomplex scalllogo scatter seascount select selgridname
|
58
|
-
seloperator selvar selzaxisname setrcaname setvar showvar sinfov smemlogo
|
59
|
-
snamelogo sort sortcode sortlevel sortname sorttaxis sorttimestamp sortvar
|
60
|
-
sp2fc specinfo spectrum sperclogo splitvar stimelogo studentt template1
|
61
|
-
template2 test test2 testdata thinout timcount timcovar tinfo transxy trms
|
62
|
-
tstepcount vardes vardup varmul varquot2test varrms vertwind write_e5ml
|
63
|
-
writegrid writerandom yearcount]
|
64
|
-
|
65
|
-
@@outputOperatorsPattern = /(diff|info|output|griddes|zaxisdes|show|ncode|ndate|nlevel|nmon|nvar|nyear|ntime|npar|gradsdes|pardes)/
|
66
|
-
|
67
|
-
private
|
68
|
-
def Cdo.getOperators(force=false)
|
69
|
-
# Do NOT compute anything, if it is not required
|
70
|
-
return State[:operators] unless (State[:operators].empty? or force)
|
71
|
-
cmd = @@CDO + ' 2>&1'
|
72
|
-
help = IO.popen(cmd).readlines.map {|l| l.chomp.lstrip}
|
73
|
-
if 5 >= help.size
|
74
|
-
warn "Operators could not get listed by running the CDO binary (#{@@CDO})"
|
75
|
-
pp help if Cdo.debug
|
76
|
-
exit
|
77
|
-
end
|
78
|
-
# in version 1.5.6 the output of '-h' has changed
|
79
|
-
State[:operators] = case
|
80
|
-
when Cdo.version < "1.5.6"
|
81
|
-
(help[help.index("Operators:")+1].split + @@undocumentedOperators).uniq
|
82
|
-
else
|
83
|
-
help[(help.index("Operators:")+1)..help.index(help.find {|v| v =~ /CDO version/}) - 2].join(' ').split
|
84
|
-
end
|
41
|
+
private # {{{
|
42
|
+
|
43
|
+
# split arguments into hash-like args and the rest
|
44
|
+
def Cdo.parseArgs(args)
|
45
|
+
operatorArgs = args.reject {|a| a.class == Hash}
|
46
|
+
opts = operatorArgs.empty? ? '' : ',' + operatorArgs.join(',')
|
47
|
+
io = args.find {|a| a.class == Hash}
|
48
|
+
io = {} if io.nil?
|
49
|
+
args.delete_if {|a| a.class == Hash}
|
50
|
+
# join input streams together if possible
|
51
|
+
io[:input] = io[:input].join(' ') if io[:input].respond_to?(:join)
|
52
|
+
|
53
|
+
return [io,opts]
|
85
54
|
end
|
86
55
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
56
|
+
# collect the complete list of possible operators
|
57
|
+
def getOperators(path2cdo)
|
58
|
+
if version <= '1.7.0' then
|
59
|
+
cmd = path2cdo + ' 2>&1'
|
60
|
+
help = IO.popen(cmd).readlines.map {|l| l.chomp.lstrip}
|
61
|
+
if 5 >= help.size
|
62
|
+
warn "Operators could not get listed by running the CDO binary (#{path2cdo})"
|
63
|
+
pp help if @debug
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
@operators = help[(help.index("Operators:")+1)..help.index(help.find {|v| v =~ /CDO version/}) - 2].join(' ').split
|
96
68
|
else
|
97
|
-
|
69
|
+
cmd = "#{path2cdo} --operators"
|
70
|
+
|
71
|
+
@operators = IO.popen(cmd).readlines.map {|l| l.split(' ').first }
|
98
72
|
end
|
99
73
|
end
|
100
74
|
|
101
|
-
|
102
|
-
|
75
|
+
# get supported IO filetypes form the binary
|
76
|
+
def getFiletypes
|
77
|
+
_, _, stderr, _ = Open3.popen3(@cdo + " -V")
|
78
|
+
supported = stderr.readlines.map(&:chomp)
|
79
|
+
|
80
|
+
supported.grep(/(Filetypes)/)[0].split(':')[1].split.map(&:downcase)
|
103
81
|
end
|
104
|
-
def Cdo.env; State[:env]; end
|
105
82
|
|
106
|
-
|
107
|
-
|
83
|
+
|
84
|
+
# Execute the given cdo call and return all outputs
|
85
|
+
def _call(cmd)
|
86
|
+
if (@debug)
|
108
87
|
puts '# DEBUG ====================================================================='
|
109
|
-
pp
|
88
|
+
pp @env unless @env.empty?
|
110
89
|
puts 'CMD: '
|
111
90
|
puts cmd
|
112
91
|
puts '# DEBUG ====================================================================='
|
113
92
|
end
|
114
|
-
stdin, stdout, stderr, wait_thr = Open3.popen3(Cdo.env,cmd)
|
115
93
|
|
94
|
+
@logger.info(cmd+"\n") if @logging
|
95
|
+
|
96
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(@env,cmd)
|
116
97
|
{
|
117
98
|
:stdout => stdout.read,
|
118
99
|
:stderr => stderr.read,
|
@@ -120,269 +101,211 @@ module Cdo
|
|
120
101
|
}
|
121
102
|
end
|
122
103
|
|
123
|
-
|
124
|
-
|
104
|
+
# Error handling for the given command
|
105
|
+
def _hasError(cmd,retvals)
|
106
|
+
if @debug
|
107
|
+
puts("RETURNCODE: #{retvals[:returncode]}")
|
108
|
+
end
|
109
|
+
if ( 0 != retvals[:returncode] )
|
110
|
+
puts("Error in calling:")
|
111
|
+
puts(">>> "+cmd+"<<<")
|
112
|
+
puts(retvals[:stderr])
|
113
|
+
@logger.error("FAILIURE in execution of:"+cmd+"| msg:"+retvals[:stderr]) if @logging
|
114
|
+
return true
|
115
|
+
else
|
116
|
+
return false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# command execution wrapper, which handles the possible return types
|
121
|
+
def _run(cmd,ofile='',options=nil,returnCdf=false,force=nil,returnArray=nil,returnMaArray=nil)
|
122
|
+
options = options.to_s
|
123
|
+
|
124
|
+
options << '-f nc' if options.empty? and ( \
|
125
|
+
( returnCdf ) or \
|
126
|
+
( not returnArray.nil? ) or \
|
127
|
+
( not returnMaArray.nil?) \
|
128
|
+
)
|
129
|
+
cmd = "#{@cdo} -O #{options} #{cmd} "
|
130
|
+
|
125
131
|
case ofile
|
126
132
|
when $stdout
|
127
|
-
retvals =
|
128
|
-
|
129
|
-
unless hasError(cmd,retvals)
|
133
|
+
retvals = _call(cmd)
|
134
|
+
unless _hasError(cmd,retvals)
|
130
135
|
return retvals[:stdout].split($/).map {|l| l.chomp.strip}
|
131
136
|
else
|
132
|
-
|
137
|
+
if @returnNilOnError then
|
138
|
+
return nil
|
139
|
+
else
|
140
|
+
raise ArgumentError,"CDO did NOT run successfully!"
|
141
|
+
end
|
133
142
|
end
|
134
143
|
else
|
135
|
-
force =
|
144
|
+
force = @forceOutput if force.nil?
|
136
145
|
if force or not File.exists?(ofile.to_s)
|
137
146
|
ofile = MyTempfile.path if ofile.nil?
|
138
147
|
cmd << "#{ofile}"
|
139
|
-
retvals =
|
140
|
-
|
141
|
-
|
142
|
-
|
148
|
+
retvals = _call(cmd)
|
149
|
+
if _hasError(cmd,retvals)
|
150
|
+
if @returnNilOnError then
|
151
|
+
return nil
|
152
|
+
else
|
153
|
+
raise ArgumentError,"CDO did NOT run successfully!"
|
154
|
+
end
|
143
155
|
end
|
144
156
|
else
|
145
|
-
warn "Use existing file '#{ofile}'" if
|
157
|
+
warn "Use existing file '#{ofile}'" if @debug
|
146
158
|
end
|
147
159
|
end
|
160
|
+
|
148
161
|
if not returnArray.nil?
|
149
|
-
|
162
|
+
readArray(ofile,returnArray)
|
150
163
|
elsif not returnMaArray.nil?
|
151
|
-
|
152
|
-
elsif returnCdf or
|
153
|
-
|
164
|
+
readMaArray(ofile,returnMaArray)
|
165
|
+
elsif returnCdf or @returnCdf
|
166
|
+
readCdf(ofile)
|
154
167
|
else
|
155
|
-
|
168
|
+
ofile
|
156
169
|
end
|
157
170
|
end
|
158
171
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
# join input streams together if possible
|
167
|
-
io[:input] = io[:input].join(' ') if io[:input].respond_to?(:join)
|
168
|
-
return [io,opts]
|
169
|
-
end
|
172
|
+
# Implementation of operator calls using ruby's meta programming skills
|
173
|
+
#
|
174
|
+
# args is expected to look like
|
175
|
+
# [opt1,...,optN,:input => iStream,:output => oStream, :options => ' ']
|
176
|
+
# where iStream could be another CDO call (timmax(selname(Temp,U,V,ifile.nc))
|
177
|
+
def method_missing(sym, *args, &block)
|
178
|
+
puts "Operator #{sym.to_s} is called" if @debug
|
170
179
|
|
171
|
-
|
172
|
-
## args is expected to look like [opt1,...,optN,:input => iStream,:output => oStream] where
|
173
|
-
# iStream could be another CDO call (timmax(selname(Temp,U,V,ifile.nc))
|
174
|
-
puts "Operator #{sym.to_s} is called" if State[:debug]
|
175
|
-
if getOperators.include?(sym.to_s)
|
180
|
+
if @operators.include?(sym.to_s)
|
176
181
|
io, opts = Cdo.parseArgs(args)
|
177
|
-
if
|
178
|
-
|
182
|
+
if OutputOperatorsPattern.match(sym.to_s)
|
183
|
+
_run(" -#{sym.to_s}#{opts} #{io[:input]} ",$stdout)
|
179
184
|
else
|
180
|
-
|
185
|
+
_run(" -#{sym.to_s}#{opts} #{io[:input]} ",io[:output],io[:options],io[:returnCdf],io[:force],io[:returnArray],io[:returnMaArray])
|
181
186
|
end
|
182
187
|
else
|
188
|
+
return false if @returnFalseOnError
|
183
189
|
raise ArgumentError,"Operator #{sym.to_s} not found"
|
184
190
|
end
|
185
191
|
end
|
186
192
|
|
187
|
-
|
193
|
+
# load the netcdf bindings
|
194
|
+
def loadCdf
|
188
195
|
begin
|
189
196
|
require "numru/netcdf_miss"
|
190
|
-
include NumRu
|
191
197
|
rescue LoadError
|
192
198
|
warn "Could not load ruby's netcdf bindings. Please install it."
|
193
199
|
raise
|
194
200
|
end
|
195
201
|
end
|
196
202
|
|
197
|
-
|
198
|
-
return unless (State[:libs].nil? or force)
|
199
|
-
_, _, stderr, _ = Open3.popen3(@@CDO + " -V")
|
200
|
-
supported = stderr.readlines.map(&:chomp)
|
201
|
-
with = supported.grep(/(with|Features)/)[0].split(':')[1].split.map(&:downcase)
|
202
|
-
libs = supported.grep(/library version/).map {|l|
|
203
|
-
l.strip.split(':').map {|l|
|
204
|
-
l.split.first.downcase
|
205
|
-
}[0,2]
|
206
|
-
}
|
207
|
-
State[:libs] = {}
|
208
|
-
with.flatten.each {|k| State[:libs][k]=true}
|
209
|
-
libs.each {|lib,version| State[:libs][lib] = version}
|
210
|
-
end
|
211
|
-
|
212
|
-
public
|
213
|
-
def Cdo.debug=(value)
|
214
|
-
State[:debug] = value
|
215
|
-
end
|
216
|
-
def Cdo.debug
|
217
|
-
State[:debug]
|
218
|
-
end
|
219
|
-
def Cdo.forceOutput=(value)
|
220
|
-
State[:forceOutput] = value
|
221
|
-
end
|
222
|
-
def Cdo.forceOutput
|
223
|
-
State[:forceOutput]
|
224
|
-
end
|
225
|
-
def Cdo.log=(value)
|
226
|
-
State[:log] = value
|
227
|
-
end
|
203
|
+
# }}}
|
228
204
|
|
229
|
-
|
230
|
-
State[:log]
|
231
|
-
end
|
205
|
+
public # {{{
|
232
206
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
207
|
+
# show Cdo's built-in help for given operator
|
208
|
+
def help(operator=nil)
|
209
|
+
if operator.nil?
|
210
|
+
puts _call([@cdo,'-h'].join(' '))[:stderr]
|
211
|
+
else
|
212
|
+
operator = operator.to_s
|
213
|
+
puts _call([@cdo,'-h',operator].join(' ')).values_at(:stdout,:stderr)
|
214
|
+
end
|
239
215
|
end
|
240
216
|
|
241
|
-
|
242
|
-
|
243
|
-
|
217
|
+
# collect logging messages
|
218
|
+
def collectLogs
|
219
|
+
if @logger.instance_variable_get(:'@logdev').filename.nil?
|
220
|
+
@logFile.rewind
|
221
|
+
return @logFile.read
|
222
|
+
else
|
223
|
+
return File.open(@logFile).readlines
|
244
224
|
end
|
245
|
-
State[:returnCdf] = value
|
246
225
|
end
|
247
|
-
|
248
|
-
def
|
249
|
-
|
226
|
+
# print the loggin messaged
|
227
|
+
def showLog
|
228
|
+
puts collectLogs
|
250
229
|
end
|
251
230
|
|
252
|
-
|
253
|
-
|
254
|
-
|
231
|
+
# check if cdo backend is working
|
232
|
+
def check
|
233
|
+
return false unless system("#@cdo -h 1>/dev/null 2>&1")
|
255
234
|
|
256
|
-
|
257
|
-
|
258
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each {|path|
|
259
|
-
return true if File.exists?([path,bin].join(File::SEPARATOR))
|
260
|
-
}
|
261
|
-
end
|
235
|
+
retval = _call("#{@cdo} -V")
|
236
|
+
pp retval if @debug
|
262
237
|
|
263
|
-
# test if @@CDO can be used
|
264
|
-
def Cdo.checkCdo
|
265
|
-
unless hasCdo?(@@CDO)
|
266
|
-
warn "Testing application #@@CDO is not available!"
|
267
|
-
exit 1
|
268
|
-
else
|
269
|
-
puts "Using CDO: #@@CDO"
|
270
|
-
puts IO.popen(@@CDO + " -V").readlines
|
271
|
-
end
|
272
238
|
return true
|
273
239
|
end
|
274
240
|
|
275
|
-
def
|
276
|
-
|
277
|
-
@@CDO = cdo
|
278
|
-
Cdo.getOperators(true)
|
279
|
-
Cdo.getSupportedLibs(true)
|
280
|
-
end
|
281
|
-
|
282
|
-
def Cdo.getCdo
|
283
|
-
@@CDO
|
241
|
+
def version
|
242
|
+
IO.popen("#{@cdo} -V 2>&1").readlines.first.split(/version/i).last.strip.split(' ').first
|
284
243
|
end
|
285
244
|
|
286
|
-
|
287
|
-
|
288
|
-
|
245
|
+
# return cdf handle to given file readonly
|
246
|
+
def readCdf(iFile)
|
247
|
+
loadCdf
|
248
|
+
NumRu::NetCDF.open(iFile)
|
289
249
|
end
|
290
250
|
|
291
|
-
|
292
|
-
|
293
|
-
|
251
|
+
# return cdf handle opened in append more
|
252
|
+
def openCdf(iFile)
|
253
|
+
loadCdf
|
254
|
+
NumRu::NetCDF.open(iFile,'r+')
|
294
255
|
end
|
295
256
|
|
296
|
-
|
297
|
-
|
298
|
-
|
257
|
+
# return narray for given variable name
|
258
|
+
def readArray(iFile,varname)
|
259
|
+
filehandle = readCdf(iFile)
|
260
|
+
if filehandle.var_names.include?(varname)
|
261
|
+
# return the data array
|
262
|
+
filehandle.var(varname).get
|
263
|
+
else
|
264
|
+
raise ArgumentError, "Cannot find variable '#{varname}'"
|
265
|
+
end
|
299
266
|
end
|
300
267
|
|
301
|
-
|
302
|
-
|
303
|
-
|
268
|
+
# return a masked array for given variable name
|
269
|
+
def readMaArray(iFile,varname)
|
270
|
+
filehandle = readCdf(iFile)
|
271
|
+
if filehandle.var_names.include?(varname)
|
272
|
+
# return the data array
|
273
|
+
filehandle.var(varname).get_with_miss
|
304
274
|
else
|
305
|
-
|
306
|
-
return State[:libs][lib]
|
307
|
-
else
|
308
|
-
warn "No version information available about '#{lib}'"
|
309
|
-
return false
|
310
|
-
end
|
275
|
+
raise ArgumentError,"Cannot find variable '#{varname}'"
|
311
276
|
end
|
312
277
|
end
|
313
278
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
end
|
279
|
+
# }}}
|
280
|
+
|
281
|
+
# Addional operators: {{{
|
318
282
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
def Cdo.boundaryLevels(args)
|
323
|
-
ilevels = Cdo.showlevel(:input => args[:input])[0].split.map(&:to_f)
|
283
|
+
# compute vertical boundary levels from full levels
|
284
|
+
def boundaryLevels(args)
|
285
|
+
ilevels = self.showlevel(:input => args[:input])[0].split.map(&:to_f)
|
324
286
|
bound_levels = Array.new(ilevels.size+1)
|
325
287
|
bound_levels[0] = 0
|
326
|
-
(1..ilevels.size).each {|i|
|
288
|
+
(1..ilevels.size).each {|i|
|
327
289
|
bound_levels[i] =bound_levels[i-1] + 2*(ilevels[i-1]-bound_levels[i-1])
|
328
290
|
}
|
329
291
|
bound_levels
|
330
292
|
end
|
331
293
|
|
332
|
-
|
333
|
-
|
294
|
+
# compute level thicknesses from given full levels
|
295
|
+
def thicknessOfLevels(args)
|
296
|
+
bound_levels = self.boundaryLevels(args)
|
334
297
|
delta_levels = []
|
335
|
-
bound_levels.each_with_index {|v,i|
|
298
|
+
bound_levels.each_with_index {|v,i|
|
336
299
|
next if 0 == i
|
337
300
|
delta_levels << v - bound_levels[i-1]
|
338
301
|
}
|
339
302
|
delta_levels
|
340
303
|
end
|
341
304
|
|
342
|
-
|
343
|
-
Cdo.loadCdf unless State[:returnCdf]
|
344
|
-
NetCDF.open(iFile)
|
345
|
-
end
|
346
|
-
|
347
|
-
def Cdo.openCdf(iFile)
|
348
|
-
Cdo.loadCdf unless State[:returnCdf]
|
349
|
-
NetCDF.open(iFile,'r+')
|
350
|
-
end
|
351
|
-
|
352
|
-
def Cdo.readArray(iFile,varname)
|
353
|
-
filehandle = Cdo.readCdf(iFile)
|
354
|
-
if filehandle.var_names.include?(varname)
|
355
|
-
# return the data array
|
356
|
-
filehandle.var(varname).get
|
357
|
-
else
|
358
|
-
raise ArgumentError, "Cannot find variable '#{varname}'"
|
359
|
-
end
|
360
|
-
end
|
305
|
+
# }}}
|
361
306
|
|
362
|
-
def Cdo.readMaArray(iFile,varname)
|
363
|
-
filehandle = Cdo.readCdf(iFile)
|
364
|
-
if filehandle.var_names.include?(varname)
|
365
|
-
# return the data array
|
366
|
-
filehandle.var(varname).get_with_miss
|
367
|
-
else
|
368
|
-
raise ArgumentError,"Cannot find variable '#{varname}'"
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
def Cdo.help(operator=nil)
|
373
|
-
if operator.nil?
|
374
|
-
puts Cdo.call([@@CDO,'-h'].join(' '))[:stderr]
|
375
|
-
else
|
376
|
-
operator = operator.to_s unless String == operator.class
|
377
|
-
if Cdo.operators.include?(operator)
|
378
|
-
puts Cdo.call([@@CDO,'-h',operator].join(' '))[:stdout]
|
379
|
-
else
|
380
|
-
puts "Unknown operator #{operator}"
|
381
|
-
end
|
382
|
-
end
|
383
|
-
end
|
384
307
|
end
|
385
|
-
|
308
|
+
#
|
386
309
|
# Helper module for easy temp file handling
|
387
310
|
module MyTempfile
|
388
311
|
require 'tempfile'
|
@@ -411,3 +334,5 @@ module MyTempfile
|
|
411
334
|
@@_tempfiles.each {|f| print(f+" ") if f.kind_of? String}
|
412
335
|
end
|
413
336
|
end
|
337
|
+
|
338
|
+
#vim:fdm=marker
|