hanami-utils 1.3.2 → 1.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Utils
3
5
  # Ordered file list, consistent across operating systems
4
6
  #
5
7
  # @since 0.9.0
6
8
  module FileList
7
- # Return an ordered list of files, consistent across operating systems
9
+ # Returns an ordered list of files, consistent across operating systems
8
10
  #
9
11
  # It has the same signature of <tt>Dir.glob</tt>, it just guarantees to
10
12
  # order the results before to return them.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pathname"
2
4
  require "fileutils"
3
5
  require "hanami/utils/deprecation"
@@ -163,6 +165,7 @@ module Hanami
163
165
  mkdir_p(path)
164
166
 
165
167
  content = ::File.readlines(path)
168
+ content << "\n" if _append_newline?(content)
166
169
  content << "#{contents}\n"
167
170
 
168
171
  write(path, content)
@@ -323,12 +326,12 @@ module Hanami
323
326
  #
324
327
  # # class App
325
328
  # # end
326
- def self.remove_block(path, target) # rubocop:disable Metrics/AbcSize
329
+ def self.remove_block(path, target)
327
330
  content = ::File.readlines(path)
328
331
  starting = index(content, path, target)
329
332
  line = content[starting]
330
333
  size = line[/\A[[:space:]]*/].bytesize
331
- closing = (" " * size) + (target =~ /{/ ? '}' : 'end')
334
+ closing = (" " * size) + (target =~ /{/ ? "}" : "end")
332
335
  ending = starting + index(content[starting..-1], path, closing)
333
336
 
334
337
  content.slice!(starting..ending)
@@ -451,6 +454,16 @@ module Hanami
451
454
  end
452
455
 
453
456
  private_class_method :line_number
457
+
458
+ # @since 1.3.6
459
+ # @api private
460
+ def self._append_newline?(content)
461
+ return false if content.empty?
462
+
463
+ !content.last.end_with?("\n")
464
+ end
465
+
466
+ private_class_method :_append_newline?
454
467
  end
455
468
  end
456
469
  end
@@ -1,12 +1,13 @@
1
- require 'hanami/utils/duplicable'
2
- require 'transproc'
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/utils/duplicable"
4
+ require "transproc"
3
5
 
4
6
  module Hanami
5
7
  module Utils
6
8
  # Hash on steroids
7
9
  # @since 0.1.0
8
10
  #
9
- # rubocop:disable ClassLength
10
11
  class Hash
11
12
  # @since 0.6.0
12
13
  # @api private
@@ -47,7 +48,7 @@ module Hanami
47
48
  self[:symbolize_keys].call(input)
48
49
  end
49
50
 
50
- # Deep symbolize the given hash
51
+ # Performs deep symbolize on the given hash
51
52
  #
52
53
  # @param input [::Hash] the input
53
54
  #
@@ -69,7 +70,7 @@ module Hanami
69
70
  self[:deep_symbolize_keys].call(input)
70
71
  end
71
72
 
72
- # Stringify the given hash
73
+ # Stringifies the given hash
73
74
  #
74
75
  # @param input [::Hash] the input
75
76
  #
@@ -89,7 +90,7 @@ module Hanami
89
90
  self[:stringify_keys].call(input)
90
91
  end
91
92
 
92
- # Deeply stringify the given hash
93
+ # Deeply stringifies the given hash
93
94
  #
94
95
  # @param input [::Hash] the input
95
96
  #
@@ -105,7 +106,7 @@ module Hanami
105
106
  #
106
107
  # hash.class
107
108
  # # => Hash
108
- def self.deep_stringify(input) # rubocop:disable Metrics/MethodLength
109
+ def self.deep_stringify(input)
109
110
  input.each_with_object({}) do |(key, value), output|
110
111
  output[key.to_s] =
111
112
  case value
@@ -121,15 +122,15 @@ module Hanami
121
122
  end
122
123
  end
123
124
 
124
- # Deep duplicate hash values
125
+ # Deep duplicates hash values
125
126
  #
126
- # The output of this function is a shallow duplicate of the input.
127
+ # The output of this function is a deep duplicate of the input.
127
128
  # Any further modification on the input, won't be reflected on the output
128
129
  # and viceversa.
129
130
  #
130
131
  # @param input [::Hash] the input
131
132
  #
132
- # @return [::Hash] the shallow duplicate of input
133
+ # @return [::Hash] the deep duplicate of input
133
134
  #
134
135
  # @since 1.0.1
135
136
  #
@@ -169,7 +170,7 @@ module Hanami
169
170
  end
170
171
  end
171
172
 
172
- # Deep serialize given object into a `Hash`
173
+ # Deep serializes given object into a `Hash`
173
174
  #
174
175
  # Please note that the returning `Hash` will use symbols as keys.
175
176
  #
@@ -193,7 +194,7 @@ module Hanami
193
194
  #
194
195
  # Hanami::Utils::Hash.deep_serialize(input)
195
196
  # # => {:foo=>"bar", :baz=>[{:hello=>"world"}]}
196
- def self.deep_serialize(input) # rubocop:disable Metrics/MethodLength
197
+ def self.deep_serialize(input)
197
198
  input.to_hash.each_with_object({}) do |(key, value), output|
198
199
  output[key.to_sym] =
199
200
  case value
@@ -239,7 +240,7 @@ module Hanami
239
240
  @hash.default_proc = blk if blk
240
241
  end
241
242
 
242
- # Convert in-place all the keys to Symbol instances.
243
+ # Converts in-place all the keys to Symbol instances.
243
244
  #
244
245
  # @return [Hash] self
245
246
  #
@@ -263,7 +264,7 @@ module Hanami
263
264
  self
264
265
  end
265
266
 
266
- # Convert in-place all the keys to Symbol instances, nested hashes are converted too.
267
+ # Converts in-place all the keys to Symbol instances, nested hashes are converted too.
267
268
  #
268
269
  # @return [Hash] self
269
270
  #
@@ -289,7 +290,7 @@ module Hanami
289
290
  self
290
291
  end
291
292
 
292
- # Convert in-place all the keys to Symbol instances, nested hashes are converted too.
293
+ # Converts in-place all the keys to Symbol instances, nested hashes are converted too.
293
294
  #
294
295
  # @return [Hash] self
295
296
  #
@@ -315,7 +316,7 @@ module Hanami
315
316
  self
316
317
  end
317
318
 
318
- # Return a deep copy of the current Hanami::Utils::Hash
319
+ # Returns a deep copy of the current Hanami::Utils::Hash
319
320
  #
320
321
  # @return [Hash] a deep duplicated self
321
322
  #
@@ -452,7 +453,7 @@ module Hanami
452
453
  end
453
454
  end
454
455
 
455
- alias to_hash to_h
456
+ alias_method :to_hash, :to_h
456
457
 
457
458
  # Converts into a nested array of [ key, value ] arrays.
458
459
  #
@@ -476,7 +477,7 @@ module Hanami
476
477
  @hash == other.to_h
477
478
  end
478
479
 
479
- alias eql? ==
480
+ alias_method :eql?, :==
480
481
 
481
482
  # Returns the hash of the internal @hash
482
483
  #
@@ -498,21 +499,23 @@ module Hanami
498
499
  @hash.inspect
499
500
  end
500
501
 
501
- # Override Ruby's method_missing in order to provide ::Hash interface
502
+ # Overrides Ruby's method_missing in order to provide ::Hash interface
502
503
  #
503
504
  # @api private
504
505
  # @since 0.3.0
505
506
  #
506
507
  # @raise [NoMethodError] If doesn't respond to the given method
507
508
  def method_missing(method_name, *args, &blk)
508
- raise NoMethodError.new(%(undefined method `#{method_name}' for #{@hash}:#{self.class})) unless respond_to?(method_name)
509
+ unless respond_to?(method_name)
510
+ raise NoMethodError.new(%(undefined method `#{method_name}' for #{@hash}:#{self.class}))
511
+ end
509
512
 
510
513
  h = @hash.__send__(method_name, *args, &blk)
511
514
  h = self.class.new(h) if h.is_a?(::Hash)
512
515
  h
513
516
  end
514
517
 
515
- # Override Ruby's respond_to_missing? in order to support ::Hash interface
518
+ # Overrides Ruby's respond_to_missing? in order to support ::Hash interface
516
519
  #
517
520
  # @api private
518
521
  # @since 0.3.0
@@ -520,6 +523,5 @@ module Hanami
520
523
  @hash.respond_to?(method_name, include_private)
521
524
  end
522
525
  end
523
- # rubocop:enable ClassLength
524
526
  end
525
527
  end
@@ -1,5 +1,7 @@
1
- require 'hanami/utils/class_attribute'
2
- require 'hanami/utils/blank'
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/utils/class_attribute"
4
+ require "hanami/utils/blank"
3
5
 
4
6
  module Hanami
5
7
  module Utils
@@ -27,163 +29,181 @@ module Hanami
27
29
  # @since 0.6.0
28
30
  # @api private
29
31
  def ===(other)
30
- key = other.downcase
32
+ key = extract_last_alphanumeric_token(other)
31
33
  @rules.key?(key) || @rules.value?(key)
32
34
  end
33
35
 
34
36
  # @since 0.6.0
35
37
  # @api private
36
38
  def apply(string)
37
- key = string.downcase
39
+ key = extract_last_alphanumeric_token(string)
38
40
  result = @rules[key] || @rules.rassoc(key).last
39
41
 
40
- string[0] + result[1..-1]
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
41
61
  end
42
62
  end
43
63
 
44
64
  # @since 0.4.1
45
65
  # @api private
46
- A = 'a'.freeze
66
+ A = "a"
47
67
 
48
68
  # @since 0.4.1
49
69
  # @api private
50
- CH = 'ch'.freeze
70
+ CH = "ch"
51
71
 
52
72
  # @since 0.4.1
53
73
  # @api private
54
- CHES = 'ches'.freeze
74
+ CHES = "ches"
55
75
 
56
76
  # @since 0.4.1
57
77
  # @api private
58
- EAUX = 'eaux'.freeze
78
+ EAUX = "eaux"
59
79
 
60
80
  # @since 0.6.0
61
81
  # @api private
62
- ES = 'es'.freeze
82
+ ES = "es"
63
83
 
64
84
  # @since 0.4.1
65
85
  # @api private
66
- F = 'f'.freeze
86
+ F = "f"
67
87
 
68
88
  # @since 0.4.1
69
89
  # @api private
70
- I = 'i'.freeze
90
+ I = "i"
71
91
 
72
92
  # @since 0.4.1
73
93
  # @api private
74
- ICE = 'ice'.freeze
94
+ ICE = "ice"
75
95
 
76
96
  # @since 0.4.1
77
97
  # @api private
78
- ICES = 'ices'.freeze
98
+ ICES = "ices"
79
99
 
80
100
  # @since 0.4.1
81
101
  # @api private
82
- IDES = 'ides'.freeze
102
+ IDES = "ides"
83
103
 
84
104
  # @since 0.4.1
85
105
  # @api private
86
- IES = 'ies'.freeze
106
+ IES = "ies"
87
107
 
88
108
  # @since 0.4.1
89
109
  # @api private
90
- IFE = 'ife'.freeze
110
+ IFE = "ife"
91
111
 
92
112
  # @since 0.4.1
93
113
  # @api private
94
- IS = 'is'.freeze
114
+ IS = "is"
95
115
 
96
116
  # @since 0.4.1
97
117
  # @api private
98
- IVES = 'ives'.freeze
118
+ IVES = "ives"
99
119
 
100
120
  # @since 0.4.1
101
121
  # @api private
102
- MA = 'ma'.freeze
122
+ MA = "ma"
103
123
 
104
124
  # @since 0.4.1
105
125
  # @api private
106
- MATA = 'mata'.freeze
126
+ MATA = "mata"
107
127
 
108
128
  # @since 0.4.1
109
129
  # @api private
110
- MEN = 'men'.freeze
130
+ MEN = "men"
111
131
 
112
132
  # @since 0.4.1
113
133
  # @api private
114
- MINA = 'mina'.freeze
134
+ MINA = "mina"
115
135
 
116
136
  # @since 0.6.0
117
137
  # @api private
118
- NA = 'na'.freeze
138
+ NA = "na"
119
139
 
120
140
  # @since 0.6.0
121
141
  # @api private
122
- NON = 'non'.freeze
142
+ NON = "non"
123
143
 
124
144
  # @since 0.4.1
125
145
  # @api private
126
- O = 'o'.freeze
146
+ O = "o"
127
147
 
128
148
  # @since 0.4.1
129
149
  # @api private
130
- OES = 'oes'.freeze
150
+ OES = "oes"
131
151
 
132
152
  # @since 0.4.1
133
153
  # @api private
134
- OUSE = 'ouse'.freeze
154
+ OUSE = "ouse"
135
155
 
136
156
  # @since 0.4.1
137
157
  # @api private
138
- RSE = 'rse'.freeze
158
+ RSE = "rse"
139
159
 
140
160
  # @since 0.4.1
141
161
  # @api private
142
- RSES = 'rses'.freeze
162
+ RSES = "rses"
143
163
 
144
164
  # @since 0.4.1
145
165
  # @api private
146
- S = 's'.freeze
166
+ S = "s"
147
167
 
148
168
  # @since 0.4.1
149
169
  # @api private
150
- SES = 'ses'.freeze
170
+ SES = "ses"
151
171
 
152
172
  # @since 0.4.1
153
173
  # @api private
154
- SSES = 'sses'.freeze
174
+ SSES = "sses"
155
175
 
156
176
  # @since 0.6.0
157
177
  # @api private
158
- TA = 'ta'.freeze
178
+ TA = "ta"
159
179
 
160
180
  # @since 0.4.1
161
181
  # @api private
162
- UM = 'um'.freeze
182
+ UM = "um"
163
183
 
164
184
  # @since 0.4.1
165
185
  # @api private
166
- US = 'us'.freeze
186
+ US = "us"
167
187
 
168
188
  # @since 0.4.1
169
189
  # @api private
170
- USES = 'uses'.freeze
190
+ USES = "uses"
171
191
 
172
192
  # @since 0.4.1
173
193
  # @api private
174
- VES = 'ves'.freeze
194
+ VES = "ves"
175
195
 
176
196
  # @since 0.4.1
177
197
  # @api private
178
- X = 'x'.freeze
198
+ X = "x"
179
199
 
180
200
  # @since 0.4.1
181
201
  # @api private
182
- XES = 'xes'.freeze
202
+ XES = "xes"
183
203
 
184
204
  # @since 0.4.1
185
205
  # @api private
186
- Y = 'y'.freeze
206
+ Y = "y"
187
207
 
188
208
  include Utils::ClassAttribute
189
209
 
@@ -194,40 +214,40 @@ module Hanami
194
214
  class_attribute :plurals
195
215
  self.plurals = IrregularRules.new(
196
216
  # irregular
197
- 'cactus' => 'cacti',
198
- 'child' => 'children',
199
- 'corpus' => 'corpora',
200
- 'foot' => 'feet',
201
- 'genus' => 'genera',
202
- 'goose' => 'geese',
203
- 'louse' => 'lice',
204
- 'man' => 'men',
205
- 'mouse' => 'mice',
206
- 'ox' => 'oxen',
207
- 'person' => 'people',
208
- 'quiz' => 'quizzes',
209
- 'sex' => 'sexes',
210
- 'testis' => 'testes',
211
- 'tooth' => 'teeth',
212
- 'woman' => 'women',
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",
213
233
  # uncountable
214
- 'deer' => 'deer',
215
- 'equipment' => 'equipment',
216
- 'fish' => 'fish',
217
- 'information' => 'information',
218
- 'means' => 'means',
219
- 'money' => 'money',
220
- 'news' => 'news',
221
- 'offspring' => 'offspring',
222
- 'rice' => 'rice',
223
- 'series' => 'series',
224
- 'sheep' => 'sheep',
225
- 'species' => 'species',
226
- 'police' => 'police',
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",
227
247
  # regressions
228
248
  # https://github.com/hanami/utils/issues/106
229
- 'album' => 'albums',
230
- 'area' => 'areas'
249
+ "album" => "albums",
250
+ "area" => "areas"
231
251
  )
232
252
 
233
253
  # Irregular rules for singulars
@@ -237,42 +257,42 @@ module Hanami
237
257
  class_attribute :singulars
238
258
  self.singulars = IrregularRules.new(
239
259
  # irregular
240
- 'cacti' => 'cactus',
241
- 'children' => 'child',
242
- 'corpora' => 'corpus',
243
- 'feet' => 'foot',
244
- 'genera' => 'genus',
245
- 'geese' => 'goose',
246
- 'lice' => 'louse',
247
- 'men' => 'man',
248
- 'mice' => 'mouse',
249
- 'oxen' => 'ox',
250
- 'people' => 'person',
251
- 'quizzes' => 'quiz',
252
- 'sexes' => 'sex',
253
- 'testes' => 'testis',
254
- 'teeth' => 'tooth',
255
- 'women' => 'woman',
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",
256
276
  # uncountable
257
- 'deer' => 'deer',
258
- 'equipment' => 'equipment',
259
- 'fish' => 'fish',
260
- 'information' => 'information',
261
- 'means' => 'means',
262
- 'money' => 'money',
263
- 'news' => 'news',
264
- 'offspring' => 'offspring',
265
- 'rice' => 'rice',
266
- 'series' => 'series',
267
- 'sheep' => 'sheep',
268
- 'species' => 'species',
269
- 'police' => 'police',
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",
270
290
  # fallback
271
- 'areas' => 'area',
272
- 'hives' => 'hive',
273
- 'phases' => 'phase',
274
- 'exercises' => 'exercise',
275
- 'releases' => 'release'
291
+ "areas" => "area",
292
+ "hives" => "hive",
293
+ "phases" => "phase",
294
+ "exercises" => "exercise",
295
+ "releases" => "release"
276
296
  )
277
297
 
278
298
  # Block for custom inflection rules.
@@ -296,7 +316,7 @@ module Hanami
296
316
  class_eval(&blk)
297
317
  end
298
318
 
299
- # Add a custom inflection exception
319
+ # Adds a custom inflection exception
300
320
  #
301
321
  # @param [String] singular form
302
322
  # @param [String] plural form
@@ -327,7 +347,7 @@ module Hanami
327
347
  Inflecto.inflections.irregular(singular, plural)
328
348
  end
329
349
 
330
- # Add an uncountable word
350
+ # Adds an uncountable word
331
351
  #
332
352
  # @param [Array<String>] words
333
353
  #
@@ -348,7 +368,7 @@ module Hanami
348
368
  end
349
369
  end
350
370
 
351
- # Pluralize the given string
371
+ # Pluralizes the given string
352
372
  #
353
373
  # @param string [String] a string to pluralize
354
374
  #
@@ -359,7 +379,6 @@ module Hanami
359
379
  #
360
380
  # rubocop:disable Metrics/AbcSize
361
381
  # rubocop:disable Metrics/CyclomaticComplexity
362
- # rubocop:disable Metrics/MethodLength
363
382
  # rubocop:disable Style/PerlBackrefs
364
383
  def self.pluralize(string)
365
384
  return string if string.nil? || string =~ Utils::Blank::STRING_MATCHER
@@ -373,15 +392,15 @@ module Hanami
373
392
  $1 + IES
374
393
  when /\A(.*)(ex|ix)\z/
375
394
  $1 + ICES
376
- when /\A(.*)(eau|#{ EAUX })\z/
395
+ when /\A(.*)(eau|#{EAUX})\z/
377
396
  $1 + EAUX
378
397
  when /\A(.*)x\z/
379
398
  $1 + XES
380
399
  when /\A(.*)ma\z/
381
400
  string + TA
382
- when /\A(.*)(um|#{ A })\z/
401
+ when /\A(.*)(um|#{A})\z/
383
402
  $1 + A
384
- when /\A(buffal|domin|ech|embarg|her|mosquit|potat|tomat)#{ O }\z/i
403
+ when /\A(buffal|domin|ech|embarg|her|mosquit|potat|tomat)#{O}\z/i
385
404
  $1 + OES
386
405
  when /\A(.*)(fee)\z/
387
406
  $1 + $2 + S
@@ -404,9 +423,8 @@ module Hanami
404
423
  # rubocop:enable Style/PerlBackrefs
405
424
  # rubocop:enable Metrics/AbcSize
406
425
  # rubocop:enable Metrics/CyclomaticComplexity
407
- # rubocop:enable Metrics/MethodLength
408
426
 
409
- # Singularize the given string
427
+ # Singularizes the given string
410
428
  #
411
429
  # @param string [String] a string to singularize
412
430
  #
@@ -417,7 +435,6 @@ module Hanami
417
435
  #
418
436
  # rubocop:disable Metrics/AbcSize
419
437
  # rubocop:disable Metrics/CyclomaticComplexity
420
- # rubocop:disable Metrics/MethodLength
421
438
  # rubocop:disable Metrics/PerceivedComplexity
422
439
  # rubocop:disable Style/PerlBackrefs
423
440
  def self.singularize(string)
@@ -469,7 +486,7 @@ module Hanami
469
486
  # rubocop:enable Style/PerlBackrefs
470
487
  # rubocop:enable Metrics/AbcSize
471
488
  # rubocop:enable Metrics/CyclomaticComplexity
472
- # rubocop:enable Metrics/MethodLength
489
+
473
490
  # rubocop:enable Metrics/PerceivedComplexity
474
491
  end
475
492
  end