chars 0.2.4 → 0.3.1

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.
@@ -1,3 +1,5 @@
1
+ require 'chars/string_enumerator'
2
+
1
3
  require 'set'
2
4
 
3
5
  module Chars
@@ -42,6 +44,12 @@ module Chars
42
44
  #
43
45
  # Creates a new {CharSet}.
44
46
  #
47
+ # @param [Array<String, Integer, Enumerable>] arguments
48
+ # The chars for the CharSet.
49
+ #
50
+ # @return [CharSet]
51
+ # The new character set.
52
+ #
45
53
  # @see #initialize
46
54
  #
47
55
  # @since 0.2.1
@@ -172,21 +180,30 @@ module Chars
172
180
  #
173
181
  # Returns a random byte from the {CharSet}.
174
182
  #
183
+ # @param [Random, SecureRandom] random
184
+ # The random number generator to use.
185
+ #
175
186
  # @return [Integer]
176
187
  # A random byte value.
177
188
  #
178
- def random_byte
179
- self.entries[rand(self.length)]
189
+ def random_byte(random: Random)
190
+ self.entries[random.rand(self.length)]
180
191
  end
181
192
 
182
193
  #
183
194
  # Returns a random character from the {CharSet}.
184
195
  #
196
+ # @param [Hash{Symbol => Object}] kwargs
197
+ # Additional keyword arguments.
198
+ #
199
+ # @option kwargs [Random, SecureRandom] :random
200
+ # The random number generator to use.
201
+ #
185
202
  # @return [String]
186
203
  # A random char value.
187
204
  #
188
- def random_char
189
- @chars[random_byte]
205
+ def random_char(**kwargs)
206
+ @chars[random_byte(**kwargs)]
190
207
  end
191
208
 
192
209
  #
@@ -195,6 +212,12 @@ module Chars
195
212
  # @param [Integer] n
196
213
  # Specifies how many times to pass a random byte to the block.
197
214
  #
215
+ # @param [Hash{Symbol => Object}] kwargs
216
+ # Additional keyword arguments.
217
+ #
218
+ # @option kwargs [Random, SecureRandom] :random
219
+ # The random number generator to use.
220
+ #
198
221
  # @yield [byte]
199
222
  # The block will receive the random bytes.
200
223
  #
@@ -204,10 +227,12 @@ module Chars
204
227
  # @return [Enumerator]
205
228
  # If no block is given, an enumerator object will be returned.
206
229
  #
207
- def each_random_byte(n,&block)
208
- return enum_for(__method__,n) unless block_given?
230
+ def each_random_byte(n,**kwargs,&block)
231
+ return enum_for(__method__,n,**kwargs) unless block_given?
209
232
 
210
- n.times { yield random_byte }
233
+ n.times do
234
+ yield random_byte(**kwargs)
235
+ end
211
236
  return nil
212
237
  end
213
238
 
@@ -217,6 +242,12 @@ module Chars
217
242
  # @param [Integer] n
218
243
  # Specifies how many times to pass a random character to the block.
219
244
  #
245
+ # @param [Hash{Symbol => Object}] kwargs
246
+ # Additional keyword arguments.
247
+ #
248
+ # @option kwargs [Random, SecureRandom] :random
249
+ # The random number generator to use.
250
+ #
220
251
  # @yield [char]
221
252
  # The block will receive the random characters.
222
253
  #
@@ -226,10 +257,12 @@ module Chars
226
257
  # @return [Enumerator]
227
258
  # If no block is given, an enumerator object will be returned.
228
259
  #
229
- def each_random_char(n,&block)
230
- return enum_for(__method__,n) unless block_given?
260
+ def each_random_char(n,**kwargs,&block)
261
+ return enum_for(__method__,n,**kwargs) unless block_given?
231
262
 
232
- each_random_byte(n) { |byte| yield @chars[byte] }
263
+ each_random_byte(n,**kwargs) do |byte|
264
+ yield @chars[byte]
265
+ end
233
266
  end
234
267
 
235
268
  #
@@ -238,17 +271,24 @@ module Chars
238
271
  # @param [Integer, Array, Range] length
239
272
  # The length of the Array of random bytes.
240
273
  #
274
+ # @param [Random, SecureRandom] random
275
+ # The random number generator to use.
276
+ #
241
277
  # @return [Array<Integer>]
242
278
  # The randomly selected bytes.
243
279
  #
244
- def random_bytes(length)
280
+ def random_bytes(length, random: Random)
245
281
  case length
246
282
  when Array
247
- Array.new(length.sample) { random_byte }
283
+ Array.new(length.sample(random: random)) do
284
+ random_byte(random: random)
285
+ end
248
286
  when Range
249
- Array.new(rand(length)) { random_byte }
287
+ Array.new(random.rand(length)) do
288
+ random_byte(random: random)
289
+ end
250
290
  else
251
- Array.new(length) { random_byte }
291
+ Array.new(length) { random_byte(random: random) }
252
292
  end
253
293
  end
254
294
 
@@ -258,17 +298,20 @@ module Chars
258
298
  # @param [Integer, Array, Range] length
259
299
  # The length of the Array of random non-repeating bytes.
260
300
  #
301
+ # @param [Random, SecureRandom] random
302
+ # The random number generator to use.
303
+ #
261
304
  # @return [Array<Integer>]
262
305
  # The randomly selected non-repeating bytes.
263
306
  #
264
- def random_distinct_bytes(length)
265
- shuffled_bytes = bytes.shuffle
307
+ def random_distinct_bytes(length, random: Random)
308
+ shuffled_bytes = bytes.shuffle(random: random)
266
309
 
267
310
  case length
268
311
  when Array
269
- shuffled_bytes[0,length.sample]
312
+ shuffled_bytes[0,length.sample(random: random)]
270
313
  when Range
271
- shuffled_bytes[0,rand(length)]
314
+ shuffled_bytes[0,random.rand(length)]
272
315
  else
273
316
  shuffled_bytes[0,length]
274
317
  end
@@ -280,11 +323,17 @@ module Chars
280
323
  # @param [Integer, Array, Range] length
281
324
  # The length of the Array of random characters.
282
325
  #
326
+ # @param [Hash{Symbol => Object}] kwargs
327
+ # Additional keyword arguments.
328
+ #
329
+ # @option kwargs [Random, SecureRandom] :random
330
+ # The random number generator to use.
331
+ #
283
332
  # @return [Array<String>]
284
333
  # The randomly selected characters.
285
334
  #
286
- def random_chars(length)
287
- random_bytes(length).map { |byte| @chars[byte] }
335
+ def random_chars(length,**kwargs)
336
+ random_bytes(length,**kwargs).map { |byte| @chars[byte] }
288
337
  end
289
338
 
290
339
  #
@@ -294,13 +343,19 @@ module Chars
294
343
  # @param [Integer, Array, Range] length
295
344
  # The length of the String of random characters.
296
345
  #
346
+ # @param [Hash{Symbol => Object}] kwargs
347
+ # Additional keyword arguments.
348
+ #
349
+ # @option kwargs [Random, SecureRandom] :random
350
+ # The random number generator to use.
351
+ #
297
352
  # @return [String]
298
353
  # The String of randomly selected characters.
299
354
  #
300
355
  # @see random_chars
301
356
  #
302
- def random_string(length)
303
- random_chars(length).join
357
+ def random_string(length,**kwargs)
358
+ random_chars(length,**kwargs).join
304
359
  end
305
360
 
306
361
  #
@@ -310,11 +365,17 @@ module Chars
310
365
  # @param [Integer, Array, Range] length
311
366
  # The length of the Array of random non-repeating characters.
312
367
  #
368
+ # @param [Hash{Symbol => Object}] kwargs
369
+ # Additional keyword arguments.
370
+ #
371
+ # @option kwargs [Random, SecureRandom] :random
372
+ # The random number generator to use.
373
+ #
313
374
  # @return [Array<Integer>]
314
375
  # The randomly selected non-repeating characters.
315
376
  #
316
- def random_distinct_chars(length)
317
- random_distinct_bytes(length).map { |byte| @chars[byte] }
377
+ def random_distinct_chars(length,**kwargs)
378
+ random_distinct_bytes(length,**kwargs).map { |byte| @chars[byte] }
318
379
  end
319
380
 
320
381
  #
@@ -324,13 +385,161 @@ module Chars
324
385
  # @param [Integer, Array, Range] length
325
386
  # The length of the String of random non-repeating characters.
326
387
  #
388
+ # @param [Hash{Symbol => Object}] kwargs
389
+ # Additional keyword arguments.
390
+ #
391
+ # @option kwargs [Random, SecureRandom] :random
392
+ # The random number generator to use.
393
+ #
327
394
  # @return [String]
328
395
  # The String of randomly selected non-repeating characters.
329
396
  #
330
397
  # @see random_distinct_chars
331
398
  #
332
- def random_distinct_string(length)
333
- random_distinct_chars(length).join
399
+ def random_distinct_string(length,**kwargs)
400
+ random_distinct_chars(length,**kwargs).join
401
+ end
402
+
403
+ #
404
+ # Enumerates over all substrings and their indices within the given string,
405
+ # of minimum length and that are made up of characters from the {CharSet}.
406
+ #
407
+ # @param [String] data
408
+ # The data to find sub-strings within.
409
+ #
410
+ # @param [Integer] min_length
411
+ # The minimum length of sub-strings found within the given data.
412
+ #
413
+ # @yield [match, index]
414
+ # The given block will be passed every matched sub-string and it's index.
415
+ #
416
+ # @yield [String] match
417
+ # A sub-string containing the characters from the {CharSet}.
418
+ #
419
+ # @yield [Integer] index
420
+ # The index the sub-string was found at.
421
+ #
422
+ # @return [Enumerator]
423
+ # If no block is given, an Enumerator object will be returned.
424
+ #
425
+ # @since 0.3.0
426
+ #
427
+ def each_substring_with_index(data, min_length: 4)
428
+ unless block_given?
429
+ return enum_for(__method__,data, min_length: min_length)
430
+ end
431
+
432
+ return if data.size < min_length
433
+
434
+ index = 0
435
+
436
+ match_start = nil
437
+ match_end = nil
438
+
439
+ while index < data.size
440
+ unless match_start
441
+ if self.include_char?(data[index])
442
+ match_start = index
443
+ end
444
+ else
445
+ unless self.include_char?(data[index])
446
+ match_end = index
447
+ match_length = (match_end - match_start)
448
+
449
+ if match_length >= min_length
450
+ match = data[match_start,match_length]
451
+
452
+ yield match, match_start
453
+ end
454
+
455
+ match_start = match_end = nil
456
+ end
457
+ end
458
+
459
+ index += 1
460
+ end
461
+
462
+ # yield the remaining match
463
+ if match_start
464
+ yield data[match_start, data.size - match_start], match_start
465
+ end
466
+ end
467
+
468
+ #
469
+ # Returns an Array of all substrings and their indices within the given
470
+ # string, of minimum length and that are made up of characters from the
471
+ # {CharSet}.
472
+ #
473
+ # @param [String] data
474
+ # The data to find sub-strings within.
475
+ #
476
+ # @param [Hash{Symbol => Object}] kwargs
477
+ # Keyword arguments for {#each_substring_with_index}.
478
+ #
479
+ # @option kwargs [Integer] :min_length
480
+ # The minimum length of sub-strings found within the given data.
481
+ #
482
+ # @return [Array<(String, Integer)>]
483
+ # Tthe array of substrings and their indices within the given `data`.
484
+ #
485
+ # @see #each_substring_with_index
486
+ #
487
+ # @since 0.3.0
488
+ #
489
+ def substrings_with_indexes(data,**kwargs)
490
+ each_substring_with_index(data,**kwargs).to_a
491
+ end
492
+
493
+ #
494
+ # Enumerates over all substrings within the given string, of minimum length
495
+ # and that are made up of characters from the {CharSet}.
496
+ #
497
+ # @param [String] data
498
+ # The data to find sub-strings within.
499
+ #
500
+ # @param [Hash{Symbol => Object}] kwargs
501
+ # Keyword arguments for {#each_substring_with_index}.
502
+ #
503
+ # @option kwargs [Integer] :min_length
504
+ # The minimum length of sub-strings found within the given data.
505
+ #
506
+ # @return [Enumerator]
507
+ # If no block is given, an Enumerator object will be returned.
508
+ #
509
+ # @see #each_substring_with_index
510
+ #
511
+ # @since 0.3.0
512
+ #
513
+ def each_substring(data,**kwargs)
514
+ return enum_for(__method__,data,**kwargs) unless block_given?
515
+
516
+ each_substring_with_index(data,**kwargs) do |substring,index|
517
+ yield substring
518
+ end
519
+ end
520
+
521
+ #
522
+ # Returns an Array of all substrings within the given string,
523
+ # of minimum length and that are made up of characters from the {CharSet}.
524
+ #
525
+ # @param [String] data
526
+ # The data to find sub-strings within.
527
+ #
528
+ # @param [Hash{Symbol => Object}] kwargs
529
+ # Keyword arguments for {#each_substring_with_index}.
530
+ #
531
+ # @option kwargs [Integer] :min_length
532
+ # The minimum length of sub-strings found within the given data.
533
+ #
534
+ # @see #each_substring
535
+ #
536
+ # @return [Array<String>]
537
+ # Tthe array of substrings within the given `data`.
538
+ #
539
+ # @since 0.3.0
540
+ #
541
+ def substrings(data,**kwargs)
542
+ each_substring(data,**kwargs).to_a
334
543
  end
335
544
 
336
545
  #
@@ -364,49 +573,75 @@ module Chars
364
573
  # @return [Array, Hash]
365
574
  # If no block is given, an Array or Hash of sub-strings is returned.
366
575
  #
576
+ # @deprecated
577
+ # Use {#each_substring_with_index}, {#substrings_with_index},
578
+ # {#each_substring}, or {#substrings} instead.
579
+ #
367
580
  def strings_in(data,options={},&block)
581
+ kwargs = {min_length: options.fetch(:length,4)}
582
+
368
583
  unless block
369
584
  if options[:offsets]
370
- found = {}
371
- block = lambda { |offset,substring| found[offset] = substring }
585
+ return Hash[substrings_with_indexes(data,**kwargs)]
372
586
  else
373
- found = []
374
- block = lambda { |substring| found << substring }
587
+ return substrings(data,**kwargs)
375
588
  end
376
-
377
- strings_in(data,options,&block)
378
- return found
379
589
  end
380
590
 
381
- min_length = options.fetch(:length,4)
382
- return if data.length < min_length
383
-
384
- index = 0
385
-
386
- while index <= (data.length - min_length)
387
- if self === data[index,min_length]
388
- sub_index = (index + min_length)
389
-
390
- while self.include_char?(data[sub_index,1])
391
- sub_index += 1
392
- end
393
-
394
- match = data[index...sub_index]
591
+ case block.arity
592
+ when 2
593
+ each_substring_with_index(data,**kwargs,&block)
594
+ else
595
+ each_substring(data,**kwargs,&block)
596
+ end
597
+ end
395
598
 
396
- case block.arity
397
- when 2
398
- yield match, index
399
- else
400
- yield match
401
- end
599
+ #
600
+ # Enumerates through every possible string belonging to the {CharSet} and
601
+ # of the given length.
602
+ #
603
+ # @param [Range, Array, Integer] length
604
+ # The desired length(s) of each string.
605
+ #
606
+ # @yield [string]
607
+ # The given block will be passed each sequential string.
608
+ #
609
+ # @yieldparam [String] string
610
+ # A string belonging to {#char_set} and `length` long.
611
+ #
612
+ # @return [Enumerator]
613
+ # If no block is given, an Enumerator will be returned.
614
+ #
615
+ # @since 0.3.0
616
+ #
617
+ def each_string_of_length(length,&block)
618
+ return enum_for(__method__,length) unless block
402
619
 
403
- index = sub_index
404
- else
405
- index += 1
620
+ case length
621
+ when Range, Array
622
+ length.each do |len|
623
+ StringEnumerator.new(self,len).each(&block)
406
624
  end
625
+ else
626
+ StringEnumerator.new(self,length).each(&block)
407
627
  end
408
628
  end
409
629
 
630
+ #
631
+ # Returns an Enumerator that enumerates through every possible string
632
+ # belonging to the {CharSEt} and of the given length.
633
+ #
634
+ # @param [Range, Array, Integer] length
635
+ # The desired length(s) of each string.
636
+ #
637
+ # @return [Enumerator]
638
+ #
639
+ # @see #each_string
640
+ #
641
+ def strings_of_length(length)
642
+ each_string_of_length(length)
643
+ end
644
+
410
645
  #
411
646
  # Creates a new CharSet object by unioning the {CharSet} with another
412
647
  # {CharSet}.
data/lib/chars/chars.rb CHANGED
@@ -6,6 +6,11 @@ module Chars
6
6
  # The numeric decimal character set
7
7
  NUMERIC = CharSet['0'..'9']
8
8
 
9
+ # @see NUMERIC
10
+ #
11
+ # @since 0.3.0
12
+ DIGITS = NUMERIC
13
+
9
14
  # The octal character set
10
15
  OCTAL = CharSet['0'..'7']
11
16
 
@@ -31,7 +36,7 @@ module Chars
31
36
  ALPHA_NUMERIC = ALPHA | NUMERIC
32
37
 
33
38
  # The punctuation character set
34
- PUNCTUATION = CharSet[' ', '\'', '"', '`', ',', ';', ':', '~', '-',
39
+ PUNCTUATION = CharSet['\'', '"', '`', ',', ';', ':', '~', '-',
35
40
  '(', ')', '[', ']', '{', '}', '.', '?', '!']
36
41
 
37
42
  # The symbolic character set
@@ -41,7 +46,11 @@ module Chars
41
46
  ]
42
47
 
43
48
  # The space character set
44
- SPACE = CharSet[' ', "\f", "\n", "\r", "\t", "\v"]
49
+ #
50
+ # @since 0.3.0
51
+ WHITESPACE = CharSet[' ', "\f", "\n", "\r", "\t", "\v"]
52
+
53
+ SPACE = WHITESPACE
45
54
 
46
55
  # The set of printable characters (not including spaces)
47
56
  VISIBLE = ALPHA_NUMERIC | CharSet[
@@ -51,7 +60,7 @@ module Chars
51
60
  ]
52
61
 
53
62
  # The set of printable characters (including spaces)
54
- PRINTABLE = ALPHA_NUMERIC | PUNCTUATION | SYMBOLS | SPACE
63
+ PRINTABLE = ALPHA_NUMERIC | PUNCTUATION | SYMBOLS | CharSet[' ']
55
64
 
56
65
  # The control-char character set
57
66
  CONTROL = CharSet[0..0x1f, 0x7f]
@@ -74,6 +83,20 @@ module Chars
74
83
  NUMERIC
75
84
  end
76
85
 
86
+ #
87
+ # Alias for {numeric}.
88
+ #
89
+ # @return [CharSet]
90
+ # The decimal-digit character set.
91
+ #
92
+ # @see numeric
93
+ #
94
+ # @since 0.3.0
95
+ #
96
+ def self.digits
97
+ numeric
98
+ end
99
+
77
100
  #
78
101
  # The octal-digit character set.
79
102
  #
@@ -195,15 +218,28 @@ module Chars
195
218
  end
196
219
 
197
220
  #
198
- # The white-space character set.
221
+ # The whitespace character set.
199
222
  #
200
223
  # @return [CharSet]
201
- # The white-space character set.
224
+ # The whitespace character set.
202
225
  #
203
226
  # @see SPACE
204
227
  #
228
+ # @since 0.3.0
229
+ #
230
+ def self.whitespace
231
+ WHITESPACE
232
+ end
233
+
234
+ #
235
+ # The whitespace character set.
236
+ #
237
+ # @return [CharSet]
238
+ #
239
+ # @see #whitespace
240
+ #
205
241
  def self.space
206
- SPACE
242
+ whitespace
207
243
  end
208
244
 
209
245
  #
@@ -0,0 +1,98 @@
1
+ module Chars
2
+ #
3
+ # Enumerates through every possible string belonging to a character set and
4
+ # of a given length.
5
+ #
6
+ # @api private
7
+ #
8
+ # @since 0.3.0
9
+ #
10
+ class StringEnumerator
11
+
12
+ include Enumerable
13
+
14
+ # The character set to generate the strings from.
15
+ #
16
+ # @return [CharSet]
17
+ attr_reader :char_set
18
+
19
+ # The desired length of each string.
20
+ #
21
+ # @return [Integer]
22
+ attr_reader :length
23
+
24
+ #
25
+ # Initializes the string enumerator.
26
+ #
27
+ # @param [Chars::CharSet] char_set
28
+ # The character set to generate the strings from.
29
+ #
30
+ # @param [Integer] length
31
+ # The desired length of each string.
32
+ #
33
+ def initialize(char_set,length)
34
+ @char_set = char_set
35
+ @length = length
36
+ end
37
+
38
+ #
39
+ # Enumerates through every possible string belonging to {#char_set} and
40
+ # {#length} long.
41
+ #
42
+ # @yield [string]
43
+ # The given block will be passed each sequential string.
44
+ #
45
+ # @yieldparam [String] string
46
+ # A string belonging to {#char_set} and {#length} long.
47
+ #
48
+ # @return [Enumerator]
49
+ # If no block is given, an Enumerator will be returned.
50
+ #
51
+ def each
52
+ return enum_for(__method__) unless block_given?
53
+
54
+ if @char_set.empty?
55
+ return
56
+ elsif @length == 0
57
+ yield ""
58
+ return
59
+ end
60
+
61
+ chars = char_set.chars
62
+ first_char = chars.first
63
+ last_char = chars.last
64
+
65
+ next_char = {}
66
+
67
+ chars.each_cons(2) do |c1,c2|
68
+ next_char[c1] = c2
69
+ end
70
+
71
+ string = String.new(first_char * @length)
72
+
73
+ last_index = @length - 1
74
+
75
+ loop do
76
+ chars.each do |c|
77
+ string[last_index] = c
78
+
79
+ yield string.dup
80
+ end
81
+
82
+ last_index.downto(0) do |i|
83
+ if string[i] == last_char
84
+ string[i] = first_char
85
+
86
+ if i == 0
87
+ return
88
+ end
89
+ else
90
+ string[i] = next_char[string[i]]
91
+ break
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+ end
data/lib/chars/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Chars
2
2
  # chars version
3
- VERSION = '0.2.4'
3
+ VERSION = '0.3.1'
4
4
  end