lite-ruby 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|