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.
@@ -14,9 +14,9 @@ module Hanami
14
14
  # @api private
15
15
  def call(app, severity, datetime, _progname)
16
16
  ::Hash[
17
- app: app,
17
+ app: app,
18
18
  severity: severity,
19
- time: datetime,
19
+ time: datetime,
20
20
  ]
21
21
  end
22
22
  end
@@ -44,9 +44,9 @@ module Hanami
44
44
  # @return [::Hash] an Hash containing the keys `:app`, `:severity`, and `:time`
45
45
  def call(app, severity, datetime, _progname)
46
46
  ::Hash[
47
- app: app(app),
47
+ app: app(app),
48
48
  severity: severity(severity),
49
- time: datetime(datetime),
49
+ time: datetime(datetime),
50
50
  ]
51
51
  end
52
52
 
@@ -57,18 +57,18 @@ module Hanami
57
57
  # @since 1.2.0
58
58
  # @api private
59
59
  COLORS = ::Hash[
60
- app: :blue,
60
+ app: :blue,
61
61
  datetime: :cyan,
62
62
  ].freeze
63
63
 
64
64
  # @since 1.2.0
65
65
  # @api private
66
66
  LEVELS = ::Hash[
67
- Hanami::Logger::DEBUG => :cyan,
68
- Hanami::Logger::INFO => :magenta,
69
- Hanami::Logger::WARN => :yellow,
70
- Hanami::Logger::ERROR => :red,
71
- Hanami::Logger::FATAL => :red,
67
+ Hanami::Logger::DEBUG => :cyan,
68
+ Hanami::Logger::INFO => :magenta,
69
+ Hanami::Logger::WARN => :yellow,
70
+ Hanami::Logger::ERROR => :red,
71
+ Hanami::Logger::FATAL => :red,
72
72
  Hanami::Logger::UNKNOWN => :blue,
73
73
  ].freeze
74
74
 
@@ -9,21 +9,19 @@ module Hanami
9
9
  # @since 1.1.0
10
10
  # @api private
11
11
  class Filter
12
- # @since 1.1.0
12
+ # @since 1.3.7
13
13
  # @api private
14
- def initialize(filters = [])
14
+ FILTERED_VALUE = "[FILTERED]"
15
+
16
+ def initialize(filters = [], mask: FILTERED_VALUE)
15
17
  @filters = filters
18
+ @mask = mask
16
19
  end
17
20
 
18
21
  # @since 1.1.0
19
22
  # @api private
20
- def call(hash)
21
- _filtered_keys(hash).each do |key|
22
- *keys, last = _actual_keys(hash, key.split("."))
23
- keys.inject(hash, :fetch)[last] = "[FILTERED]"
24
- end
25
-
26
- hash
23
+ def call(params)
24
+ _filter(_copy_params(params))
27
25
  end
28
26
 
29
27
  private
@@ -32,6 +30,29 @@ module Hanami
32
30
  # @api private
33
31
  attr_reader :filters
34
32
 
33
+ # @since 1.3.7
34
+ # @api private
35
+ attr_reader :mask
36
+
37
+ # This is a simple deep merge to merge the original input
38
+ # with the filtered hash which contains '[FILTERED]' string.
39
+ #
40
+ # It only deep-merges if the conflict values are both hashes.
41
+ #
42
+ # @since 1.3.7
43
+ # @api private
44
+ def _deep_merge(original_hash, filtered_hash)
45
+ original_hash.merge(filtered_hash) do |_key, original_item, filtered_item|
46
+ if original_item.is_a?(Hash) && filtered_item.is_a?(Hash)
47
+ _deep_merge(original_item, filtered_item)
48
+ elsif filtered_item == FILTERED_VALUE
49
+ filtered_item
50
+ else
51
+ original_item
52
+ end
53
+ end
54
+ end
55
+
35
56
  # @since 1.1.0
36
57
  # @api private
37
58
  def _filtered_keys(hash)
@@ -74,6 +95,50 @@ module Hanami
74
95
  def _key_paths?(value)
75
96
  value.is_a?(Enumerable) && !value.is_a?(File)
76
97
  end
98
+
99
+ # @since 1.3.7
100
+ # @api private
101
+ def _deep_dup(hash)
102
+ hash.transform_values do |value|
103
+ if value.is_a?(Hash)
104
+ _deep_dup(value)
105
+ else
106
+ _key_paths?(value) ? value.dup : value
107
+ end
108
+ end
109
+ end
110
+
111
+ # @since 1.3.7
112
+ # @api private
113
+ def _copy_params(params)
114
+ case params
115
+ when Hash
116
+ _deep_dup(params)
117
+ when Array
118
+ params.map { |hash| _deep_dup(hash) }
119
+ end
120
+ end
121
+
122
+ # @since 1.3.7
123
+ # @api private
124
+ def _filter_hash(hash)
125
+ _filtered_keys(hash).each do |key|
126
+ *keys, last = _actual_keys(hash, key.split("."))
127
+ keys.inject(hash, :fetch)[last] = mask
128
+ end
129
+ hash
130
+ end
131
+
132
+ # @since 1.3.7
133
+ # @api private
134
+ def _filter(params)
135
+ case params
136
+ when Hash
137
+ _filter_hash(params)
138
+ when Array
139
+ params.map { |hash| _filter_hash(hash) }
140
+ end
141
+ end
77
142
  end
78
143
  end
79
144
  end
@@ -103,25 +103,25 @@ module Hanami
103
103
 
104
104
  # @since 0.8.0
105
105
  # @api private
106
- def _message_hash(message) # rubocop:disable Metrics/MethodLength
106
+ def _message_hash(message)
107
107
  case message
108
- when Hash
108
+ when ::Hash
109
109
  @filter.call(message)
110
110
  when Exception
111
- Hash[
112
- message: message.message,
111
+ ::Hash[
112
+ message: message.message,
113
113
  backtrace: message.backtrace || [],
114
- error: message.class
114
+ error: message.class
115
115
  ]
116
116
  else
117
- Hash[message: message]
117
+ ::Hash[message: message]
118
118
  end
119
119
  end
120
120
 
121
121
  # @since 0.8.0
122
122
  # @api private
123
123
  def _format(hash)
124
- "#{_line_front_matter(hash.delete(:app), hash.delete(:severity), hash.delete(:time))}#{SEPARATOR}#{_format_message(hash)}"
124
+ "#{_line_front_matter(hash.delete(:app), hash.delete(:severity), hash.delete(:time))}#{SEPARATOR}#{_format_message(hash)}" # rubocop:disable Layout/LineLength
125
125
  end
126
126
 
127
127
  # @since 1.2.0
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Middleware
5
+ # Hanami middleware utils
6
+
7
+ # @since 2.0.0
8
+ class Error < ::StandardError
9
+ end
10
+ end
11
+ end
data/lib/hanami/utils.rb CHANGED
@@ -1,11 +1,13 @@
1
- require 'pathname'
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
2
4
 
3
5
  # Hanami - The web, with simplicity
4
6
  #
5
7
  # @since 0.1.0
6
8
  module Hanami
7
- require 'hanami/utils/version'
8
- require 'hanami/utils/file_list'
9
+ require "hanami/utils/version"
10
+ require "hanami/utils/file_list"
9
11
 
10
12
  # Ruby core extentions and Hanami utilities
11
13
  #
@@ -13,15 +15,15 @@ module Hanami
13
15
  module Utils
14
16
  # @since 0.3.1
15
17
  # @api private
16
- HANAMI_JRUBY = 'java'.freeze
18
+ HANAMI_JRUBY = "java"
17
19
 
18
20
  # @since 0.3.1
19
21
  # @api private
20
- HANAMI_RUBINIUS = 'rbx'.freeze
22
+ HANAMI_RUBINIUS = "rbx"
21
23
 
22
24
  # Checks if the current VM is JRuby
23
25
  #
24
- # @return [TrueClass,FalseClass] return if the VM is JRuby or not
26
+ # @return [TrueClass,FalseClass] info whether the VM is JRuby or not
25
27
  #
26
28
  # @since 0.3.1
27
29
  # @api private
@@ -31,7 +33,7 @@ module Hanami
31
33
 
32
34
  # Checks if the current VM is Rubinius
33
35
  #
34
- # @return [TrueClass,FalseClass] return if the VM is Rubinius or not
36
+ # @return [TrueClass,FalseClass] info whether the VM is Rubinius or not
35
37
  #
36
38
  # @since 0.3.1
37
39
  # @api private
@@ -39,7 +41,7 @@ module Hanami
39
41
  RUBY_ENGINE == HANAMI_RUBINIUS
40
42
  end
41
43
 
42
- # Recursively require Ruby files under the given directory.
44
+ # Recursively requires Ruby files under the given directory.
43
45
  #
44
46
  # If the directory is relative, it implies it's the path from current directory.
45
47
  # If the directory is absolute, it uses as it is.
@@ -54,22 +56,6 @@ module Hanami
54
56
  for_each_file_in(directory) { |file| require_relative(file) }
55
57
  end
56
58
 
57
- # Recursively reload Ruby files under the given directory.
58
- #
59
- # If the directory is relative, it implies it's the path from current directory.
60
- # If the directory is absolute, it uses as it is.
61
- #
62
- # It respects file separator of the current operating system.
63
- # A pattern like <tt>"path/to/files"</tt> will work both on *NIX and Windows machines.
64
- #
65
- # @param directory [String, Pathname] the directory
66
- #
67
- # @since 1.0.0
68
- # @api private
69
- def self.reload!(directory)
70
- for_each_file_in(directory) { |file| load(file) }
71
- end
72
-
73
59
  # Recursively scans through the given directory and yields the given block
74
60
  # for each Ruby source file.
75
61
  #
@@ -85,9 +71,9 @@ module Hanami
85
71
  # @since 1.0.0
86
72
  # @api private
87
73
  def self.for_each_file_in(directory, &blk)
88
- directory = directory.to_s.gsub(%r{(\/|\\)}, File::SEPARATOR)
74
+ directory = directory.to_s.gsub(%r{(/|\\)}, File::SEPARATOR)
89
75
  directory = Pathname.new(Dir.pwd).join(directory).to_s
90
- directory = File.join(directory, '**', '*.rb') unless directory =~ /(\*\*)/
76
+ directory = File.join(directory, "**", "*.rb") unless directory =~ /(\*\*)/
91
77
 
92
78
  FileList[directory].each(&blk)
93
79
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Utils
3
5
  # BasicObject
4
6
  #
5
7
  # @since 0.3.5
6
8
  class BasicObject < ::BasicObject
7
- # Lookup constants at the top-level namespace, if they are missing in the
9
+ # Lookups constants at the top-level namespace, if they are missing in the
8
10
  # current context.
9
11
  #
10
12
  # @param name [Symbol] the constant name
@@ -21,7 +23,7 @@ module Hanami
21
23
  ::Object.const_get(name)
22
24
  end
23
25
 
24
- # Return the class for debugging purposes.
26
+ # Returns the class for debugging purposes.
25
27
  #
26
28
  # @since 0.3.5
27
29
  #
@@ -38,17 +40,15 @@ module Hanami
38
40
  #
39
41
  # @see http://ruby-doc.org/core/Object.html#method-i-inspect
40
42
  #
41
- # rubocop:disable Style/FormatString
42
43
  # rubocop:disable Style/FormatStringToken
43
44
  def inspect
44
45
  "#<#{self.class}:#{'0x0000%x' % (__id__ << 1)}#{__inspect}>"
45
46
  end
46
47
  # rubocop:enable Style/FormatStringToken
47
- # rubocop:enable Style/FormatString
48
48
 
49
49
  # @!macro [attach] instance_of?(class)
50
50
  #
51
- # Determine if self is an instance of given class or module
51
+ # Determines if self is an instance of given class or module
52
52
  #
53
53
  # @param class [Class,Module] the class of module to verify
54
54
  #
@@ -63,7 +63,7 @@ module Hanami
63
63
 
64
64
  # @!macro [attach] is_a?(class)
65
65
  #
66
- # Determine if self is of the type of the object class or module
66
+ # Determines if self is of the type of the object class or module
67
67
  #
68
68
  # @param class [Class,Module] the class of module to verify
69
69
  #
@@ -78,7 +78,7 @@ module Hanami
78
78
 
79
79
  # @!macro [attach] kind_of?(class)
80
80
  #
81
- # Determine if self is of the kind of the object class or module
81
+ # Determines if self is of the kind of the object class or module
82
82
  #
83
83
  # @param class [Class,Module] the class of module to verify
84
84
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hanami
2
4
  module Utils
3
5
  # Checks for blank
@@ -11,7 +13,7 @@ module Hanami
11
13
  # @api private
12
14
  STRING_MATCHER = /\A[[:space:]]*\z/.freeze
13
15
 
14
- # Checks object is blank
16
+ # Checks if object is blank
15
17
  #
16
18
  # @example Basic Usage
17
19
  # require 'hanami/utils/blank'
@@ -19,21 +21,20 @@ module Hanami
19
21
  # Hanami::Utils::Blank.blank?(Hanami::Utils::String.new('')) # => true
20
22
  # Hanami::Utils::Blank.blank?(' ') # => true
21
23
  # Hanami::Utils::Blank.blank?(nil) # => true
22
- # Hanami::Utils::Blank.blank?(Hanami::Utils::Hash.new({})) # => true
23
24
  # Hanami::Utils::Blank.blank?(true) # => false
24
25
  # Hanami::Utils::Blank.blank?(1) # => false
25
26
  #
26
27
  # @param object the argument
27
28
  #
28
- # @return [TrueClass,FalseClass]
29
+ # @return [TrueClass,FalseClass] info, whether object is blank
29
30
  #
30
31
  # @since 0.8.0
31
32
  # @api private
32
- def self.blank?(object) # rubocop:disable Metrics/MethodLength
33
+ def self.blank?(object)
33
34
  case object
34
35
  when String, ::String
35
- STRING_MATCHER === object # rubocop:disable Style/CaseEquality
36
- when Hash, ::Hash, ::Array
36
+ STRING_MATCHER === object
37
+ when ::Hash, ::Array
37
38
  object.empty?
38
39
  when TrueClass, Numeric
39
40
  false
@@ -44,7 +45,7 @@ module Hanami
44
45
  end
45
46
  end
46
47
 
47
- # Checks object is filled
48
+ # Checks if object is filled
48
49
  #
49
50
  # @example Basic Usage
50
51
  # require 'hanami/utils/blank'
@@ -54,11 +55,10 @@ module Hanami
54
55
  # Hanami::Utils::Blank.filled?(Hanami::Utils::String.new('')) # => false
55
56
  # Hanami::Utils::Blank.filled?(' ') # => false
56
57
  # Hanami::Utils::Blank.filled?(nil) # => false
57
- # Hanami::Utils::Blank.filled?(Hanami::Utils::Hash.new({})) # => false
58
58
  #
59
59
  # @param object the argument
60
60
  #
61
- # @return [TrueClass,FalseClass]
61
+ # @return [TrueClass,FalseClass] whether the object is filled
62
62
  #
63
63
  # @since 1.0.0
64
64
  # @api private
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/array"
4
+
1
5
  module Hanami
2
6
  module Utils
3
7
  # Before and After callbacks
@@ -10,13 +14,13 @@ module Hanami
10
14
  # @since 0.1.0
11
15
  # @private
12
16
  class Chain
13
- # Return a new chain
17
+ # Returns a new chain
14
18
  #
15
19
  # @return [Hanami::Utils::Callbacks::Chain]
16
20
  #
17
21
  # @since 0.2.0
18
22
  def initialize
19
- @chain = []
23
+ @chain = Concurrent::Array.new
20
24
  end
21
25
 
22
26
  # Appends the given callbacks to the end of the chain.
@@ -148,6 +152,17 @@ module Hanami
148
152
  end
149
153
  end
150
154
 
155
+ # Return a duplicate callbacks chain
156
+ #
157
+ # @return [Hanami::Utils::Callbacks] the duplicated chain
158
+ #
159
+ # @since 2.0.0
160
+ def dup
161
+ super.tap do |instance|
162
+ instance.instance_variable_set(:@chain, instance.chain.dup)
163
+ end
164
+ end
165
+
151
166
  # It freezes the object by preventing further modifications.
152
167
  #
153
168
  # @since 0.2.0
@@ -168,6 +183,10 @@ module Hanami
168
183
  @chain.freeze
169
184
  end
170
185
 
186
+ protected
187
+
188
+ attr_reader :chain
189
+
171
190
  private
172
191
 
173
192
  # @api private
@@ -248,7 +267,9 @@ module Hanami
248
267
  end
249
268
 
250
269
  # Method callback
251
- # It wraps a symbol or a string representing a method name that is implemented by the context within it will be called.
270
+ #
271
+ # It wraps a symbol or a string representing a method name that is
272
+ # implemented by the context within it will be called.
252
273
  #
253
274
  # @since 0.1.0
254
275
  # @api private