hanami-utils 1.3.7 → 2.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Hanami
4
- module Utils
5
- # Safe dup logic
6
- #
7
- # @since 0.6.0
8
- module Duplicable
9
- # Duplicates the given value.
10
- #
11
- # It accepts a block to customize the logic.
12
- #
13
- # The following types aren't duped:
14
- #
15
- # * <tt>NilClass</tt>
16
- # * <tt>FalseClass</tt>
17
- # * <tt>TrueClass</tt>
18
- # * <tt>Symbol</tt>
19
- # * <tt>Numeric</tt>
20
- #
21
- # All the other types are duped via <tt>#dup</tt>
22
- #
23
- # @param value [Object] the value to duplicate
24
- # @param blk [Proc] the optional block to customize the logic
25
- #
26
- # @return [Object] the duped value
27
- #
28
- # @since 0.6.0
29
- #
30
- # @example Basic Usage With Types That Can't Be Duped
31
- # require 'hanami/utils/duplicable'
32
- #
33
- # object = 23
34
- # puts object.object_id # => 47
35
- #
36
- # result = Hanami::Utils::Duplicable.dup(object)
37
- #
38
- # puts result # => 23
39
- # puts result.object_id # => 47 - Same object, because numbers can't be duped
40
- #
41
- # @example Basic Usage With Types That Can Be Duped
42
- # require 'hanami/utils/duplicable'
43
- #
44
- # object = "hello"
45
- # puts object.object_id # => 70172661782360
46
- #
47
- # result = Hanami::Utils::Duplicable.dup(object)
48
- #
49
- # puts result # => "hello"
50
- # puts result.object_id # => 70172671467020 - Different object
51
- #
52
- # @example Custom Logic
53
- # require 'hanami/utils/duplicable'
54
- # require 'hanami/utils/hash'
55
- #
56
- # hash = { a: 1 }
57
- # puts hash.object_id # => 70207105061680
58
- #
59
- # result = Hanami::Utils::Duplicable.dup(hash) do |value|
60
- # case value
61
- # when Hanami::Utils::Hash
62
- # value.deep_dup
63
- # when ::Hash
64
- # Hanami::Utils::Hash.new(value).deep_dup.to_h
65
- # end
66
- # end
67
- #
68
- # puts result # => "{:a=>1}"
69
- # puts result.object_id # => 70207105185500 - Different object
70
- def self.dup(value, &blk)
71
- case value
72
- when NilClass, FalseClass, TrueClass, Symbol, Numeric
73
- value
74
- when v = blk&.call(value)
75
- v
76
- else
77
- value.dup
78
- end
79
- end
80
- end
81
- end
82
- end
@@ -1,493 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "hanami/utils/class_attribute"
4
- require "hanami/utils/blank"
5
-
6
- module Hanami
7
- module Utils
8
- # String inflector
9
- #
10
- # @since 0.4.1
11
- module Inflector # rubocop:disable Metrics/ModuleLength
12
- # Rules for irregular plurals
13
- #
14
- # @since 0.6.0
15
- # @api private
16
- class IrregularRules
17
- # @since 0.6.0
18
- # @api private
19
- def initialize(rules)
20
- @rules = rules
21
- end
22
-
23
- # @since 0.6.0
24
- # @api private
25
- def add(key, value)
26
- @rules[key.downcase] = value.downcase
27
- end
28
-
29
- # @since 0.6.0
30
- # @api private
31
- def ===(other)
32
- key = extract_last_alphanumeric_token(other)
33
- @rules.key?(key) || @rules.value?(key)
34
- end
35
-
36
- # @since 0.6.0
37
- # @api private
38
- def apply(string)
39
- key = extract_last_alphanumeric_token(string)
40
- result = @rules[key] || @rules.rassoc(key).last
41
-
42
- prefix = if key == string.downcase
43
- string[0]
44
- else
45
- string[0..string.index(key)]
46
- end
47
-
48
- prefix + result[1..-1]
49
- end
50
-
51
- private
52
-
53
- # @since 1.3.3
54
- # @api private
55
- def extract_last_alphanumeric_token(string)
56
- if string.downcase =~ /_([[:alpha:]]*)\z/
57
- Regexp.last_match(1)
58
- else
59
- string.downcase
60
- end
61
- end
62
- end
63
-
64
- # @since 0.4.1
65
- # @api private
66
- A = "a"
67
-
68
- # @since 0.4.1
69
- # @api private
70
- CH = "ch"
71
-
72
- # @since 0.4.1
73
- # @api private
74
- CHES = "ches"
75
-
76
- # @since 0.4.1
77
- # @api private
78
- EAUX = "eaux"
79
-
80
- # @since 0.6.0
81
- # @api private
82
- ES = "es"
83
-
84
- # @since 0.4.1
85
- # @api private
86
- F = "f"
87
-
88
- # @since 0.4.1
89
- # @api private
90
- I = "i"
91
-
92
- # @since 0.4.1
93
- # @api private
94
- ICE = "ice"
95
-
96
- # @since 0.4.1
97
- # @api private
98
- ICES = "ices"
99
-
100
- # @since 0.4.1
101
- # @api private
102
- IDES = "ides"
103
-
104
- # @since 0.4.1
105
- # @api private
106
- IES = "ies"
107
-
108
- # @since 0.4.1
109
- # @api private
110
- IFE = "ife"
111
-
112
- # @since 0.4.1
113
- # @api private
114
- IS = "is"
115
-
116
- # @since 0.4.1
117
- # @api private
118
- IVES = "ives"
119
-
120
- # @since 0.4.1
121
- # @api private
122
- MA = "ma"
123
-
124
- # @since 0.4.1
125
- # @api private
126
- MATA = "mata"
127
-
128
- # @since 0.4.1
129
- # @api private
130
- MEN = "men"
131
-
132
- # @since 0.4.1
133
- # @api private
134
- MINA = "mina"
135
-
136
- # @since 0.6.0
137
- # @api private
138
- NA = "na"
139
-
140
- # @since 0.6.0
141
- # @api private
142
- NON = "non"
143
-
144
- # @since 0.4.1
145
- # @api private
146
- O = "o"
147
-
148
- # @since 0.4.1
149
- # @api private
150
- OES = "oes"
151
-
152
- # @since 0.4.1
153
- # @api private
154
- OUSE = "ouse"
155
-
156
- # @since 0.4.1
157
- # @api private
158
- RSE = "rse"
159
-
160
- # @since 0.4.1
161
- # @api private
162
- RSES = "rses"
163
-
164
- # @since 0.4.1
165
- # @api private
166
- S = "s"
167
-
168
- # @since 0.4.1
169
- # @api private
170
- SES = "ses"
171
-
172
- # @since 0.4.1
173
- # @api private
174
- SSES = "sses"
175
-
176
- # @since 0.6.0
177
- # @api private
178
- TA = "ta"
179
-
180
- # @since 0.4.1
181
- # @api private
182
- UM = "um"
183
-
184
- # @since 0.4.1
185
- # @api private
186
- US = "us"
187
-
188
- # @since 0.4.1
189
- # @api private
190
- USES = "uses"
191
-
192
- # @since 0.4.1
193
- # @api private
194
- VES = "ves"
195
-
196
- # @since 0.4.1
197
- # @api private
198
- X = "x"
199
-
200
- # @since 0.4.1
201
- # @api private
202
- XES = "xes"
203
-
204
- # @since 0.4.1
205
- # @api private
206
- Y = "y"
207
-
208
- include Utils::ClassAttribute
209
-
210
- # Irregular rules for plurals
211
- #
212
- # @since 0.6.0
213
- # @api private
214
- class_attribute :plurals
215
- self.plurals = IrregularRules.new(
216
- # irregular
217
- "cactus" => "cacti",
218
- "child" => "children",
219
- "corpus" => "corpora",
220
- "foot" => "feet",
221
- "genus" => "genera",
222
- "goose" => "geese",
223
- "louse" => "lice",
224
- "man" => "men",
225
- "mouse" => "mice",
226
- "ox" => "oxen",
227
- "person" => "people",
228
- "quiz" => "quizzes",
229
- "sex" => "sexes",
230
- "testis" => "testes",
231
- "tooth" => "teeth",
232
- "woman" => "women",
233
- # uncountable
234
- "deer" => "deer",
235
- "equipment" => "equipment",
236
- "fish" => "fish",
237
- "information" => "information",
238
- "means" => "means",
239
- "money" => "money",
240
- "news" => "news",
241
- "offspring" => "offspring",
242
- "rice" => "rice",
243
- "series" => "series",
244
- "sheep" => "sheep",
245
- "species" => "species",
246
- "police" => "police",
247
- # regressions
248
- # https://github.com/hanami/utils/issues/106
249
- "album" => "albums",
250
- "area" => "areas"
251
- )
252
-
253
- # Irregular rules for singulars
254
- #
255
- # @since 0.6.0
256
- # @api private
257
- class_attribute :singulars
258
- self.singulars = IrregularRules.new(
259
- # irregular
260
- "cacti" => "cactus",
261
- "children" => "child",
262
- "corpora" => "corpus",
263
- "feet" => "foot",
264
- "genera" => "genus",
265
- "geese" => "goose",
266
- "lice" => "louse",
267
- "men" => "man",
268
- "mice" => "mouse",
269
- "oxen" => "ox",
270
- "people" => "person",
271
- "quizzes" => "quiz",
272
- "sexes" => "sex",
273
- "testes" => "testis",
274
- "teeth" => "tooth",
275
- "women" => "woman",
276
- # uncountable
277
- "deer" => "deer",
278
- "equipment" => "equipment",
279
- "fish" => "fish",
280
- "information" => "information",
281
- "means" => "means",
282
- "money" => "money",
283
- "news" => "news",
284
- "offspring" => "offspring",
285
- "rice" => "rice",
286
- "series" => "series",
287
- "sheep" => "sheep",
288
- "species" => "species",
289
- "police" => "police",
290
- # fallback
291
- "areas" => "area",
292
- "hives" => "hive",
293
- "phases" => "phase",
294
- "exercises" => "exercise",
295
- "releases" => "release"
296
- )
297
-
298
- # Block for custom inflection rules.
299
- #
300
- # @param [Proc] blk custom inflections
301
- #
302
- # @since 0.6.0
303
- #
304
- # @see Hanami::Utils::Inflector.exception
305
- # @see Hanami::Utils::Inflector.uncountable
306
- #
307
- # @example
308
- # require 'hanami/utils/inflector'
309
- #
310
- # Hanami::Utils::Inflector.inflections do
311
- # exception 'analysis', 'analyses'
312
- # exception 'alga', 'algae'
313
- # uncountable 'music', 'butter'
314
- # end
315
- def self.inflections(&blk)
316
- class_eval(&blk)
317
- end
318
-
319
- # Adds a custom inflection exception
320
- #
321
- # @param [String] singular form
322
- # @param [String] plural form
323
- #
324
- # @since 0.6.0
325
- #
326
- # @see Hanami::Utils::Inflector.inflections
327
- # @see Hanami::Utils::Inflector.uncountable
328
- #
329
- # @example
330
- # require 'hanami/utils/inflector'
331
- #
332
- # Hanami::Utils::Inflector.inflections do
333
- # exception 'alga', 'algae'
334
- # end
335
- def self.exception(singular, plural)
336
- add_to_inflecto(singular, plural)
337
- singulars.add(plural, singular)
338
- plurals.add(singular, plural)
339
- end
340
-
341
- # Since ROM uses Inflecto for it inferences, we need to add an exception to it
342
- # when one is registered against our Inflector.
343
- # @api private
344
- def self.add_to_inflecto(singular, plural)
345
- return unless defined? Inflecto
346
-
347
- Inflecto.inflections.irregular(singular, plural)
348
- end
349
-
350
- # Adds an uncountable word
351
- #
352
- # @param [Array<String>] words
353
- #
354
- # @since 0.6.0
355
- #
356
- # @see Hanami::Utils::Inflector.inflections
357
- # @see Hanami::Utils::Inflector.exception
358
- #
359
- # @example
360
- # require 'hanami/utils/inflector'
361
- #
362
- # Hanami::Utils::Inflector.inflections do
363
- # uncountable 'music', 'art'
364
- # end
365
- def self.uncountable(*words)
366
- Array(words).each do |word|
367
- exception(word, word)
368
- end
369
- end
370
-
371
- # Pluralizes the given string
372
- #
373
- # @param string [String] a string to pluralize
374
- #
375
- # @return [String,NilClass] the pluralized string, if present
376
- #
377
- # @api private
378
- # @since 0.4.1
379
- #
380
- # rubocop:disable Metrics/AbcSize
381
- # rubocop:disable Metrics/CyclomaticComplexity
382
- # rubocop:disable Style/PerlBackrefs
383
- def self.pluralize(string)
384
- return string if string.nil? || string =~ Utils::Blank::STRING_MATCHER
385
-
386
- case string
387
- when plurals
388
- plurals.apply(string)
389
- when /\A((.*)[^aeiou])ch\z/
390
- $1 + CHES
391
- when /\A((.*)[^aeiou])y\z/
392
- $1 + IES
393
- when /\A(.*)(ex|ix)\z/
394
- $1 + ICES
395
- when /\A(.*)(eau|#{EAUX})\z/
396
- $1 + EAUX
397
- when /\A(.*)x\z/
398
- $1 + XES
399
- when /\A(.*)ma\z/
400
- string + TA
401
- when /\A(.*)(um|#{A})\z/
402
- $1 + A
403
- when /\A(buffal|domin|ech|embarg|her|mosquit|potat|tomat)#{O}\z/i
404
- $1 + OES
405
- when /\A(.*)(fee)\z/
406
- $1 + $2 + S
407
- when /\A(.*)(?:([^f]))f[e]*\z/
408
- $1 + $2 + VES
409
- when /\A(.*)us\z/
410
- $1 + USES
411
- when /\A(.*)non\z/
412
- $1 + NA
413
- when /\A((.*)[^aeiou])is\z/
414
- $1 + ES
415
- when /\A(.*)ss\z/
416
- $1 + SSES
417
- when /s\z/
418
- string
419
- else
420
- string + S
421
- end
422
- end
423
- # rubocop:enable Style/PerlBackrefs
424
- # rubocop:enable Metrics/AbcSize
425
- # rubocop:enable Metrics/CyclomaticComplexity
426
-
427
- # Singularizes the given string
428
- #
429
- # @param string [String] a string to singularize
430
- #
431
- # @return [String,NilClass] the singularized string, if present
432
- #
433
- # @api private
434
- # @since 0.4.1
435
- #
436
- # rubocop:disable Metrics/AbcSize
437
- # rubocop:disable Metrics/CyclomaticComplexity
438
- # rubocop:disable Metrics/PerceivedComplexity
439
- # rubocop:disable Style/PerlBackrefs
440
- def self.singularize(string)
441
- return string if string.nil? || string =~ Utils::Blank::STRING_MATCHER
442
-
443
- case string
444
- when singulars
445
- singulars.apply(string)
446
- when /\A.*[^aeiou]#{CHES}\z/
447
- string.sub(CHES, CH)
448
- when /\A.*[^aeiou]#{IES}\z/
449
- string.sub(IES, Y)
450
- when /\A.*#{EAUX}\z/
451
- string.chop
452
- when /\A(.*)#{IDES}\z/
453
- $1 + IS
454
- when /\A(.*)#{US}\z/
455
- $1 + I
456
- when /\A(.*)#{RSES}\z/
457
- $1 + RSE
458
- when /\A(.*)#{SES}\z/
459
- $1 + S
460
- when /\A(.*)#{MATA}\z/
461
- $1 + MA
462
- when /\A(.*)#{OES}\z/
463
- $1 + O
464
- when /\A(.*)#{MINA}\z/
465
- $1 + MEN
466
- when /\A(.*)#{XES}\z/
467
- $1 + X
468
- when /\A(.*)#{IVES}\z/
469
- $1 + IFE
470
- when /\A(.*)#{VES}\z/
471
- $1 + F
472
- when /\A(.*)#{I}\z/
473
- $1 + US
474
- when /\A(.*)ae\z/
475
- $1 + A
476
- when /\A(.*)na\z/
477
- $1 + NON
478
- when /\A(.*)#{A}\z/
479
- $1 + UM
480
- when /[^s]\z/
481
- string
482
- else
483
- string.chop
484
- end
485
- end
486
- # rubocop:enable Style/PerlBackrefs
487
- # rubocop:enable Metrics/AbcSize
488
- # rubocop:enable Metrics/CyclomaticComplexity
489
-
490
- # rubocop:enable Metrics/PerceivedComplexity
491
- end
492
- end
493
- end