web-utils 0.1.4 → 0.1.5
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/lib/web_utils.rb +153 -69
- data/test/test_web_utils.rb +22 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74c9972b2a2cfeb97d05475c3833378dfe7b83350e5764e281888c3f7e206b67
|
4
|
+
data.tar.gz: 82f8929a62f9b94e130514f9191f0be756b7f7ef49ab1e6e5105113d53068ce4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4488aa8e08eddc957a2626662bc3eda75b59c049435e9f4b37eb2cbd6574335d178373c0cf97e289797b9451966838017753f2c2e15e21f4fe751cb4bde55def
|
7
|
+
data.tar.gz: 144b9995c41472af73386bfe7ffa1a4e0f4df5f5dca6d929dbd10a0118c42a265b0d99ef753f2916935535e182580038b1c51fcf85c679c84a69ffa17f2f4ed1
|
data/lib/web_utils.rb
CHANGED
@@ -5,59 +5,104 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module WebUtils
|
7
7
|
|
8
|
-
VERSION = '0.1.
|
8
|
+
VERSION = '0.1.5'.freeze
|
9
9
|
|
10
10
|
# Most methods are supposed to be as simple as possible
|
11
11
|
# and just cover most cases.
|
12
|
-
# I would rather override specific cases
|
12
|
+
# I would rather override specific cases than making
|
13
13
|
# complicated methods.
|
14
14
|
|
15
15
|
extend Rack::Utils
|
16
16
|
|
17
|
+
# Global string constants
|
18
|
+
EMPTY_STRING = ''.freeze
|
19
|
+
IES_STRING = 'ies'.freeze
|
20
|
+
E_STRING = 'e'.freeze
|
21
|
+
S_STRING = 's'.freeze
|
22
|
+
Y_STRING = 'y'.freeze
|
23
|
+
X_STRING = 'x'.freeze
|
24
|
+
XES_STRING = 'xes'.freeze
|
25
|
+
SPACE = ' '.freeze
|
26
|
+
DASH = '-'.freeze
|
27
|
+
UNDERSCORE = '_'.freeze
|
28
|
+
AMPERSAND = '&'.freeze
|
29
|
+
PERCENT = '%'.freeze
|
30
|
+
PIPE = '|'
|
31
|
+
DOT = '.'.freeze
|
32
|
+
COMMA = ','.freeze
|
33
|
+
CONST_SEP = '::'.freeze
|
34
|
+
ELLIPSIS = '...'
|
35
|
+
AND_STRING = 'and'.freeze
|
36
|
+
SPACE_PERCENT_STRING = ' percent'.freeze
|
37
|
+
TRUE_STRING = 'true'.freeze
|
38
|
+
FALSE_STRING = 'false'.freeze
|
39
|
+
BR_TAG = '<br>'.freeze
|
40
|
+
ARG1_SUB = '\1'.freeze
|
41
|
+
|
42
|
+
# From then on, constants preceed the methods they are
|
43
|
+
# used on.
|
44
|
+
|
45
|
+
BLANK_RE = /\A[[:space:]]*\z/.freeze
|
46
|
+
|
17
47
|
def blank? s
|
18
|
-
s.
|
48
|
+
return true if s.nil?
|
49
|
+
# Not much difference with strip on benchmarks
|
50
|
+
# return (s.empty? or BLANK_RE.match?(s)) if s.is_a?(String)
|
51
|
+
return (s.strip.empty?) if s.is_a?(String)
|
52
|
+
return s.empty? if s.respond_to?(:empty?)
|
53
|
+
return true if s==false
|
54
|
+
false
|
19
55
|
end
|
20
56
|
module_function :blank?
|
21
57
|
|
58
|
+
PLURAL_RE = /([b-df-hj-np-tv-z])ys\z/.freeze
|
59
|
+
PLURAL_SUB = '\1ies'.freeze
|
60
|
+
|
22
61
|
def pluralize s
|
23
|
-
s
|
24
|
-
s<<
|
25
|
-
s
|
62
|
+
s = s.dup
|
63
|
+
s<<E_STRING if s[-1,1]==X_STRING
|
64
|
+
s<<S_STRING
|
65
|
+
s.sub PLURAL_RE, PLURAL_SUB
|
26
66
|
end
|
27
67
|
module_function :pluralize
|
28
68
|
|
69
|
+
SINGULAR_RE = /ies\z/.freeze
|
70
|
+
|
29
71
|
def singularize s
|
30
|
-
|
31
|
-
when /xes$/
|
72
|
+
if s.end_with? XES_STRING
|
32
73
|
s[0..-3]
|
33
|
-
|
34
|
-
s.sub(
|
35
|
-
|
74
|
+
elsif s.end_with? IES_STRING
|
75
|
+
s.sub(SINGULAR_RE, Y_STRING)
|
76
|
+
elsif s.end_with? S_STRING
|
36
77
|
s[0..-2]
|
37
78
|
else
|
38
|
-
s
|
79
|
+
s.dup
|
39
80
|
end
|
40
81
|
end
|
41
82
|
module_function :singularize
|
42
83
|
|
84
|
+
UPPER_OR_NUM_RE = /([A-Z]|\d+)/.freeze
|
85
|
+
|
43
86
|
def dasherize_class_name s
|
44
|
-
s.gsub(
|
87
|
+
s.gsub(UPPER_OR_NUM_RE) {|str| "-#{str.downcase}" }[1..-1].gsub(CONST_SEP, DASH)
|
45
88
|
end
|
46
89
|
module_function :dasherize_class_name
|
47
90
|
|
91
|
+
DASH_LOWER_OR_NUM_RE = /\-([a-z0-9])/.freeze
|
92
|
+
|
48
93
|
def undasherize_class_name s
|
49
|
-
s.capitalize.gsub(
|
94
|
+
s.capitalize.gsub(DASH_LOWER_OR_NUM_RE) {|str| $1.upcase }.gsub(DASH, CONST_SEP)
|
50
95
|
end
|
51
96
|
module_function :undasherize_class_name
|
52
97
|
|
53
98
|
def resolve_class_name s, context=Kernel
|
54
|
-
current, *payload = s.to_s.split(
|
99
|
+
current, *payload = s.to_s.split(CONST_SEP)
|
55
100
|
raise(NameError) if current.nil?
|
56
101
|
const = context.const_get(current)
|
57
102
|
if payload.empty?
|
58
103
|
const
|
59
104
|
else
|
60
|
-
resolve_class_name(payload.join(
|
105
|
+
resolve_class_name(payload.join(CONST_SEP),const)
|
61
106
|
end
|
62
107
|
end
|
63
108
|
module_function :resolve_class_name
|
@@ -67,12 +112,15 @@ module WebUtils
|
|
67
112
|
end
|
68
113
|
module_function :resolve_dasherized_class_name
|
69
114
|
|
115
|
+
START_UPPER_RE = /^[A-Z]/.freeze
|
116
|
+
START_LOWER_RE = /^[a-z]/.freeze
|
117
|
+
|
70
118
|
def guess_related_class_name context, clue
|
71
119
|
context.respond_to?(:name) ? context.name : context.to_s
|
72
120
|
clue = clue.to_s
|
73
|
-
return clue if clue
|
74
|
-
if clue
|
75
|
-
clue = undasherize_class_name singularize(clue).gsub(
|
121
|
+
return clue if clue =~ START_UPPER_RE
|
122
|
+
if clue =~ START_LOWER_RE
|
123
|
+
clue = undasherize_class_name singularize(clue).gsub(UNDERSCORE, DASH)
|
76
124
|
clue = "::#{clue}"
|
77
125
|
end
|
78
126
|
"#{context}#{clue}"
|
@@ -96,39 +144,43 @@ module WebUtils
|
|
96
144
|
module_function :deep_copy
|
97
145
|
|
98
146
|
def ensure_key! h, k, v
|
99
|
-
h
|
100
|
-
h[k]
|
147
|
+
h.fetch(k) {|k| h.store(k, v) }
|
101
148
|
end
|
102
149
|
module_function :ensure_key!
|
103
150
|
|
104
151
|
def ensure_key h, k, v
|
105
|
-
|
106
|
-
self.ensure_key! new_h, k, v
|
107
|
-
new_h
|
152
|
+
{k=>v}.merge h
|
108
153
|
end
|
109
154
|
module_function :ensure_key
|
110
155
|
|
111
|
-
ACCENTS = "ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž"
|
112
|
-
WITHOUT_ACCENTS = "AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz"
|
156
|
+
ACCENTS = "ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž".freeze
|
157
|
+
WITHOUT_ACCENTS = "AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz".freeze
|
158
|
+
DASHIFY_RE = /(\-|[^0-9a-zA-Z])+/.freeze
|
159
|
+
EDGE_DASH_RE = /(\A-|-\z)/.freeze
|
160
|
+
|
113
161
|
def slugify s, force_lower=true
|
114
162
|
s = s.to_s
|
115
163
|
.tr(ACCENTS, WITHOUT_ACCENTS)
|
116
|
-
.gsub(
|
117
|
-
.gsub(
|
118
|
-
.gsub(
|
119
|
-
.gsub(
|
164
|
+
.gsub(AMPERSAND, AND_STRING)
|
165
|
+
.gsub(PERCENT, SPACE_PERCENT_STRING)
|
166
|
+
.gsub(DASHIFY_RE, DASH)
|
167
|
+
.gsub(EDGE_DASH_RE, EMPTY_STRING)
|
120
168
|
s = s.downcase if force_lower
|
121
169
|
escape(s)
|
122
170
|
end
|
123
171
|
module_function :slugify
|
124
172
|
|
173
|
+
ALPHA_NUM_RE = /[a-zA-Z0-9]+/.freeze
|
174
|
+
|
125
175
|
def label_for_field field_name
|
126
|
-
field_name.to_s.scan(
|
176
|
+
field_name.to_s.scan(ALPHA_NUM_RE).map(&:capitalize).join(SPACE)
|
127
177
|
end
|
128
178
|
module_function :label_for_field
|
129
179
|
|
180
|
+
EACH_STUB_ERR_MSG = 'WebUtils.each_stub expects an object which respond to each_with_index.'
|
181
|
+
|
130
182
|
def each_stub obj, &block
|
131
|
-
raise TypeError,
|
183
|
+
raise TypeError, EACH_STUB_ERR_MSG unless obj.respond_to?(:each_with_index)
|
132
184
|
obj.each_with_index do |(k,v),i|
|
133
185
|
value = v || k
|
134
186
|
if value.is_a?(Hash) || value.is_a?(Array)
|
@@ -140,7 +192,10 @@ module WebUtils
|
|
140
192
|
end
|
141
193
|
module_function :each_stub
|
142
194
|
|
143
|
-
TYPECASTABLE = [:bool, :boolean, :nil, :int, :integer, :float]
|
195
|
+
TYPECASTABLE = [:bool, :boolean, :nil, :int, :integer, :float].freeze
|
196
|
+
INT_RE = /\A-?\d+\z/.freeze
|
197
|
+
FLOAT_RE = /\A-?\d*\.\d+\z/.freeze
|
198
|
+
|
144
199
|
def automatic_typecast str, casted=TYPECASTABLE
|
145
200
|
return str unless str.is_a?(String)
|
146
201
|
casted = casted.map do |sym|
|
@@ -153,15 +208,15 @@ module WebUtils
|
|
153
208
|
sym
|
154
209
|
end
|
155
210
|
end
|
156
|
-
if casted.include?(:boolean) and str==
|
211
|
+
if casted.include?(:boolean) and str == TRUE_STRING
|
157
212
|
true
|
158
|
-
elsif casted.include?(:boolean) and str==
|
213
|
+
elsif casted.include?(:boolean) and str == FALSE_STRING
|
159
214
|
false
|
160
|
-
elsif casted.include?(:nil) and str==
|
215
|
+
elsif casted.include?(:nil) and str == EMPTY_STRING
|
161
216
|
nil
|
162
|
-
elsif casted.include?(:integer) and str
|
217
|
+
elsif casted.include?(:integer) and str =~ INT_RE
|
163
218
|
str.to_i
|
164
|
-
elsif casted.include?(:float) and str
|
219
|
+
elsif casted.include?(:float) and str =~ FLOAT_RE
|
165
220
|
str.to_f
|
166
221
|
else
|
167
222
|
str
|
@@ -169,23 +224,29 @@ module WebUtils
|
|
169
224
|
end
|
170
225
|
module_function :automatic_typecast
|
171
226
|
|
172
|
-
ID_CHARS = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
|
227
|
+
ID_CHARS = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a).freeze.map(&:freeze)
|
173
228
|
ID_SIZE = 16
|
229
|
+
DEPRECATED_RANDOM_ID_STRING = 'WebUtils::generate_random_id is deprecated. Use standard SecureRandom instead.'.freeze
|
230
|
+
|
174
231
|
def generate_random_id size=ID_SIZE
|
175
|
-
warn
|
176
|
-
id =
|
232
|
+
warn DEPRECATED_RANDOM_ID_STRING
|
233
|
+
id = String.new
|
177
234
|
size.times{id << ID_CHARS[rand(ID_CHARS.size)]}
|
178
235
|
id
|
179
236
|
end
|
180
237
|
module_function :generate_random_id
|
181
238
|
|
182
|
-
|
183
|
-
|
239
|
+
RN_RE = /\r?\n/.freeze
|
240
|
+
|
241
|
+
def nl2br s, br=BR_TAG
|
242
|
+
s.to_s.gsub(RN_RE, br)
|
184
243
|
end
|
185
244
|
module_function :nl2br
|
186
245
|
|
246
|
+
COMPLETE_LINK_RE = /^(\/|[a-z]*:)/.freeze
|
247
|
+
|
187
248
|
def complete_link link
|
188
|
-
if blank?(link) or link
|
249
|
+
if blank?(link) or link =~ COMPLETE_LINK_RE
|
189
250
|
link
|
190
251
|
else
|
191
252
|
"//#{link}"
|
@@ -193,14 +254,17 @@ module WebUtils
|
|
193
254
|
end
|
194
255
|
module_function :complete_link
|
195
256
|
|
257
|
+
EXTERNAL_LINK_RE = /\A[a-z]*:?\/\//.freeze
|
258
|
+
|
196
259
|
def external_link? link
|
197
|
-
!!(link =~
|
260
|
+
!!(link =~ EXTERNAL_LINK_RE)
|
198
261
|
end
|
199
262
|
module_function :external_link?
|
200
263
|
|
201
|
-
EMAIL_REGEX = /([^\s]+@[^\s]*[a-zA-Z])
|
202
|
-
LINK_REGEX = /\b((https?:\/\/|ftps?:\/\/|www\.)([A-Za-z0-9\-_=%&@\?\.\/]+))\b
|
203
|
-
|
264
|
+
EMAIL_REGEX = /([^\s]+@[^\s]*[a-zA-Z])/.freeze
|
265
|
+
LINK_REGEX = /\b((https?:\/\/|ftps?:\/\/|www\.)([A-Za-z0-9\-_=%&@\?\.\/]+))\b/.freeze
|
266
|
+
|
267
|
+
def automatic_html s, br=BR_TAG
|
204
268
|
replaced = s.to_s.
|
205
269
|
gsub(LINK_REGEX) do |str|
|
206
270
|
url = complete_link $1
|
@@ -213,51 +277,69 @@ module WebUtils
|
|
213
277
|
end
|
214
278
|
module_function :automatic_html
|
215
279
|
|
216
|
-
TAG_REGEX = /<[^>]
|
217
|
-
|
280
|
+
TAG_REGEX = /<[^>]*>/.freeze
|
281
|
+
NL_RE = /\n/.freeze
|
282
|
+
|
283
|
+
def truncate s, c=320, ellipsis=ELLIPSIS
|
218
284
|
s.to_s
|
219
|
-
.gsub(TAG_REGEX,
|
220
|
-
.gsub(
|
221
|
-
.sub(/^(.{#{c}}\w*).*$/m,
|
285
|
+
.gsub(TAG_REGEX, EMPTY_STRING)
|
286
|
+
.gsub(NL_RE, SPACE)
|
287
|
+
.sub(/^(.{#{c}}\w*).*$/m, ARG1_SUB+ellipsis)
|
222
288
|
end
|
223
289
|
module_function :truncate
|
224
290
|
|
291
|
+
QUERY_SPLITTER = /[^a-zA-Z0-9\&]+/.freeze
|
292
|
+
|
225
293
|
def regex_for_query query, exhaustive=true
|
226
|
-
atoms = query.split(
|
294
|
+
atoms = query.split(QUERY_SPLITTER)
|
227
295
|
atom_patterns = atoms.map{|a| "(?=.*\\b#{a})" }
|
228
|
-
sep = exhaustive ?
|
229
|
-
|
296
|
+
sep = exhaustive ? EMPTY_STRING : PIPE
|
297
|
+
/#{atom_patterns.join(sep)}/i.freeze
|
230
298
|
end
|
231
299
|
module_function :regex_for_query
|
232
300
|
|
301
|
+
PRICE_ERR_MSG = 'The price needs to be the price in cents/pence as an integer'.freeze
|
302
|
+
PRICE_FMT = '%.2f'.freeze
|
303
|
+
NO_CENTS_RE = /\.00/.freeze
|
304
|
+
THOUSANDS_RE = /(\d{3})(?=\d)/.freeze
|
305
|
+
THOUSANDS_SUB = '\1,'.freeze
|
306
|
+
|
233
307
|
def display_price int
|
234
308
|
unless int.is_a?(Integer)
|
235
|
-
raise(TypeError,
|
309
|
+
raise(TypeError, PRICE_ERR_MSG)
|
236
310
|
end
|
237
|
-
(
|
238
|
-
.sub(
|
311
|
+
(PRICE_FMT % (int/100.0))
|
312
|
+
.sub(NO_CENTS_RE, EMPTY_STRING)
|
239
313
|
.reverse
|
240
|
-
.gsub(
|
314
|
+
.gsub(THOUSANDS_RE, THOUSANDS_SUB)
|
241
315
|
.reverse
|
242
316
|
end
|
243
317
|
module_function :display_price
|
244
318
|
|
319
|
+
PRICE_PARSE_ERR_MSG = 'The price needs to be parsed from a String'.freeze
|
320
|
+
SWITCH_DOT_COMMA_TR = ['.,'.freeze, ',.'.freeze].freeze
|
321
|
+
COMMA_BASED_PRICE_RE = /(\.\d\d\d|,\d\d?)\z/.freeze
|
322
|
+
NON_PRICE_CHARS_RE = /[^\d\.\-,]/.freeze
|
323
|
+
|
245
324
|
def parse_price string
|
246
325
|
unless string.is_a?(String)
|
247
|
-
raise(TypeError,
|
326
|
+
raise(TypeError, PRICE_PARSE_ERR_MSG)
|
248
327
|
end
|
249
|
-
string = string.gsub(
|
250
|
-
if string[
|
328
|
+
string = string.gsub(NON_PRICE_CHARS_RE, EMPTY_STRING)
|
329
|
+
if string[COMMA_BASED_PRICE_RE]
|
251
330
|
# comma-based price
|
252
|
-
string = string.tr
|
331
|
+
string = string.tr(*SWITCH_DOT_COMMA_TR)
|
253
332
|
end
|
254
|
-
(
|
333
|
+
(PRICE_FMT % string.gsub(COMMA, EMPTY_STRING)).gsub(DOT, EMPTY_STRING).to_i
|
255
334
|
end
|
256
335
|
module_function :parse_price
|
257
336
|
|
258
|
-
|
337
|
+
DEFAULT_BRAND = self.name
|
338
|
+
START_DOT_SLASH_RE = /\A\.\//.freeze
|
339
|
+
|
340
|
+
def branded_filename path, brand=DEFAULT_BRAND
|
259
341
|
"#{File.dirname(path)}/#{brand}-#{File.basename(path)}"
|
260
|
-
.sub(
|
342
|
+
.sub(START_DOT_SLASH_RE, EMPTY_STRING)
|
261
343
|
end
|
262
344
|
module_function :branded_filename
|
263
345
|
|
@@ -268,12 +350,14 @@ module WebUtils
|
|
268
350
|
module_function :filename_variation
|
269
351
|
|
270
352
|
def initial_request? request
|
271
|
-
return true unless request.referer=~URI.regexp
|
272
353
|
URI.parse(request.referer).host!=request.host
|
354
|
+
rescue URI::InvalidURIError
|
355
|
+
return true
|
273
356
|
end
|
274
357
|
module_function :initial_request?
|
275
358
|
|
276
|
-
BOT_REGEX = /bot|crawl|slurp|spider/i
|
359
|
+
BOT_REGEX = /bot|crawl|slurp|spider/i.freeze
|
360
|
+
|
277
361
|
def being_crawled? request
|
278
362
|
request.user_agent =~ BOT_REGEX
|
279
363
|
end
|
data/test/test_web_utils.rb
CHANGED
@@ -26,6 +26,9 @@ describe WebUtils do
|
|
26
26
|
describe 'with nil' do
|
27
27
|
it('is true') { assert utils.blank?(nil) }
|
28
28
|
end
|
29
|
+
describe 'with false' do
|
30
|
+
it('is true') { assert utils.blank?(false) }
|
31
|
+
end
|
29
32
|
describe 'with non-blank strings' do
|
30
33
|
it 'is false' do
|
31
34
|
['a','abc', ' abc '].each do |s|
|
@@ -54,6 +57,11 @@ describe WebUtils do
|
|
54
57
|
assert_equal 'copies', utils.pluralize('copy')
|
55
58
|
end
|
56
59
|
end
|
60
|
+
it "Does not mutate input" do
|
61
|
+
input = 'bag'
|
62
|
+
utils.pluralize(input)
|
63
|
+
assert_equal 'bag', input
|
64
|
+
end
|
57
65
|
|
58
66
|
end
|
59
67
|
|
@@ -72,6 +80,14 @@ describe WebUtils do
|
|
72
80
|
assert_equal 'copy', utils.singularize('copies')
|
73
81
|
end
|
74
82
|
end
|
83
|
+
describe "The word does not seem plural" do
|
84
|
+
it "Returns the same" do
|
85
|
+
input = 'bag'
|
86
|
+
output = utils.singularize(input)
|
87
|
+
assert_equal 'bag', output
|
88
|
+
refute_same input, output
|
89
|
+
end
|
90
|
+
end
|
75
91
|
|
76
92
|
end
|
77
93
|
|
@@ -350,14 +366,14 @@ describe WebUtils do
|
|
350
366
|
|
351
367
|
describe '#generate_random_id' do
|
352
368
|
it 'Has the correct format' do
|
353
|
-
|
354
|
-
assert_match
|
369
|
+
_, err = capture_io do
|
370
|
+
assert_match(/[a-zA-Z0-9]{16}/, utils.generate_random_id )
|
355
371
|
end
|
356
372
|
assert_match "WebUtils::generate_random_id is deprecated", err
|
357
373
|
end
|
358
374
|
it 'Can have a specific length' do
|
359
|
-
|
360
|
-
assert_match
|
375
|
+
_, err = capture_io do
|
376
|
+
assert_match(/[a-zA-Z0-9]{32}/, utils.generate_random_id(32) )
|
361
377
|
end
|
362
378
|
assert_match "WebUtils::generate_random_id is deprecated", err
|
363
379
|
end
|
@@ -508,13 +524,13 @@ describe WebUtils do
|
|
508
524
|
assert_equal 2800, utils.parse_price('28')
|
509
525
|
end
|
510
526
|
it 'Ignores visual help but works with negative prices' do
|
511
|
-
assert_equal
|
527
|
+
assert_equal(-1234567890, utils.parse_price(' £-12,345,678.90 ') )
|
512
528
|
end
|
513
529
|
it 'Parses comma-based prices - french/german style' do
|
514
530
|
assert_equal 2390, utils.parse_price('23,90')
|
515
531
|
assert_equal 2390, utils.parse_price('23,9')
|
516
532
|
assert_equal 2000000, utils.parse_price('20.000')
|
517
|
-
assert_equal
|
533
|
+
assert_equal(-1234567890, utils.parse_price(' £-12.345.678,90 ') )
|
518
534
|
end
|
519
535
|
it 'Raises when argument is not string' do
|
520
536
|
assert_raises(TypeError) do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mickael Riga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|