tracklib 0.1.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/src/rwtfile.rs ADDED
@@ -0,0 +1,429 @@
1
+ use lazy_static::lazy_static;
2
+ use rutie::{
3
+ class, methods, wrappable_struct, AnyObject, Array, Boolean, Class, Encoding, Float, Hash,
4
+ Integer, Module, Object, RString, VM,
5
+ };
6
+ use rutie_serde::{ruby_class, rutie_serde_methods};
7
+ use std::collections::HashMap;
8
+ use std::convert::TryFrom;
9
+ use std::io::BufWriter;
10
+ use tracklib::{parse_rwtf, DataField, RWTFMetadata, RWTFile, TrackType};
11
+ use super::polyline;
12
+ use super::surface;
13
+
14
+ fn any_to_float(o: AnyObject) -> f64 {
15
+ match o.try_convert_to::<Float>() {
16
+ Ok(f) => f.to_f64(),
17
+ Err(float_e) => o
18
+ .try_convert_to::<Integer>()
19
+ .map_err(|_| VM::raise_ex(float_e))
20
+ .unwrap()
21
+ .to_i64() as f64,
22
+ }
23
+ }
24
+
25
+ fn any_to_int(o: AnyObject) -> i64 {
26
+ match o.try_convert_to::<Integer>() {
27
+ Ok(i) => i.to_i64(),
28
+ Err(int_e) => o
29
+ .try_convert_to::<Float>()
30
+ .map_err(|_| VM::raise_ex(int_e))
31
+ .unwrap()
32
+ .to_f64() as i64,
33
+ }
34
+ }
35
+
36
+ fn any_to_str(o: AnyObject) -> String {
37
+ o.try_convert_to::<RString>()
38
+ .map_err(|e| VM::raise_ex(e))
39
+ .unwrap()
40
+ .to_string()
41
+ }
42
+
43
+ fn any_to_bool(o: AnyObject) -> bool {
44
+ o.try_convert_to::<Boolean>()
45
+ .map_err(|e| VM::raise_ex(e))
46
+ .unwrap()
47
+ .to_bool()
48
+ }
49
+
50
+ fn any_to_ids(o: AnyObject) -> Vec<u64> {
51
+ o.try_convert_to::<Array>()
52
+ .map_err(|e| VM::raise_ex(e))
53
+ .unwrap()
54
+ .into_iter()
55
+ .map(|ele| {
56
+ ele.try_convert_to::<Integer>()
57
+ .map_err(|e| VM::raise_ex(e))
58
+ .unwrap()
59
+ .to_u64()
60
+ })
61
+ .collect()
62
+ }
63
+
64
+ #[derive(Debug, Copy, Clone)]
65
+ enum ColumnType {
66
+ Numbers,
67
+ LongFloat,
68
+ ShortFloat,
69
+ Base64,
70
+ String,
71
+ Bool,
72
+ IDs,
73
+ }
74
+
75
+ impl ColumnType {
76
+ fn from_str(name: &str) -> Option<Self> {
77
+ match name {
78
+ "Number" => Some(ColumnType::Numbers),
79
+ "LongFloat" => Some(ColumnType::LongFloat),
80
+ "ShortFloat" => Some(ColumnType::ShortFloat),
81
+ "Base64" => Some(ColumnType::Base64),
82
+ "String" => Some(ColumnType::String),
83
+ "Bool" => Some(ColumnType::Bool),
84
+ "IDs" => Some(ColumnType::IDs),
85
+ _ => None,
86
+ }
87
+ }
88
+
89
+ fn exponent(&self) -> u8 {
90
+ match self {
91
+ ColumnType::Numbers => 48,
92
+ ColumnType::LongFloat => 24,
93
+ ColumnType::ShortFloat => 38,
94
+ _ => {
95
+ VM::raise(
96
+ Class::from_existing("Exception"),
97
+ &format!("can't handle numeric value for non-numeric field"),
98
+ );
99
+ unreachable!();
100
+ }
101
+ }
102
+ }
103
+
104
+ fn max_integer(&self) -> i64 {
105
+ 2i64.pow(u32::from(self.exponent()))
106
+ }
107
+
108
+ fn max_float(&self) -> f64 {
109
+ 2f64.powi(i32::from(self.exponent()))
110
+ }
111
+ }
112
+
113
+ fn convert_config(config: Hash) -> HashMap<String, ColumnType> {
114
+ let mut hm = HashMap::new();
115
+
116
+ config.each(|rwtf_type_name, array_of_field_names| {
117
+ let type_name_obj = rwtf_type_name
118
+ .try_convert_to::<RString>()
119
+ .map_err(|e| VM::raise_ex(e))
120
+ .unwrap();
121
+ let type_name_str = type_name_obj.to_str();
122
+
123
+ if let Some(column_type) = ColumnType::from_str(type_name_str) {
124
+ let array_obj = array_of_field_names
125
+ .try_convert_to::<Array>()
126
+ .map_err(|e| VM::raise_ex(e))
127
+ .unwrap();
128
+
129
+ for field_name in array_obj.into_iter() {
130
+ let field_name_obj = field_name
131
+ .try_convert_to::<RString>()
132
+ .map_err(|e| VM::raise_ex(e))
133
+ .unwrap();
134
+
135
+ hm.insert(field_name_obj.to_string(), column_type);
136
+ }
137
+ } else {
138
+ VM::raise(
139
+ Class::from_existing("Exception"),
140
+ &format!("unknown rwtf_field_config type: {}", type_name_str),
141
+ );
142
+ unreachable!();
143
+ }
144
+ });
145
+
146
+ hm
147
+ }
148
+
149
+ fn is_empty_string(v: &AnyObject) -> bool {
150
+ match v.try_convert_to::<RString>() {
151
+ Ok(s) => s.to_str().is_empty(),
152
+ Err(_) => false,
153
+ }
154
+ }
155
+
156
+ fn is_empty_array(v: &AnyObject) -> bool {
157
+ match v.try_convert_to::<Array>() {
158
+ Ok(a) => a.length() == 0,
159
+ Err(_) => false,
160
+ }
161
+ }
162
+
163
+ fn is_number_and_too_large(v: &AnyObject, field_type: ColumnType) -> bool {
164
+ // First we have to try to cast `v` to a numeric type (Integer or Float)
165
+ // and then call to_i64/f64(). This will raise an exception if the number
166
+ // is too large to turn into a primitive.
167
+ let is_number_result = VM::protect(|| {
168
+ match v.try_convert_to::<Integer>() {
169
+ Ok(i) => {
170
+ let _ = i.to_i64(); // force a conversion
171
+ Boolean::new(true)
172
+ }
173
+ Err(_) => match v.try_convert_to::<Float>() {
174
+ Ok(f) => {
175
+ let _ = f.to_f64(); // force a conversion
176
+ Boolean::new(true)
177
+ }
178
+ Err(_) => Boolean::new(false),
179
+ },
180
+ }
181
+ .to_any_object()
182
+ });
183
+
184
+ match is_number_result {
185
+ Ok(is_number) => {
186
+ // Here we know that no exception was raised during the attempted primitive conversion.
187
+ // We also know that `is_number` is a Boolean, so this unsafe cast is fine.
188
+ if unsafe { is_number.to::<Boolean>().to_bool() } {
189
+ match v.try_convert_to::<Integer>() {
190
+ Ok(i) => i.to_i64().abs() > field_type.max_integer(),
191
+ Err(_) => match v.try_convert_to::<Float>() {
192
+ Ok(f) => f.to_f64().abs() > field_type.max_float(),
193
+ Err(_) => false,
194
+ },
195
+ }
196
+ } else {
197
+ false
198
+ }
199
+ }
200
+ Err(_) => {
201
+ VM::clear_error_info(); // clear ruby VM error register
202
+ true // this IS a number and it IS too large
203
+ }
204
+ }
205
+ }
206
+
207
+ fn add_points(
208
+ source: &Hash,
209
+ section_points_config: &HashMap<String, ColumnType>,
210
+ section_type: &str,
211
+ mut callback: impl FnMut(usize, &str, DataField),
212
+ ) {
213
+ let maybe_section_points = source
214
+ .at(&RString::new_utf8(section_type))
215
+ .try_convert_to::<Array>();
216
+
217
+ if let Ok(section_points) = maybe_section_points {
218
+ for (i, maybe_point) in section_points.into_iter().enumerate() {
219
+ let point = maybe_point
220
+ .try_convert_to::<Hash>()
221
+ .map_err(|e| VM::raise_ex(e))
222
+ .unwrap();
223
+
224
+ point.each(|k: AnyObject, v: AnyObject| {
225
+ let field_name_obj = k
226
+ .try_convert_to::<RString>()
227
+ .map_err(|e| VM::raise_ex(e))
228
+ .unwrap();
229
+ let name = field_name_obj.to_str();
230
+
231
+ if !name.is_empty() {
232
+ if let Some(field_type) = section_points_config.get(name) {
233
+ if !v.is_nil()
234
+ && !is_empty_string(&v)
235
+ && !is_empty_array(&v)
236
+ && !is_number_and_too_large(&v, *field_type)
237
+ {
238
+ let data = match field_type {
239
+ ColumnType::LongFloat => DataField::LongFloat(any_to_float(v)),
240
+ ColumnType::ShortFloat => DataField::ShortFloat(any_to_float(v)),
241
+ ColumnType::Numbers => DataField::Number(any_to_int(v)),
242
+ ColumnType::Base64 => {
243
+ DataField::Base64(any_to_str(v).replace("\n", ""))
244
+ }
245
+ ColumnType::String => DataField::String(any_to_str(v)),
246
+ ColumnType::Bool => DataField::Bool(any_to_bool(v)),
247
+ ColumnType::IDs => DataField::IDs(any_to_ids(v)),
248
+ };
249
+
250
+ callback(i, name, data);
251
+ }
252
+ } else {
253
+ VM::raise(
254
+ Module::from_existing("Tracklib").get_nested_class("UnknownFieldError"),
255
+ &format!("unknown {} field: {}", section_type, name),
256
+ );
257
+ unreachable!();
258
+ }
259
+ }
260
+ });
261
+ }
262
+ }
263
+ }
264
+
265
+ pub struct Inner {
266
+ inner: RWTFile,
267
+ }
268
+
269
+ wrappable_struct!(Inner, InnerWrapper, INNER_WRAPPER);
270
+
271
+ class!(RubyRWTFile);
272
+
273
+ methods!(
274
+ RubyRWTFile,
275
+ itself,
276
+ fn rwtf_from_bytes(bytes: RString) -> AnyObject {
277
+ let source = bytes.map_err(|e| VM::raise_ex(e)).unwrap();
278
+ let (_, rwtf) = parse_rwtf(source.to_bytes_unchecked())
279
+ .map_err(|e| VM::raise(Class::from_existing("Exception"), &format!("{}", e)))
280
+ .unwrap();
281
+ let inner = Inner { inner: rwtf };
282
+
283
+ Class::from_existing("RWTFile").wrap_data(inner, &*INNER_WRAPPER)
284
+ }
285
+
286
+ fn rwtf_to_bytes() -> RString {
287
+ let mut writer = BufWriter::new(Vec::new());
288
+ itself
289
+ .get_data(&*INNER_WRAPPER)
290
+ .inner
291
+ .write(&mut writer)
292
+ .map_err(|e| VM::raise(Class::from_existing("Exception"), &format!("{}", e)))
293
+ .unwrap();
294
+
295
+ let encoding = Encoding::find("ASCII-8BIT")
296
+ .map_err(|e| VM::raise_ex(e))
297
+ .unwrap();
298
+
299
+ let buf = writer
300
+ .into_inner()
301
+ .map_err(|e| VM::raise(Class::from_existing("Exception"), &format!("{}", e)))
302
+ .unwrap();
303
+
304
+ RString::from_bytes(&buf, &encoding)
305
+ }
306
+
307
+ fn rwtf_from_hash(input: Hash, config_input: Hash, metadata: Hash) -> AnyObject {
308
+ let source = input.map_err(|e| VM::raise_ex(e)).unwrap();
309
+ let config = config_input.map_err(|e| VM::raise_ex(e)).unwrap();
310
+ let track_points_config = convert_config(
311
+ config
312
+ .at(&RString::new_utf8("track_points"))
313
+ .try_convert_to::<Hash>()
314
+ .map_err(|e| VM::raise_ex(e))
315
+ .unwrap(),
316
+ );
317
+ let course_points_config = convert_config(
318
+ config
319
+ .at(&RString::new_utf8("course_points"))
320
+ .try_convert_to::<Hash>()
321
+ .map_err(|e| VM::raise_ex(e))
322
+ .unwrap(),
323
+ );
324
+
325
+ let mut rwtf = if let Some(md) = metadata.ok() {
326
+ let tt_metadata = md
327
+ .at(&RString::new_utf8("track_type"))
328
+ .try_convert_to::<Hash>()
329
+ .map_err(|e| VM::raise_ex(e))
330
+ .unwrap();
331
+
332
+ let track_type = tt_metadata
333
+ .at(&RString::new_utf8("type"))
334
+ .try_convert_to::<RString>()
335
+ .map_err(|e| VM::raise_ex(e))
336
+ .unwrap();
337
+
338
+ let id = u32::try_from(
339
+ tt_metadata
340
+ .at(&RString::new_utf8("id"))
341
+ .try_convert_to::<Integer>()
342
+ .map_err(|e| VM::raise_ex(e))
343
+ .unwrap()
344
+ .to_u64(),
345
+ )
346
+ .map_err(|e| VM::raise(Class::from_existing("Exception"), &format!("{}", e)))
347
+ .unwrap();
348
+
349
+ let tt = match track_type.to_str() {
350
+ "trip" => TrackType::Trip(id),
351
+ "route" => TrackType::Route(id),
352
+ "segment" => TrackType::Segment(id),
353
+ _ => {
354
+ VM::raise(
355
+ Class::from_existing("Exception"),
356
+ &format!("unknown track_type metadata: {}", track_type.to_str()),
357
+ );
358
+ unreachable!();
359
+ }
360
+ };
361
+
362
+ RWTFile::with_track_type(tt)
363
+ } else {
364
+ RWTFile::new()
365
+ };
366
+
367
+ add_points(
368
+ &source,
369
+ &track_points_config,
370
+ "track_points",
371
+ |i, name, data| {
372
+ rwtf.add_track_point(i, name, data)
373
+ .map_err(|e| VM::raise(Class::from_existing("Exception"), &format!("{}", e)))
374
+ .unwrap();
375
+ },
376
+ );
377
+
378
+ add_points(
379
+ &source,
380
+ &course_points_config,
381
+ "course_points",
382
+ |i, name, data| {
383
+ rwtf.add_course_point(i, name, data)
384
+ .map_err(|e| VM::raise(Class::from_existing("Exception"), &format!("{}", e)))
385
+ .unwrap();
386
+ },
387
+ );
388
+
389
+ let inner = Inner { inner: rwtf };
390
+ Class::from_existing("RWTFile").wrap_data(inner, &*INNER_WRAPPER)
391
+ }
392
+
393
+ fn rwtf_simplify_track_points(surface_mapping: surface::RubySurfaceMapping,
394
+ tolerance: Float,
395
+ encode_options: polyline::RubyFieldEncodeOptionsVec) -> RString {
396
+ let track_points = &itself.get_data(&*INNER_WRAPPER).inner.track_points;
397
+ let surface_mapping_container = surface_mapping.map_err(|e| VM::raise_ex(e)).unwrap();
398
+ let mapping = surface_mapping_container.inner();
399
+ let tol = tolerance.map_err(|e| VM::raise_ex(e)).unwrap().to_f64();
400
+ let encode_options_container = encode_options.map_err(|e| VM::raise_ex(e)).unwrap();
401
+ let enc_opts = encode_options_container.inner();
402
+
403
+ RString::new_utf8(&track_points.simplify_and_encode(mapping, tol, enc_opts))
404
+ }
405
+
406
+ fn rwtf_inspect() -> RString {
407
+ let rwtf = &itself.get_data(&*INNER_WRAPPER).inner;
408
+
409
+ RString::new_utf8(&format!(
410
+ "RWTFile<track_points: {}, course_points: {}>",
411
+ rwtf.track_points.len(),
412
+ rwtf.course_points.len()
413
+ ))
414
+ }
415
+ );
416
+
417
+ rutie_serde_methods!(
418
+ RubyRWTFile,
419
+ itself,
420
+ ruby_class!(Exception),
421
+
422
+ fn rwtf_to_hash() -> &RWTFile {
423
+ &itself.get_data(&*INNER_WRAPPER).inner
424
+ }
425
+
426
+ fn rwtf_metadata() -> &RWTFMetadata {
427
+ &itself.get_data(&*INNER_WRAPPER).inner.metadata()
428
+ }
429
+ );
data/src/surface.rs ADDED
@@ -0,0 +1,143 @@
1
+ use lazy_static::lazy_static;
2
+ use rutie::{
3
+ class, methods, wrappable_struct, AnyObject, Array, Class, Float, Integer, NilClass, Object,
4
+ RString, VerifiedObject, VM,
5
+ };
6
+ use tracklib::{RoadClassMapping, SurfaceMapping};
7
+
8
+ pub struct RoadClassInner {
9
+ inner: RoadClassMapping,
10
+ }
11
+
12
+ wrappable_struct!(
13
+ RoadClassInner,
14
+ RoadClassInnerWrapper,
15
+ ROAD_CLASS_INNER_WRAPPER
16
+ );
17
+
18
+ class!(RubyRoadClassMapping);
19
+
20
+ methods!(
21
+ RubyRoadClassMapping,
22
+ itself,
23
+
24
+ fn road_class_mapping_new(bbox_array: Array) -> AnyObject {
25
+ let bbox_vec: Vec<f64> = bbox_array
26
+ .map_err(|e| VM::raise_ex(e))
27
+ .unwrap()
28
+ .into_iter()
29
+ .map(|ele| match ele.try_convert_to::<Float>() {
30
+ Ok(f) => f.to_f64(),
31
+ Err(float_e) => ele
32
+ .try_convert_to::<Integer>()
33
+ .map_err(|_| VM::raise_ex(float_e))
34
+ .unwrap()
35
+ .to_i32()
36
+ .into(),
37
+ })
38
+ .collect();
39
+ if bbox_vec.len() != 4 {
40
+ VM::raise(
41
+ Class::from_existing("Exception"),
42
+ "BBOX Array len must be 4",
43
+ );
44
+ }
45
+ let bbox = [bbox_vec[0], bbox_vec[1], bbox_vec[2], bbox_vec[3]];
46
+
47
+ let inner = RoadClassInner {
48
+ inner: tracklib::RoadClassMapping::new(bbox),
49
+ };
50
+
51
+ Class::from_existing("TracklibRoadClassMapping").wrap_data(inner, &*ROAD_CLASS_INNER_WRAPPER)
52
+ }
53
+
54
+ fn road_class_mapping_add_road_class(road_class_id: Integer, surface_id: Integer) -> NilClass {
55
+ let rc_id = road_class_id.map_err(|e| VM::raise_ex(e)).unwrap().to_i64();
56
+ let s_id = surface_id.map_err(|e| VM::raise_ex(e)).unwrap().to_i64();
57
+ let mapping = &mut itself.get_data_mut(&*ROAD_CLASS_INNER_WRAPPER).inner;
58
+ mapping.add_road_class(rc_id, s_id);
59
+
60
+ NilClass::new()
61
+ }
62
+
63
+ fn road_class_mapping_to_s() -> RString {
64
+ let mapping = &itself.get_data(&*ROAD_CLASS_INNER_WRAPPER).inner;
65
+
66
+ RString::new_utf8(&format!("{:?}", mapping))
67
+ }
68
+ );
69
+
70
+ impl VerifiedObject for RubyRoadClassMapping {
71
+ fn is_correct_type<T: Object>(object: &T) -> bool {
72
+ Class::from_existing("TracklibRoadClassMapping").case_equals(object)
73
+ }
74
+
75
+ fn error_message() -> &'static str {
76
+ "Error converting to RoadClassMapping"
77
+ }
78
+ }
79
+
80
+ pub struct SurfaceInner {
81
+ inner: SurfaceMapping,
82
+ }
83
+
84
+ wrappable_struct!(SurfaceInner, SurfaceInnerWrapper, SURFACE_INNER_WRAPPER);
85
+
86
+ class!(RubySurfaceMapping);
87
+
88
+ methods!(
89
+ RubySurfaceMapping,
90
+ itself,
91
+
92
+ fn surface_mapping_new(unknown_surface_id: Integer) -> AnyObject {
93
+ let id = unknown_surface_id
94
+ .map_err(|e| VM::raise_ex(e))
95
+ .unwrap()
96
+ .to_i64();
97
+ let inner = SurfaceInner {
98
+ inner: tracklib::SurfaceMapping::new(id),
99
+ };
100
+
101
+ Class::from_existing("TracklibSurfaceMapping").wrap_data(inner, &*SURFACE_INNER_WRAPPER)
102
+ }
103
+
104
+ fn surface_mapping_add_surface(surface_id: Integer, group: RString) -> NilClass {
105
+ let id = surface_id.map_err(|e| VM::raise_ex(e)).unwrap().to_i64();
106
+ let group_name = group.map_err(|e| VM::raise_ex(e)).unwrap().to_string();
107
+ let mapping = &mut itself.get_data_mut(&*SURFACE_INNER_WRAPPER).inner;
108
+ mapping.add_surface(id, group_name);
109
+
110
+ NilClass::new()
111
+ }
112
+
113
+ fn surface_mapping_add_road_class_mapping(road_class_mapping: RubyRoadClassMapping) -> NilClass {
114
+ let rcm = road_class_mapping.map_err(|e| VM::raise_ex(e)).unwrap();
115
+ let mapping = &mut itself.get_data_mut(&*SURFACE_INNER_WRAPPER).inner;
116
+ let road_class = &rcm.get_data(&*ROAD_CLASS_INNER_WRAPPER).inner;
117
+ mapping.add_road_class_mapping(road_class.clone());
118
+
119
+ NilClass::new()
120
+ }
121
+
122
+ fn surface_mapping_to_s() -> RString {
123
+ let mapping = &itself.get_data(&*SURFACE_INNER_WRAPPER).inner;
124
+
125
+ RString::new_utf8(&format!("{:?}", mapping))
126
+ }
127
+ );
128
+
129
+ impl RubySurfaceMapping {
130
+ pub fn inner(&self) -> &SurfaceMapping {
131
+ &self.get_data(&*SURFACE_INNER_WRAPPER).inner
132
+ }
133
+ }
134
+
135
+ impl VerifiedObject for RubySurfaceMapping {
136
+ fn is_correct_type<T: Object>(object: &T) -> bool {
137
+ Class::from_existing("TracklibSurfaceMapping").case_equals(object)
138
+ }
139
+
140
+ fn error_message() -> &'static str {
141
+ "Error converting to SurfaceMapping"
142
+ }
143
+ }
data/tracklib.gemspec CHANGED
@@ -20,12 +20,15 @@ Gem::Specification.new do |spec|
20
20
  "lib/tracklib/version.rb",
21
21
  "Cargo.toml",
22
22
  "Cargo.lock",
23
- "src/lib.rs"]
23
+ "src/lib.rs",
24
+ "src/polyline.rs",
25
+ "src/rwtfile.rs",
26
+ "src/surface.rs"]
24
27
 
25
28
  spec.require_paths = ["lib"]
26
29
  spec.extensions = ["ext/Rakefile"]
27
30
 
28
- spec.add_development_dependency "minitest", "~> 5.11"
31
+ spec.add_development_dependency "rspec"
29
32
 
30
33
  spec.add_runtime_dependency "rake", "~> 12.3"
31
34
  spec.add_runtime_dependency 'thermite', '~> 0.13'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tracklib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Larkin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-01 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: minitest
14
+ name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.11'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5.11'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -82,13 +82,16 @@ files:
82
82
  - lib/tracklib.rb
83
83
  - lib/tracklib/version.rb
84
84
  - src/lib.rs
85
+ - src/polyline.rs
86
+ - src/rwtfile.rs
87
+ - src/surface.rs
85
88
  - tracklib.gemspec
86
89
  homepage: https://ridewithgps.com
87
90
  licenses:
88
91
  - Apache-2.0
89
92
  - MIT
90
93
  metadata: {}
91
- post_install_message:
94
+ post_install_message:
92
95
  rdoc_options: []
93
96
  require_paths:
94
97
  - lib
@@ -103,9 +106,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
106
  - !ruby/object:Gem::Version
104
107
  version: '0'
105
108
  requirements: []
106
- rubyforge_project:
107
- rubygems_version: 2.6.14.3
108
- signing_key:
109
+ rubygems_version: 3.2.16
110
+ signing_key:
109
111
  specification_version: 4
110
112
  summary: tracklib
111
113
  test_files: []