lite-ruby 1.0.31 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +15 -2
- data/Gemfile.lock +33 -32
- data/README.md +1 -0
- data/docs/ARRAY.md +2 -10
- data/docs/HASH.md +2 -2
- data/docs/NUMERIC.md +0 -10
- data/docs/STRING.md +2 -2
- data/docs/TIME.md +17 -17
- data/lib/lite/ruby/array.rb +15 -100
- data/lib/lite/ruby/boolean.rb +4 -4
- data/lib/lite/ruby/enumerable.rb +4 -40
- data/lib/lite/ruby/hash.rb +23 -97
- data/lib/lite/ruby/helpers/time_helper.rb +21 -21
- data/lib/lite/ruby/numeric.rb +10 -33
- data/lib/lite/ruby/object.rb +4 -38
- data/lib/lite/ruby/open_struct.rb +1 -2
- data/lib/lite/ruby/range.rb +2 -4
- data/lib/lite/ruby/safe/array.rb +93 -0
- data/lib/lite/ruby/safe/enumerable.rb +42 -0
- data/lib/lite/ruby/safe/hash.rb +83 -0
- data/lib/lite/ruby/safe/object.rb +41 -0
- data/lib/lite/ruby/safe/range.rb +9 -0
- data/lib/lite/ruby/safe/string.rb +187 -0
- data/lib/lite/ruby/string.rb +39 -194
- data/lib/lite/ruby/version.rb +1 -1
- metadata +8 -2
data/lib/lite/ruby/object.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
if Lite::Ruby.configuration.monkey_patches.include?('object')
|
4
|
+
require 'lite/ruby/safe/object' unless defined?(ActiveSupport)
|
5
|
+
|
4
6
|
class Object
|
5
7
|
|
6
8
|
FALSE_VALUES ||= %w[
|
@@ -14,14 +16,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('object')
|
|
14
16
|
is_a?(Array)
|
15
17
|
end
|
16
18
|
|
17
|
-
def blank?
|
18
|
-
object = self
|
19
|
-
object = object.strip if respond_to?(:strip)
|
20
|
-
return object.empty? if respond_to?(:empty?)
|
21
|
-
|
22
|
-
!object
|
23
|
-
end
|
24
|
-
|
25
19
|
def bool?
|
26
20
|
true? || false?
|
27
21
|
end
|
@@ -35,14 +29,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('object')
|
|
35
29
|
is_a?(Date)
|
36
30
|
end
|
37
31
|
|
38
|
-
def deep_dup
|
39
|
-
duplicable? ? dup : self
|
40
|
-
end
|
41
|
-
|
42
|
-
def duplicable?
|
43
|
-
true
|
44
|
-
end
|
45
|
-
|
46
32
|
# rubocop:disable Style/YodaCondition
|
47
33
|
def false?
|
48
34
|
false == self
|
@@ -87,14 +73,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('object')
|
|
87
73
|
to_s == to_s.reverse
|
88
74
|
end
|
89
75
|
|
90
|
-
def present?
|
91
|
-
!blank?
|
92
|
-
end
|
93
|
-
|
94
|
-
def presence
|
95
|
-
self if present?
|
96
|
-
end
|
97
|
-
|
98
76
|
def range?
|
99
77
|
is_a?(Range)
|
100
78
|
end
|
@@ -160,8 +138,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('object')
|
|
160
138
|
nil
|
161
139
|
end
|
162
140
|
|
163
|
-
alias to_b to_bool
|
164
|
-
|
165
141
|
# rubocop:disable Style/YodaCondition
|
166
142
|
def true?
|
167
143
|
true == self
|
@@ -172,18 +148,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('object')
|
|
172
148
|
TRUE_VALUES.include?(to_s.downcase)
|
173
149
|
end
|
174
150
|
|
175
|
-
def try(*obj, &block)
|
176
|
-
try!(*obj, &block) if obj.empty? || respond_to?(obj.first)
|
177
|
-
end
|
178
|
-
|
179
|
-
def try!(*obj, &block)
|
180
|
-
if obj.empty? && defined?(yield)
|
181
|
-
block.arity.zero? ? instance_eval(&block) : yield(self)
|
182
|
-
else
|
183
|
-
public_send(*obj, &block)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
151
|
def try_call(*keys)
|
188
152
|
return unless respond_to?(:call)
|
189
153
|
|
@@ -196,5 +160,7 @@ if Lite::Ruby.configuration.monkey_patches.include?('object')
|
|
196
160
|
nil
|
197
161
|
end
|
198
162
|
|
163
|
+
alias to_b to_bool
|
164
|
+
|
199
165
|
end
|
200
166
|
end
|
@@ -46,13 +46,12 @@ if Lite::Ruby.configuration.monkey_patches.include?('open_struct')
|
|
46
46
|
{ table: attributes }
|
47
47
|
end
|
48
48
|
|
49
|
-
alias to_h to_hash
|
50
|
-
|
51
49
|
def to_json(table: true)
|
52
50
|
to_hash(table: table).to_json
|
53
51
|
end
|
54
52
|
|
55
53
|
alias as_json to_json
|
54
|
+
alias to_h to_hash
|
56
55
|
|
57
56
|
end
|
58
57
|
end
|
data/lib/lite/ruby/range.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
if Lite::Ruby.configuration.monkey_patches.include?('range')
|
4
|
+
require 'lite/ruby/safe/range' unless defined?(ActiveSupport)
|
5
|
+
|
4
6
|
class Range
|
5
7
|
|
6
8
|
def combine(other)
|
@@ -14,10 +16,6 @@ if Lite::Ruby.configuration.monkey_patches.include?('range')
|
|
14
16
|
include?(other.first) && other.last.send(operator, last)
|
15
17
|
end
|
16
18
|
|
17
|
-
def overlaps?(other)
|
18
|
-
cover?(other.first) || other.cover?(first)
|
19
|
-
end
|
20
|
-
|
21
19
|
def sample
|
22
20
|
to_a.sample
|
23
21
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Array
|
4
|
+
|
5
|
+
def deep_dup
|
6
|
+
map(&:deep_dup)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from(position)
|
10
|
+
self[position, size] || []
|
11
|
+
end
|
12
|
+
|
13
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
14
|
+
def in_groups(number, fill_with = nil, &block)
|
15
|
+
collection_size = size
|
16
|
+
division = collection_size.div(number)
|
17
|
+
modulo = collection_size % number
|
18
|
+
collection = []
|
19
|
+
start = 0
|
20
|
+
|
21
|
+
number.times do |int|
|
22
|
+
mod_gt_zero = modulo.positive?
|
23
|
+
grouping = division + (mod_gt_zero && modulo > int ? 1 : 0)
|
24
|
+
collection << last_group = slice(start, grouping)
|
25
|
+
last_group << fill_with if (fill_with != false) && mod_gt_zero && (grouping == division)
|
26
|
+
start += grouping
|
27
|
+
end
|
28
|
+
|
29
|
+
return collection unless defined?(yield)
|
30
|
+
|
31
|
+
collection.each(&block)
|
32
|
+
end
|
33
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
34
|
+
|
35
|
+
# rubocop:disable Metrics/MethodLength, Style/GuardClause
|
36
|
+
def in_groups_of(number, fill_with = nil, &block)
|
37
|
+
if number.to_i <= 0
|
38
|
+
raise ArgumentError, "Group size must be a positive integer, was #{number.inspect}"
|
39
|
+
elsif fill_with == false
|
40
|
+
collection = self
|
41
|
+
else
|
42
|
+
padding = (number - size % number) % number
|
43
|
+
collection = dup.concat(Array.new(padding, fill_with))
|
44
|
+
end
|
45
|
+
|
46
|
+
sliced_collection = collection.each_slice(number)
|
47
|
+
return sliced_collection.to_a unless defined?(yield)
|
48
|
+
|
49
|
+
sliced_collection(&block)
|
50
|
+
end
|
51
|
+
# rubocop:enable Metrics/MethodLength, Style/GuardClause
|
52
|
+
|
53
|
+
# rubocop:disable Metrics/MethodLength, Style/ExplicitBlockArgument
|
54
|
+
def split(value = nil)
|
55
|
+
arr = dup
|
56
|
+
result = []
|
57
|
+
|
58
|
+
if block_given?
|
59
|
+
while (idx = arr.index { |i| yield(i) })
|
60
|
+
result << arr.shift(idx)
|
61
|
+
arr.shift
|
62
|
+
end
|
63
|
+
else
|
64
|
+
while (idx = arr.index(value))
|
65
|
+
result << arr.shift(idx)
|
66
|
+
arr.shift
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
result << arr
|
71
|
+
end
|
72
|
+
# rubocop:enable Metrics/MethodLength, Style/ExplicitBlockArgument
|
73
|
+
|
74
|
+
def to(position)
|
75
|
+
return first(position + 1) if position >= 0
|
76
|
+
|
77
|
+
self[0..position]
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_sentence(options = {})
|
81
|
+
words_connector = options[:words_connector] || ', '
|
82
|
+
two_words_connector = options[:two_words_connector] || ' and '
|
83
|
+
last_word_connector = options[:last_word_connector] || ', and '
|
84
|
+
|
85
|
+
case size
|
86
|
+
when 0 then ''
|
87
|
+
when 1 then self[0].to_s
|
88
|
+
when 2 then "#{self[0]}#{two_words_connector}#{self[1]}"
|
89
|
+
else "#{self[0...-1].join(words_connector)}#{last_word_connector}#{self[-1]}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Enumerable
|
4
|
+
|
5
|
+
def exclude?(object)
|
6
|
+
!include?(object)
|
7
|
+
end
|
8
|
+
|
9
|
+
def excluding(*elements)
|
10
|
+
elements.flatten!(1)
|
11
|
+
reject { |element| elements.include?(element) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def including(*elements)
|
15
|
+
to_a.including(*elements)
|
16
|
+
end
|
17
|
+
|
18
|
+
def many?
|
19
|
+
found_count = 0
|
20
|
+
|
21
|
+
if defined?(yield)
|
22
|
+
any? do |val|
|
23
|
+
found_count += 1 if yield(val)
|
24
|
+
found_count > 1
|
25
|
+
end
|
26
|
+
else
|
27
|
+
any? { (found_count += 1) > 1 }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def pluck(*keys)
|
32
|
+
if keys.many?
|
33
|
+
map { |element| keys.map { |key| element[key] } }
|
34
|
+
else
|
35
|
+
map { |element| element[keys.first] }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
alias with including
|
40
|
+
alias without excluding
|
41
|
+
|
42
|
+
end
|
@@ -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,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
|