lotus-utils 0.4.0 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 64d787540b5ba2d1447be4ca787761da010c880b
4
- data.tar.gz: a8346f11b65e9500e7a260b53d077bf344e2c00b
3
+ metadata.gz: 3582ab69182aac292556f21c4a1021c09a9a4d50
4
+ data.tar.gz: 0f0e3a5561dee1797652203eb4fd6bdf75d01189
5
5
  SHA512:
6
- metadata.gz: b41336646647d1afd5280133b27fab60b88c267693aaef772ad43cc8fb460366be9ee80e04b16ff636a0b92382cb06287df8b2472815a87a3a6ed1d74731f1de
7
- data.tar.gz: d7da2e60819e1c78de89b3b880ad7793475224b6647e5420d0446856aecff7dcdfa55fb621fc66ec1e1b0db16538d8052f8c9aef69336e98b66eca8482173e62
6
+ metadata.gz: efcbf3a494ad1c10a1fd9f76dfbccc181af68eb001035633c603cf19bc01e4f66832c97169269b7af35f276cec245bc375a01166cdfd94dd6225a5f186855a89
7
+ data.tar.gz: 7f6ec20ba5908141c698eb3d1893b0e894621ee8c4e21f1a01e1bc22206da2eaa78f3bf86a8059ae9e81e84916bebd573ee1df63cce2496a9b4077ee9e603f20
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Lotus::Utils
2
2
  Ruby core extentions and class utilities for Lotus
3
3
 
4
+ ## v0.4.1 - 2015-05-15
5
+ ### Added
6
+ - [Luca Guidi & Alfonso Uceda Pompa] Introduced `Lotus::Utils::Inflector`, `Lotus::Utils::String#pluralize` and `#singularize`
7
+
8
+ ### Fixed
9
+ - [Luca Guidi] Ensure `Lotus::Utils::Attributes#to_h` to safely return nested `::Hash` instances for complex data structures.
10
+ - [Luca Guidi] Let `Lotus::Interactor#error` to return a falsey value for control flow. (eg. `check_permissions or error "You can't access"`)
11
+
4
12
  ## v0.4.0 - 2015-03-23
5
13
  ### Added
6
14
  - [Luca Guidi] Introduced `Lotus::Utils::Escape`. It implements OWASP/ESAPI suggestions for HTML, HTML attribute and URL escape utilities.
@@ -176,6 +176,8 @@ module Lotus
176
176
  # require 'lotus/interactor'
177
177
  #
178
178
  # class Signup
179
+ # include Lotus::Interactor
180
+ #
179
181
  # def initialize(params)
180
182
  # @params = params
181
183
  # @user = User.new(@params)
@@ -198,6 +200,8 @@ module Lotus
198
200
  # require 'lotus/interactor'
199
201
  #
200
202
  # class Signup
203
+ # include Lotus::Interactor
204
+ #
201
205
  # def initialize(params)
202
206
  # @params = params
203
207
  # @user = User.new(@params)
@@ -293,6 +297,8 @@ module Lotus
293
297
  #
294
298
  # @param message [String] the error message
295
299
  #
300
+ # @return false
301
+ #
296
302
  # @since 0.3.5
297
303
  #
298
304
  # @see Lotus::Interactor#error!
@@ -336,6 +342,7 @@ module Lotus
336
342
  # result.logger # => [:prepare_data!, :persist!, :sync!]
337
343
  def error(message)
338
344
  @_errors << message
345
+ false
339
346
  end
340
347
 
341
348
  # Log an error AND interrupting the flow.
@@ -110,7 +110,24 @@ module Lotus
110
110
  #
111
111
  # @see Lotus::Utils::Hash
112
112
  def to_h
113
- @attributes.deep_dup
113
+ Utils::Hash.new.tap do |result|
114
+ @attributes.each do |k, v|
115
+ result[k] = _read_value(v)
116
+ end
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ # @since 0.4.1
123
+ # @api private
124
+ def _read_value(value)
125
+ case val = value
126
+ when ::Hash, ::Lotus::Utils::Hash, ->(v) { v.respond_to?(:lotus_nested_attributes?) }
127
+ val.to_h
128
+ else
129
+ val
130
+ end
114
131
  end
115
132
  end
116
133
  end
@@ -0,0 +1,586 @@
1
+ module Lotus
2
+ module Utils
3
+ # String inflector
4
+ #
5
+ # @since 0.4.1
6
+ # @api private
7
+ module Inflector
8
+ # Rule for irregular plural
9
+ #
10
+ # @since 0.4.1
11
+ # @api private
12
+ class IrregularRule
13
+ # @since 0.4.1
14
+ # @api private
15
+ def initialize(rules)
16
+ @rules = rules
17
+ @rules.freeze
18
+ end
19
+
20
+ # @since 0.4.1
21
+ # @api private
22
+ def ===(other)
23
+ key = other.downcase
24
+ @rules.key?(key) || @rules.value?(key)
25
+ end
26
+
27
+ # @since 0.4.1
28
+ # @api private
29
+ def apply(string)
30
+ key = string.downcase
31
+ result = @rules[key] || @rules.rassoc(key).last
32
+
33
+ string[0] + result[1..-1]
34
+ end
35
+ end
36
+
37
+ # Rule for irregular plural, that uses a suffix.
38
+ #
39
+ # @since 0.4.1
40
+ # @api private
41
+ class SuffixRule < IrregularRule
42
+ def initialize(matcher, replacement, rules)
43
+ super(rules)
44
+ @matcher = matcher
45
+ @replacement = replacement
46
+ end
47
+
48
+ # @since 0.4.1
49
+ # @api private
50
+ def ===(other)
51
+ @rules.key?(other.downcase)
52
+ end
53
+
54
+ # @since 0.4.1
55
+ # @api private
56
+ def apply(string)
57
+ string.sub(@matcher, @replacement)
58
+ end
59
+ end
60
+
61
+ # Matcher for blank strings
62
+ #
63
+ # @since 0.4.1
64
+ # @api private
65
+ BLANK_STRING_MATCHER = /\A[[:space:]]*\z/.freeze
66
+
67
+ # @since 0.4.1
68
+ # @api private
69
+ A = 'a'.freeze
70
+
71
+ # @since 0.4.1
72
+ # @api private
73
+ CH = 'ch'.freeze
74
+
75
+ # @since 0.4.1
76
+ # @api private
77
+ CHES = 'ches'.freeze
78
+
79
+ # @since 0.4.1
80
+ # @api private
81
+ EAUX = 'eaux'.freeze
82
+
83
+ # @since 0.4.1
84
+ # @api private
85
+ F = 'f'.freeze
86
+
87
+ # @since 0.4.1
88
+ # @api private
89
+ I = 'i'.freeze
90
+
91
+ # @since 0.4.1
92
+ # @api private
93
+ ICE = 'ice'.freeze
94
+
95
+ # @since 0.4.1
96
+ # @api private
97
+ ICES = 'ices'.freeze
98
+
99
+ # @since 0.4.1
100
+ # @api private
101
+ IDES = 'ides'.freeze
102
+
103
+ # @since 0.4.1
104
+ # @api private
105
+ IES = 'ies'.freeze
106
+
107
+ # @since 0.4.1
108
+ # @api private
109
+ IFE = 'ife'.freeze
110
+
111
+ # @since 0.4.1
112
+ # @api private
113
+ INA = 'ina'.freeze
114
+
115
+ # @since 0.4.1
116
+ # @api private
117
+ IS = 'is'.freeze
118
+
119
+ # @since 0.4.1
120
+ # @api private
121
+ IVES = 'ives'.freeze
122
+
123
+ # @since 0.4.1
124
+ # @api private
125
+ MA = 'ma'.freeze
126
+
127
+ # @since 0.4.1
128
+ # @api private
129
+ MATA = 'mata'.freeze
130
+
131
+ # @since 0.4.1
132
+ # @api private
133
+ MEN = 'men'.freeze
134
+
135
+ # @since 0.4.1
136
+ # @api private
137
+ MINA = 'mina'.freeze
138
+
139
+ # @since 0.4.1
140
+ # @api private
141
+ O = 'o'.freeze
142
+
143
+ # @since 0.4.1
144
+ # @api private
145
+ OES = 'oes'.freeze
146
+
147
+ # @since 0.4.1
148
+ # @api private
149
+ OUSE = 'ouse'.freeze
150
+
151
+ # @since 0.4.1
152
+ # @api private
153
+ S = 's'.freeze
154
+
155
+ # @since 0.4.1
156
+ # @api private
157
+ SES = 'ses'.freeze
158
+
159
+ # @since 0.4.1
160
+ # @api private
161
+ SSES = 'sses'.freeze
162
+
163
+ # @since 0.4.1
164
+ # @api private
165
+ UM = 'um'.freeze
166
+
167
+ # @since 0.4.1
168
+ # @api private
169
+ US = 'us'.freeze
170
+
171
+ # @since 0.4.1
172
+ # @api private
173
+ USES = 'uses'.freeze
174
+
175
+ # @since 0.4.1
176
+ # @api private
177
+ VES = 'ves'.freeze
178
+
179
+ # @since 0.4.1
180
+ # @api private
181
+ X = 'x'.freeze
182
+
183
+ # @since 0.4.1
184
+ # @api private
185
+ XES = 'xes'.freeze
186
+
187
+ # @since 0.4.1
188
+ # @api private
189
+ Y = 'y'.freeze
190
+
191
+ # Plural rule "is" => "es"
192
+ #
193
+ # @since 0.4.1
194
+ # @api private
195
+ PLURAL_IS_ES = SuffixRule.new( /is\z/, 'es', {
196
+ 'analysis' => true,
197
+ 'axis' => true,
198
+ 'basis' => true,
199
+ 'crisis' => true,
200
+ 'diagnosis' => true,
201
+ 'ellipsis' => true,
202
+ 'hypothesis' => true,
203
+ 'oasis' => true,
204
+ 'paralysis' => true,
205
+ 'parenthesis' => true,
206
+ 'synopsis' => true,
207
+ 'synthesis' => true,
208
+ 'thesis' => true,
209
+ })
210
+
211
+ # Plural rule "is" => "ides"
212
+ #
213
+ # @since 0.4.1
214
+ # @api private
215
+ PLURAL_IS_IDES = SuffixRule.new( /is\z/, 'ides', {
216
+ 'clitoris' => true,
217
+ 'iris' => true,
218
+ })
219
+
220
+ # Plural rule "f" => "s"
221
+ #
222
+ # @since 0.4.1
223
+ # @api private
224
+ PLURAL_F_S = SuffixRule.new( /\z/, 's', {
225
+ 'chief' => true,
226
+ 'spoof' => true,
227
+ })
228
+
229
+ # Plural rule "o" => "oes"
230
+ #
231
+ # @since 0.4.1
232
+ # @api private
233
+ PLURAL_O_OES = SuffixRule.new( /\z/, 'es', {
234
+ 'buffalo' => true,
235
+ 'domino' => true,
236
+ 'echo' => true,
237
+ 'embargo' => true,
238
+ 'hero' => true,
239
+ 'mosquito' => true,
240
+ 'potato' => true,
241
+ 'tomato' => true,
242
+ 'torpedo' => true,
243
+ 'veto' => true,
244
+ })
245
+
246
+ # Irregular rules
247
+ #
248
+ # @since 0.4.1
249
+ # @api private
250
+ PLURAL_IRREGULAR = IrregularRule.new({
251
+ # irregular
252
+ 'cactus' => 'cacti',
253
+ 'child' => 'children',
254
+ 'corpus' => 'corpora',
255
+ 'foot' => 'feet',
256
+ 'genus' => 'genera',
257
+ 'goose' => 'geese',
258
+ 'man' => 'men',
259
+ 'ox' => 'oxen',
260
+ 'person' => 'people',
261
+ 'quiz' => 'quizzes',
262
+ 'sex' => 'sexes',
263
+ 'testis' => 'testes',
264
+ 'tooth' => 'teeth',
265
+ 'woman' => 'women',
266
+ # uncountable
267
+ 'deer' => 'deer',
268
+ 'equipment' => 'equipment',
269
+ 'fish' => 'fish',
270
+ 'information' => 'information',
271
+ 'means' => 'means',
272
+ 'money' => 'money',
273
+ 'news' => 'news',
274
+ 'offspring' => 'offspring',
275
+ 'rice' => 'rice',
276
+ 'series' => 'series',
277
+ 'sheep' => 'sheep',
278
+ 'species' => 'species',
279
+ # a => ae
280
+ 'alumna' => 'alumnae',
281
+ 'alga' => 'algae',
282
+ 'vertebra' => 'vertebrae',
283
+ 'persona' => 'personae',
284
+ 'antenna' => 'antennae',
285
+ 'formula' => 'formulae',
286
+ 'nebula' => 'nebulae',
287
+ 'vita' => 'vitae',
288
+ # on => a
289
+ 'criterion' => 'criteria',
290
+ 'perihelion' => 'perihelia',
291
+ 'aphelion' => 'aphelia',
292
+ 'phenomenon' => 'phenomena',
293
+ 'prolegomenon' => 'prolegomena',
294
+ 'noumenon' => 'noumena',
295
+ 'organon' => 'organa',
296
+ 'asyndeton' => 'asyndeta',
297
+ 'hyperbaton' => 'hyperbata',
298
+ # us => i
299
+ 'alumnus' => 'alumni',
300
+ 'alveolus' => 'alveoli',
301
+ 'bacillus' => 'bacilli',
302
+ 'bronchus' => 'bronchi',
303
+ 'locus' => 'loci',
304
+ 'nucleus' => 'nuclei',
305
+ 'stimulus' => 'stimuli',
306
+ 'meniscus' => 'menisci',
307
+ 'thesaurus' => 'thesauri',
308
+ # a => ata
309
+ 'anathema' => 'anathemata',
310
+ 'enema' => 'enemata',
311
+ 'oedema' => 'oedemata',
312
+ 'bema' => 'bemata',
313
+ 'enigma' => 'enigmata',
314
+ 'sarcoma' => 'sarcomata',
315
+ 'carcinoma' => 'carcinomata',
316
+ 'gumma' => 'gummata',
317
+ 'schema' => 'schemata',
318
+ 'charisma' => 'charismata',
319
+ 'lemma' => 'lemmata',
320
+ 'soma' => 'somata',
321
+ 'diploma' => 'diplomata',
322
+ 'lymphoma' => 'lymphomata',
323
+ 'stigma' => 'stigmata',
324
+ 'dogma' => 'dogmata',
325
+ 'magma' => 'magmata',
326
+ 'stoma' => 'stomata',
327
+ 'drama' => 'dramata',
328
+ 'melisma' => 'melismata',
329
+ 'trauma' => 'traumata',
330
+ 'edema' => 'edemata',
331
+ 'miasma' => 'miasmata',
332
+ # s => es
333
+ 'acropolis' => 'acropolises',
334
+ 'chaos' => 'chaoses',
335
+ 'lens' => 'lenses',
336
+ 'aegis' => 'aegises',
337
+ 'cosmos' => 'cosmoses',
338
+ 'mantis' => 'mantises',
339
+ 'alias' => 'aliases',
340
+ 'dais' => 'daises',
341
+ 'marquis' => 'marquises',
342
+ 'asbestos' => 'asbestoses',
343
+ 'digitalis' => 'digitalises',
344
+ 'metropolis' => 'metropolises',
345
+ 'atlas' => 'atlases',
346
+ 'epidermis' => 'epidermises',
347
+ 'pathos' => 'pathoses',
348
+ 'bathos' => 'bathoses',
349
+ 'ethos' => 'ethoses',
350
+ 'pelvis' => 'pelvises',
351
+ 'bias' => 'biases',
352
+ 'gas' => 'gases',
353
+ 'polis' => 'polises',
354
+ 'caddis' => 'caddises',
355
+ 'rhinoceros' => 'rhinoceroses',
356
+ 'cannabis' => 'cannabises',
357
+ 'glottis' => 'glottises',
358
+ 'sassafras' => 'sassafrases',
359
+ 'canvas' => 'canvases',
360
+ 'ibis' => 'ibises',
361
+ 'trellis' => 'trellises',
362
+ })
363
+
364
+ # Irregular rules
365
+ #
366
+ # @since 0.4.1
367
+ # @api private
368
+ SINGULAR_IRREGULAR = IrregularRule.new({
369
+ # irregular
370
+ 'cacti' => 'cactus',
371
+ 'children'=> 'child',
372
+ 'corpora' => 'corpus',
373
+ 'feet' => 'foot',
374
+ 'genera' => 'genus',
375
+ 'geese' => 'goose',
376
+ 'men' => 'man',
377
+ 'oxen' => 'ox',
378
+ 'people' => 'person',
379
+ 'quizzes' => 'quiz',
380
+ 'sexes' => 'sex',
381
+ 'testes' => 'testis',
382
+ 'teeth' => 'tooth',
383
+ 'women' => 'woman',
384
+ # uncountable
385
+ 'deer' => 'deer',
386
+ 'equipment' => 'equipment',
387
+ 'fish' => 'fish',
388
+ 'information' => 'information',
389
+ 'means' => 'means',
390
+ 'money' => 'money',
391
+ 'news' => 'news',
392
+ 'offspring' => 'offspring',
393
+ 'rice' => 'rice',
394
+ 'series' => 'series',
395
+ 'sheep' => 'sheep',
396
+ 'species' => 'species',
397
+ 'police' => 'police',
398
+ # ae => a
399
+ 'alumnae' => 'alumna',
400
+ 'algae' => 'alga',
401
+ 'vertebrae' => 'vertebra',
402
+ 'personae' => 'persona',
403
+ 'antennae' => 'antenna',
404
+ 'formulae' => 'formula',
405
+ 'nebulae' => 'nebula',
406
+ 'vitae' => 'vita',
407
+ # a = on
408
+ 'criteria' => 'criterion',
409
+ 'perihelia' => 'perihelion',
410
+ 'aphelia' => 'aphelion',
411
+ 'phenomena' => 'phenomenon',
412
+ 'prolegomena' => 'prolegomenon',
413
+ 'noumena' => 'noumenon',
414
+ 'organa' => 'organon',
415
+ 'asyndeta' => 'asyndeton',
416
+ 'hyperbata' => 'hyperbaton',
417
+ # ses => s
418
+ 'acropolises' => 'acropolis',
419
+ 'chaoses' => 'chaos',
420
+ 'lenses' => 'lens',
421
+ 'aegises' => 'aegis',
422
+ 'cosmoses' => 'cosmos',
423
+ 'mantises' => 'mantis',
424
+ 'aliases' => 'alias',
425
+ 'daises' => 'dais',
426
+ 'marquises' => 'marquis',
427
+ 'asbestoses' => 'asbestos',
428
+ 'digitalises' => 'digitalis',
429
+ 'metropolises' => 'metropolis',
430
+ 'atlases' => 'atlas',
431
+ 'epidermises' => 'epidermis',
432
+ 'pathoses' => 'pathos',
433
+ 'bathoses' => 'bathos',
434
+ 'ethoses' => 'ethos',
435
+ 'pelvises' => 'pelvis',
436
+ 'biases' => 'bias',
437
+ 'gases' => 'gas',
438
+ 'polises' => 'polis',
439
+ 'caddises' => 'caddis',
440
+ 'rhinoceroses' => 'rhinoceros',
441
+ 'cannabises' => 'cannabis',
442
+ 'glottises' => 'glottis',
443
+ 'sassafrases' => 'sassafras',
444
+ 'canvases' => 'canvas',
445
+ 'ibises' => 'ibis',
446
+ 'trellises' => 'trellis',
447
+ # fallback
448
+ 'hives' => 'hive',
449
+ # ices => ex
450
+ "codices" => "codex",
451
+ "murices" => "murex",
452
+ "silices" => "silex",
453
+ "apices" => "apex",
454
+ "latices" => "latex",
455
+ "vertices" => "vertex",
456
+ "cortices" => "cortex",
457
+ "pontifices" => "pontifex",
458
+ "vortices" => "vortex",
459
+ "indices" => "index",
460
+ "simplices" => "simplex",
461
+ # ices => ix
462
+ "radices" => "radix",
463
+ "helices" => "helix",
464
+ "appendices" => "appendix",
465
+ # es => is
466
+ "axes" => "axis",
467
+ "analyses" => "analysis",
468
+ "bases" => "basis",
469
+ "crises" => "crisis",
470
+ "diagnoses" => "diagnosis",
471
+ "ellipses" => "ellipsis",
472
+ "hypotheses" => "hypothesis",
473
+ "oases" => "oasis",
474
+ "paralyses" => "paralysis",
475
+ "parentheses" => "parenthesis",
476
+ "syntheses" => "synthesis",
477
+ "synopses" => "synopsis",
478
+ "theses" => "thesis",
479
+ })
480
+
481
+ # Pluralize the given string
482
+ #
483
+ # @param string [String] a string to pluralize
484
+ #
485
+ # @return [String,NilClass] the pluralized string, if present
486
+ #
487
+ # @api private
488
+ # @since 0.4.1
489
+ def self.pluralize(string)
490
+ return string if string.nil? || string.match(BLANK_STRING_MATCHER)
491
+
492
+ case string
493
+ when PLURAL_IRREGULAR
494
+ PLURAL_IRREGULAR.apply(string)
495
+ when /\A((.*)[^aeiou])ch\z/
496
+ $1 + CHES
497
+ when /\A((.*)[^aeiou])y\z/
498
+ $1 + IES
499
+ when /\A(.*)(ex|ix)\z/
500
+ $1 + ICES
501
+ when /\A(.*)(eau|#{ EAUX })\z/
502
+ $1 + EAUX
503
+ when /\A(.*)x\z/
504
+ $1 + XES
505
+ when /\A(.*)(um|#{ A })\z/
506
+ $1 + A
507
+ when /\A(.*)(ouse|#{ ICE })\z/
508
+ $1 + ICE
509
+ when PLURAL_O_OES
510
+ PLURAL_O_OES.apply(string)
511
+ when /\A(.*)(en|#{ INA })\z/
512
+ $1 + INA
513
+ when PLURAL_F_S
514
+ PLURAL_F_S.apply(string)
515
+ when /\A(.*)(?:([^f]))f[e]*\z/
516
+ $1 + $2 + VES
517
+ when /\A(.*)us\z/
518
+ $1 + USES
519
+ when PLURAL_IS_ES
520
+ PLURAL_IS_ES.apply(string)
521
+ when PLURAL_IS_IDES
522
+ PLURAL_IS_IDES.apply(string)
523
+ when /\A(.*)ss\z/
524
+ $1 + SSES
525
+ when /s\z/
526
+ string
527
+ else
528
+ string + S
529
+ end
530
+ end
531
+
532
+ # Singularize the given string
533
+ #
534
+ # @param string [String] a string to singularize
535
+ #
536
+ # @return [String,NilClass] the singularized string, if present
537
+ #
538
+ # @api private
539
+ # @since 0.4.1
540
+ def self.singularize(string)
541
+ return string if string.nil? || string.match(BLANK_STRING_MATCHER)
542
+
543
+ case string
544
+ when SINGULAR_IRREGULAR
545
+ SINGULAR_IRREGULAR.apply(string)
546
+ when /\A.*[^aeiou]#{CHES}\z/
547
+ string.sub(CHES, CH)
548
+ when /\A.*[^aeiou]#{IES}\z/
549
+ string.sub(IES, Y)
550
+ when /\A(.*)#{ICE}\z/
551
+ $1 + OUSE
552
+ when /\A.*#{EAUX}\z/
553
+ string.chop
554
+ when /\A(.*)#{IDES}\z/
555
+ $1 + IS
556
+ when /\A(.*)#{US}\z/
557
+ $1 + I
558
+ when /\A(.*)#{SES}\z/
559
+ $1 + S
560
+ when /\A(.*)#{OUSE}\z/
561
+ $1 + ICE
562
+ when /\A(.*)#{MATA}\z/
563
+ $1 + MA
564
+ when /\A(.*)#{OES}\z/
565
+ $1 + O
566
+ when /\A(.*)#{MINA}\z/
567
+ $1 + MEN
568
+ when /\A(.*)#{XES}\z/
569
+ $1 + X
570
+ when /\A(.*)#{IVES}\z/
571
+ $1 + IFE
572
+ when /\A(.*)#{VES}\z/
573
+ $1 + F
574
+ when /\A(.*)#{I}\z/
575
+ $1 + US
576
+ when /\A(.*)#{A}\z/
577
+ $1 + UM
578
+ when /[^s]\z/
579
+ string
580
+ else
581
+ string.chop
582
+ end
583
+ end
584
+ end
585
+ end
586
+ end
@@ -1,3 +1,5 @@
1
+ require 'lotus/utils/inflector'
2
+
1
3
  module Lotus
2
4
  module Utils
3
5
  # String on steroids
@@ -220,6 +222,30 @@ module Lotus
220
222
  nil
221
223
  end
222
224
 
225
+ # Return a pluralized version of self.
226
+ #
227
+ # @return [Lotus::Utils::String] the pluralized string.
228
+ #
229
+ # @api private
230
+ # @since 0.4.1
231
+ #
232
+ # @see Lotus::Utils::Inflector
233
+ def pluralize
234
+ self.class.new Inflector.pluralize(self)
235
+ end
236
+
237
+ # Return a singularized version of self.
238
+ #
239
+ # @return [Lotus::Utils::String] the singularized string.
240
+ #
241
+ # @api private
242
+ # @since 0.4.1
243
+ #
244
+ # @see Lotus::Utils::Inflector
245
+ def singularize
246
+ self.class.new Inflector.singularize(self)
247
+ end
248
+
223
249
  # Returns the hash of the internal string
224
250
  #
225
251
  # @return [Fixnum]
@@ -3,6 +3,6 @@ module Lotus
3
3
  # Defines the version
4
4
  #
5
5
  # @since 0.1.0
6
- VERSION = '0.4.0'.freeze
6
+ VERSION = '0.4.1'.freeze
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lotus-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-23 00:00:00.000000000 Z
12
+ date: 2015-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -74,6 +74,7 @@ files:
74
74
  - lib/lotus/utils/deprecation.rb
75
75
  - lib/lotus/utils/escape.rb
76
76
  - lib/lotus/utils/hash.rb
77
+ - lib/lotus/utils/inflector.rb
77
78
  - lib/lotus/utils/io.rb
78
79
  - lib/lotus/utils/kernel.rb
79
80
  - lib/lotus/utils/load_paths.rb