lite-ruby 1.0.1 → 1.0.2
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 +55 -1
- data/Gemfile.lock +1 -1
- data/README.md +2 -1
- data/docs/ARRAY.md +1 -1
- data/docs/ENUMERABLE.md +51 -20
- data/docs/HASH.md +149 -0
- data/docs/INTEGER.md +45 -0
- data/docs/NUMERIC.md +36 -2
- data/docs/OPEN_STRUCT.md +51 -0
- data/docs/STRING.md +123 -1
- data/docs/STRUCT.md +24 -0
- data/lib/generators/lite/ruby/templates/install.rb +1 -1
- data/lib/lite/ruby/configuration.rb +2 -1
- data/lib/lite/ruby/enumerable.rb +75 -15
- data/lib/lite/ruby/hash.rb +132 -6
- data/lib/lite/ruby/integer.rb +32 -0
- data/lib/lite/ruby/numeric.rb +44 -1
- data/lib/lite/ruby/open_struct.rb +44 -0
- data/lib/lite/ruby/string.rb +249 -72
- data/lib/lite/ruby/struct.rb +8 -0
- data/lib/lite/ruby/version.rb +1 -1
- metadata +4 -2
data/lib/lite/ruby/hash.rb
CHANGED
@@ -2,6 +2,19 @@
|
|
2
2
|
|
3
3
|
class Hash
|
4
4
|
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def zip(keys, values)
|
8
|
+
keys.size.times.with_object({}) { |i, hash| hash[keys[i]] = values[i] }
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
def alias(new_key, old_key)
|
14
|
+
self[new_key] = self[old_key] if key?(old_key)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
5
18
|
def assert_valid_keys!(*valid_keys)
|
6
19
|
each_key do |key|
|
7
20
|
next if valid_keys.include?(key)
|
@@ -50,6 +63,31 @@ class Hash
|
|
50
63
|
end
|
51
64
|
# rubocop:enable Style/GuardClause
|
52
65
|
|
66
|
+
# rubocop:disable Metrics/MethodLength
|
67
|
+
def collate(*others)
|
68
|
+
hash = {}
|
69
|
+
|
70
|
+
each_key { |key| hash[key] = [] }
|
71
|
+
|
72
|
+
others.each do |other|
|
73
|
+
other.each_key { |key| hash[key] = [] }
|
74
|
+
end
|
75
|
+
|
76
|
+
each { |key, val| hash[key] << val }
|
77
|
+
|
78
|
+
others.each do |other|
|
79
|
+
other.each { |key, val| hash[key] << val }
|
80
|
+
end
|
81
|
+
|
82
|
+
hash.each_value(&:flatten!)
|
83
|
+
hash
|
84
|
+
end
|
85
|
+
# rubocop:enable Metrics/MethodLength
|
86
|
+
|
87
|
+
def collate!(other_hash)
|
88
|
+
replace(collate(other_hash))
|
89
|
+
end
|
90
|
+
|
53
91
|
def collect_keys
|
54
92
|
collect { |key, _| yield(key) }
|
55
93
|
end
|
@@ -58,16 +96,41 @@ class Hash
|
|
58
96
|
collect { |_, val| yield(val) }
|
59
97
|
end
|
60
98
|
|
99
|
+
def dearray_values(idx = 0)
|
100
|
+
each_with_object({}) do |(key, val), hash|
|
101
|
+
hash[key] = case val
|
102
|
+
when Array then val[idx] || val[-1]
|
103
|
+
else val
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def dearray_values!(idx = 0)
|
109
|
+
replace(dearray_values(idx))
|
110
|
+
end
|
111
|
+
|
112
|
+
def dearray_singular_values
|
113
|
+
each_with_object({}) do |(key, val), hash|
|
114
|
+
hash[key] = case val
|
115
|
+
when Array then val.size < 2 ? val[0] : val
|
116
|
+
else val
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def dearray_singular_values!
|
122
|
+
replace(dearray_singular_values)
|
123
|
+
end
|
124
|
+
|
61
125
|
def deep_merge(other_hash, &block)
|
62
126
|
dup.deep_merge!(other_hash, &block)
|
63
127
|
end
|
64
128
|
|
65
|
-
# rubocop:disable Metrics/MethodLength
|
66
129
|
def deep_merge!(other_hash, &block)
|
67
|
-
other_hash.each_pair do |current_key, other_value|
|
68
|
-
this_value =
|
130
|
+
other_hash.each_pair.with_object(self) do |(current_key, other_value), hash|
|
131
|
+
this_value = hash[current_key]
|
69
132
|
|
70
|
-
|
133
|
+
hash[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
71
134
|
this_value.deep_merge(other_value, yield(block))
|
72
135
|
elsif block_given? && key?(current_key)
|
73
136
|
yield(current_key, this_value, other_value)
|
@@ -75,10 +138,20 @@ class Hash
|
|
75
138
|
other_value
|
76
139
|
end
|
77
140
|
end
|
141
|
+
end
|
78
142
|
|
79
|
-
|
143
|
+
def delete_unless
|
144
|
+
delete_if { |key, val| !yield(key, val) }
|
145
|
+
end
|
146
|
+
|
147
|
+
def delete_values(*values)
|
148
|
+
each_key.with_object([]) do |key, array|
|
149
|
+
next unless values.include?(self[key])
|
150
|
+
|
151
|
+
array << key
|
152
|
+
delete(key)
|
153
|
+
end
|
80
154
|
end
|
81
|
-
# rubocop:enable Metrics/MethodLength
|
82
155
|
|
83
156
|
def demote(key)
|
84
157
|
dup.demote!(key)
|
@@ -99,6 +172,12 @@ class Hash
|
|
99
172
|
each { |key, val| self[key] = val.nil? ? value : val }
|
100
173
|
end
|
101
174
|
|
175
|
+
def diff(hash)
|
176
|
+
h1 = dup.delete_if { |k, v| hash[k] == v }
|
177
|
+
h2 = hash.dup.delete_if { |k, _| key?(k) }
|
178
|
+
h1.merge(h2)
|
179
|
+
end
|
180
|
+
|
102
181
|
def except(*keys)
|
103
182
|
dup.except!(*keys)
|
104
183
|
end
|
@@ -119,6 +198,30 @@ class Hash
|
|
119
198
|
inject(self) { |hash, (key, val)| hash.merge(yield(key, val)) }
|
120
199
|
end
|
121
200
|
|
201
|
+
def insert(name, value)
|
202
|
+
return false if key?(name)
|
203
|
+
|
204
|
+
store(name, value)
|
205
|
+
true
|
206
|
+
end
|
207
|
+
|
208
|
+
def invert
|
209
|
+
each_pair.with_object({}) do |(key, val), hash|
|
210
|
+
if val.is_a?(Array)
|
211
|
+
val.each { |x| hash[x] = (hash.key?(x) ? [key, hash[x]].flatten : key) }
|
212
|
+
else
|
213
|
+
hash[val] = (hash.key?(val) ? [key, hash[val]].flatten : key)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def keys?(*check_keys)
|
219
|
+
unknown_keys = check_keys - keys
|
220
|
+
unknown_keys.empty?
|
221
|
+
end
|
222
|
+
|
223
|
+
alias has_keys? keys?
|
224
|
+
|
122
225
|
def nillify
|
123
226
|
dup.nillify!
|
124
227
|
end
|
@@ -137,6 +240,13 @@ class Hash
|
|
137
240
|
replace(only_fill(*keys, placeholder: placeholder))
|
138
241
|
end
|
139
242
|
|
243
|
+
def only_keys?(*check_keys)
|
244
|
+
unknown_keys = keys - check_keys
|
245
|
+
unknown_keys.empty?
|
246
|
+
end
|
247
|
+
|
248
|
+
alias has_only_keys? only_keys?
|
249
|
+
|
140
250
|
def pair?(key, value)
|
141
251
|
self[key] == value
|
142
252
|
end
|
@@ -277,6 +387,22 @@ class Hash
|
|
277
387
|
|
278
388
|
alias to_o to_object
|
279
389
|
|
390
|
+
def update_each
|
391
|
+
replace(each_with_object({}) { |(key, val), hash| hash.update(yield(key, val)) })
|
392
|
+
end
|
393
|
+
|
394
|
+
def update_keys
|
395
|
+
return to_enum(:update_keys) unless block_given?
|
396
|
+
|
397
|
+
replace(each_with_object({}) { |(key, val), hash| hash[yield(key)] = val })
|
398
|
+
end
|
399
|
+
|
400
|
+
def update_values
|
401
|
+
return to_enum(:update_values) unless block_given?
|
402
|
+
|
403
|
+
replace(each_with_object({}) { |(key, val), hash| hash[key] = yield(val) })
|
404
|
+
end
|
405
|
+
|
280
406
|
def vacant?(key)
|
281
407
|
self[key].blank?
|
282
408
|
end
|
data/lib/lite/ruby/integer.rb
CHANGED
@@ -7,6 +7,38 @@ class Integer
|
|
7
7
|
I: 1
|
8
8
|
}.freeze
|
9
9
|
|
10
|
+
def bit(bit)
|
11
|
+
if bit.negative?
|
12
|
+
mask = (1 << ~bit)
|
13
|
+
self & ~mask
|
14
|
+
else
|
15
|
+
mask = (1 << bit)
|
16
|
+
self | mask
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def bit?(bit)
|
21
|
+
mask = (1 << bit)
|
22
|
+
(self & mask) != 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def bit_clear(bit)
|
26
|
+
mask = (1 << bit)
|
27
|
+
self & ~mask
|
28
|
+
end
|
29
|
+
|
30
|
+
def bitmask(mask)
|
31
|
+
if mask.negative?
|
32
|
+
self & mask
|
33
|
+
else
|
34
|
+
self | mask
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def bitmask?(mask)
|
39
|
+
(self & mask) != 0
|
40
|
+
end
|
41
|
+
|
10
42
|
def factorial
|
11
43
|
return 1 if zero?
|
12
44
|
|
data/lib/lite/ruby/numeric.rb
CHANGED
@@ -6,6 +6,14 @@ class Numeric
|
|
6
6
|
self + num
|
7
7
|
end
|
8
8
|
|
9
|
+
def at_least(lower)
|
10
|
+
self >= lower ? self : lower
|
11
|
+
end
|
12
|
+
|
13
|
+
def at_most(upper)
|
14
|
+
self <= upper ? self : upper
|
15
|
+
end
|
16
|
+
|
9
17
|
# rubocop:disable Metrics/MethodLength
|
10
18
|
def clamp(minimum, maximum = nil)
|
11
19
|
if minimum.is_a?(Range)
|
@@ -23,14 +31,43 @@ class Numeric
|
|
23
31
|
end
|
24
32
|
# rubocop:enable Metrics/MethodLength
|
25
33
|
|
34
|
+
def close?(number, epsilon = 0.01)
|
35
|
+
return self == number if epsilon.zero?
|
36
|
+
|
37
|
+
a = to_f
|
38
|
+
b = number.to_f
|
39
|
+
|
40
|
+
if a.zero? || b.zero?
|
41
|
+
(a - b).abs < epsilon
|
42
|
+
else
|
43
|
+
(a / b - 1).abs < epsilon
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
26
47
|
def decrement(amount = 1.0)
|
27
48
|
self - amount
|
28
49
|
end
|
29
50
|
|
30
|
-
def
|
51
|
+
def delimit(options = {})
|
52
|
+
delimiter = options[:delimiter] || ','
|
53
|
+
separator = options[:separator] || '.'
|
54
|
+
|
55
|
+
digits, decimals = to_s.split('.')
|
56
|
+
digits = digits.reverse.chars.each_slice(3).map(&:join).join(delimiter).reverse
|
57
|
+
|
58
|
+
return digits unless decimals
|
59
|
+
|
60
|
+
[digits, decimals].join(separator)
|
61
|
+
end
|
62
|
+
|
63
|
+
def delta(num)
|
31
64
|
(self - num).abs
|
32
65
|
end
|
33
66
|
|
67
|
+
def distance(num)
|
68
|
+
self - num
|
69
|
+
end
|
70
|
+
|
34
71
|
def divide(num)
|
35
72
|
return num if num.zero?
|
36
73
|
|
@@ -158,6 +195,12 @@ class Numeric
|
|
158
195
|
self**num
|
159
196
|
end
|
160
197
|
|
198
|
+
def range(value)
|
199
|
+
(self - value)..(self + value)
|
200
|
+
end
|
201
|
+
|
202
|
+
alias plus_minus range
|
203
|
+
|
161
204
|
def root(num)
|
162
205
|
self**(1.0 / num)
|
163
206
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
class OpenStruct
|
6
|
+
|
7
|
+
def initialize(hash = nil, &block)
|
8
|
+
@table = if block && block.arity == 2
|
9
|
+
Hash.new(&block)
|
10
|
+
else
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
|
14
|
+
if hash
|
15
|
+
hash.each do |key, val|
|
16
|
+
@table[key.to_sym] = val
|
17
|
+
new_ostruct_member(key)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
yield self if block && block.arity == 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
key = key.to_sym unless key.is_a?(Symbol)
|
26
|
+
@table[key]
|
27
|
+
end
|
28
|
+
|
29
|
+
def []=(key, val)
|
30
|
+
raise TypeError, "can't modify frozen #{self.class}", caller(1) if frozen?
|
31
|
+
|
32
|
+
key = key.to_sym unless key.is_a?(Symbol)
|
33
|
+
@table[key] = val
|
34
|
+
end
|
35
|
+
|
36
|
+
def attributes
|
37
|
+
each_pair.with_object({}) { |(key, val), hash| hash[key] = val }
|
38
|
+
end
|
39
|
+
|
40
|
+
def replace(args)
|
41
|
+
args.each_pair { |key, val| send("#{key}=", val) }
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/lite/ruby/string.rb
CHANGED
@@ -33,28 +33,34 @@ class String
|
|
33
33
|
}.freeze
|
34
34
|
|
35
35
|
def acronym
|
36
|
-
|
36
|
+
dup.acronym!
|
37
37
|
end
|
38
38
|
|
39
39
|
def acronym!
|
40
|
-
|
40
|
+
gsub!(/(([a-zA-Z0-9])([a-zA-Z0-9])*)./, '\\2') || self
|
41
41
|
end
|
42
42
|
|
43
43
|
def any?(*keys)
|
44
44
|
keys.any? { |key| include?(key) }
|
45
45
|
end
|
46
46
|
|
47
|
+
def ascii_only(alt = '')
|
48
|
+
dup.ascii_only!(alt)
|
49
|
+
end
|
50
|
+
|
51
|
+
def ascii_only!(alt = '')
|
52
|
+
encode_only!('ASCII', alt)
|
53
|
+
end
|
54
|
+
|
47
55
|
def at(position)
|
48
56
|
self[position]
|
49
57
|
end
|
50
58
|
|
51
59
|
def camelize(first_letter = :upper)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
"#{to_s.first.chr.downcase}#{camelize(self)[1..-1]}"
|
57
|
-
end
|
60
|
+
case first_letter
|
61
|
+
when :upper, true then gsub(/(\A|\s)([a-z])/) { $1 + $2.upcase }
|
62
|
+
when :lower, false then gsub(/(\A|\s)([A-Z])/) { $1 + $2.downcase }
|
63
|
+
end || self
|
58
64
|
end
|
59
65
|
|
60
66
|
alias camelcase camelize
|
@@ -65,12 +71,17 @@ class String
|
|
65
71
|
|
66
72
|
alias camelcase! camelize!
|
67
73
|
|
74
|
+
def capitalized?
|
75
|
+
capitalize == self
|
76
|
+
end
|
77
|
+
|
68
78
|
def classify
|
69
|
-
|
79
|
+
dup.classify!
|
70
80
|
end
|
71
81
|
|
72
82
|
def classify!
|
73
|
-
|
83
|
+
sub!(/.*\./, '')
|
84
|
+
camelize!
|
74
85
|
end
|
75
86
|
|
76
87
|
def constantize
|
@@ -78,15 +89,15 @@ class String
|
|
78
89
|
end
|
79
90
|
|
80
91
|
def dasherize
|
81
|
-
|
92
|
+
dup.dasherize!
|
82
93
|
end
|
83
94
|
|
84
95
|
def dasherize!
|
85
|
-
|
96
|
+
tr!('_', '-')
|
86
97
|
end
|
87
98
|
|
88
99
|
def deconstantize
|
89
|
-
|
100
|
+
[0, rindex('::') || 0]
|
90
101
|
end
|
91
102
|
|
92
103
|
def deconstantize!
|
@@ -94,7 +105,7 @@ class String
|
|
94
105
|
end
|
95
106
|
|
96
107
|
def demodulize
|
97
|
-
|
108
|
+
gsub(/^.*::/, '')
|
98
109
|
end
|
99
110
|
|
100
111
|
def demodulize!
|
@@ -111,6 +122,25 @@ class String
|
|
111
122
|
downcase == self
|
112
123
|
end
|
113
124
|
|
125
|
+
def each_word(&block)
|
126
|
+
words.each(&block)
|
127
|
+
end
|
128
|
+
|
129
|
+
def encode_only(encoding, alt = '')
|
130
|
+
dup.encode_only!(encoding, alt)
|
131
|
+
end
|
132
|
+
|
133
|
+
def encode_only!(encoding, alt = '')
|
134
|
+
encoding_options = {
|
135
|
+
invalid: :replace,
|
136
|
+
undef: :replace,
|
137
|
+
replace: alt,
|
138
|
+
UNIVERSAL_NEWLINE_DECORATOR: true
|
139
|
+
}
|
140
|
+
|
141
|
+
encode!(Encoding.find(encoding), encoding_options)
|
142
|
+
end
|
143
|
+
|
114
144
|
def ellipsize(ellipsize_at, options = {})
|
115
145
|
return self if length <= ellipsize_at
|
116
146
|
|
@@ -139,7 +169,7 @@ class String
|
|
139
169
|
end
|
140
170
|
|
141
171
|
def headerize
|
142
|
-
squish.
|
172
|
+
squish.each_word(&:capitalize!).join(' ')
|
143
173
|
end
|
144
174
|
|
145
175
|
def headerize!
|
@@ -147,28 +177,28 @@ class String
|
|
147
177
|
end
|
148
178
|
|
149
179
|
def humanize(options = {})
|
150
|
-
|
151
|
-
|
152
|
-
underscore.gsub(/_id\z/, '')
|
153
|
-
.tr('_', ' ')
|
154
|
-
.squish
|
155
|
-
.gsub(/([a-z\d]*)/i, &:downcase)
|
156
|
-
.gsub(/\A\w/) { |str| capitalize ? str.upcase : str }
|
180
|
+
dup.humanize!(options)
|
157
181
|
end
|
158
182
|
|
159
|
-
def humanize!(
|
160
|
-
|
183
|
+
def humanize!(capitalize: true)
|
184
|
+
underscore!
|
185
|
+
gsub!(/_id\z/, '')
|
186
|
+
tr!('_', ' ')
|
187
|
+
squish!
|
188
|
+
gsub!(/([a-z\d]*)/i, &:downcase)
|
189
|
+
gsub!(/\A\w/) { |str| capitalize ? str.upcase : str } || self
|
161
190
|
end
|
162
191
|
|
163
|
-
def indent(amount,
|
164
|
-
|
165
|
-
substitutes = indent_empty_lines ? /^/ : /^(?!$)/
|
166
|
-
|
167
|
-
gsub(substitutes, indent_string * amount)
|
192
|
+
def indent(amount, seperator = ' ')
|
193
|
+
dup.indent!(amount, seperator)
|
168
194
|
end
|
169
195
|
|
170
|
-
def indent!(amount,
|
171
|
-
|
196
|
+
def indent!(amount, seperator = ' ')
|
197
|
+
if amount >= 0
|
198
|
+
gsub!(/^/, seperator * amount)
|
199
|
+
else
|
200
|
+
gsub!(/^#{Regexp.escape(seperator)}{0,#{-amount}}/, '')
|
201
|
+
end
|
172
202
|
end
|
173
203
|
|
174
204
|
def index_all(pattern)
|
@@ -186,19 +216,18 @@ class String
|
|
186
216
|
end
|
187
217
|
|
188
218
|
def labelize(options = {})
|
189
|
-
|
190
|
-
|
191
|
-
underscore.tr('_', ' ')
|
192
|
-
.squish
|
193
|
-
.gsub(/([a-z\d]*)/i, &:downcase)
|
194
|
-
.gsub(/\A\w/) { |str| capitalize ? str.upcase : str }
|
195
|
-
.gsub(/ id\z/, ' ID')
|
219
|
+
dup.labelize!(options)
|
196
220
|
end
|
197
221
|
|
198
222
|
alias labelcase labelize
|
199
223
|
|
200
|
-
def labelize!(
|
201
|
-
|
224
|
+
def labelize!(capitalize: true)
|
225
|
+
underscore!
|
226
|
+
tr!('_', ' ')
|
227
|
+
squish!
|
228
|
+
gsub!(/([a-z\d]*)/i, &:downcase)
|
229
|
+
gsub!(/\A\w/) { |str| capitalize ? str.upcase : str }
|
230
|
+
gsub!(/ id\z/, ' ID') || self
|
202
231
|
end
|
203
232
|
|
204
233
|
alias labelcase! labelize!
|
@@ -213,6 +242,40 @@ class String
|
|
213
242
|
end
|
214
243
|
end
|
215
244
|
|
245
|
+
def lchomp(match)
|
246
|
+
dup.lchomp!(match)
|
247
|
+
end
|
248
|
+
|
249
|
+
def lchomp!(match)
|
250
|
+
return self unless index(match)
|
251
|
+
|
252
|
+
self[0...match.size] = ''
|
253
|
+
self
|
254
|
+
end
|
255
|
+
|
256
|
+
def methodize
|
257
|
+
dup.methodize!
|
258
|
+
end
|
259
|
+
|
260
|
+
def methodize!
|
261
|
+
gsub!(/([A-Z]+)([A-Z])/, '\1_\2')
|
262
|
+
gsub!(/([a-z])([A-Z])/, '\1_\2')
|
263
|
+
gsub!('/', '__')
|
264
|
+
gsub!('::', '__')
|
265
|
+
downcase! || self
|
266
|
+
end
|
267
|
+
|
268
|
+
def modulize
|
269
|
+
dup.modulize!
|
270
|
+
end
|
271
|
+
|
272
|
+
def modulize!
|
273
|
+
gsub!(/__(.?)/) { "::#{$1.upcase}" }
|
274
|
+
gsub!(%r{/(.?)}) { "::#{$1.upcase}" }
|
275
|
+
gsub!(/(?:_+|-+)([a-z])/) { $1.upcase }
|
276
|
+
gsub!(/(\A|\s)([a-z])/) { $1 + $2.upcase } || self
|
277
|
+
end
|
278
|
+
|
216
279
|
def mixedcase?
|
217
280
|
!upcase? && !downcase?
|
218
281
|
end
|
@@ -226,15 +289,31 @@ class String
|
|
226
289
|
end
|
227
290
|
|
228
291
|
def parameterize(separator: '-')
|
229
|
-
|
292
|
+
dup.parameterize!(separator: separator)
|
230
293
|
end
|
231
294
|
|
232
295
|
def parameterize!(separator: '-')
|
233
|
-
|
296
|
+
underscore!
|
297
|
+
gsub!(/\s+/, separator)
|
298
|
+
downcase! || self
|
299
|
+
end
|
300
|
+
|
301
|
+
def pathize
|
302
|
+
dup.pathize!
|
303
|
+
end
|
304
|
+
|
305
|
+
def pathize!
|
306
|
+
gsub!(/([A-Z]+)([A-Z])/, '\1_\2')
|
307
|
+
gsub!(/([a-z])([A-Z])/, '\1_\2')
|
308
|
+
gsub!('__', '/')
|
309
|
+
gsub!('::', '/')
|
310
|
+
gsub!(/\s+/, '')
|
311
|
+
gsub!(/[?%*:|"<>.]+/, '')
|
312
|
+
downcase! || self
|
234
313
|
end
|
235
314
|
|
236
315
|
def pollute(delimiter = '^--^--^')
|
237
|
-
|
316
|
+
chars.map { |chr| "#{chr}#{delimiter}" }.join
|
238
317
|
end
|
239
318
|
|
240
319
|
def pollute!(delimiter = '^--^--^')
|
@@ -249,22 +328,75 @@ class String
|
|
249
328
|
replace(concat(string))
|
250
329
|
end
|
251
330
|
|
252
|
-
|
253
|
-
|
254
|
-
|
331
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
332
|
+
def quote(type = :double, amount = nil)
|
333
|
+
if type.is_a?(Integer)
|
334
|
+
tmp = amount
|
335
|
+
amount = type
|
336
|
+
type = tmp || :mixed
|
337
|
+
else
|
338
|
+
amount ||= 1
|
339
|
+
end
|
340
|
+
|
341
|
+
case type.to_s
|
342
|
+
when "'", 'single', 's', '1'
|
343
|
+
f = "'" * amount
|
344
|
+
b = f
|
345
|
+
when '"', 'double', 'd', '2'
|
346
|
+
f = '"' * amount
|
347
|
+
b = f
|
348
|
+
when '`', 'back', 'backtick', 'b', '-1'
|
349
|
+
f = '`' * amount
|
350
|
+
b = f
|
351
|
+
when "`'", 'bracket', 'sb'
|
352
|
+
f = '`' * amount
|
353
|
+
b = "'" * amount
|
354
|
+
when "'\"", 'mixed', 'm', 'Integer'
|
355
|
+
c = (amount.to_f / 2).to_i
|
356
|
+
f = '"' * c
|
357
|
+
b = f
|
358
|
+
|
359
|
+
if amount.odd?
|
360
|
+
f = "'" + f
|
361
|
+
b += "'"
|
362
|
+
end
|
363
|
+
else
|
364
|
+
raise ArgumentError, "Invalid quote type: #{type.inspect}"
|
255
365
|
end
|
366
|
+
|
367
|
+
"#{f}#{self}#{b}"
|
368
|
+
end
|
369
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
370
|
+
|
371
|
+
def quote!(type = :double, amount = nil)
|
372
|
+
replace(quote(type, amount))
|
373
|
+
end
|
374
|
+
|
375
|
+
def remove(*patterns)
|
376
|
+
dup.remove!(*patterns)
|
256
377
|
end
|
257
378
|
|
258
379
|
def remove!(*patterns)
|
259
|
-
|
380
|
+
patterns.each_with_object(self) do |pat, str|
|
381
|
+
pat.is_a?(Range) ? str.slice!(pat) : str.gsub!(pat, '')
|
382
|
+
end
|
260
383
|
end
|
261
384
|
|
262
385
|
def remove_tags
|
263
|
-
|
386
|
+
dup.remove_tags!
|
264
387
|
end
|
265
388
|
|
266
389
|
def remove_tags!
|
267
|
-
|
390
|
+
gsub!(%r{<\/?[^>]*>}, '') || self
|
391
|
+
end
|
392
|
+
|
393
|
+
def rotate(amount = 1)
|
394
|
+
dup.rotate!(amount)
|
395
|
+
end
|
396
|
+
|
397
|
+
def rotate!(amount = 1)
|
398
|
+
amount += size if amount.negative?
|
399
|
+
slice!(amount, size - amount) + slice!(0, amount)
|
268
400
|
end
|
269
401
|
|
270
402
|
def sample(separator = ' ')
|
@@ -276,13 +408,13 @@ class String
|
|
276
408
|
end
|
277
409
|
|
278
410
|
def shift(*patterns)
|
279
|
-
|
280
|
-
|
281
|
-
patterns.each_with_object(dup) { |pat, str| str.sub!(pat, '') }
|
411
|
+
dup.shift!(*patterns)
|
282
412
|
end
|
283
413
|
|
284
414
|
def shift!(*patterns)
|
285
|
-
|
415
|
+
return self[0] if patterns.empty?
|
416
|
+
|
417
|
+
patterns.each_with_object(self) { |pat, str| str.sub!(pat, '') }
|
286
418
|
end
|
287
419
|
|
288
420
|
def shuffle(separator = '')
|
@@ -298,7 +430,7 @@ class String
|
|
298
430
|
when String then keep.chars
|
299
431
|
when Array then keep.map(&:to_s)
|
300
432
|
when Range then keep.to_a.map(&:to_s)
|
301
|
-
else raise TypeError, "Invalid parameter #{keep.inspect}"
|
433
|
+
else raise TypeError, "Invalid parameter: #{keep.inspect}"
|
302
434
|
end
|
303
435
|
|
304
436
|
chars.keep_if { |chr| keep.include?(chr) }.join
|
@@ -309,23 +441,24 @@ class String
|
|
309
441
|
end
|
310
442
|
|
311
443
|
def slugify
|
312
|
-
|
313
|
-
.gsub(/[^\w_ \-]+/i, '')
|
314
|
-
.gsub(/[ \-]+/i, '-')
|
315
|
-
.gsub(/^\-|\-$/i, '')
|
316
|
-
.downcase
|
444
|
+
dup.slugify!
|
317
445
|
end
|
318
446
|
|
319
447
|
def slugify!
|
320
|
-
|
448
|
+
gsub!(/[^\x00-\x7F]+/, '')
|
449
|
+
gsub!(/[^\w_ \-]+/i, '')
|
450
|
+
gsub!(/[ \-]+/i, '-')
|
451
|
+
gsub!(/^\-|\-$/i, '')
|
452
|
+
downcase! || self
|
321
453
|
end
|
322
454
|
|
323
455
|
def squish
|
324
|
-
|
456
|
+
dup.squish!
|
325
457
|
end
|
326
458
|
|
327
459
|
def squish!
|
328
|
-
|
460
|
+
strip!
|
461
|
+
gsub!(/\s+/, ' ') || self
|
329
462
|
end
|
330
463
|
|
331
464
|
def sort
|
@@ -337,13 +470,15 @@ class String
|
|
337
470
|
end
|
338
471
|
|
339
472
|
def titleize
|
340
|
-
|
473
|
+
dup.titleize!
|
341
474
|
end
|
342
475
|
|
343
476
|
alias titlecase titleize
|
344
477
|
|
345
478
|
def titleize!
|
346
|
-
|
479
|
+
underscore!
|
480
|
+
humanize!
|
481
|
+
gsub!(/\b(?<!['’`])[a-z]/) { $&.capitalize } || self
|
347
482
|
end
|
348
483
|
|
349
484
|
alias titlecase! titleize!
|
@@ -385,23 +520,27 @@ class String
|
|
385
520
|
end
|
386
521
|
|
387
522
|
def underscore
|
388
|
-
|
389
|
-
.gsub(/([A-Z\d]+)([A-Z][a-z])/, "\1_\2")
|
390
|
-
.gsub(/([a-z\d])([A-Z])/, "\1_\2")
|
391
|
-
.tr('-', '_')
|
392
|
-
.downcase
|
523
|
+
dup.underscore!
|
393
524
|
end
|
394
525
|
|
526
|
+
alias snakecase underscore
|
527
|
+
|
395
528
|
def underscore!
|
396
|
-
|
529
|
+
gsub!(/::/, '/')
|
530
|
+
gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
531
|
+
gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
532
|
+
tr!('-', '_')
|
533
|
+
downcase! || self
|
397
534
|
end
|
398
535
|
|
536
|
+
alias snakecase! underscore!
|
537
|
+
|
399
538
|
def unpollute(delimiter = '^--^--^')
|
400
|
-
|
539
|
+
dup.unpollute!(delimiter)
|
401
540
|
end
|
402
541
|
|
403
542
|
def unpollute!(delimiter = '^--^--^')
|
404
|
-
|
543
|
+
gsub!(delimiter, '') || self
|
405
544
|
end
|
406
545
|
|
407
546
|
def upcase?
|
@@ -417,4 +556,42 @@ class String
|
|
417
556
|
replace(unshift(*patterns))
|
418
557
|
end
|
419
558
|
|
559
|
+
def unquote
|
560
|
+
dup.unquote!
|
561
|
+
end
|
562
|
+
|
563
|
+
def unquote!
|
564
|
+
[0, -1].each do |i|
|
565
|
+
case self[i, 1]
|
566
|
+
when "'", '"', '`' then self[i] = ''
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
self
|
571
|
+
end
|
572
|
+
|
573
|
+
def words
|
574
|
+
split(/\s+/)
|
575
|
+
end
|
576
|
+
|
577
|
+
def words_without_punctuation
|
578
|
+
str = dup
|
579
|
+
str.gsub!(%r{[.?¿¡…!,::;—"。?!、‘“”„«»〈〉《》,/\[\]]}, ' ')
|
580
|
+
str.gsub!('- ', ' ')
|
581
|
+
str.squeeze!(' ')
|
582
|
+
str.strip!
|
583
|
+
str.words
|
584
|
+
end
|
585
|
+
|
586
|
+
def variablize
|
587
|
+
"@#{gsub(/\W/, '_')}"
|
588
|
+
end
|
589
|
+
|
590
|
+
def variablize!
|
591
|
+
replace(variablize)
|
592
|
+
end
|
593
|
+
|
594
|
+
alias ends_with? end_with?
|
595
|
+
alias starts_with? start_with?
|
596
|
+
|
420
597
|
end
|