lite-ruby 1.0.27 → 1.1.0

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.
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+
5
+ # rubocop:disable Style/CaseEquality
6
+ def deep_dup
7
+ hash = dup
8
+
9
+ each_pair do |key, value|
10
+ if key.frozen? && ::String === key
11
+ hash[key] = value.deep_dup
12
+ else
13
+ hash.delete(key)
14
+ hash[key.deep_dup] = value.deep_dup
15
+ end
16
+ end
17
+
18
+ hash
19
+ end
20
+ # rubocop:enable Style/CaseEquality
21
+
22
+ def deep_merge(other_hash, &block)
23
+ dup.deep_merge!(other_hash, &block)
24
+ end
25
+
26
+ def deep_merge!(other_hash, &block)
27
+ merge!(other_hash) do |key, this_val, other_val|
28
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
29
+ this_val.deep_merge(other_val, &block)
30
+ elsif defined?(yield)
31
+ yield(key, this_val, other_val)
32
+ else
33
+ other_val
34
+ end
35
+ end
36
+ end
37
+
38
+ def except(*keys)
39
+ slice(*self.keys - keys)
40
+ end
41
+
42
+ def except!(*keys)
43
+ keys.each { |key| delete(key) }
44
+ self
45
+ end
46
+
47
+ def extract!(*keys)
48
+ keys.each_with_object({}) { |key, hash| hash[key] = delete(key) if key?(key) }
49
+ end
50
+
51
+ def reverse_merge(other_hash)
52
+ other_hash.merge(self)
53
+ end
54
+
55
+ def reverse_merge!(other_hash)
56
+ other_hash.merge!(self)
57
+ end
58
+
59
+ def stringify_keys
60
+ transform_keys(&:to_s)
61
+ end
62
+
63
+ def stringify_keys!
64
+ transform_keys!(&:to_s)
65
+ end
66
+
67
+ def symbolize_keys
68
+ transform_keys do |key|
69
+ key.to_sym
70
+ rescue StandardError
71
+ key
72
+ end
73
+ end
74
+
75
+ def symbolize_keys!
76
+ transform_keys! do |key|
77
+ key.to_sym
78
+ rescue StandardError
79
+ key
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+
5
+ def blank?
6
+ object = self
7
+ object = object.strip if respond_to?(:strip)
8
+ return object.empty? if respond_to?(:empty?)
9
+
10
+ !object
11
+ end
12
+
13
+ def deep_dup
14
+ duplicable? ? dup : self
15
+ end
16
+
17
+ def duplicable?
18
+ true
19
+ end
20
+
21
+ def present?
22
+ !blank?
23
+ end
24
+
25
+ def presence
26
+ self if present?
27
+ end
28
+
29
+ def try(*obj, &block)
30
+ try!(*obj, &block) if obj.empty? || respond_to?(obj.first)
31
+ end
32
+
33
+ def try!(*obj, &block)
34
+ if obj.empty? && defined?(yield)
35
+ block.arity.zero? ? instance_eval(&block) : yield(self)
36
+ else
37
+ public_send(*obj, &block)
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Range
4
+
5
+ def overlaps?(other)
6
+ cover?(other.first) || other.cover?(first)
7
+ end
8
+
9
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+
5
+ def at(position)
6
+ self[position]
7
+ end
8
+
9
+ def camelize(first_letter = :upper)
10
+ case first_letter
11
+ when :upper, true then modulize.gsub(/(\A|\s)([a-z])/) { $1 + $2.upcase }
12
+ when :lower, false then modulize.gsub(/(\A|\s)([A-Z])/) { $1 + $2.downcase }
13
+ else modulize
14
+ end
15
+ end
16
+
17
+ def classify
18
+ str = dup
19
+ str = str.sub!(/.*\./, '')
20
+ str.camelize!
21
+ end
22
+
23
+ def constantize
24
+ Object.const_get(camelize)
25
+ end
26
+
27
+ def dasherize
28
+ underscore.tr('_', '-')
29
+ end
30
+
31
+ def deconstantize
32
+ [0, rindex('::') || 0]
33
+ end
34
+
35
+ def demodulize
36
+ gsub(/^.*::/, '')
37
+ end
38
+
39
+ def first(limit = 1)
40
+ if limit.zero?
41
+ ''
42
+ elsif limit >= length
43
+ self
44
+ else
45
+ to(limit - 1)
46
+ end
47
+ end
48
+
49
+ def from(position)
50
+ self[position..-1]
51
+ end
52
+
53
+ def humanize(capitalize: true)
54
+ str = dup
55
+ str = str.underscore!
56
+ str = str.delete_suffix!('_id')
57
+ str = str.tr!('_', ' ')
58
+ str = str.squish!
59
+ str = str.gsub!(/([a-z\d]*)/i, &:downcase)
60
+ str = str.gsub!(/\A\w/) { |s| capitalize ? s.upcase : s }
61
+ str || self
62
+ end
63
+
64
+ def indent(amount, seperator = ' ')
65
+ dup.indent!(amount, seperator)
66
+ end
67
+
68
+ def indent!(amount, seperator = ' ')
69
+ if amount >= 0
70
+ gsub!(/^/, seperator * amount)
71
+ else
72
+ gsub!(/^#{Regexp.escape(seperator)}{0,#{-amount}}/, '')
73
+ end
74
+ end
75
+
76
+ def last(limit = 1)
77
+ if limit.zero?
78
+ ''
79
+ elsif limit >= length
80
+ self
81
+ else
82
+ from(-limit)
83
+ end
84
+ end
85
+
86
+ def parameterize(separator: '-')
87
+ str = dup
88
+ str = str.underscore!
89
+ str = str.gsub!(/\s+/, separator)
90
+ str = str.downcase!
91
+ str || self
92
+ end
93
+
94
+ def remove(*patterns)
95
+ dup.remove!(*patterns)
96
+ end
97
+
98
+ def remove!(*patterns)
99
+ patterns.each_with_object(self) do |pat, str|
100
+ pat.is_a?(Range) ? str.slice!(pat) : str.gsub!(pat, '')
101
+ end
102
+ end
103
+
104
+ def squish
105
+ dup.squish!
106
+ end
107
+
108
+ def squish!
109
+ strip!
110
+ gsub!(/\s+/, ' ') || self
111
+ end
112
+
113
+ def titleize
114
+ str = dup
115
+ str = str.underscore!
116
+ str = str.humanize!
117
+ str = str.gsub!(/\b(?<!['’`])[a-z]/) { $&.capitalize }
118
+ str || self
119
+ end
120
+
121
+ def to(position)
122
+ self[0..position]
123
+ end
124
+
125
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
126
+ # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
127
+ def to_time(form = :local)
128
+ parts = Date.parse(self, false)
129
+ used_keys = %i[year mon mday hour min sec sec_fraction offset]
130
+ return if (parts.keys & used_keys).empty?
131
+
132
+ now = Time.now
133
+ time = Time.new(
134
+ parts[:year] || now.year,
135
+ parts[:mon] || now.month,
136
+ parts[:mday] || now.day,
137
+ parts[:hour] || 0,
138
+ parts[:min] || 0,
139
+ (parts[:sec] || 0) + (parts[:sec_fraction] || 0),
140
+ parts[:offset] || (form == :utc ? 0 : nil)
141
+ )
142
+
143
+ form == :utc ? time.utc : time.to_time
144
+ end
145
+ # rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
146
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
147
+
148
+ def transliterate
149
+ TRANSLITERATIONS.each_with_object(dup) { |(k, v), s| s.gsub!(k, v) }
150
+ end
151
+
152
+ def truncate(truncate_at, options = {})
153
+ return self unless length > truncate_at
154
+
155
+ omission = options[:omission] || '...'
156
+ seperator = options[:separator]
157
+
158
+ size_with_room_for_omission = truncate_at - omission.length
159
+
160
+ stop = if seperator
161
+ rindex(seperator || '', size_with_room_for_omission) || size_with_room_for_omission
162
+ else
163
+ size_with_room_for_omission
164
+ end
165
+
166
+ "#{self[0, stop]}#{omission}"
167
+ end
168
+
169
+ def underscore
170
+ str = dup
171
+ str = str.camelize!
172
+ str = str.gsub!(/::/, '/')
173
+ str = str.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
174
+ str = str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
175
+ str = str.tr!('-', '_')
176
+ str = str.downcase!
177
+ str || self
178
+ end
179
+
180
+ alias camelcase camelize
181
+ alias ends_with? end_with?
182
+ alias snakecase underscore
183
+ alias starts_with? start_with?
184
+ alias titlecase titleize
185
+ alias to_t to_time unless defined?(to_t)
186
+
187
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  if Lite::Ruby.configuration.monkey_patches.include?('string')
4
+ require 'lite/ruby/safe/string' unless defined?(ActiveSupport)
5
+
4
6
  class String
5
7
 
6
8
  TRANSLITERATIONS ||= {
@@ -34,73 +36,33 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
34
36
  }.freeze
35
37
 
36
38
  def acronym
37
- dup.acronym!
39
+ gsub(/(([a-zA-Z0-9])([a-zA-Z0-9])*)./, '\\2') || self
38
40
  end
39
41
 
40
42
  def acronym!
41
- gsub!(/(([a-zA-Z0-9])([a-zA-Z0-9])*)./, '\\2') || self
43
+ replace(acronym)
42
44
  end
43
45
 
44
46
  def any?(*keys)
45
47
  keys.any? { |key| include?(key) }
46
48
  end
47
49
 
48
- def ascii_only(alt = '')
49
- dup.ascii_only!(alt)
50
- end
51
-
52
- def ascii_only!(alt = '')
53
- encode_only!('ASCII', alt)
54
- end
55
-
56
- def at(position)
57
- self[position]
58
- end
59
-
60
- def camelize(first_letter = :upper)
61
- case first_letter
62
- when :upper, true then modulize.gsub(/(\A|\s)([a-z])/) { $1 + $2.upcase }
63
- when :lower, false then modulize.gsub(/(\A|\s)([A-Z])/) { $1 + $2.downcase }
64
- end || modulize
65
- end
66
-
67
- alias camelcase camelize
68
-
69
50
  def camelize!(first_letter = :upper)
70
51
  replace(camelize(first_letter))
71
52
  end
72
53
 
73
- alias camelcase! camelize!
74
-
75
54
  def capitalized?
76
55
  capitalize == self
77
56
  end
78
57
 
79
- def classify
80
- dup.classify!
81
- end
82
-
83
58
  def classify!
84
- sub!(/.*\./, '')
85
- camelize!
86
- end
87
-
88
- def constantize
89
- Object.const_get(camelize)
90
- end
91
-
92
- def dasherize
93
- underscore.tr('_', '-')
59
+ replace(classify)
94
60
  end
95
61
 
96
62
  def dasherize!
97
63
  replace(dasherize)
98
64
  end
99
65
 
100
- def deconstantize
101
- [0, rindex('::') || 0]
102
- end
103
-
104
66
  def deconstantize!
105
67
  replace(deconstantize)
106
68
  end
@@ -114,10 +76,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
114
76
  self
115
77
  end
116
78
 
117
- def demodulize
118
- gsub(/^.*::/, '')
119
- end
120
-
121
79
  def demodulize!
122
80
  replace(demodulize)
123
81
  end
@@ -136,21 +94,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
136
94
  words.each(&block)
137
95
  end
138
96
 
139
- def encode_only(encoding, alt = '')
140
- dup.encode_only!(encoding, alt)
141
- end
142
-
143
- def encode_only!(encoding, alt = '')
144
- encoding_options = {
145
- invalid: :replace,
146
- undef: :replace,
147
- replace: alt,
148
- UNIVERSAL_NEWLINE_DECORATOR: true
149
- }
150
-
151
- encode!(Encoding.find(encoding), encoding_options)
152
- end
153
-
154
97
  def ellipsize(ellipsize_at, options = {})
155
98
  return self if length <= ellipsize_at
156
99
 
@@ -160,24 +103,10 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
160
103
  "#{self[0, offset]}#{separator}#{self[-offset, offset]}"
161
104
  end
162
105
 
163
- def first(limit = 1)
164
- if limit.zero?
165
- ''
166
- elsif limit >= length
167
- self
168
- else
169
- to(limit - 1)
170
- end
171
- end
172
-
173
106
  def format(*args)
174
107
  super(self, *args.flatten)
175
108
  end
176
109
 
177
- def from(position)
178
- self[position..-1]
179
- end
180
-
181
110
  def headerize
182
111
  squish.each_word(&:capitalize!).join(' ')
183
112
  end
@@ -186,29 +115,8 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
186
115
  replace(headerize)
187
116
  end
188
117
 
189
- def humanize(options = {})
190
- dup.humanize!(options)
191
- end
192
-
193
118
  def humanize!(capitalize: true)
194
- underscore!
195
- gsub!(/_id\z/, '')
196
- tr!('_', ' ')
197
- squish!
198
- gsub!(/([a-z\d]*)/i, &:downcase)
199
- gsub!(/\A\w/) { |str| capitalize ? str.upcase : str } || self
200
- end
201
-
202
- def indent(amount, seperator = ' ')
203
- dup.indent!(amount, seperator)
204
- end
205
-
206
- def indent!(amount, seperator = ' ')
207
- if amount >= 0
208
- gsub!(/^/, seperator * amount)
209
- else
210
- gsub!(/^#{Regexp.escape(seperator)}{0,#{-amount}}/, '')
211
- end
119
+ replace(humanize(capitalize: capitalize))
212
120
  end
213
121
 
214
122
  def index_all(pattern)
@@ -225,12 +133,10 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
225
133
  arr_indexes.reverse
226
134
  end
227
135
 
228
- def labelize(options = {})
229
- dup.labelize!(options)
136
+ def labelize(capitalize: true)
137
+ dup.labelize!(capitalize: capitalize)
230
138
  end
231
139
 
232
- alias labelcase labelize
233
-
234
140
  def labelize!(capitalize: true)
235
141
  underscore!
236
142
  tr!('_', ' ')
@@ -240,18 +146,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
240
146
  gsub!(/ id\z/, ' ID') || self
241
147
  end
242
148
 
243
- alias labelcase! labelize!
244
-
245
- def last(limit = 1)
246
- if limit.zero?
247
- ''
248
- elsif limit >= length
249
- self
250
- else
251
- from(-limit)
252
- end
253
- end
254
-
255
149
  def lchomp(match)
256
150
  dup.lchomp!(match)
257
151
  end
@@ -290,6 +184,16 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
290
184
  !upcase? && !downcase?
291
185
  end
292
186
 
187
+ def non_possessive
188
+ dup.non_possessive!
189
+ end
190
+
191
+ def non_possessive!
192
+ return self unless possessive?
193
+
194
+ chomp!("'s") || chomp!("'") || self
195
+ end
196
+
293
197
  def ordinal
294
198
  to_i.ordinal
295
199
  end
@@ -298,14 +202,8 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
298
202
  to_i.ordinalize
299
203
  end
300
204
 
301
- def parameterize(separator: '-')
302
- dup.parameterize!(separator: separator)
303
- end
304
-
305
205
  def parameterize!(separator: '-')
306
- underscore!
307
- gsub!(/\s+/, separator)
308
- downcase! || self
206
+ replace(parameterize(separator: separator))
309
207
  end
310
208
 
311
209
  def pathize
@@ -334,16 +232,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
334
232
  self[-1]
335
233
  end
336
234
 
337
- def non_possessive
338
- dup.non_possessive!
339
- end
340
-
341
- def non_possessive!
342
- return self unless possessive?
343
-
344
- chomp!("'s") || chomp!("'") || self
345
- end
346
-
347
235
  def possessive
348
236
  return self if possessive?
349
237
 
@@ -392,7 +280,7 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
392
280
  b = f
393
281
 
394
282
  if amount.odd?
395
- f = "'" + f
283
+ f = "'#{f}"
396
284
  b += "'"
397
285
  end
398
286
  else
@@ -407,16 +295,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
407
295
  replace(quote(type, amount))
408
296
  end
409
297
 
410
- def remove(*patterns)
411
- dup.remove!(*patterns)
412
- end
413
-
414
- def remove!(*patterns)
415
- patterns.each_with_object(self) do |pat, str|
416
- pat.is_a?(Range) ? str.slice!(pat) : str.gsub!(pat, '')
417
- end
418
- end
419
-
420
298
  def remove_tags
421
299
  dup.remove_tags!
422
300
  end
@@ -434,6 +312,26 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
434
312
  slice!(amount, size - amount) + slice!(0, amount)
435
313
  end
436
314
 
315
+ # rubocop:disable Metrics/MethodLength
316
+ def safe_encode(target_encoding, replacement = '')
317
+ encode(target_encoding)
318
+ rescue Encoding::InvalidByteSequenceError
319
+ force_encoding(target_encoding).scrub!(replacement)
320
+ rescue Encoding::UndefinedConversionError
321
+ encode(
322
+ target_encoding,
323
+ invalid: :replace,
324
+ undef: :replace,
325
+ replace: replacement,
326
+ UNIVERSAL_NEWLINE_DECORATOR: true
327
+ )
328
+ end
329
+ # rubocop:enable Metrics/MethodLength
330
+
331
+ def safe_encode!(target_encoding, replacement = '')
332
+ replace(safe_encode(target_encoding, replacement))
333
+ end
334
+
437
335
  def sample(separator = ' ')
438
336
  split(separator).sample
439
337
  end
@@ -487,15 +385,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
487
385
  downcase! || self
488
386
  end
489
387
 
490
- def squish
491
- dup.squish!
492
- end
493
-
494
- def squish!
495
- strip!
496
- gsub!(/\s+/, ' ') || self
497
- end
498
-
499
388
  def sort
500
389
  chars.sort.join
501
390
  end
@@ -504,73 +393,32 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
504
393
  replace(sort)
505
394
  end
506
395
 
507
- def titleize
508
- dup.titleize!
396
+ def transliterate!
397
+ replace(transliterate)
509
398
  end
510
399
 
511
- alias titlecase titleize
512
-
513
400
  def titleize!
514
- underscore!
515
- humanize!
516
- gsub!(/\b(?<!['’`])[a-z]/) { $&.capitalize } || self
517
- end
518
-
519
- alias titlecase! titleize!
520
-
521
- def to(position)
522
- self[0..position]
523
- end
524
-
525
- def transliterize
526
- dup.transliterize!
401
+ replace(titleize)
527
402
  end
528
403
 
529
- def transliterize!
530
- TRANSLITERATIONS.each_with_object(self) { |(k, v), str| str.gsub!(k, v) }
531
- end
532
-
533
- def truncate(truncate_at, options = {})
534
- return dup unless length > truncate_at
535
-
536
- seperator = options[:separator]
404
+ def truncate_words(word_count, options = {})
537
405
  omission = options[:omission] || '...'
538
- size_with_room_for_omission = truncate_at - omission.length
539
-
540
- stop = if seperator
541
- rindex(seperator || '', size_with_room_for_omission) || size_with_room_for_omission
542
- else
543
- size_with_room_for_omission
544
- end
545
-
546
- "#{self[0, stop]}#{omission}"
547
- end
406
+ seperator = options[:separator] || /\s+/
548
407
 
549
- def truncate_words(words_count, options = {})
550
- sep = options[:separator] || /\s+/
551
- sep = Regexp.escape(sep.to_s) unless sep.is_a(Regexp)
552
- return self unless /\A((?:.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m.match?(self)
408
+ seperator = Regexp.escape(seperator.to_s) unless seperator.is_a(Regexp)
409
+ return self unless /\A((?:.+?#{seperator}){#{word_count - 1}}.+?)#{seperator}.*/m.match?(self)
553
410
 
554
- "#{::Regexp.last_match(1)}#{options[:omissio] || '...'}"
411
+ "#{::Regexp.last_match(1)}#{omission}"
555
412
  end
556
413
 
557
- def underscore
558
- dup.underscore!
414
+ def upcase?
415
+ upcase == self
559
416
  end
560
417
 
561
- alias snakecase underscore
562
-
563
418
  def underscore!
564
- camelize!
565
- gsub!(/::/, '/')
566
- gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
567
- gsub!(/([a-z\d])([A-Z])/, '\1_\2')
568
- tr!('-', '_')
569
- downcase! || self
419
+ replace(underscore)
570
420
  end
571
421
 
572
- alias snakecase! underscore!
573
-
574
422
  def unpollute(delimiter = '^--^--^')
575
423
  dup.unpollute!(delimiter)
576
424
  end
@@ -579,19 +427,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
579
427
  gsub!(delimiter, '') || self
580
428
  end
581
429
 
582
- def upcase?
583
- upcase == self
584
- end
585
-
586
- def unshift(*patterns)
587
- patterns.each_with_object('') { |pat, str| str << pat }
588
- .concat(self)
589
- end
590
-
591
- def unshift!(*patterns)
592
- replace(unshift(*patterns))
593
- end
594
-
595
430
  def unquote
596
431
  dup.unquote!
597
432
  end
@@ -606,6 +441,15 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
606
441
  self
607
442
  end
608
443
 
444
+ def unshift(*patterns)
445
+ patterns.each_with_object('') { |pat, str| str << pat }
446
+ .concat(self)
447
+ end
448
+
449
+ def unshift!(*patterns)
450
+ replace(unshift(*patterns))
451
+ end
452
+
609
453
  def words
610
454
  split(/\s+/)
611
455
  end
@@ -627,8 +471,11 @@ if Lite::Ruby.configuration.monkey_patches.include?('string')
627
471
  replace(variablize)
628
472
  end
629
473
 
630
- alias ends_with? end_with?
631
- alias starts_with? start_with?
474
+ alias camelcase! camelize!
475
+ alias labelcase labelize
476
+ alias labelcase! labelize!
477
+ alias snakecase! underscore!
478
+ alias titlecase! titleize!
632
479
 
633
480
  end
634
481
  end