geotree 1.1.4 → 1.1.5
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 +4 -4
- data/CHANGELOG.txt +2 -0
- data/lib/geotree/tools.rb +237 -112
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85af00a89ad99ed45458d35e01dccd40130f1425
|
4
|
+
data.tar.gz: f09de405c3d93b22b4ad09433a145ca5f55178fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4391cce4097615644b4fa91925528e571ce5f0820aaefba2c7724f6d99d080fc0d400aa1e7f2f5775402a85944d206f1dae7cb1a772c2cdc1338c5e00031372
|
7
|
+
data.tar.gz: cdfff7ccafcb22a97141ae2b19addb6f3031e38d0e1f8ff110adce39c8337b3a302a1fdce2345f850b8bd9188d2afc74fe72e16a6bb8a0f5ae00cd00a1191557
|
data/CHANGELOG.txt
CHANGED
data/lib/geotree/tools.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
|
+
###############################################################
|
5
|
+
#
|
4
6
|
# Various utility and debug convenience functions.
|
5
7
|
#
|
8
|
+
###############################################################
|
9
|
+
|
10
|
+
# Exception class for objects in illegal states
|
11
|
+
#
|
12
|
+
class IllegalStateException < Exception
|
13
|
+
end
|
6
14
|
|
7
15
|
# A string containing a single zero, with ASCII 8-bit encoding (i.e., plain old bytes)
|
8
16
|
ZERO_CHAR = "\0".force_encoding("ASCII-8BIT")
|
9
17
|
|
10
|
-
|
18
|
+
# Construct a string of zeros
|
19
|
+
# @param count number of zeros
|
20
|
+
#
|
11
21
|
def zero_bytes(count)
|
12
22
|
ZERO_CHAR * count
|
13
23
|
end
|
@@ -28,20 +38,16 @@ def req(fileListStr,subdir = nil)
|
|
28
38
|
end
|
29
39
|
|
30
40
|
# Shorthand for printf(...)
|
31
|
-
#
|
32
|
-
|
33
|
-
printf(*args)
|
34
|
-
end
|
35
|
-
|
41
|
+
#
|
42
|
+
alias :pr :printf
|
36
43
|
|
37
44
|
# Convert an object to a human-readable string,
|
38
|
-
# or <nil
|
45
|
+
# or <nil>; should be considered a debug-only feature
|
39
46
|
#
|
40
47
|
def d(arg)
|
41
48
|
arg.nil? ? "<nil>" : arg.inspect
|
42
49
|
end
|
43
50
|
|
44
|
-
|
45
51
|
# Convert an object to a human-readable string,
|
46
52
|
# by calling a type-appropriate function: da, dh, or just d.
|
47
53
|
# @param arg object
|
@@ -120,8 +126,6 @@ def df(flag, label=nil)
|
|
120
126
|
s
|
121
127
|
end
|
122
128
|
|
123
|
-
|
124
|
-
|
125
129
|
# Assert that a value is true. Should be considered a
|
126
130
|
# very temporary, debug-only option; it is slow and
|
127
131
|
# generates a warning that it is being called.
|
@@ -134,6 +138,9 @@ def assert!(cond, *msg)
|
|
134
138
|
raise Exception, str
|
135
139
|
end
|
136
140
|
end
|
141
|
+
|
142
|
+
# Abort with message about unimplemented code
|
143
|
+
#
|
137
144
|
def unimp!(msg = nil)
|
138
145
|
msg2 = "Unimplemented code"
|
139
146
|
if msg
|
@@ -142,7 +149,27 @@ def unimp!(msg = nil)
|
|
142
149
|
raise Exception, msg2
|
143
150
|
end
|
144
151
|
|
145
|
-
|
152
|
+
# Extensions to the Enumerable module
|
153
|
+
#
|
154
|
+
module Enumerable
|
155
|
+
# Calculate a value for each item, and return the item with the
|
156
|
+
# highest value, its index, and the value.
|
157
|
+
# @yieldparam function to calculate value of an object, given that object as a parameter
|
158
|
+
# @return the triple [object, index, value] reflecting the maximum value, or
|
159
|
+
# nil if there were no items
|
160
|
+
def max_with_index
|
161
|
+
|
162
|
+
best = nil
|
163
|
+
|
164
|
+
each_with_index do |obj,ind|
|
165
|
+
sc = yield(obj)
|
166
|
+
if !best || best[2] < sc
|
167
|
+
best = [obj,ind,sc]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
best
|
171
|
+
end
|
172
|
+
end
|
146
173
|
|
147
174
|
# Get a nice, concise description of the file and line
|
148
175
|
# of some caller within the stack.
|
@@ -211,6 +238,19 @@ def warn(*args)
|
|
211
238
|
one_time_alert("warning",0, *args)
|
212
239
|
end
|
213
240
|
|
241
|
+
# Convenience method for setting 'db' true within methods,
|
242
|
+
# and to print a one-time warning if so.
|
243
|
+
# @param val value to set db to; it is convenient to disable
|
244
|
+
# debug printing quickly by adding a zero, e.g., 'warndb 0'
|
245
|
+
#
|
246
|
+
def warndb(val = true)
|
247
|
+
if !val || val == 0
|
248
|
+
return false
|
249
|
+
end
|
250
|
+
one_time_alert("warning",1,"Debug printing enabled")
|
251
|
+
true
|
252
|
+
end
|
253
|
+
|
214
254
|
# Print an 'unimplemented' alert, one time only
|
215
255
|
# @param args if present, calls printf() with these
|
216
256
|
def unimp(*args)
|
@@ -242,22 +282,30 @@ def block
|
|
242
282
|
yield
|
243
283
|
end
|
244
284
|
|
245
|
-
#
|
285
|
+
# Construct hex representation of value
|
286
|
+
# @param value integer value
|
287
|
+
# @param num_digits number of hex digits
|
246
288
|
#
|
247
|
-
class IllegalStateException < Exception
|
248
|
-
end
|
249
|
-
|
250
|
-
|
251
289
|
def to_hex(value, num_digits=4)
|
252
290
|
s = sprintf("%x", value)
|
253
291
|
s.rjust(num_digits,'0')
|
254
292
|
end
|
255
293
|
|
294
|
+
# Hex dump a string or byte array
|
295
|
+
# @param byte_array_or_string
|
296
|
+
# @param title
|
297
|
+
# @param offset offset to first value within array
|
298
|
+
# @param length number of values to dump
|
299
|
+
# @param bytes_per_row
|
300
|
+
# @param with_text if true, displays ASCII values to right of hex dump
|
301
|
+
#
|
256
302
|
def hex_dump(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
257
303
|
ss = hex_dump_to_string(byte_array_or_string, title, offset, length, bytes_per_row, with_text)
|
258
304
|
puts ss
|
259
305
|
end
|
260
306
|
|
307
|
+
# Hex dump a string or byte array to a string; see hex_dump for parameter descriptions
|
308
|
+
#
|
261
309
|
def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
262
310
|
|
263
311
|
byte_array = byte_array_or_string
|
@@ -300,10 +348,8 @@ def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, by
|
|
300
348
|
else
|
301
349
|
ss << ' '
|
302
350
|
end
|
303
|
-
|
304
351
|
end
|
305
352
|
|
306
|
-
|
307
353
|
if with_text
|
308
354
|
ss << ' |'
|
309
355
|
bytes_per_row.times do |i|
|
@@ -327,6 +373,7 @@ $prevTime = nil
|
|
327
373
|
|
328
374
|
# Calculate time elapsed, in seconds, from last call to this function;
|
329
375
|
# if it's never been called, returns zero
|
376
|
+
#
|
330
377
|
def elapsed
|
331
378
|
curr = Time.now.to_f
|
332
379
|
elap = 0
|
@@ -337,74 +384,9 @@ def elapsed
|
|
337
384
|
elap
|
338
385
|
end
|
339
386
|
|
340
|
-
# Construct a string from an array of bytes
|
341
|
-
# @param byte_array array of bytes, or string (in which case it
|
342
|
-
# returns it unchanged)
|
343
|
-
#
|
344
|
-
def bytes_to_str(byte_array)
|
345
|
-
return byte_array if byte_array.is_a? String
|
346
|
-
|
347
|
-
byte_array.pack('C*')
|
348
|
-
end
|
349
|
-
|
350
|
-
# Construct an array of bytes from a string
|
351
|
-
# @param str string, or array of bytes (in which case it
|
352
|
-
# returns it unchanged)
|
353
|
-
#
|
354
|
-
def str_to_bytes(str)
|
355
|
-
return str if str.is_a? Array
|
356
|
-
str.bytes
|
357
|
-
end
|
358
|
-
|
359
|
-
# Get directory entries, excluding '.' and '..'
|
360
|
-
#
|
361
|
-
def dir_entries(path)
|
362
|
-
ents = Dir.entries(path)
|
363
|
-
ents.reject!{|entry| entry == '.' || entry == '..'}
|
364
|
-
end
|
365
|
-
|
366
|
-
# Convenience method for setting 'db' true within methods,
|
367
|
-
# and to print a one-time warning if so.
|
368
|
-
# @param val value to set db to; it is convenient to disable
|
369
|
-
# debug printing quickly by adding a zero, e.g., 'warndb 0'
|
370
|
-
#
|
371
|
-
def warndb(val = true)
|
372
|
-
if !val || val == 0
|
373
|
-
return false
|
374
|
-
end
|
375
|
-
one_time_alert("warning",1, "Debug printing enabled")
|
376
|
-
true
|
377
|
-
end
|
378
|
-
|
379
|
-
|
380
|
-
def int_to_bytes(x)
|
381
|
-
[(x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]
|
382
|
-
end
|
383
|
-
|
384
|
-
def short_to_bytes(x)
|
385
|
-
[(x >> 8) & 0xff, x & 0xff]
|
386
|
-
end
|
387
|
-
|
388
|
-
# Decode a short from an array of bytes (big-endian).
|
389
|
-
# @param ba array of bytes
|
390
|
-
# @param offset offset of first (most significant) byte
|
391
|
-
#
|
392
|
-
def short_from_bytes(ba, offset=0)
|
393
|
-
(ba[offset] << 8) | ba[offset + 1]
|
394
|
-
end
|
395
|
-
|
396
|
-
# Decode an int from an array of bytes (big-endian).
|
397
|
-
# @param ba array of bytes
|
398
|
-
# @param offset offset of first (most significant) byte
|
399
|
-
#
|
400
|
-
def int_from_bytes(ba, offset=0)
|
401
|
-
(((((ba[offset] << 8) | ba[offset + 1]) << 8) | \
|
402
|
-
ba[offset + 2]) << 8) | ba[offset + 3]
|
403
|
-
end
|
404
|
-
|
405
|
-
|
406
387
|
# Delete a file or directory, if it exists.
|
407
388
|
# Caution! If directory, deletes all files and subdirectories.
|
389
|
+
#
|
408
390
|
def remove_file_or_dir(pth)
|
409
391
|
if File.directory?(pth)
|
410
392
|
FileUtils.remove_dir(pth)
|
@@ -413,46 +395,101 @@ def remove_file_or_dir(pth)
|
|
413
395
|
end
|
414
396
|
end
|
415
397
|
|
416
|
-
|
398
|
+
require 'stringio'
|
399
|
+
|
400
|
+
$IODest = nil
|
401
|
+
$OldStdOut = nil
|
402
|
+
|
403
|
+
# Redirect standard output to an internal string
|
417
404
|
#
|
418
|
-
def
|
419
|
-
|
405
|
+
def capture_begin
|
406
|
+
raise IllegalStateException if $IODest
|
407
|
+
$IODest = StringIO.new
|
408
|
+
$OldStdOut, $stdout = $stdout, $IODest
|
420
409
|
end
|
421
410
|
|
422
|
-
#
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
411
|
+
# Restore standard output; return captured text
|
412
|
+
# @return text that was redirected
|
413
|
+
#
|
414
|
+
def capture_end
|
415
|
+
raise IllegalStateException if !$IODest
|
416
|
+
$stdout = $OldStdOut
|
417
|
+
ret = $IODest.string
|
418
|
+
$IODest = nil
|
419
|
+
ret
|
428
420
|
end
|
429
421
|
|
430
|
-
#
|
422
|
+
# Compare a string with disk file; abort if different. Disk filename is derived
|
423
|
+
# from caller function name; e.g., test_xxx produces filename _output_xxx
|
431
424
|
#
|
432
|
-
# @param
|
433
|
-
# @param size
|
434
|
-
# @param pad padding character to use if string needs to grow
|
435
|
-
# @return modified string
|
425
|
+
# @param str if not nil, string to compare; if nil, calls capture_end to get string
|
436
426
|
#
|
437
|
-
def
|
438
|
-
s[0...size].ljust(size,pad)
|
439
|
-
end
|
427
|
+
def match_expected_output(str = nil)
|
440
428
|
|
441
|
-
|
442
|
-
|
443
|
-
#
|
444
|
-
def windows?
|
445
|
-
if !defined? $__windows__
|
446
|
-
$__windows__ = (RUBY_PLATFORM =~ /mswin/)
|
429
|
+
if !str
|
430
|
+
str = capture_end
|
447
431
|
end
|
448
|
-
$__windows__
|
449
|
-
end
|
450
432
|
|
433
|
+
cl_method = caller[0][/`.*'/][1..-2]
|
434
|
+
if (cl_method.start_with?("test_"))
|
435
|
+
cl_method = cl_method[5..-1]
|
436
|
+
end
|
437
|
+
path = "_output_" + cl_method + ".txt"
|
438
|
+
|
439
|
+
if !File.file?(path)
|
440
|
+
printf("no such file #{path} exists, writing it...\n")
|
441
|
+
write_text_file(path,str)
|
442
|
+
else
|
443
|
+
exp_cont = read_text_file(path)
|
444
|
+
if str != exp_cont
|
445
|
+
d1 = str
|
446
|
+
d2 = exp_cont
|
447
|
+
|
448
|
+
# Find location where they differ
|
449
|
+
lines1 = d1.split("\n")
|
450
|
+
lines2 = d2.split("\n")
|
451
|
+
j = [lines1.size, lines2.size].max
|
452
|
+
|
453
|
+
s = "???"
|
454
|
+
found_diff = false
|
455
|
+
hist = []
|
456
|
+
|
457
|
+
found_count = 0
|
458
|
+
j.times do |i|
|
459
|
+
found_diff ||= (i >= lines1.size || i >= lines2.size || lines1[i] != lines2[i])
|
460
|
+
s = sprintf("%3d:",i)
|
461
|
+
if !found_diff
|
462
|
+
hist << "#{s} #{lines1[i]}\n #{lines2[i]}\n"
|
463
|
+
else
|
464
|
+
if found_count < 3
|
465
|
+
if i < lines1.size
|
466
|
+
s << " #{lines1[i]}\n"
|
467
|
+
else
|
468
|
+
s << " ---END---\n"
|
469
|
+
end
|
470
|
+
if i < lines2.size
|
471
|
+
s << " #{lines2[i]}\n"
|
472
|
+
else
|
473
|
+
s << " ---END---\n"
|
474
|
+
end
|
475
|
+
hist << s
|
476
|
+
end
|
477
|
+
found_count += 1
|
478
|
+
end
|
479
|
+
while hist.size > 6
|
480
|
+
hist.shift
|
481
|
+
end
|
482
|
+
end
|
483
|
+
dash = "-" * 95 + "\n"
|
484
|
+
raise IllegalStateException,"output did not match expected:\n#{dash}#{hist.join('')}#{dash}"
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
451
488
|
|
452
489
|
# Convenience method to detect if a script is being run
|
453
490
|
# e.g. as a 'main' method (for debug purposes only).
|
454
491
|
# If so, it changes the current directory to the
|
455
|
-
# directory containing the script.
|
492
|
+
# directory containing the script (if such a directory exists).
|
456
493
|
#
|
457
494
|
# @param file pass __FILE__ in here
|
458
495
|
# @return true if so
|
@@ -469,7 +506,10 @@ def main?(file)
|
|
469
506
|
end
|
470
507
|
|
471
508
|
if (ret = (file == scr))
|
472
|
-
|
509
|
+
dr = File.dirname(file)
|
510
|
+
if File.directory?(dr)
|
511
|
+
Dir.chdir(dr)
|
512
|
+
end
|
473
513
|
end
|
474
514
|
ret
|
475
515
|
end
|
@@ -577,6 +617,92 @@ if defined? Test::Unit
|
|
577
617
|
end
|
578
618
|
end
|
579
619
|
|
620
|
+
# Construct a string from an array of bytes
|
621
|
+
# @param byte_array array of bytes, or string (in which case it
|
622
|
+
# returns it unchanged)
|
623
|
+
#
|
624
|
+
def bytes_to_str(byte_array)
|
625
|
+
return byte_array if byte_array.is_a? String
|
626
|
+
|
627
|
+
byte_array.pack('C*')
|
628
|
+
end
|
629
|
+
|
630
|
+
# Construct an array of bytes from a string
|
631
|
+
# @param str string, or array of bytes (in which case it
|
632
|
+
# returns it unchanged)
|
633
|
+
#
|
634
|
+
def str_to_bytes(str)
|
635
|
+
return str if str.is_a? Array
|
636
|
+
str.bytes
|
637
|
+
end
|
638
|
+
|
639
|
+
# Get directory entries, excluding '.' and '..'
|
640
|
+
#
|
641
|
+
def dir_entries(path)
|
642
|
+
ents = Dir.entries(path)
|
643
|
+
ents.reject!{|entry| entry == '.' || entry == '..'}
|
644
|
+
end
|
645
|
+
|
646
|
+
def int_to_bytes(x)
|
647
|
+
[(x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]
|
648
|
+
end
|
649
|
+
|
650
|
+
def short_to_bytes(x)
|
651
|
+
[(x >> 8) & 0xff, x & 0xff]
|
652
|
+
end
|
653
|
+
|
654
|
+
# Decode a short from an array of bytes (big-endian).
|
655
|
+
# @param ba array of bytes
|
656
|
+
# @param offset offset of first (most significant) byte
|
657
|
+
#
|
658
|
+
def short_from_bytes(ba, offset=0)
|
659
|
+
(ba[offset] << 8) | ba[offset + 1]
|
660
|
+
end
|
661
|
+
|
662
|
+
# Decode an int from an array of bytes (big-endian).
|
663
|
+
# @param ba array of bytes
|
664
|
+
# @param offset offset of first (most significant) byte
|
665
|
+
#
|
666
|
+
def int_from_bytes(ba, offset=0)
|
667
|
+
(((((ba[offset] << 8) | ba[offset + 1]) << 8) | \
|
668
|
+
ba[offset + 2]) << 8) | ba[offset + 3]
|
669
|
+
end
|
670
|
+
|
671
|
+
# Transform string to 8-bit ASCII (i.e., just treat each byte as-is)
|
672
|
+
#
|
673
|
+
def to_ascii8(str)
|
674
|
+
str.force_encoding("ASCII-8BIT")
|
675
|
+
end
|
676
|
+
|
677
|
+
# Verify that a string is encoded as ASCII-8BIT
|
678
|
+
def simple_str(s)
|
679
|
+
if s.encoding.name != 'ASCII-8BIT' && s.encoding.name != 'UTF-8'
|
680
|
+
pr("string [%s]\n encoding is %s,\n expected ASCII-8BIT\n",s,s.encoding.name)
|
681
|
+
assert!(false)
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
# Truncate or pad string so it has a particular size
|
686
|
+
#
|
687
|
+
# @param s input string
|
688
|
+
# @param size
|
689
|
+
# @param pad padding character to use if string needs to grow
|
690
|
+
# @return modified string
|
691
|
+
#
|
692
|
+
def str_sized(s, size, pad="\0")
|
693
|
+
s[0...size].ljust(size,pad)
|
694
|
+
end
|
695
|
+
|
696
|
+
# Determine if running on the Windows operating system.
|
697
|
+
# Note: there is some debate about the best way to do this.
|
698
|
+
#
|
699
|
+
def windows?
|
700
|
+
if !defined? $__windows__
|
701
|
+
$__windows__ = (RUBY_PLATFORM =~ /mswin/)
|
702
|
+
end
|
703
|
+
$__windows__
|
704
|
+
end
|
705
|
+
|
580
706
|
# Mark all constants ending with '_' as private constants
|
581
707
|
#
|
582
708
|
# @param entity the class to examine
|
@@ -624,4 +750,3 @@ def privatize(entity, add_non_suffix_versions = false)
|
|
624
750
|
eval(cmd2)
|
625
751
|
end
|
626
752
|
end
|
627
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geotree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Sember
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-04-
|
11
|
+
date: 2013-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: " \nA GeoTree is a variant of a k-d tree, and stores data points that
|
14
14
|
have a latitude and longitude, \na unique integer identifier, and an optional 'weight'
|