lenc 1.1.2 → 1.1.3
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 +3 -1
- data/lib/lenc/_OLD_tools.rb +628 -0
- data/lib/lenc/tools.rb +292 -176
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4b56f1960462bf9fd9382ff2059182a881e51dd
|
4
|
+
data.tar.gz: 0cb704fcc7bda5e7a326202be609027d1cb7edfa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41948757b4d963f3b7cc23f6c8292e8ce51b918b2f1860087cb34c3d95765f6b82900fee46c47adb399b01cb6050a09761c6d56caf3c921badbb542263f45a1a
|
7
|
+
data.tar.gz: da5a5af9488d3901d29b71c29556df4c343f0dfa82c882556dad404ef24148e593e046d022604abef1cb2b4859c832fa49b41695d1d20fbb4e49bcf7fb3ad038
|
data/CHANGELOG.txt
CHANGED
@@ -0,0 +1,628 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
# Various utility and debug convenience functions.
|
5
|
+
#
|
6
|
+
|
7
|
+
# Convenience method to perform 'require_relative' on a set of files
|
8
|
+
#
|
9
|
+
# @param fileListStr space-delimited file/path items, without .rb extensions
|
10
|
+
# @param subdir optional path to files relative to this file
|
11
|
+
#
|
12
|
+
def req(fileListStr,subdir = nil)
|
13
|
+
fileListStr.split(' ').each do |x|
|
14
|
+
if subdir
|
15
|
+
x = File.join(subdir,x)
|
16
|
+
end
|
17
|
+
x += '.rb'
|
18
|
+
require_relative(x)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Shorthand for printf(...)
|
23
|
+
# @param args passed to printf
|
24
|
+
def pr(*args)
|
25
|
+
printf(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert an object to a human-readable string,
|
29
|
+
# or <nil>; should be considered a debug-only feature
|
30
|
+
#
|
31
|
+
def d(arg)
|
32
|
+
arg.nil? ? "<nil>" : arg.inspect
|
33
|
+
end
|
34
|
+
|
35
|
+
# Convert an object to a human-readable string,
|
36
|
+
# by calling a type-appropriate function: da, dh, or just d.
|
37
|
+
# @param arg object
|
38
|
+
# @param indent optional indentation for pretty printing; if result
|
39
|
+
# spans multiple lines, each line should be indented by this amount
|
40
|
+
#
|
41
|
+
def d2(arg, indent = 0)
|
42
|
+
return da(arg, indent) if arg.is_a? Array
|
43
|
+
return dh(arg, indent) if arg.is_a? Hash
|
44
|
+
return df(arg) if arg.class == FalseClass || arg.class == TrueClass
|
45
|
+
return d(arg)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Convert an object to a human-readable string, prefixed with its type
|
49
|
+
#
|
50
|
+
def dt(arg)
|
51
|
+
if arg.nil?
|
52
|
+
return "<nil>"
|
53
|
+
end
|
54
|
+
s = arg.class.to_s
|
55
|
+
s << ':'
|
56
|
+
s << arg.inspect
|
57
|
+
s
|
58
|
+
end
|
59
|
+
|
60
|
+
# Append a particular number of spaces to a string
|
61
|
+
def add_sp(s, indent = 0)
|
62
|
+
s << ' ' * indent
|
63
|
+
end
|
64
|
+
|
65
|
+
# Pretty-print an array,
|
66
|
+
# one element to a line
|
67
|
+
# @param indent indentation of each line, in spaces
|
68
|
+
def da(array, indent = 0)
|
69
|
+
return d(array) if !array
|
70
|
+
s = 'Array ['
|
71
|
+
indent += 2
|
72
|
+
array.each do |x|
|
73
|
+
s << "\n"
|
74
|
+
add_sp(s,indent)
|
75
|
+
s2 = d2(x, indent + 2)
|
76
|
+
s << s2
|
77
|
+
end
|
78
|
+
s << " ]"
|
79
|
+
s
|
80
|
+
end
|
81
|
+
|
82
|
+
# Pretty-print a hash,
|
83
|
+
# one element to a line
|
84
|
+
# @param indent indentation of each line, in spaces
|
85
|
+
def dh(hash, indent = 0)
|
86
|
+
return d(hash) if !hash
|
87
|
+
s = 'Hash {'
|
88
|
+
indent += 2
|
89
|
+
hash.each_pair do |key,val|
|
90
|
+
s2 = d(key)
|
91
|
+
s3 = d2(val, indent + 4)
|
92
|
+
s << "\n "
|
93
|
+
add_sp(s,indent)
|
94
|
+
s << s2.chomp << " => " << s3.chomp
|
95
|
+
end
|
96
|
+
s << " }"
|
97
|
+
s
|
98
|
+
end
|
99
|
+
|
100
|
+
# Generate debug description of a boolean value
|
101
|
+
# @param flag value to interpret as a boolean; prints 'T' iff not nil
|
102
|
+
# @param label optional label
|
103
|
+
def df(flag, label=nil)
|
104
|
+
s = ''
|
105
|
+
if label
|
106
|
+
s << label << ':'
|
107
|
+
end
|
108
|
+
s << (flag ? "T" : "F")
|
109
|
+
s << ' '
|
110
|
+
s
|
111
|
+
end
|
112
|
+
|
113
|
+
# Assert that a value is true. Should be considered a
|
114
|
+
# very temporary, debug-only option; it is slow and
|
115
|
+
# generates a warning that it is being called.
|
116
|
+
# @param cond condition
|
117
|
+
# @param msg generates additional message using printf(), if these arguments exist
|
118
|
+
def assert!(cond, *msg)
|
119
|
+
one_time_alert("warning",0,"Checking assertion")
|
120
|
+
if not cond
|
121
|
+
str = (msg.size == 0) ? "assertion error" : sprintf(*msg)
|
122
|
+
raise Exception, str
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Extensions to the Enumerable module
|
127
|
+
#
|
128
|
+
module Enumerable
|
129
|
+
# Calculate a value for each item, and return the item with the
|
130
|
+
# highest value, its index, and the value.
|
131
|
+
# @yieldparam function to calculate value of an object, given that object as a parameter
|
132
|
+
# @return the triple [object, index, value] reflecting the maximum value, or
|
133
|
+
# nil if there were no items
|
134
|
+
def max_with_index
|
135
|
+
|
136
|
+
best = nil
|
137
|
+
|
138
|
+
each_with_index do |obj,ind|
|
139
|
+
sc = yield(obj)
|
140
|
+
if !best || best[2] < sc
|
141
|
+
best = [obj,ind,sc]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
best
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Get a nice, concise description of the file and line
|
149
|
+
# of some caller within the stack.
|
150
|
+
#
|
151
|
+
# @param nSkip the number of items deep in the call stack to look
|
152
|
+
#
|
153
|
+
def get_caller_location(nSkip = 2)
|
154
|
+
|
155
|
+
filename = nil
|
156
|
+
linenumber = nil
|
157
|
+
|
158
|
+
if nSkip >= 0 && nSkip < caller.size
|
159
|
+
fi = caller[nSkip]
|
160
|
+
|
161
|
+
i = fi.index(':')
|
162
|
+
j = nil
|
163
|
+
if i
|
164
|
+
j = fi.index(':',i+1)
|
165
|
+
end
|
166
|
+
if j
|
167
|
+
pth = fi[0,i].split('/')
|
168
|
+
if pth.size
|
169
|
+
filename = pth[-1]
|
170
|
+
end
|
171
|
+
linenumber = fi[i+1,j-i-1]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
if filename && linenumber
|
175
|
+
loc = filename + " ("+linenumber+")"
|
176
|
+
else
|
177
|
+
loc = "(UNKNOWN LOCATION)"
|
178
|
+
end
|
179
|
+
loc
|
180
|
+
end
|
181
|
+
|
182
|
+
# Set of alert strings that have already been reported
|
183
|
+
# (to avoid printing anything on subsequent invocations)
|
184
|
+
#
|
185
|
+
$AlertStrings = Set.new
|
186
|
+
|
187
|
+
# Print a message if it hasn't yet been printed,
|
188
|
+
# which includes the caller's location
|
189
|
+
#
|
190
|
+
# @param typeString e.g., "warning", "unimplemented"
|
191
|
+
# @param nSkip the number of levels deep that the caller is in the stack
|
192
|
+
# @param args if present, calls sprintf(...) with these to append to the message
|
193
|
+
#
|
194
|
+
def one_time_alert(typeString, nSkip, *args)
|
195
|
+
loc = get_caller_location(nSkip + 2)
|
196
|
+
s = "*** "+typeString+" " + loc
|
197
|
+
if args && args.size
|
198
|
+
s2 = sprintf(args[0], *args[1..-1])
|
199
|
+
msg = s + ": " + s2
|
200
|
+
else
|
201
|
+
msg = s
|
202
|
+
end
|
203
|
+
|
204
|
+
if $AlertStrings.add?(msg)
|
205
|
+
puts msg
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Print a 'warning' alert, one time only
|
210
|
+
# @param args if present, calls printf() with these
|
211
|
+
def warn(*args)
|
212
|
+
one_time_alert("warning",0, *args)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Convenience method for setting 'db' true within methods,
|
216
|
+
# and to print a one-time warning if so.
|
217
|
+
# @param val value to set db to; it is convenient to disable
|
218
|
+
# debug printing quickly by adding a zero, e.g., 'warndb 0'
|
219
|
+
#
|
220
|
+
def warndb(val = true)
|
221
|
+
if !val || val == 0
|
222
|
+
return false
|
223
|
+
end
|
224
|
+
one_time_alert("warning",1, "Debug printing enabled")
|
225
|
+
true
|
226
|
+
end
|
227
|
+
|
228
|
+
# Print an 'unimplemented' alert, one time only
|
229
|
+
# @param args if present, calls printf() with these
|
230
|
+
def unimp(*args)
|
231
|
+
one_time_alert("unimplemented", 0, *args)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Write a string to a text file
|
235
|
+
#
|
236
|
+
def write_text_file(path, contents)
|
237
|
+
File.open(path, "wb") {|f| f.write(contents) }
|
238
|
+
end
|
239
|
+
|
240
|
+
# Read a file's contents, return as a string
|
241
|
+
#
|
242
|
+
def read_text_file(path)
|
243
|
+
contents = nil
|
244
|
+
File.open(path,"rb") {|f| contents = f.read }
|
245
|
+
contents
|
246
|
+
end
|
247
|
+
|
248
|
+
# Method that takes a code block as an argument to
|
249
|
+
# achieve the same functionality as Java/C++'s
|
250
|
+
# do {
|
251
|
+
# ...
|
252
|
+
# ... possibly with 'break' to jump to the end ...
|
253
|
+
# } while (false);
|
254
|
+
#
|
255
|
+
def block
|
256
|
+
yield
|
257
|
+
end
|
258
|
+
|
259
|
+
# Exception class for objects in illegal states
|
260
|
+
#
|
261
|
+
class IllegalStateException < Exception
|
262
|
+
end
|
263
|
+
|
264
|
+
def to_hex(value, num_digits=4)
|
265
|
+
s = sprintf("%x", value)
|
266
|
+
s.rjust(num_digits,'0')
|
267
|
+
end
|
268
|
+
|
269
|
+
def hex_dump(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
270
|
+
ss = hex_dump_to_string(byte_array_or_string, title, offset, length, bytes_per_row, with_text)
|
271
|
+
puts ss
|
272
|
+
end
|
273
|
+
|
274
|
+
def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
275
|
+
|
276
|
+
byte_array = byte_array_or_string
|
277
|
+
if byte_array.is_a? String
|
278
|
+
byte_array = byte_array.bytes.to_a
|
279
|
+
end
|
280
|
+
|
281
|
+
ss = ''
|
282
|
+
|
283
|
+
if title
|
284
|
+
ss << title << ":\n"
|
285
|
+
end
|
286
|
+
|
287
|
+
if length < 0
|
288
|
+
length = byte_array.size - offset
|
289
|
+
end
|
290
|
+
|
291
|
+
length = [length, byte_array.size - offset].min
|
292
|
+
|
293
|
+
max_addr = offset + length - 1
|
294
|
+
num_digits = 4
|
295
|
+
while (1 << (4 * num_digits)) <= max_addr
|
296
|
+
num_digits += 1
|
297
|
+
end
|
298
|
+
|
299
|
+
while true
|
300
|
+
ss << to_hex(offset, num_digits)
|
301
|
+
ss << ': '
|
302
|
+
|
303
|
+
chunk = [length, bytes_per_row].min
|
304
|
+
bytes_per_row.times do |i|
|
305
|
+
if i % 4 == 0
|
306
|
+
ss << ' '
|
307
|
+
end
|
308
|
+
|
309
|
+
if i < chunk
|
310
|
+
v = byte_array[offset + i]
|
311
|
+
ss << ((v != 0) ? to_hex(v,2) : '..')
|
312
|
+
ss << ' '
|
313
|
+
else
|
314
|
+
ss << ' '
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
if with_text
|
321
|
+
ss << ' |'
|
322
|
+
bytes_per_row.times do |i|
|
323
|
+
if i < chunk
|
324
|
+
v = byte_array[offset + i]
|
325
|
+
ss << ((v >= 32 && v < 127) ? v : '_')
|
326
|
+
end
|
327
|
+
end
|
328
|
+
ss << '|'
|
329
|
+
end
|
330
|
+
ss << "\n"
|
331
|
+
|
332
|
+
length -= chunk
|
333
|
+
offset += chunk
|
334
|
+
break if length <= 0
|
335
|
+
end
|
336
|
+
|
337
|
+
ss << "\n"
|
338
|
+
ss
|
339
|
+
end
|
340
|
+
|
341
|
+
$prevTime = nil
|
342
|
+
|
343
|
+
# Calculate time elapsed, in seconds, from last call to this function;
|
344
|
+
# if it's never been called, returns zero
|
345
|
+
def elapsed
|
346
|
+
curr = Time.now.to_f
|
347
|
+
elap = 0
|
348
|
+
if $prevTime
|
349
|
+
elap = curr - $prevTime
|
350
|
+
end
|
351
|
+
$prevTime = curr
|
352
|
+
elap
|
353
|
+
end
|
354
|
+
|
355
|
+
# Delete a file or directory, if it exists.
|
356
|
+
# Caution! If directory, deletes all files and subdirectories.
|
357
|
+
def remove_file_or_dir(pth)
|
358
|
+
if File.directory?(pth)
|
359
|
+
FileUtils.remove_dir(pth)
|
360
|
+
elsif File.file?(pth)
|
361
|
+
FileUtils.remove_file(pth)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
require 'stringio'
|
366
|
+
|
367
|
+
$IODest = nil
|
368
|
+
$OldStdOut = nil
|
369
|
+
|
370
|
+
def capture_begin
|
371
|
+
raise IllegalStateException if $IODest
|
372
|
+
$IODest = StringIO.new
|
373
|
+
$OldStdOut, $stdout = $stdout, $IODest
|
374
|
+
end
|
375
|
+
|
376
|
+
def capture_end
|
377
|
+
raise IllegalStateException if !$IODest
|
378
|
+
$stdout = $OldStdOut
|
379
|
+
ret = $IODest.string
|
380
|
+
$IODest = nil
|
381
|
+
ret
|
382
|
+
end
|
383
|
+
|
384
|
+
def match_expected_output(str = nil)
|
385
|
+
|
386
|
+
if !str
|
387
|
+
str = capture_end
|
388
|
+
end
|
389
|
+
|
390
|
+
cl_method = caller[0][/`.*'/][1..-2]
|
391
|
+
if (cl_method.start_with?("test_"))
|
392
|
+
cl_method = cl_method[5..-1]
|
393
|
+
end
|
394
|
+
path = "_output_" + cl_method + ".txt"
|
395
|
+
# path = File.absolute_path(path)
|
396
|
+
|
397
|
+
if !File.file?(path)
|
398
|
+
printf("no such file #{path} exists, writing it...\n")
|
399
|
+
writeTextFile(path,str)
|
400
|
+
else
|
401
|
+
exp_cont = read_text_file(path)
|
402
|
+
if str != exp_cont
|
403
|
+
d1 = str
|
404
|
+
d2 = exp_cont
|
405
|
+
# d1 = hex_dump_to_string(str,"Output")
|
406
|
+
# d2 = hex_dump_to_string(exp_cont,"Expected")
|
407
|
+
|
408
|
+
raise IllegalStateException,"output did not match expected:\n#{d1}#{d2}"
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# Convenience method to detect if a script is being run
|
414
|
+
# e.g. as a 'main' method (for debug purposes only).
|
415
|
+
# If so, it changes the current directory to the
|
416
|
+
# directory containing the script (if such a directory exists).
|
417
|
+
#
|
418
|
+
# @param file pass __FILE__ in here
|
419
|
+
# @return true if so
|
420
|
+
#
|
421
|
+
def main?(file)
|
422
|
+
|
423
|
+
scr = $0
|
424
|
+
|
425
|
+
# The test/unit framework seems to be adding a suffix ": xxx#xxx.."
|
426
|
+
# to the .rb filename, so adjust in this case
|
427
|
+
i = scr.index(".rb: ")
|
428
|
+
if i
|
429
|
+
scr = scr[0...i+3]
|
430
|
+
end
|
431
|
+
|
432
|
+
if (ret = (file == scr))
|
433
|
+
dr = File.dirname(file)
|
434
|
+
if File.directory?(dr)
|
435
|
+
Dir.chdir(dr)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
ret
|
439
|
+
end
|
440
|
+
|
441
|
+
if defined? Test::Unit
|
442
|
+
|
443
|
+
# A simple extension to Ruby's Test::Unit class that provides
|
444
|
+
# suite-level setup/teardown methods.
|
445
|
+
#
|
446
|
+
# If test suite functionality is desired within a script,
|
447
|
+
# then require 'test/unit' before requiring 'tools.rb'.
|
448
|
+
# This will cause the following class, MyTestSuite, to be defined.
|
449
|
+
#
|
450
|
+
# The user's test script can define subclasses of this,
|
451
|
+
# and declare test methods with the name 'test_xxxx', where
|
452
|
+
# xxxx is lexicographically between 01 and zz.
|
453
|
+
#
|
454
|
+
# There are two levels of setup/teardown called : suite level, and
|
455
|
+
# method level. For example, if the user's test class performs two tests:
|
456
|
+
#
|
457
|
+
# def test_b ... end
|
458
|
+
# def test_c ... end
|
459
|
+
#
|
460
|
+
# Then the test framework will make these calls:
|
461
|
+
#
|
462
|
+
# suite_setup
|
463
|
+
#
|
464
|
+
# method_setup
|
465
|
+
# test_b
|
466
|
+
# method_teardown
|
467
|
+
#
|
468
|
+
# method_setup
|
469
|
+
# test_c
|
470
|
+
# method_teardown
|
471
|
+
#
|
472
|
+
# suite_teardown
|
473
|
+
#
|
474
|
+
# Notes
|
475
|
+
# -----
|
476
|
+
# 1) The usual setup / teardown methods should NOT be overridden; instead,
|
477
|
+
# use the method_xxx alternatives.
|
478
|
+
#
|
479
|
+
# 2) The base class implementations of method_/suite_xxx do nothing.
|
480
|
+
#
|
481
|
+
# 3) The number of test cases reported may be higher than you expect, since
|
482
|
+
# there are additional test methods defined by the TestSuite class to
|
483
|
+
# implement the suite setup / teardown functionality.
|
484
|
+
#
|
485
|
+
# 4) Avoid naming test methods that fall outside of test_01 ... test_zz.
|
486
|
+
#
|
487
|
+
class MyTestSuite < Test::Unit::TestCase
|
488
|
+
|
489
|
+
# This is named to be the FIRST test called. It
|
490
|
+
# will do suite-level setup, and nothing else.
|
491
|
+
def test_00_setup
|
492
|
+
@@suiteSetup = true
|
493
|
+
suite_setup()
|
494
|
+
end
|
495
|
+
|
496
|
+
# This is named to be the LAST test called. It
|
497
|
+
# will do suite-level teardown, and nothing else.
|
498
|
+
def test_zzzzzz_teardown
|
499
|
+
suite_teardown()
|
500
|
+
@@suiteSetup = false
|
501
|
+
end
|
502
|
+
|
503
|
+
# True if called within suite-level setup/teardown window
|
504
|
+
def _suite_active?
|
505
|
+
!(@__name__ == "test_00_setup" || @__name__ == "test_zzzzzz_teardown")
|
506
|
+
end
|
507
|
+
|
508
|
+
def setup
|
509
|
+
if _suite_active?
|
510
|
+
# If only a specific test was requested, the
|
511
|
+
# suite setup may not have run... if not, do it now.
|
512
|
+
if !defined? @@suiteSetup
|
513
|
+
suite_setup
|
514
|
+
end
|
515
|
+
return
|
516
|
+
end
|
517
|
+
method_setup
|
518
|
+
end
|
519
|
+
|
520
|
+
def teardown
|
521
|
+
if _suite_active?
|
522
|
+
if !defined? @@suiteSetup
|
523
|
+
suite_teardown
|
524
|
+
end
|
525
|
+
return
|
526
|
+
end
|
527
|
+
method_teardown
|
528
|
+
end
|
529
|
+
|
530
|
+
def suite_setup
|
531
|
+
end
|
532
|
+
|
533
|
+
def suite_teardown
|
534
|
+
end
|
535
|
+
|
536
|
+
def method_setup
|
537
|
+
end
|
538
|
+
|
539
|
+
def method_teardown
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
# Construct a string from an array of bytes
|
545
|
+
# @param byte_array array of bytes, or string (in which case it
|
546
|
+
# returns it unchanged)
|
547
|
+
#
|
548
|
+
def bytes_to_str(byte_array)
|
549
|
+
return byte_array if byte_array.is_a? String
|
550
|
+
|
551
|
+
byte_array.pack('C*')
|
552
|
+
end
|
553
|
+
|
554
|
+
# Construct an array of bytes from a string
|
555
|
+
# @param str string, or array of bytes (in which case it
|
556
|
+
# returns it unchanged)
|
557
|
+
#
|
558
|
+
def str_to_bytes(str)
|
559
|
+
return str if str.is_a? Array
|
560
|
+
str.bytes
|
561
|
+
end
|
562
|
+
|
563
|
+
# Get directory entries, excluding '.' and '..'
|
564
|
+
#
|
565
|
+
def dir_entries(path)
|
566
|
+
ents = Dir.entries(path)
|
567
|
+
ents.reject!{|entry| entry == '.' || entry == '..'}
|
568
|
+
end
|
569
|
+
|
570
|
+
def int_to_bytes(x)
|
571
|
+
[(x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]
|
572
|
+
end
|
573
|
+
|
574
|
+
def short_to_bytes(x)
|
575
|
+
[(x >> 8) & 0xff, x & 0xff]
|
576
|
+
end
|
577
|
+
|
578
|
+
# Decode a short from an array of bytes (big-endian).
|
579
|
+
# @param ba array of bytes
|
580
|
+
# @param offset offset of first (most significant) byte
|
581
|
+
#
|
582
|
+
def short_from_bytes(ba, offset=0)
|
583
|
+
(ba[offset] << 8) | ba[offset + 1]
|
584
|
+
end
|
585
|
+
|
586
|
+
# Decode an int from an array of bytes (big-endian).
|
587
|
+
# @param ba array of bytes
|
588
|
+
# @param offset offset of first (most significant) byte
|
589
|
+
#
|
590
|
+
def int_from_bytes(ba, offset=0)
|
591
|
+
(((((ba[offset] << 8) | ba[offset + 1]) << 8) | \
|
592
|
+
ba[offset + 2]) << 8) | ba[offset + 3]
|
593
|
+
end
|
594
|
+
|
595
|
+
# Transform string to 8-bit ASCII (i.e., just treat each byte as-is)
|
596
|
+
#
|
597
|
+
def to_ascii8(str)
|
598
|
+
str.force_encoding("ASCII-8BIT")
|
599
|
+
end
|
600
|
+
|
601
|
+
# Verify that a string is encoded as ASCII-8BIT
|
602
|
+
def simple_str(s)
|
603
|
+
if s.encoding.name != 'ASCII-8BIT' && s.encoding.name != 'UTF-8'
|
604
|
+
pr("string [%s]\n encoding is %s,\n expected ASCII-8BIT\n",s,s.encoding.name)
|
605
|
+
assert!(false)
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
# Truncate or pad string so it has a particular size
|
610
|
+
#
|
611
|
+
# @param s input string
|
612
|
+
# @param size
|
613
|
+
# @param pad padding character to use if string needs to grow
|
614
|
+
# @return modified string
|
615
|
+
#
|
616
|
+
def str_sized(s, size, pad="\0")
|
617
|
+
s[0...size].ljust(size,pad)
|
618
|
+
end
|
619
|
+
|
620
|
+
# Determine if running on the Windows operating system.
|
621
|
+
# Note: there is some debate about the best way to do this.
|
622
|
+
#
|
623
|
+
def windows?
|
624
|
+
if !defined? $__windows__
|
625
|
+
$__windows__ = (RUBY_PLATFORM =~ /mswin/)
|
626
|
+
end
|
627
|
+
$__windows__
|
628
|
+
end
|
data/lib/lenc/tools.rb
CHANGED
@@ -1,8 +1,26 @@
|
|
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
|
14
|
+
|
15
|
+
# A string containing a single zero, with ASCII 8-bit encoding (i.e., plain old bytes)
|
16
|
+
ZERO_CHAR = "\0".force_encoding("ASCII-8BIT")
|
17
|
+
|
18
|
+
# Construct a string of zeros
|
19
|
+
# @param count number of zeros
|
20
|
+
#
|
21
|
+
def zero_bytes(count)
|
22
|
+
ZERO_CHAR * count
|
23
|
+
end
|
6
24
|
|
7
25
|
# Convenience method to perform 'require_relative' on a set of files
|
8
26
|
#
|
@@ -20,20 +38,16 @@ def req(fileListStr,subdir = nil)
|
|
20
38
|
end
|
21
39
|
|
22
40
|
# Shorthand for printf(...)
|
23
|
-
#
|
24
|
-
|
25
|
-
printf(*args)
|
26
|
-
end
|
27
|
-
|
41
|
+
#
|
42
|
+
alias :pr :printf
|
28
43
|
|
29
44
|
# Convert an object to a human-readable string,
|
30
|
-
# or <nil
|
45
|
+
# or <nil>; should be considered a debug-only feature
|
31
46
|
#
|
32
47
|
def d(arg)
|
33
48
|
arg.nil? ? "<nil>" : arg.inspect
|
34
49
|
end
|
35
50
|
|
36
|
-
|
37
51
|
# Convert an object to a human-readable string,
|
38
52
|
# by calling a type-appropriate function: da, dh, or just d.
|
39
53
|
# @param arg object
|
@@ -112,8 +126,6 @@ def df(flag, label=nil)
|
|
112
126
|
s
|
113
127
|
end
|
114
128
|
|
115
|
-
|
116
|
-
|
117
129
|
# Assert that a value is true. Should be considered a
|
118
130
|
# very temporary, debug-only option; it is slow and
|
119
131
|
# generates a warning that it is being called.
|
@@ -127,63 +139,37 @@ def assert!(cond, *msg)
|
|
127
139
|
end
|
128
140
|
end
|
129
141
|
|
142
|
+
# Abort with message about unimplemented code
|
143
|
+
#
|
144
|
+
def unimp!(msg = nil)
|
145
|
+
msg2 = "Unimplemented code"
|
146
|
+
if msg
|
147
|
+
msg2 << ": " << msg
|
148
|
+
end
|
149
|
+
raise Exception, msg2
|
150
|
+
end
|
130
151
|
|
131
|
-
|
132
|
-
#
|
133
|
-
|
134
|
-
#
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
## Convert a .dot file (string) to a PDF file "__mygraph__nnn.pdf"
|
153
|
-
## in the test directory.
|
154
|
-
##
|
155
|
-
## It does this by making a system call to the 'dot' utility.
|
156
|
-
##
|
157
|
-
#def dotToPDF(dotFile, name = "")
|
158
|
-
# gr = dotFile
|
159
|
-
# dotPath = withinTestDir(".__mygraph__.dot")
|
160
|
-
# write_text_file(dotPath,gr)
|
161
|
-
# destName = withinTestDir( "__mygraph__"+name+".pdf")
|
162
|
-
# system("dot -Tpdf "+dotPath+" -o "+destName)
|
163
|
-
#end
|
164
|
-
|
165
|
-
## Extensions to the Enumerable module
|
166
|
-
##
|
167
|
-
#module Enumerable
|
168
|
-
# # Calculate a value for each item, and return the item with the
|
169
|
-
# # highest value, its index, and the value.
|
170
|
-
# # @yieldparam function to calculate value of an object, given that object as a parameter
|
171
|
-
# # @return the triple [object, index, value] reflecting the maximum value, or
|
172
|
-
# # nil if there were no items
|
173
|
-
# def max_with_index
|
174
|
-
#
|
175
|
-
# best = nil
|
176
|
-
#
|
177
|
-
# each_with_index do |obj,ind|
|
178
|
-
# sc = yield(obj)
|
179
|
-
# if !best || best[2] < sc
|
180
|
-
# best = [obj,ind,sc]
|
181
|
-
# end
|
182
|
-
# end
|
183
|
-
# best
|
184
|
-
# end
|
185
|
-
#end
|
186
|
-
|
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
|
187
173
|
|
188
174
|
# Get a nice, concise description of the file and line
|
189
175
|
# of some caller within the stack.
|
@@ -252,6 +238,19 @@ def warn(*args)
|
|
252
238
|
one_time_alert("warning",0, *args)
|
253
239
|
end
|
254
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
|
+
|
255
254
|
# Print an 'unimplemented' alert, one time only
|
256
255
|
# @param args if present, calls printf() with these
|
257
256
|
def unimp(*args)
|
@@ -283,22 +282,30 @@ def block
|
|
283
282
|
yield
|
284
283
|
end
|
285
284
|
|
286
|
-
#
|
285
|
+
# Construct hex representation of value
|
286
|
+
# @param value integer value
|
287
|
+
# @param num_digits number of hex digits
|
287
288
|
#
|
288
|
-
class IllegalStateException < Exception
|
289
|
-
end
|
290
|
-
|
291
|
-
|
292
289
|
def to_hex(value, num_digits=4)
|
293
290
|
s = sprintf("%x", value)
|
294
291
|
s.rjust(num_digits,'0')
|
295
292
|
end
|
296
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
|
+
#
|
297
302
|
def hex_dump(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
298
303
|
ss = hex_dump_to_string(byte_array_or_string, title, offset, length, bytes_per_row, with_text)
|
299
304
|
puts ss
|
300
305
|
end
|
301
306
|
|
307
|
+
# Hex dump a string or byte array to a string; see hex_dump for parameter descriptions
|
308
|
+
#
|
302
309
|
def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, bytes_per_row=16, with_text=true)
|
303
310
|
|
304
311
|
byte_array = byte_array_or_string
|
@@ -341,10 +348,8 @@ def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, by
|
|
341
348
|
else
|
342
349
|
ss << ' '
|
343
350
|
end
|
344
|
-
|
345
351
|
end
|
346
352
|
|
347
|
-
|
348
353
|
if with_text
|
349
354
|
ss << ' |'
|
350
355
|
bytes_per_row.times do |i|
|
@@ -361,8 +366,6 @@ def hex_dump_to_string(byte_array_or_string, title=nil, offset=0, length= -1, by
|
|
361
366
|
offset += chunk
|
362
367
|
break if length <= 0
|
363
368
|
end
|
364
|
-
|
365
|
-
ss << "\n"
|
366
369
|
ss
|
367
370
|
end
|
368
371
|
|
@@ -370,6 +373,7 @@ $prevTime = nil
|
|
370
373
|
|
371
374
|
# Calculate time elapsed, in seconds, from last call to this function;
|
372
375
|
# if it's never been called, returns zero
|
376
|
+
#
|
373
377
|
def elapsed
|
374
378
|
curr = Time.now.to_f
|
375
379
|
elap = 0
|
@@ -380,74 +384,9 @@ def elapsed
|
|
380
384
|
elap
|
381
385
|
end
|
382
386
|
|
383
|
-
# Construct a string from an array of bytes
|
384
|
-
# @param byte_array array of bytes, or string (in which case it
|
385
|
-
# returns it unchanged)
|
386
|
-
#
|
387
|
-
def bytes_to_str(byte_array)
|
388
|
-
return byte_array if byte_array.is_a? String
|
389
|
-
|
390
|
-
byte_array.pack('C*')
|
391
|
-
end
|
392
|
-
|
393
|
-
# Construct an array of bytes from a string
|
394
|
-
# @param str string, or array of bytes (in which case it
|
395
|
-
# returns it unchanged)
|
396
|
-
#
|
397
|
-
def str_to_bytes(str)
|
398
|
-
return str if str.is_a? Array
|
399
|
-
str.bytes
|
400
|
-
end
|
401
|
-
|
402
|
-
# Get directory entries, excluding '.' and '..'
|
403
|
-
#
|
404
|
-
def dir_entries(path)
|
405
|
-
ents = Dir.entries(path)
|
406
|
-
ents.reject!{|entry| entry == '.' || entry == '..'}
|
407
|
-
end
|
408
|
-
|
409
|
-
# Convenience method for setting 'db' true within methods,
|
410
|
-
# and to print a one-time warning if so.
|
411
|
-
# @param val value to set db to; it is convenient to disable
|
412
|
-
# debug printing quickly by adding a zero, e.g., 'warndb 0'
|
413
|
-
#
|
414
|
-
def warndb(val = true)
|
415
|
-
if !val || val == 0
|
416
|
-
return false
|
417
|
-
end
|
418
|
-
one_time_alert("warning",1, "Debug printing enabled")
|
419
|
-
true
|
420
|
-
end
|
421
|
-
|
422
|
-
|
423
|
-
def int_to_bytes(x)
|
424
|
-
[(x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff]
|
425
|
-
end
|
426
|
-
|
427
|
-
def short_to_bytes(x)
|
428
|
-
[(x >> 8) & 0xff, x & 0xff]
|
429
|
-
end
|
430
|
-
|
431
|
-
# Decode a short from an array of bytes (big-endian).
|
432
|
-
# @param ba array of bytes
|
433
|
-
# @param offset offset of first (most significant) byte
|
434
|
-
#
|
435
|
-
def short_from_bytes(ba, offset=0)
|
436
|
-
(ba[offset] << 8) | ba[offset + 1]
|
437
|
-
end
|
438
|
-
|
439
|
-
# Decode an int from an array of bytes (big-endian).
|
440
|
-
# @param ba array of bytes
|
441
|
-
# @param offset offset of first (most significant) byte
|
442
|
-
#
|
443
|
-
def int_from_bytes(ba, offset=0)
|
444
|
-
(((((ba[offset] << 8) | ba[offset + 1]) << 8) | \
|
445
|
-
ba[offset + 2]) << 8) | ba[offset + 3]
|
446
|
-
end
|
447
|
-
|
448
|
-
|
449
387
|
# Delete a file or directory, if it exists.
|
450
388
|
# Caution! If directory, deletes all files and subdirectories.
|
389
|
+
#
|
451
390
|
def remove_file_or_dir(pth)
|
452
391
|
if File.directory?(pth)
|
453
392
|
FileUtils.remove_dir(pth)
|
@@ -456,52 +395,96 @@ def remove_file_or_dir(pth)
|
|
456
395
|
end
|
457
396
|
end
|
458
397
|
|
459
|
-
|
398
|
+
require 'stringio'
|
399
|
+
|
400
|
+
$IODest = nil
|
401
|
+
$OldStdOut = nil
|
402
|
+
|
403
|
+
# Redirect standard output to an internal string
|
460
404
|
#
|
461
|
-
def
|
462
|
-
|
405
|
+
def capture_begin
|
406
|
+
raise IllegalStateException if $IODest
|
407
|
+
$IODest = StringIO.new
|
408
|
+
$OldStdOut, $stdout = $stdout, $IODest
|
463
409
|
end
|
464
410
|
|
465
|
-
#
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
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
|
471
420
|
end
|
472
421
|
|
473
|
-
#
|
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
|
474
424
|
#
|
475
|
-
# @param
|
476
|
-
# @param size
|
477
|
-
# @param pad padding character to use if string needs to grow
|
478
|
-
# @return modified string
|
425
|
+
# @param str if not nil, string to compare; if nil, calls capture_end to get string
|
479
426
|
#
|
480
|
-
def
|
481
|
-
s[0...size].ljust(size,pad)
|
482
|
-
end
|
427
|
+
def match_expected_output(str = nil)
|
483
428
|
|
484
|
-
|
485
|
-
|
486
|
-
#
|
487
|
-
def windows?
|
488
|
-
if !defined? $__windows__
|
489
|
-
$__windows__ = (RUBY_PLATFORM =~ /mswin/)
|
429
|
+
if !str
|
430
|
+
str = capture_end
|
490
431
|
end
|
491
|
-
$__windows__
|
492
|
-
end
|
493
432
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
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
|
505
488
|
|
506
489
|
# Convenience method to detect if a script is being run
|
507
490
|
# e.g. as a 'main' method (for debug purposes only).
|
@@ -634,3 +617,136 @@ if defined? Test::Unit
|
|
634
617
|
end
|
635
618
|
end
|
636
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
|
+
|
706
|
+
# Mark all constants ending with '_' as private constants
|
707
|
+
#
|
708
|
+
# @param entity the class to examine
|
709
|
+
# @param add_non_suffix_versions if true, for each constant ABC_ found, also
|
710
|
+
# defines a constant ABC with the same value that is also private
|
711
|
+
#
|
712
|
+
def privatize(entity, add_non_suffix_versions = false)
|
713
|
+
|
714
|
+
db = false
|
715
|
+
|
716
|
+
# First command defines constants ABC = n for each constant ABC_ = n;
|
717
|
+
# Second declares both versions to be private
|
718
|
+
|
719
|
+
cmd1 = nil
|
720
|
+
cmd2 = nil
|
721
|
+
|
722
|
+
entity.constants.each do |c|
|
723
|
+
nm = c.to_s
|
724
|
+
|
725
|
+
if nm.end_with?('_')
|
726
|
+
nm_small = nm[0..-2]
|
727
|
+
|
728
|
+
if !cmd2
|
729
|
+
if add_non_suffix_versions
|
730
|
+
cmd1 = ''
|
731
|
+
end
|
732
|
+
cmd2 = 'private_constant '
|
733
|
+
else
|
734
|
+
cmd2 << ','
|
735
|
+
end
|
736
|
+
|
737
|
+
|
738
|
+
!cmd1 || cmd1 << entity.to_s << '::' << nm_small << '=' << entity.const_get(c).to_s << "\n"
|
739
|
+
!cmd1 || cmd2 << ':' << nm_small << ','
|
740
|
+
cmd2 << ':' << nm
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
744
|
+
if cmd2
|
745
|
+
if cmd1
|
746
|
+
!db || pr("about to eval:\n%s\n",cmd1)
|
747
|
+
eval(cmd1)
|
748
|
+
end
|
749
|
+
!db || pr("about to eval:\n%s\n",cmd2)
|
750
|
+
eval(cmd2)
|
751
|
+
end
|
752
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lenc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
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: "Encrypts a set of local files, and copies the encrypted versions to
|
14
14
|
a repository, \nwhich may be located within a free cloud service (Dropbox, Google
|
@@ -22,6 +22,7 @@ extensions: []
|
|
22
22
|
extra_rdoc_files: []
|
23
23
|
files:
|
24
24
|
- lib/lenc.rb
|
25
|
+
- lib/lenc/_OLD_tools.rb
|
25
26
|
- lib/lenc/aes.rb
|
26
27
|
- lib/lenc/config_file.rb
|
27
28
|
- lib/lenc/lencrypt.rb
|