lx 1.0 → 1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -2
- data/lib/lx.rb +351 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0129287631d7874f63195026285a321e29b8beb2ed2959a02d6ed59a7edda3ba'
|
4
|
+
data.tar.gz: 3b2ce691ff835795825aae039084bfa68a908b275028d3d4ec5a58b37d26c16b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5b6723a4103a00ba8769c6a60d696481d3048e5359b7448ab3afa5d35d5ded07f6d271b214a67eead90ce9c62718245b48d851b4f49d47a31ead16175bf1bcc
|
7
|
+
data.tar.gz: e06b0f7724126c604993825f5640f5fcd18cbbbf7526282a17f745e82a912c68602f052f4d3aca2d8998ef62538e1b416830b73e5a6540f1ceb17857adcc4ca5
|
data/README.md
CHANGED
@@ -25,10 +25,11 @@ mike@idocs.com
|
|
25
25
|
## Name
|
26
26
|
|
27
27
|
"LX" doesn't mean anything in particular. It's concise and it was available on
|
28
|
-
rubygems.
|
28
|
+
rubygems.
|
29
29
|
|
30
30
|
## History
|
31
31
|
|
32
32
|
| version | date | notes |
|
33
33
|
|---------|--------------|-------------------------------|
|
34
|
-
| 1.0 | May 29, 2020 | Initial upload. |
|
34
|
+
| 1.0 | May 29, 2020 | Initial upload. |
|
35
|
+
| 1.1 | January 3, 2021 | Added deep_dup for arrays and hashes, LX.randstr, File.lx.atomic_write(), and File.lx.temp_path. |
|
data/lib/lx.rb
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
# The LX module is the home for utilities that don't particularly fit in one
|
6
6
|
# class. For now, it only contains the randstr method.
|
7
7
|
module LX
|
8
|
-
# version
|
9
|
-
VERSION = '1.
|
8
|
+
# version
|
9
|
+
VERSION = '1.1'
|
10
10
|
|
11
11
|
#---------------------------------------------------------------------------
|
12
12
|
# verbose
|
@@ -62,6 +62,109 @@ module LX
|
|
62
62
|
#
|
63
63
|
# randstr
|
64
64
|
#---------------------------------------------------------------------------
|
65
|
+
|
66
|
+
|
67
|
+
#---------------------------------------------------------------------------
|
68
|
+
# scope
|
69
|
+
#
|
70
|
+
|
71
|
+
# A little method that does nothing more than allow you to create a 'do'
|
72
|
+
# block.
|
73
|
+
def self.scope
|
74
|
+
yield
|
75
|
+
end
|
76
|
+
|
77
|
+
# Same as LX::scope.
|
78
|
+
def self.block
|
79
|
+
yield
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# scope
|
84
|
+
#---------------------------------------------------------------------------
|
85
|
+
|
86
|
+
|
87
|
+
#---------------------------------------------------------------------------
|
88
|
+
# deep_dup
|
89
|
+
#
|
90
|
+
|
91
|
+
# Deep suplicates a hash or array. Don't call this method directly. Call
|
92
|
+
# Array#lx#deep_dup or Hash#lx#deep_dup.
|
93
|
+
|
94
|
+
def self.deep_dup(obj, opts={})
|
95
|
+
# $tm.hrm
|
96
|
+
rv = nil
|
97
|
+
|
98
|
+
# default options
|
99
|
+
opts = {'done'=>{}}.merge(opts)
|
100
|
+
|
101
|
+
# error if object has already been cloned
|
102
|
+
if obj.is_a?(::Array) or obj.is_a?(::Hash)
|
103
|
+
if opts['done'][obj.object_id]
|
104
|
+
raise "object #{obj.object_id} has already been dupped"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
if obj.is_a?(::Array)
|
109
|
+
rv = deep_dup_array(obj, opts)
|
110
|
+
elsif obj.is_a?(::Hash)
|
111
|
+
rv = deep_dup_hash(obj, opts)
|
112
|
+
else
|
113
|
+
begin
|
114
|
+
rv = obj.dup
|
115
|
+
rescue
|
116
|
+
rv = obj
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# note object as done
|
121
|
+
opts['done'][obj.object_id] = true
|
122
|
+
|
123
|
+
# return rv
|
124
|
+
return rv
|
125
|
+
end
|
126
|
+
#
|
127
|
+
# deep_dup
|
128
|
+
#---------------------------------------------------------------------------
|
129
|
+
|
130
|
+
|
131
|
+
#---------------------------------------------------------------------------
|
132
|
+
# deep_dup_hash
|
133
|
+
#
|
134
|
+
def self.deep_dup_hash(hsh, opts)
|
135
|
+
# $tm.hrm
|
136
|
+
rv = {}
|
137
|
+
|
138
|
+
hsh.each do |key, val|
|
139
|
+
rv[key.dup] = self.deep_dup(val, opts)
|
140
|
+
end
|
141
|
+
|
142
|
+
return rv
|
143
|
+
end
|
144
|
+
|
145
|
+
private_class_method :deep_dup_hash
|
146
|
+
#
|
147
|
+
# deep_dup_hash
|
148
|
+
#---------------------------------------------------------------------------
|
149
|
+
|
150
|
+
|
151
|
+
#---------------------------------------------------------------------------
|
152
|
+
# deep_dup_array
|
153
|
+
#
|
154
|
+
def self.deep_dup_array(arr, opts)
|
155
|
+
rv = []
|
156
|
+
|
157
|
+
arr.each do |val|
|
158
|
+
rv.push self.deep_dup(val, opts)
|
159
|
+
end
|
160
|
+
|
161
|
+
return rv
|
162
|
+
end
|
163
|
+
|
164
|
+
private_class_method :deep_dup_array
|
165
|
+
#
|
166
|
+
# deep_dup_array
|
167
|
+
#---------------------------------------------------------------------------
|
65
168
|
end
|
66
169
|
#
|
67
170
|
# LX
|
@@ -89,7 +192,7 @@ end
|
|
89
192
|
# A helper class to add methods to the Array class. When you use the Array::lx
|
90
193
|
# you're creating an instance of LX::Array.
|
91
194
|
class LX::Array
|
92
|
-
#
|
195
|
+
# initialize a LX::Array object. The only param is the array itself.
|
93
196
|
def initialize(p_arr)
|
94
197
|
@arr = p_arr
|
95
198
|
end
|
@@ -130,12 +233,59 @@ class LX::Array
|
|
130
233
|
# return
|
131
234
|
return rv
|
132
235
|
end
|
236
|
+
|
237
|
+
# draw
|
238
|
+
def draw
|
239
|
+
rv = @arr[0]
|
240
|
+
@arr.rotate!
|
241
|
+
return rv
|
242
|
+
end
|
243
|
+
|
244
|
+
# deep_dup
|
245
|
+
def deep_dup
|
246
|
+
return LX.deep_dup(@arr)
|
247
|
+
end
|
133
248
|
end
|
134
249
|
#
|
135
250
|
# Array
|
136
251
|
#===============================================================================
|
137
252
|
|
138
253
|
|
254
|
+
#===============================================================================
|
255
|
+
# Hash
|
256
|
+
#
|
257
|
+
|
258
|
+
# Adds a single method to the Hash class. This is the only method that is
|
259
|
+
# added to the Hash class itself. Access LX utilities through the array's new
|
260
|
+
# +lx+ method.
|
261
|
+
#
|
262
|
+
# For example, the use the move method, call the method like this:
|
263
|
+
# hsh = {'a'=>1, 'b'=>2, 'c'=>3}
|
264
|
+
class Hash
|
265
|
+
# Creates a LX::Array object and returns it.
|
266
|
+
def lx
|
267
|
+
return LX::Hash.new(self)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# A helper class to add methods to the Hash class. When you use the Hash::lx
|
272
|
+
# you're creating an instance of LX::Hash.
|
273
|
+
class LX::Hash
|
274
|
+
# initialize a LX::Array object. The only param is the array itself.
|
275
|
+
def initialize(p_hsh)
|
276
|
+
@hsh = p_hsh
|
277
|
+
end
|
278
|
+
|
279
|
+
# deep_dup
|
280
|
+
def deep_dup
|
281
|
+
return LX.deep_dup(@hsh)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
#
|
285
|
+
# Hash
|
286
|
+
#===============================================================================
|
287
|
+
|
288
|
+
|
139
289
|
#===============================================================================
|
140
290
|
# String
|
141
291
|
#
|
@@ -191,7 +341,205 @@ class LX::String
|
|
191
341
|
#
|
192
342
|
# collapse
|
193
343
|
#---------------------------------------------------------------------------
|
344
|
+
|
345
|
+
|
346
|
+
#---------------------------------------------------------------------------
|
347
|
+
# inner_collapse
|
348
|
+
#
|
349
|
+
def inner_collapse
|
350
|
+
rv = @str.clone
|
351
|
+
rv.gsub!(/[\u00A0\s]+/imu, ' ')
|
352
|
+
return rv
|
353
|
+
end
|
354
|
+
#
|
355
|
+
# inner_collapse
|
356
|
+
#---------------------------------------------------------------------------
|
357
|
+
|
358
|
+
|
359
|
+
#---------------------------------------------------------------------------
|
360
|
+
# content?, no_content?, nocontent?
|
361
|
+
#
|
362
|
+
|
363
|
+
# Returns true if the string contains a non-whitespace character.
|
364
|
+
def hascontent?
|
365
|
+
return @str.match(/\S/mu) ? true : false
|
366
|
+
end
|
367
|
+
|
368
|
+
# Same as hascontent?
|
369
|
+
def has_content?
|
370
|
+
return hascontent?
|
371
|
+
end
|
372
|
+
|
373
|
+
# Return true if the string does *not* have any non-whitespace characters.
|
374
|
+
def nocontent?
|
375
|
+
return !hascontent?
|
376
|
+
end
|
377
|
+
|
378
|
+
# Same as no_content?
|
379
|
+
def no_content?
|
380
|
+
return nocontent?
|
381
|
+
end
|
382
|
+
|
383
|
+
#
|
384
|
+
# content?, no_content?, nocontent?
|
385
|
+
#---------------------------------------------------------------------------
|
386
|
+
|
387
|
+
|
388
|
+
#---------------------------------------------------------------------------
|
389
|
+
# tmp_untaint
|
390
|
+
#
|
391
|
+
def tmp_untaint(rx)
|
392
|
+
# dangerous
|
393
|
+
if rx == LX::String::Dangerous
|
394
|
+
tmp = @str.dup.untaint
|
395
|
+
else
|
396
|
+
if @str.match(rx)
|
397
|
+
tmp = @str.dup.untaint
|
398
|
+
else
|
399
|
+
raise 'string-does-not-match-untaint-pattern'
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
# yield
|
404
|
+
yield tmp
|
405
|
+
end
|
406
|
+
#
|
407
|
+
# tmp_untaint
|
408
|
+
#---------------------------------------------------------------------------
|
409
|
+
end
|
410
|
+
|
411
|
+
module LX::String::Dangerous
|
194
412
|
end
|
195
413
|
#
|
196
414
|
# String
|
415
|
+
#===============================================================================
|
416
|
+
|
417
|
+
|
418
|
+
#===============================================================================
|
419
|
+
# Integer
|
420
|
+
#
|
421
|
+
class Integer
|
422
|
+
# Creates a LX::Array object and returns it.
|
423
|
+
def lx
|
424
|
+
return LX::Integer.new(self)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
class LX::Integer
|
429
|
+
def initialize(int)
|
430
|
+
@int = int
|
431
|
+
end
|
432
|
+
|
433
|
+
def multiple_of?(number)
|
434
|
+
number != 0 ? @int % number == 0 : @int.zero?
|
435
|
+
end
|
436
|
+
end
|
437
|
+
#
|
438
|
+
# Integer
|
439
|
+
#===============================================================================
|
440
|
+
|
441
|
+
|
442
|
+
#===============================================================================
|
443
|
+
# File
|
444
|
+
#
|
445
|
+
class File
|
446
|
+
def self.lx
|
447
|
+
return LX::File::Class.new(self)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
module LX::File
|
452
|
+
end
|
453
|
+
|
454
|
+
class LX::File::Class
|
455
|
+
def initialize(clss)
|
456
|
+
end
|
457
|
+
|
458
|
+
# Atomically writes content to the given path. Does so by creating a temp
|
459
|
+
# file, writing to it, then renaming the temp file to the final destination.
|
460
|
+
def atomic_write(path_final, content)
|
461
|
+
# $tm.hrm
|
462
|
+
temp_path do |path_tmp|
|
463
|
+
File.write path_tmp, content
|
464
|
+
File.rename path_tmp, path_final
|
465
|
+
end
|
466
|
+
|
467
|
+
# path_tmp = path_final + '.' + rand.to_s.sub(/\A.*\./mu, '')
|
468
|
+
end
|
469
|
+
|
470
|
+
# Creates a temporary path. Does *not* create a file. If, after the `do`
|
471
|
+
# block, a file exists at that path, that file is deleted.
|
472
|
+
def temp_path(opts = {})
|
473
|
+
opts = {'delete'=>true}.merge(opts)
|
474
|
+
|
475
|
+
# root
|
476
|
+
if opts['root']
|
477
|
+
root = opts['root'].sub(/\/*\z/mu, '/')
|
478
|
+
else
|
479
|
+
root = './'
|
480
|
+
end
|
481
|
+
|
482
|
+
# full path
|
483
|
+
path = root + LX.randstr
|
484
|
+
|
485
|
+
# add extension
|
486
|
+
if opts['ext']
|
487
|
+
ext = opts['ext']
|
488
|
+
ext = ext.sub(/\A\.*/mu, '.')
|
489
|
+
path += ext
|
490
|
+
end
|
491
|
+
|
492
|
+
if block_given?
|
493
|
+
begin
|
494
|
+
yield path
|
495
|
+
ensure
|
496
|
+
if opts['delete'] and File.exist?(path)
|
497
|
+
File.delete path
|
498
|
+
end
|
499
|
+
end
|
500
|
+
else
|
501
|
+
return path
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
#
|
506
|
+
# File
|
507
|
+
#===============================================================================
|
508
|
+
|
509
|
+
|
510
|
+
#===============================================================================
|
511
|
+
# NilClass
|
512
|
+
#
|
513
|
+
class NilClass
|
514
|
+
def lx
|
515
|
+
return LX::NilClass.new(self)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
class LX::NilClass
|
520
|
+
def initialize(obj)
|
521
|
+
end
|
522
|
+
|
523
|
+
# Always returns false.
|
524
|
+
def hascontent?
|
525
|
+
return false
|
526
|
+
end
|
527
|
+
|
528
|
+
# Always returns false.
|
529
|
+
def has_content?
|
530
|
+
return false
|
531
|
+
end
|
532
|
+
|
533
|
+
# Always returns true.
|
534
|
+
def nocontent?
|
535
|
+
return true
|
536
|
+
end
|
537
|
+
|
538
|
+
# Always returns true.
|
539
|
+
def no_content?
|
540
|
+
return true
|
541
|
+
end
|
542
|
+
end
|
543
|
+
#
|
544
|
+
# NilClass
|
197
545
|
#===============================================================================
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike O'Sullivan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Misc utilities for
|
13
|
+
description: Misc utilities, mostly for use in other libraries that I'm uploading.
|
14
14
|
email: mike@idocs.com
|
15
15
|
executables: []
|
16
16
|
extensions: []
|