hanami-utils 1.3.5 → 2.0.0.alpha2

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.
@@ -12,8 +14,28 @@ module Hanami
12
14
  # @since 0.9.0
13
15
  #
14
16
  # @see https://ruby-doc.org/core/Dir.html#method-c-glob
17
+ #
18
+ # @example simple usage
19
+ # require "hanami/utils/file_list"
20
+ #
21
+ # Hanami::Utils::FileList["spec/support/fixtures/file_list/*.rb"]
22
+ # # => [
23
+ # "spec/support/fixtures/file_list/a.rb",
24
+ # "spec/support/fixtures/file_list/aa.rb",
25
+ # "spec/support/fixtures/file_list/ab.rb"
26
+ # ]
27
+ #
28
+ # @example token usage
29
+ # require "hanami/utils/file_list"
30
+ #
31
+ # Hanami::Utils::FileList["spec", "support", "fixtures", "file_list", "*.rb"]
32
+ # # => [
33
+ # "spec/support/fixtures/file_list/a.rb",
34
+ # "spec/support/fixtures/file_list/aa.rb",
35
+ # "spec/support/fixtures/file_list/ab.rb"
36
+ # ]
15
37
  def self.[](*args)
16
- Dir.glob(*args).sort!
38
+ Dir.glob(::File.join(*args)).sort!
17
39
  end
18
40
  end
19
41
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pathname"
2
4
  require "fileutils"
3
5
  require "hanami/utils/deprecation"
@@ -32,24 +34,6 @@ module Hanami
32
34
  open(path, ::File::CREAT | ::File::WRONLY | ::File::TRUNC, *content) # rubocop:disable Security/Open - this isn't a call to `::Kernel.open`, but to `self.open`
33
35
  end
34
36
 
35
- # Rewrites the contents of an existing file.
36
- # If the path already exists, it replaces the contents.
37
- #
38
- # @param path [String,Pathname] the path to file
39
- # @param content [String, Array<String>] the content to write
40
- #
41
- # @raise [Errno::ENOENT] if the path doesn't exist
42
- #
43
- # @since 1.1.0
44
- def self.rewrite(path, *content)
45
- Hanami::Utils::Deprecation.new(
46
- "`.rewrite' is deprecated, please use `.write'"
47
- )
48
- raise Errno::ENOENT unless File.exist?(path)
49
-
50
- write(path, *content)
51
- end
52
-
53
37
  # Copies source into destination.
54
38
  # All the intermediate directories are created.
55
39
  # If the destination already exists, it overrides the contents.
@@ -163,7 +147,7 @@ module Hanami
163
147
  mkdir_p(path)
164
148
 
165
149
  content = ::File.readlines(path)
166
- content << "\n" unless content.last.end_with?("\n")
150
+ content << "\n" if _append_newline?(content)
167
151
  content << "#{contents}\n"
168
152
 
169
153
  write(path, content)
@@ -324,13 +308,13 @@ module Hanami
324
308
  #
325
309
  # # class App
326
310
  # # end
327
- def self.remove_block(path, target) # rubocop:disable Metrics/AbcSize
311
+ def self.remove_block(path, target)
328
312
  content = ::File.readlines(path)
329
313
  starting = index(content, path, target)
330
314
  line = content[starting]
331
315
  size = line[/\A[[:space:]]*/].bytesize
332
- closing = (" " * size) + (target =~ /{/ ? '}' : 'end')
333
- ending = starting + index(content[starting..-1], path, closing)
316
+ closing = (" " * size) + (/{/.match?(target) ? "}" : "end")
317
+ ending = starting + index(content[starting..], path, closing)
334
318
 
335
319
  content.slice!(starting..ending)
336
320
  write(path, content)
@@ -452,6 +436,16 @@ module Hanami
452
436
  end
453
437
 
454
438
  private_class_method :line_number
439
+
440
+ # @since 1.3.6
441
+ # @api private
442
+ def self._append_newline?(content)
443
+ return false if content.empty?
444
+
445
+ !content.last.end_with?("\n")
446
+ end
447
+
448
+ private_class_method :_append_newline?
455
449
  end
456
450
  end
457
451
  end
@@ -1,29 +1,14 @@
1
- require 'hanami/utils/duplicable'
2
- require 'transproc'
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-transformer"
3
4
 
4
5
  module Hanami
5
6
  module Utils
6
- # Hash on steroids
7
+ # Hash transformations
7
8
  # @since 0.1.0
8
- #
9
- # rubocop:disable Metrics/ClassLength
10
- class Hash
11
- # @since 0.6.0
12
- # @api private
13
- #
14
- # @see Hanami::Utils::Hash#deep_dup
15
- # @see Hanami::Utils::Duplicable
16
- DUPLICATE_LOGIC = proc do |value|
17
- case value
18
- when Hash
19
- value.deep_dup
20
- when ::Hash
21
- Hash.new(value).deep_dup.to_h
22
- end
23
- end.freeze
24
-
25
- extend Transproc::Registry
26
- import Transproc::HashTransformations
9
+ module Hash
10
+ extend Dry::Transformer::Registry
11
+ import Dry::Transformer::HashTransformations
27
12
 
28
13
  # Symbolize the given hash
29
14
  #
@@ -47,7 +32,7 @@ module Hanami
47
32
  self[:symbolize_keys].call(input)
48
33
  end
49
34
 
50
- # Deep symbolize the given hash
35
+ # Performs deep symbolize on the given hash
51
36
  #
52
37
  # @param input [::Hash] the input
53
38
  #
@@ -69,7 +54,7 @@ module Hanami
69
54
  self[:deep_symbolize_keys].call(input)
70
55
  end
71
56
 
72
- # Stringify the given hash
57
+ # Stringifies the given hash
73
58
  #
74
59
  # @param input [::Hash] the input
75
60
  #
@@ -89,7 +74,7 @@ module Hanami
89
74
  self[:stringify_keys].call(input)
90
75
  end
91
76
 
92
- # Deeply stringify the given hash
77
+ # Deeply stringifies the given hash
93
78
  #
94
79
  # @param input [::Hash] the input
95
80
  #
@@ -105,31 +90,19 @@ module Hanami
105
90
  #
106
91
  # hash.class
107
92
  # # => Hash
108
- def self.deep_stringify(input) # rubocop:disable Metrics/MethodLength
109
- input.each_with_object({}) do |(key, value), output|
110
- output[key.to_s] =
111
- case value
112
- when ::Hash
113
- deep_stringify(value)
114
- when Array
115
- value.map do |item|
116
- item.is_a?(::Hash) ? deep_stringify(item) : item
117
- end
118
- else
119
- value
120
- end
121
- end
93
+ def self.deep_stringify(input)
94
+ self[:deep_stringify_keys].call(input)
122
95
  end
123
96
 
124
- # Deep duplicate hash values
97
+ # Deep duplicates hash values
125
98
  #
126
- # The output of this function is a shallow duplicate of the input.
99
+ # The output of this function is a deep duplicate of the input.
127
100
  # Any further modification on the input, won't be reflected on the output
128
101
  # and viceversa.
129
102
  #
130
103
  # @param input [::Hash] the input
131
104
  #
132
- # @return [::Hash] the shallow duplicate of input
105
+ # @return [::Hash] the deep duplicate of input
133
106
  #
134
107
  # @since 1.0.1
135
108
  #
@@ -159,17 +132,17 @@ module Hanami
159
132
  # input
160
133
  # # => {"a"=>{"b"=>{"c"=>[1,2,3,4]}}}
161
134
  def self.deep_dup(input)
162
- input.each_with_object({}) do |(k, v), result|
163
- result[k] = case v
164
- when ::Hash
165
- deep_dup(v)
166
- else
167
- Duplicable.dup(v)
168
- end
135
+ input.transform_values do |v|
136
+ case v
137
+ when ::Hash
138
+ deep_dup(v)
139
+ else
140
+ v.dup
141
+ end
169
142
  end
170
143
  end
171
144
 
172
- # Deep serialize given object into a `Hash`
145
+ # Deep serializes given object into a `Hash`
173
146
  #
174
147
  # Please note that the returning `Hash` will use symbols as keys.
175
148
  #
@@ -193,7 +166,7 @@ module Hanami
193
166
  #
194
167
  # Hanami::Utils::Hash.deep_serialize(input)
195
168
  # # => {:foo=>"bar", :baz=>[{:hello=>"world"}]}
196
- def self.deep_serialize(input) # rubocop:disable Metrics/MethodLength
169
+ def self.deep_serialize(input)
197
170
  input.to_hash.each_with_object({}) do |(key, value), output|
198
171
  output[key.to_sym] =
199
172
  case value
@@ -208,318 +181,6 @@ module Hanami
208
181
  end
209
182
  end
210
183
  end
211
-
212
- # Initialize the hash
213
- #
214
- # @param hash [#to_h] the value we want to use to initialize this instance
215
- # @param blk [Proc] define the default value
216
- #
217
- # @return [Hanami::Utils::Hash] self
218
- #
219
- # @since 0.1.0
220
- # @deprecated
221
- #
222
- # @see http://www.ruby-doc.org/core/Hash.html#method-c-5B-5D
223
- #
224
- # @example Passing a Hash
225
- # require 'hanami/utils/hash'
226
- #
227
- # hash = Hanami::Utils::Hash.new('l' => 23)
228
- # hash['l'] # => 23
229
- #
230
- # @example Passing a block for default
231
- # require 'hanami/utils/hash'
232
- #
233
- # hash = Hanami::Utils::Hash.new {|h,k| h[k] = [] }
234
- # hash['foo'].push 'bar'
235
- #
236
- # hash.to_h # => { 'foo' => ['bar'] }
237
- def initialize(hash = {}, &blk)
238
- @hash = hash.to_hash
239
- @hash.default_proc = blk if blk
240
- end
241
-
242
- # Convert in-place all the keys to Symbol instances.
243
- #
244
- # @return [Hash] self
245
- #
246
- # @since 0.1.0
247
- # @deprecated Use {Hanami::Utils::Hash.symbolize}
248
- #
249
- # @example
250
- # require 'hanami/utils/hash'
251
- #
252
- # hash = Hanami::Utils::Hash.new 'a' => 23, 'b' => { 'c' => ['x','y','z'] }
253
- # hash.symbolize!
254
- #
255
- # hash.keys # => [:a, :b]
256
- # hash.inspect # => { :a => 23, :b => { 'c' => ["x", "y", "z"] } }
257
- def symbolize!
258
- keys.each do |k|
259
- v = delete(k)
260
- self[k.to_sym] = v
261
- end
262
-
263
- self
264
- end
265
-
266
- # Convert in-place all the keys to Symbol instances, nested hashes are converted too.
267
- #
268
- # @return [Hash] self
269
- #
270
- # @since 1.0.0
271
- # @deprecated Use {Hanami::Utils::Hash.deep_symbolize}
272
- #
273
- # @example
274
- # require 'hanami/utils/hash'
275
- #
276
- # hash = Hanami::Utils::Hash.new 'a' => 23, 'b' => { 'c' => ['x','y','z'] }
277
- # hash.deep_symbolize!
278
- #
279
- # hash.keys # => [:a, :b]
280
- # hash.inspect # => {:a=>23, :b=>{:c=>["x", "y", "z"]}}
281
- def deep_symbolize!
282
- keys.each do |k|
283
- v = delete(k)
284
- v = self.class.new(v).deep_symbolize! if v.respond_to?(:to_hash)
285
-
286
- self[k.to_sym] = v
287
- end
288
-
289
- self
290
- end
291
-
292
- # Convert in-place all the keys to Symbol instances, nested hashes are converted too.
293
- #
294
- # @return [Hash] self
295
- #
296
- # @since 0.3.2
297
- # @deprecated Use {Hanami::Utils::Hash.stringify}
298
- #
299
- # @example
300
- # require 'hanami/utils/hash'
301
- #
302
- # hash = Hanami::Utils::Hash.new a: 23, b: { c: ['x','y','z'] }
303
- # hash.stringify!
304
- #
305
- # hash.keys # => [:a, :b]
306
- # hash.inspect # => {"a"=>23, "b"=>{"c"=>["x", "y", "z"]}}
307
- def stringify!
308
- keys.each do |k|
309
- v = delete(k)
310
- v = self.class.new(v).stringify! if v.respond_to?(:to_hash)
311
-
312
- self[k.to_s] = v
313
- end
314
-
315
- self
316
- end
317
-
318
- # Return a deep copy of the current Hanami::Utils::Hash
319
- #
320
- # @return [Hash] a deep duplicated self
321
- #
322
- # @since 0.3.1
323
- # @deprecated Use {Hanami::Utils::Hash.deep_dup}
324
- #
325
- # @example
326
- # require 'hanami/utils/hash'
327
- #
328
- # hash = Hanami::Utils::Hash.new(
329
- # 'nil' => nil,
330
- # 'false' => false,
331
- # 'true' => true,
332
- # 'symbol' => :foo,
333
- # 'fixnum' => 23,
334
- # 'bignum' => 13289301283 ** 2,
335
- # 'float' => 1.0,
336
- # 'complex' => Complex(0.3),
337
- # 'bigdecimal' => BigDecimal('12.0001'),
338
- # 'rational' => Rational(0.3),
339
- # 'string' => 'foo bar',
340
- # 'hash' => { a: 1, b: 'two', c: :three },
341
- # 'u_hash' => Hanami::Utils::Hash.new({ a: 1, b: 'two', c: :three })
342
- # )
343
- #
344
- # duped = hash.deep_dup
345
- #
346
- # hash.class # => Hanami::Utils::Hash
347
- # duped.class # => Hanami::Utils::Hash
348
- #
349
- # hash.object_id # => 70147385937100
350
- # duped.object_id # => 70147385950620
351
- #
352
- # # unduplicated values
353
- # duped['nil'] # => nil
354
- # duped['false'] # => false
355
- # duped['true'] # => true
356
- # duped['symbol'] # => :foo
357
- # duped['fixnum'] # => 23
358
- # duped['bignum'] # => 176605528590345446089
359
- # duped['float'] # => 1.0
360
- # duped['complex'] # => (0.3+0i)
361
- # duped['bigdecimal'] # => #<BigDecimal:7f9ffe6e2fd0,'0.120001E2',18(18)>
362
- # duped['rational'] # => 5404319552844595/18014398509481984)
363
- #
364
- # # it duplicates values
365
- # duped['string'].reverse!
366
- # duped['string'] # => "rab oof"
367
- # hash['string'] # => "foo bar"
368
- #
369
- # # it deeply duplicates Hash, by preserving the class
370
- # duped['hash'].class # => Hash
371
- # duped['hash'].delete(:a)
372
- # hash['hash'][:a] # => 1
373
- #
374
- # duped['hash'][:b].upcase!
375
- # duped['hash'][:b] # => "TWO"
376
- # hash['hash'][:b] # => "two"
377
- #
378
- # # it deeply duplicates Hanami::Utils::Hash, by preserving the class
379
- # duped['u_hash'].class # => Hanami::Utils::Hash
380
- def deep_dup
381
- self.class.new.tap do |result|
382
- @hash.each { |k, v| result[k] = Duplicable.dup(v, &DUPLICATE_LOGIC) }
383
- end
384
- end
385
-
386
- # Returns a new array populated with the keys from this hash
387
- #
388
- # @return [Array] the keys
389
- #
390
- # @since 0.3.0
391
- # @deprecated
392
- #
393
- # @see http://www.ruby-doc.org/core/Hash.html#method-i-keys
394
- def keys
395
- @hash.keys
396
- end
397
-
398
- # Deletes the key-value pair and returns the value from hsh whose key is
399
- # equal to key.
400
- #
401
- # @param key [Object] the key to remove
402
- #
403
- # @return [Object,nil] the value hold by the given key, if present
404
- #
405
- # @since 0.3.0
406
- # @deprecated
407
- #
408
- # @see http://www.ruby-doc.org/core/Hash.html#method-i-keys
409
- def delete(key)
410
- @hash.delete(key)
411
- end
412
-
413
- # Retrieves the value object corresponding to the key object.
414
- #
415
- # @param key [Object] the key
416
- #
417
- # @return [Object,nil] the correspoding value, if present
418
- #
419
- # @since 0.3.0
420
- # @deprecated
421
- #
422
- # @see http://www.ruby-doc.org/core/Hash.html#method-i-5B-5D
423
- def [](key)
424
- @hash[key]
425
- end
426
-
427
- # Associates the value given by value with the key given by key.
428
- #
429
- # @param key [Object] the key to assign
430
- # @param value [Object] the value to assign
431
- #
432
- # @since 0.3.0
433
- # @deprecated
434
- #
435
- # @see http://www.ruby-doc.org/core/Hash.html#method-i-5B-5D-3D
436
- def []=(key, value)
437
- @hash[key] = value
438
- end
439
-
440
- # Returns a Ruby Hash as duplicated version of self
441
- #
442
- # @return [::Hash] the hash
443
- #
444
- # @since 0.3.0
445
- # @deprecated
446
- #
447
- # @see http://www.ruby-doc.org/core/Hash.html#method-i-to_h
448
- def to_h
449
- @hash.each_with_object({}) do |(k, v), result|
450
- v = v.to_h if v.respond_to?(:to_hash)
451
- result[k] = v
452
- end
453
- end
454
-
455
- alias to_hash to_h
456
-
457
- # Converts into a nested array of [ key, value ] arrays.
458
- #
459
- # @return [::Array] the array
460
- #
461
- # @since 0.3.0
462
- # @deprecated
463
- #
464
- # @see http://www.ruby-doc.org/core/Hash.html#method-i-to_a
465
- def to_a
466
- @hash.to_a
467
- end
468
-
469
- # Equality
470
- #
471
- # @return [TrueClass,FalseClass]
472
- #
473
- # @since 0.3.0
474
- # @deprecated
475
- def ==(other)
476
- @hash == other.to_h
477
- end
478
-
479
- alias eql? ==
480
-
481
- # Returns the hash of the internal @hash
482
- #
483
- # @return [Fixnum]
484
- #
485
- # @since 0.3.0
486
- # @deprecated
487
- def hash
488
- @hash.hash
489
- end
490
-
491
- # Returns a string describing the internal @hash
492
- #
493
- # @return [String]
494
- #
495
- # @since 0.3.0
496
- # @deprecated
497
- def inspect
498
- @hash.inspect
499
- end
500
-
501
- # Override Ruby's method_missing in order to provide ::Hash interface
502
- #
503
- # @api private
504
- # @since 0.3.0
505
- #
506
- # @raise [NoMethodError] If doesn't respond to the given method
507
- 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
-
510
- h = @hash.__send__(method_name, *args, &blk)
511
- h = self.class.new(h) if h.is_a?(::Hash)
512
- h
513
- end
514
-
515
- # Override Ruby's respond_to_missing? in order to support ::Hash interface
516
- #
517
- # @api private
518
- # @since 0.3.0
519
- def respond_to_missing?(method_name, include_private = false)
520
- @hash.respond_to?(method_name, include_private)
521
- end
522
184
  end
523
- # rubocop:enable Metrics/ClassLength
524
185
  end
525
186
  end