hanami-utils 1.3.2 → 1.3.7

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.
@@ -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