netcdf 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +34 -0
- data/LICENSE +21 -0
- data/README.md +82 -0
- data/docs/00_introduction.md +34 -0
- data/docs/01_getting_started.md +127 -0
- data/docs/02_buffers.md +95 -0
- data/docs/03_reference.md +410 -0
- data/ext/netcdf/extconf.rb +61 -0
- data/ext/netcdf/internal.h +64 -0
- data/ext/netcdf/nc_att.c +431 -0
- data/ext/netcdf/nc_dim.c +74 -0
- data/ext/netcdf/nc_file.c +349 -0
- data/ext/netcdf/nc_group.c +171 -0
- data/ext/netcdf/nc_io.c +1284 -0
- data/ext/netcdf/nc_types.c +278 -0
- data/ext/netcdf/nc_var.c +551 -0
- data/ext/netcdf/netcdf.c +289 -0
- data/lib/netcdf/version.rb +3 -0
- data/lib/netcdf.rb +29 -0
- data/netcdf.gemspec +30 -0
- metadata +66 -0
data/ext/netcdf/netcdf.c
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* netcdf.c — entry point. Defines the NetCDF module, the error class,
|
|
3
|
+
* shared helpers used by the submodules, and the constants table.
|
|
4
|
+
*/
|
|
5
|
+
#include "internal.h"
|
|
6
|
+
|
|
7
|
+
VALUE mNetCDF;
|
|
8
|
+
VALUE eError;
|
|
9
|
+
|
|
10
|
+
void
|
|
11
|
+
nc_raise (int status)
|
|
12
|
+
{
|
|
13
|
+
VALUE msg, err;
|
|
14
|
+
|
|
15
|
+
msg = rb_str_new_cstr(nc_strerror(status));
|
|
16
|
+
err = rb_funcall(eError, rb_intern("new"), 1, msg);
|
|
17
|
+
rb_funcall(err, rb_intern("status="), 1, INT2NUM(status));
|
|
18
|
+
rb_exc_raise(err);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* ---------------------------------------------------------- */
|
|
22
|
+
/* Common helpers used by io.c, var.c, etc. */
|
|
23
|
+
/* ---------------------------------------------------------- */
|
|
24
|
+
|
|
25
|
+
/* The array helpers below fill an array the caller provides -- one of
|
|
26
|
+
NC_MAX_VAR_DIMS entries on its stack holds any variable's -- rather
|
|
27
|
+
than allocating one, so a raise partway through (a length mismatch, an
|
|
28
|
+
entry that is not an Integer) leaves nothing to free. */
|
|
29
|
+
void
|
|
30
|
+
ary_to_sizet (VALUE ary, int ndims, const char *role, size_t *out)
|
|
31
|
+
{
|
|
32
|
+
long n, i;
|
|
33
|
+
|
|
34
|
+
Check_Type(ary, T_ARRAY);
|
|
35
|
+
n = RARRAY_LEN(ary);
|
|
36
|
+
if ( n != ndims ) {
|
|
37
|
+
rb_raise(rb_eArgError, "%s length mismatch (%ld for %d)", role, n, ndims);
|
|
38
|
+
}
|
|
39
|
+
for (i=0; i<n; i++) {
|
|
40
|
+
out[i] = NUM2SIZET(RARRAY_AREF(ary, i));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Returns false, leaving `out` untouched, when `ary` is nil. */
|
|
45
|
+
bool
|
|
46
|
+
ary_to_ptrdiff (VALUE ary, int ndims, const char *role, ptrdiff_t *out)
|
|
47
|
+
{
|
|
48
|
+
long n, i;
|
|
49
|
+
|
|
50
|
+
if ( NIL_P(ary) ) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
Check_Type(ary, T_ARRAY);
|
|
54
|
+
n = RARRAY_LEN(ary);
|
|
55
|
+
if ( n != ndims ) {
|
|
56
|
+
rb_raise(rb_eArgError, "%s length mismatch (%ld for %d)", role, n, ndims);
|
|
57
|
+
}
|
|
58
|
+
for (i=0; i<n; i++) {
|
|
59
|
+
out[i] = (ptrdiff_t) NUM2LL(RARRAY_AREF(ary, i));
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
ssize_t
|
|
65
|
+
nc_xtype_size (nc_type xt)
|
|
66
|
+
{
|
|
67
|
+
switch ( xt ) {
|
|
68
|
+
case NC_BYTE: case NC_UBYTE: case NC_CHAR: return 1;
|
|
69
|
+
case NC_SHORT: case NC_USHORT: return 2;
|
|
70
|
+
case NC_INT: case NC_UINT: case NC_FLOAT: return 4;
|
|
71
|
+
case NC_INT64: case NC_UINT64: case NC_DOUBLE: return 8;
|
|
72
|
+
default: return -1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Integer conversions that refuse a value the C type cannot hold. A cast
|
|
77
|
+
would store 300 as NC_BYTE 44, and Ruby's own NUM2UINT / NUM2ULL wrap a
|
|
78
|
+
negative value around rather than raise, so -1 would be stored as the
|
|
79
|
+
type's maximum. */
|
|
80
|
+
static long long
|
|
81
|
+
num_in_range (VALUE v, long long lo, long long hi, const char *type)
|
|
82
|
+
{
|
|
83
|
+
long long x;
|
|
84
|
+
|
|
85
|
+
x = NUM2LL(v);
|
|
86
|
+
if ( x < lo || x > hi ) {
|
|
87
|
+
rb_raise(rb_eRangeError, "integer %lld out of range for %s", x, type);
|
|
88
|
+
}
|
|
89
|
+
return x;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
signed char
|
|
93
|
+
num_to_schar (VALUE v)
|
|
94
|
+
{
|
|
95
|
+
return (signed char) num_in_range(v, SCHAR_MIN, SCHAR_MAX, "NC_BYTE");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
unsigned char
|
|
99
|
+
num_to_uchar (VALUE v)
|
|
100
|
+
{
|
|
101
|
+
return (unsigned char) num_in_range(v, 0, UCHAR_MAX, "NC_UBYTE");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
short
|
|
105
|
+
num_to_short (VALUE v)
|
|
106
|
+
{
|
|
107
|
+
return (short) num_in_range(v, SHRT_MIN, SHRT_MAX, "NC_SHORT");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
unsigned short
|
|
111
|
+
num_to_ushort (VALUE v)
|
|
112
|
+
{
|
|
113
|
+
return (unsigned short) num_in_range(v, 0, USHRT_MAX, "NC_USHORT");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
unsigned int
|
|
117
|
+
num_to_uint (VALUE v)
|
|
118
|
+
{
|
|
119
|
+
return (unsigned int) num_in_range(v, 0, UINT_MAX, "NC_UINT");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
unsigned long long
|
|
123
|
+
num_to_ulonglong (VALUE v)
|
|
124
|
+
{
|
|
125
|
+
VALUE i;
|
|
126
|
+
|
|
127
|
+
i = rb_to_int(v);
|
|
128
|
+
if ( FIXNUM_P(i) ? FIX2LONG(i) < 0 : RBIGNUM_NEGATIVE_P(i) ) {
|
|
129
|
+
rb_raise(rb_eRangeError, "integer %"PRIsVALUE" out of range for NC_UINT64", i);
|
|
130
|
+
}
|
|
131
|
+
return NUM2ULL(i);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
void
|
|
135
|
+
indices_to_c (int ncid, int varid, VALUE index_ary, size_t *out)
|
|
136
|
+
{
|
|
137
|
+
int ndims;
|
|
138
|
+
|
|
139
|
+
/* libnetcdf reads one coordinate per dimension of the variable, so a
|
|
140
|
+
shorter index would have it read past the array. */
|
|
141
|
+
NC_CHECK(nc_inq_varndims(ncid, varid, &ndims));
|
|
142
|
+
ary_to_sizet(index_ary, ndims, "index", out);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* ---------------------------------------------------------- */
|
|
146
|
+
/* Init */
|
|
147
|
+
/* ---------------------------------------------------------- */
|
|
148
|
+
|
|
149
|
+
#define DEF_CONST(name) rb_define_const(mNetCDF, #name, INT2NUM(name))
|
|
150
|
+
|
|
151
|
+
void
|
|
152
|
+
Init_netcdf (void)
|
|
153
|
+
{
|
|
154
|
+
mNetCDF = rb_define_module("NetCDF");
|
|
155
|
+
|
|
156
|
+
eError = rb_define_class_under(mNetCDF, "Error", rb_eStandardError);
|
|
157
|
+
rb_define_attr(eError, "status", 1, 1);
|
|
158
|
+
|
|
159
|
+
init_nc_file();
|
|
160
|
+
init_nc_dim();
|
|
161
|
+
init_nc_var();
|
|
162
|
+
init_nc_att();
|
|
163
|
+
init_nc_io();
|
|
164
|
+
init_nc_group();
|
|
165
|
+
init_nc_types();
|
|
166
|
+
|
|
167
|
+
/* Open / create modes */
|
|
168
|
+
DEF_CONST(NC_NOWRITE);
|
|
169
|
+
DEF_CONST(NC_WRITE);
|
|
170
|
+
DEF_CONST(NC_CLOBBER);
|
|
171
|
+
DEF_CONST(NC_NOCLOBBER);
|
|
172
|
+
DEF_CONST(NC_SHARE);
|
|
173
|
+
DEF_CONST(NC_NETCDF4);
|
|
174
|
+
DEF_CONST(NC_CLASSIC_MODEL);
|
|
175
|
+
DEF_CONST(NC_64BIT_OFFSET);
|
|
176
|
+
#ifdef NC_DISKLESS
|
|
177
|
+
DEF_CONST(NC_DISKLESS);
|
|
178
|
+
#endif
|
|
179
|
+
#ifdef NC_PERSIST
|
|
180
|
+
DEF_CONST(NC_PERSIST);
|
|
181
|
+
#endif
|
|
182
|
+
#ifdef NC_MMAP
|
|
183
|
+
DEF_CONST(NC_MMAP);
|
|
184
|
+
#endif
|
|
185
|
+
#ifdef NC_INMEMORY
|
|
186
|
+
DEF_CONST(NC_INMEMORY);
|
|
187
|
+
#endif
|
|
188
|
+
|
|
189
|
+
/* Fill */
|
|
190
|
+
DEF_CONST(NC_FILL);
|
|
191
|
+
DEF_CONST(NC_NOFILL);
|
|
192
|
+
|
|
193
|
+
/* Global / unlimited */
|
|
194
|
+
DEF_CONST(NC_GLOBAL);
|
|
195
|
+
DEF_CONST(NC_UNLIMITED);
|
|
196
|
+
|
|
197
|
+
/* Types */
|
|
198
|
+
DEF_CONST(NC_BYTE);
|
|
199
|
+
DEF_CONST(NC_CHAR);
|
|
200
|
+
DEF_CONST(NC_SHORT);
|
|
201
|
+
DEF_CONST(NC_INT);
|
|
202
|
+
DEF_CONST(NC_FLOAT);
|
|
203
|
+
DEF_CONST(NC_DOUBLE);
|
|
204
|
+
DEF_CONST(NC_UBYTE);
|
|
205
|
+
DEF_CONST(NC_USHORT);
|
|
206
|
+
DEF_CONST(NC_UINT);
|
|
207
|
+
DEF_CONST(NC_INT64);
|
|
208
|
+
DEF_CONST(NC_UINT64);
|
|
209
|
+
DEF_CONST(NC_STRING);
|
|
210
|
+
|
|
211
|
+
DEF_CONST(NC_MAX_NAME);
|
|
212
|
+
DEF_CONST(NC_MAX_VAR_DIMS);
|
|
213
|
+
|
|
214
|
+
/* File-format codes */
|
|
215
|
+
DEF_CONST(NC_FORMAT_CLASSIC);
|
|
216
|
+
DEF_CONST(NC_FORMAT_64BIT_OFFSET);
|
|
217
|
+
#ifdef NC_FORMAT_64BIT_DATA
|
|
218
|
+
DEF_CONST(NC_FORMAT_64BIT_DATA); /* CDF-5; libnetcdf 4.4+ */
|
|
219
|
+
#endif
|
|
220
|
+
DEF_CONST(NC_FORMAT_NETCDF4);
|
|
221
|
+
DEF_CONST(NC_FORMAT_NETCDF4_CLASSIC);
|
|
222
|
+
|
|
223
|
+
#ifdef NC_FORMATX_NC3
|
|
224
|
+
DEF_CONST(NC_FORMATX_NC3);
|
|
225
|
+
#endif
|
|
226
|
+
#ifdef NC_FORMATX_NC_HDF5
|
|
227
|
+
DEF_CONST(NC_FORMATX_NC_HDF5);
|
|
228
|
+
#endif
|
|
229
|
+
#ifdef NC_FORMATX_NC_HDF4
|
|
230
|
+
DEF_CONST(NC_FORMATX_NC_HDF4);
|
|
231
|
+
#endif
|
|
232
|
+
#ifdef NC_FORMATX_PNETCDF
|
|
233
|
+
DEF_CONST(NC_FORMATX_PNETCDF);
|
|
234
|
+
#endif
|
|
235
|
+
#ifdef NC_FORMATX_DAP2
|
|
236
|
+
DEF_CONST(NC_FORMATX_DAP2);
|
|
237
|
+
#endif
|
|
238
|
+
#ifdef NC_FORMATX_DAP4
|
|
239
|
+
DEF_CONST(NC_FORMATX_DAP4);
|
|
240
|
+
#endif
|
|
241
|
+
#ifdef NC_FORMATX_UDF0
|
|
242
|
+
DEF_CONST(NC_FORMATX_UDF0);
|
|
243
|
+
#endif
|
|
244
|
+
#ifdef NC_FORMATX_UDF1
|
|
245
|
+
DEF_CONST(NC_FORMATX_UDF1);
|
|
246
|
+
#endif
|
|
247
|
+
#ifdef NC_FORMATX_ZARR
|
|
248
|
+
DEF_CONST(NC_FORMATX_ZARR);
|
|
249
|
+
#endif
|
|
250
|
+
#ifdef NC_FORMATX_UNDEFINED
|
|
251
|
+
DEF_CONST(NC_FORMATX_UNDEFINED);
|
|
252
|
+
#endif
|
|
253
|
+
|
|
254
|
+
/* Chunking / storage */
|
|
255
|
+
DEF_CONST(NC_CONTIGUOUS);
|
|
256
|
+
DEF_CONST(NC_CHUNKED);
|
|
257
|
+
DEF_CONST(NC_COMPACT);
|
|
258
|
+
|
|
259
|
+
/* Fletcher32 checksum modes */
|
|
260
|
+
DEF_CONST(NC_NOCHECKSUM);
|
|
261
|
+
DEF_CONST(NC_FLETCHER32);
|
|
262
|
+
|
|
263
|
+
/* Endian */
|
|
264
|
+
DEF_CONST(NC_ENDIAN_NATIVE);
|
|
265
|
+
DEF_CONST(NC_ENDIAN_LITTLE);
|
|
266
|
+
DEF_CONST(NC_ENDIAN_BIG);
|
|
267
|
+
|
|
268
|
+
/* Quantize modes (libnetcdf >= 4.9) */
|
|
269
|
+
#ifdef NC_NOQUANTIZE
|
|
270
|
+
DEF_CONST(NC_NOQUANTIZE);
|
|
271
|
+
#endif
|
|
272
|
+
#ifdef NC_QUANTIZE_BITGROOM
|
|
273
|
+
DEF_CONST(NC_QUANTIZE_BITGROOM);
|
|
274
|
+
#endif
|
|
275
|
+
#ifdef NC_QUANTIZE_GRANULARBR
|
|
276
|
+
DEF_CONST(NC_QUANTIZE_GRANULARBR);
|
|
277
|
+
#endif
|
|
278
|
+
#ifdef NC_QUANTIZE_BITROUND
|
|
279
|
+
DEF_CONST(NC_QUANTIZE_BITROUND);
|
|
280
|
+
#endif
|
|
281
|
+
|
|
282
|
+
/* User-defined type classes (returned by nc_inq_user_type) */
|
|
283
|
+
DEF_CONST(NC_VLEN);
|
|
284
|
+
DEF_CONST(NC_OPAQUE);
|
|
285
|
+
DEF_CONST(NC_ENUM);
|
|
286
|
+
DEF_CONST(NC_COMPOUND);
|
|
287
|
+
|
|
288
|
+
DEF_CONST(NC_FIRSTUSERTYPEID);
|
|
289
|
+
}
|
data/lib/netcdf.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "monitor"
|
|
2
|
+
require "netcdf/netcdf"
|
|
3
|
+
require "netcdf/version"
|
|
4
|
+
|
|
5
|
+
module NetCDF
|
|
6
|
+
# libnetcdf, and the HDF5 under it, keep process-wide state and are not
|
|
7
|
+
# thread-safe: two threads inside them at once corrupt it even when they
|
|
8
|
+
# work on different files. Array I/O runs with the GVL released, and a
|
|
9
|
+
# thread holding the GVL can meanwhile call any other function -- an
|
|
10
|
+
# nc_close of the file being read included -- so every call is
|
|
11
|
+
# serialized on one lock. Waiting for it releases the GVL, so threads
|
|
12
|
+
# that are not using netCDF keep running. The lock is reentrant, for a
|
|
13
|
+
# conversion (a #to_int, say) that calls back into NetCDF.
|
|
14
|
+
LOCK = Monitor.new
|
|
15
|
+
private_constant :LOCK
|
|
16
|
+
|
|
17
|
+
synchronized = lambda do |names, visibility|
|
|
18
|
+
Module.new do
|
|
19
|
+
names.each do |name|
|
|
20
|
+
define_method(name) { |*args, &blk| LOCK.synchronize { super(*args, &blk) } }
|
|
21
|
+
end
|
|
22
|
+
send(visibility, *names)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
# Both copies module_function makes: NetCDF.nc_open, and the private
|
|
26
|
+
# nc_open a class gets by including NetCDF.
|
|
27
|
+
singleton_class.prepend(synchronized.(singleton_methods(false), :public))
|
|
28
|
+
prepend(synchronized.(private_instance_methods(false), :private))
|
|
29
|
+
end
|
data/netcdf.gemspec
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Gem::Specification.new do |spec|
|
|
2
|
+
spec.name = "netcdf"
|
|
3
|
+
spec.version = File.read(File.expand_path("lib/netcdf/version.rb", __dir__))[/VERSION\s*=\s*"([^"]+)"/, 1]
|
|
4
|
+
spec.summary = "Ruby binding to the NetCDF C library, one Ruby method per C function"
|
|
5
|
+
spec.description = <<~TEXT
|
|
6
|
+
A literal translation of the NetCDF C library into Ruby: every function
|
|
7
|
+
under its own name, with libnetcdf's own documentation to read it by.
|
|
8
|
+
Bulk data is passed through Ruby's MemoryView protocol: an array
|
|
9
|
+
library's own memory is handed to libnetcdf, which reads or writes it
|
|
10
|
+
where it lies, and array I/O runs with the GVL released.
|
|
11
|
+
TEXT
|
|
12
|
+
spec.authors = ["himotoyoshi"]
|
|
13
|
+
spec.email = ["himotoyoshi@users.noreply.github.com"]
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.homepage = "https://github.com/himotoyoshi/netcdf"
|
|
16
|
+
|
|
17
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
18
|
+
|
|
19
|
+
spec.files = Dir[
|
|
20
|
+
"lib/**/*.rb",
|
|
21
|
+
"ext/netcdf/*.{c,h,rb}",
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"docs/*.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"netcdf.gemspec",
|
|
27
|
+
]
|
|
28
|
+
spec.require_paths = ["lib"]
|
|
29
|
+
spec.extensions = ["ext/netcdf/extconf.rb"]
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: netcdf
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- himotoyoshi
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: |
|
|
13
|
+
A literal translation of the NetCDF C library into Ruby: every function
|
|
14
|
+
under its own name, with libnetcdf's own documentation to read it by.
|
|
15
|
+
Bulk data is passed through Ruby's MemoryView protocol: an array
|
|
16
|
+
library's own memory is handed to libnetcdf, which reads or writes it
|
|
17
|
+
where it lies, and array I/O runs with the GVL released.
|
|
18
|
+
email:
|
|
19
|
+
- himotoyoshi@users.noreply.github.com
|
|
20
|
+
executables: []
|
|
21
|
+
extensions:
|
|
22
|
+
- ext/netcdf/extconf.rb
|
|
23
|
+
extra_rdoc_files: []
|
|
24
|
+
files:
|
|
25
|
+
- CHANGELOG.md
|
|
26
|
+
- LICENSE
|
|
27
|
+
- README.md
|
|
28
|
+
- docs/00_introduction.md
|
|
29
|
+
- docs/01_getting_started.md
|
|
30
|
+
- docs/02_buffers.md
|
|
31
|
+
- docs/03_reference.md
|
|
32
|
+
- ext/netcdf/extconf.rb
|
|
33
|
+
- ext/netcdf/internal.h
|
|
34
|
+
- ext/netcdf/nc_att.c
|
|
35
|
+
- ext/netcdf/nc_dim.c
|
|
36
|
+
- ext/netcdf/nc_file.c
|
|
37
|
+
- ext/netcdf/nc_group.c
|
|
38
|
+
- ext/netcdf/nc_io.c
|
|
39
|
+
- ext/netcdf/nc_types.c
|
|
40
|
+
- ext/netcdf/nc_var.c
|
|
41
|
+
- ext/netcdf/netcdf.c
|
|
42
|
+
- lib/netcdf.rb
|
|
43
|
+
- lib/netcdf/version.rb
|
|
44
|
+
- netcdf.gemspec
|
|
45
|
+
homepage: https://github.com/himotoyoshi/netcdf
|
|
46
|
+
licenses:
|
|
47
|
+
- MIT
|
|
48
|
+
metadata: {}
|
|
49
|
+
rdoc_options: []
|
|
50
|
+
require_paths:
|
|
51
|
+
- lib
|
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 3.1.0
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
requirements: []
|
|
63
|
+
rubygems_version: 4.0.8
|
|
64
|
+
specification_version: 4
|
|
65
|
+
summary: Ruby binding to the NetCDF C library, one Ruby method per C function
|
|
66
|
+
test_files: []
|