hanami-utils 1.3.5 → 2.0.0.alpha2

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