hanami-utils 1.3.8 → 2.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,19 +9,21 @@ module Hanami
9
9
  # @since 1.1.0
10
10
  # @api private
11
11
  class Filter
12
- # @since 1.3.7
12
+ # @since 1.1.0
13
13
  # @api private
14
- FILTERED_VALUE = "[FILTERED]"
15
-
16
- def initialize(filters = [], mask: FILTERED_VALUE)
14
+ def initialize(filters = [])
17
15
  @filters = filters
18
- @mask = mask
19
16
  end
20
17
 
21
18
  # @since 1.1.0
22
19
  # @api private
23
- def call(params)
24
- _filter(_copy_params(params))
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
25
27
  end
26
28
 
27
29
  private
@@ -30,29 +32,6 @@ module Hanami
30
32
  # @api private
31
33
  attr_reader :filters
32
34
 
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
-
56
35
  # @since 1.1.0
57
36
  # @api private
58
37
  def _filtered_keys(hash)
@@ -63,7 +42,7 @@ module Hanami
63
42
  # @api private
64
43
  def _key_paths(hash, base = nil)
65
44
  hash.inject([]) do |results, (k, v)|
66
- results + (_key_paths?(v) ? _key_paths(v, _build_path(base, k)) : [_build_path(base, k)])
45
+ results + (v.respond_to?(:each) ? _key_paths(v, _build_path(base, k)) : [_build_path(base, k)])
67
46
  end
68
47
  end
69
48
 
@@ -84,64 +63,6 @@ module Hanami
84
63
  res + [correct_key]
85
64
  end
86
65
  end
87
-
88
- # Check if the given value can be iterated (`Enumerable`) and that isn't a `File`.
89
- # This is useful to detect closed `Tempfiles`.
90
- #
91
- # @since 1.3.5
92
- # @api private
93
- #
94
- # @see https://github.com/hanami/utils/pull/342
95
- def _key_paths?(value)
96
- value.is_a?(Enumerable) && !value.is_a?(File)
97
- end
98
-
99
- # @since 1.3.7
100
- # @api private
101
- def _deep_dup(hash)
102
- hash.map do |key, value|
103
- [
104
- key,
105
- if value.is_a?(Hash)
106
- _deep_dup(value)
107
- else
108
- _key_paths?(value) ? value.dup : value
109
- end
110
- ]
111
- end.to_h
112
- end
113
-
114
- # @since 1.3.7
115
- # @api private
116
- def _copy_params(params)
117
- case params
118
- when Hash
119
- _deep_dup(params)
120
- when Array
121
- params.map { |hash| _deep_dup(hash) }
122
- end
123
- end
124
-
125
- # @since 1.3.7
126
- # @api private
127
- def _filter_hash(hash)
128
- _filtered_keys(hash).each do |key|
129
- *keys, last = _actual_keys(hash, key.split("."))
130
- keys.inject(hash, :fetch)[last] = mask
131
- end
132
- hash
133
- end
134
-
135
- # @since 1.3.7
136
- # @api private
137
- def _filter(params)
138
- case params
139
- when Hash
140
- _filter_hash(params)
141
- when Array
142
- params.map { |hash| _filter_hash(hash) }
143
- end
144
- end
145
66
  end
146
67
  end
147
68
  end
@@ -103,25 +103,25 @@ module Hanami
103
103
 
104
104
  # @since 0.8.0
105
105
  # @api private
106
- def _message_hash(message)
106
+ def _message_hash(message) # rubocop:disable Metrics/MethodLength
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)}" # rubocop:disable Layout/LineLength
124
+ "#{_line_front_matter(hash.delete(:app), hash.delete(:severity), hash.delete(:time))}#{SEPARATOR}#{_format_message(hash)}"
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
@@ -23,7 +23,7 @@ module Hanami
23
23
 
24
24
  # Checks if the current VM is JRuby
25
25
  #
26
- # @return [TrueClass,FalseClass] info whether the VM is JRuby or not
26
+ # @return [TrueClass,FalseClass] return if the VM is JRuby or not
27
27
  #
28
28
  # @since 0.3.1
29
29
  # @api private
@@ -33,7 +33,7 @@ module Hanami
33
33
 
34
34
  # Checks if the current VM is Rubinius
35
35
  #
36
- # @return [TrueClass,FalseClass] info whether the VM is Rubinius or not
36
+ # @return [TrueClass,FalseClass] return if the VM is Rubinius or not
37
37
  #
38
38
  # @since 0.3.1
39
39
  # @api private
@@ -41,7 +41,7 @@ module Hanami
41
41
  RUBY_ENGINE == HANAMI_RUBINIUS
42
42
  end
43
43
 
44
- # Recursively requires Ruby files under the given directory.
44
+ # Recursively require Ruby files under the given directory.
45
45
  #
46
46
  # If the directory is relative, it implies it's the path from current directory.
47
47
  # If the directory is absolute, it uses as it is.
@@ -56,22 +56,6 @@ module Hanami
56
56
  for_each_file_in(directory) { |file| require_relative(file) }
57
57
  end
58
58
 
59
- # Recursively reloads Ruby files under the given directory.
60
- #
61
- # If the directory is relative, it implies it's the path from current directory.
62
- # If the directory is absolute, it uses as it is.
63
- #
64
- # It respects file separator of the current operating system.
65
- # A pattern like <tt>"path/to/files"</tt> will work both on *NIX and Windows machines.
66
- #
67
- # @param directory [String, Pathname] the directory
68
- #
69
- # @since 1.0.0
70
- # @api private
71
- def self.reload!(directory)
72
- for_each_file_in(directory) { |file| load(file) }
73
- end
74
-
75
59
  # Recursively scans through the given directory and yields the given block
76
60
  # for each Ruby source file.
77
61
  #
@@ -6,24 +6,7 @@ module Hanami
6
6
  #
7
7
  # @since 0.3.5
8
8
  class BasicObject < ::BasicObject
9
- # Lookups constants at the top-level namespace, if they are missing in the
10
- # current context.
11
- #
12
- # @param name [Symbol] the constant name
13
- #
14
- # @return [Object, Module] the constant
15
- #
16
- # @raise [NameError] if the constant cannot be found
17
- #
18
- # @since 1.3.4
19
- # @api private
20
- #
21
- # @see https://ruby-doc.org/core/Module.html#method-i-const_missing
22
- def self.const_missing(name)
23
- ::Object.const_get(name)
24
- end
25
-
26
- # Returns the class for debugging purposes.
9
+ # Return the class for debugging purposes.
27
10
  #
28
11
  # @since 0.3.5
29
12
  #
@@ -40,56 +23,13 @@ module Hanami
40
23
  #
41
24
  # @see http://ruby-doc.org/core/Object.html#method-i-inspect
42
25
  #
26
+ # rubocop:disable Style/FormatString
43
27
  # rubocop:disable Style/FormatStringToken
44
28
  def inspect
45
29
  "#<#{self.class}:#{'0x0000%x' % (__id__ << 1)}#{__inspect}>"
46
30
  end
47
31
  # rubocop:enable Style/FormatStringToken
48
-
49
- # @!macro [attach] instance_of?(class)
50
- #
51
- # Determines if self is an instance of given class or module
52
- #
53
- # @param class [Class,Module] the class of module to verify
54
- #
55
- # @return [TrueClass,FalseClass] the result of the check
56
- #
57
- # @raise [TypeError] if the given argument is not of the expected types
58
- #
59
- # @since 1.3.2
60
- #
61
- # @see http://ruby-doc.org/core/Object.html#method-i-instance_of-3F
62
- define_method :instance_of?, ::Object.instance_method(:instance_of?)
63
-
64
- # @!macro [attach] is_a?(class)
65
- #
66
- # Determines if self is of the type of the object class or module
67
- #
68
- # @param class [Class,Module] the class of module to verify
69
- #
70
- # @return [TrueClass,FalseClass] the result of the check
71
- #
72
- # @raise [TypeError] if the given argument is not of the expected types
73
- #
74
- # @since 1.3.2
75
- #
76
- # @see http://ruby-doc.org/core/Object.html#method-i-is_a-3F
77
- define_method :is_a?, ::Object.instance_method(:is_a?)
78
-
79
- # @!macro [attach] kind_of?(class)
80
- #
81
- # Determines if self is of the kind of the object class or module
82
- #
83
- # @param class [Class,Module] the class of module to verify
84
- #
85
- # @return [TrueClass,FalseClass] the result of the check
86
- #
87
- # @raise [TypeError] if the given argument is not of the expected types
88
- #
89
- # @since 1.3.2
90
- #
91
- # @see http://ruby-doc.org/core/Object.html#method-i-kind_of-3F
92
- define_method :kind_of?, ::Object.instance_method(:kind_of?)
32
+ # rubocop:enable Style/FormatString
93
33
 
94
34
  # Alias for __id__
95
35
  #
@@ -13,7 +13,7 @@ module Hanami
13
13
  # @api private
14
14
  STRING_MATCHER = /\A[[:space:]]*\z/.freeze
15
15
 
16
- # Checks if object is blank
16
+ # Checks object is blank
17
17
  #
18
18
  # @example Basic Usage
19
19
  # require 'hanami/utils/blank'
@@ -21,21 +21,20 @@ module Hanami
21
21
  # Hanami::Utils::Blank.blank?(Hanami::Utils::String.new('')) # => true
22
22
  # Hanami::Utils::Blank.blank?(' ') # => true
23
23
  # Hanami::Utils::Blank.blank?(nil) # => true
24
- # Hanami::Utils::Blank.blank?(Hanami::Utils::Hash.new({})) # => true
25
24
  # Hanami::Utils::Blank.blank?(true) # => false
26
25
  # Hanami::Utils::Blank.blank?(1) # => false
27
26
  #
28
27
  # @param object the argument
29
28
  #
30
- # @return [TrueClass,FalseClass] info, whether object is blank
29
+ # @return [TrueClass,FalseClass]
31
30
  #
32
31
  # @since 0.8.0
33
32
  # @api private
34
- def self.blank?(object)
33
+ def self.blank?(object) # rubocop:disable Metrics/MethodLength
35
34
  case object
36
35
  when String, ::String
37
36
  STRING_MATCHER === object # rubocop:disable Style/CaseEquality
38
- when Hash, ::Hash, ::Array
37
+ when ::Hash, ::Array
39
38
  object.empty?
40
39
  when TrueClass, Numeric
41
40
  false
@@ -46,7 +45,7 @@ module Hanami
46
45
  end
47
46
  end
48
47
 
49
- # Checks if object is filled
48
+ # Checks object is filled
50
49
  #
51
50
  # @example Basic Usage
52
51
  # require 'hanami/utils/blank'
@@ -56,11 +55,10 @@ module Hanami
56
55
  # Hanami::Utils::Blank.filled?(Hanami::Utils::String.new('')) # => false
57
56
  # Hanami::Utils::Blank.filled?(' ') # => false
58
57
  # Hanami::Utils::Blank.filled?(nil) # => false
59
- # Hanami::Utils::Blank.filled?(Hanami::Utils::Hash.new({})) # => false
60
58
  #
61
59
  # @param object the argument
62
60
  #
63
- # @return [TrueClass,FalseClass] whether the object is filled
61
+ # @return [TrueClass,FalseClass]
64
62
  #
65
63
  # @since 1.0.0
66
64
  # @api private
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "concurrent/array"
4
+
3
5
  module Hanami
4
6
  module Utils
5
7
  # Before and After callbacks
@@ -12,13 +14,13 @@ module Hanami
12
14
  # @since 0.1.0
13
15
  # @private
14
16
  class Chain
15
- # Returns a new chain
17
+ # Return a new chain
16
18
  #
17
19
  # @return [Hanami::Utils::Callbacks::Chain]
18
20
  #
19
21
  # @since 0.2.0
20
22
  def initialize
21
- @chain = []
23
+ @chain = Concurrent::Array.new
22
24
  end
23
25
 
24
26
  # Appends the given callbacks to the end of the chain.
@@ -150,6 +152,17 @@ module Hanami
150
152
  end
151
153
  end
152
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
+
153
166
  # It freezes the object by preventing further modifications.
154
167
  #
155
168
  # @since 0.2.0
@@ -170,6 +183,10 @@ module Hanami
170
183
  @chain.freeze
171
184
  end
172
185
 
186
+ protected
187
+
188
+ attr_reader :chain
189
+
173
190
  private
174
191
 
175
192
  # @api private
@@ -250,9 +267,7 @@ module Hanami
250
267
  end
251
268
 
252
269
  # Method callback
253
- #
254
- # It wraps a symbol or a string representing a method name that is
255
- # implemented by the context within it will be called.
270
+ # It wraps a symbol or a string representing a method name that is implemented by the context within it will be called.
256
271
  #
257
272
  # @since 0.1.0
258
273
  # @api private
@@ -74,59 +74,9 @@ module Hanami
74
74
  load!(name, namespace) if namespace.const_defined?(name.to_s, false)
75
75
  end
76
76
 
77
- # Loads a class from the given pattern name and namespace
78
- #
79
- # @param pattern [String] the class name pattern
80
- # @param namespace [Class, Module] the Ruby namespace where we want to perform the lookup.
81
- # @return [Class, Module] the found Ruby constant.
82
- #
83
- # @raise [NameError] if no constant can be found.
84
- #
85
- # @since 0.3.1
86
- #
87
- # @see Hanami::Utils::String#tokenize
88
- #
89
- # @example
90
- # require 'hanami/utils/class'
91
- #
92
- # module App
93
- # module Service
94
- # class Endpoint
95
- # end
96
- # end
97
- #
98
- # class ServiceEndpoint
99
- # end
100
- # end
101
- #
102
- # # basic usage
103
- # Hanami::Utils::Class.load_from_pattern!('App::Service') # => App::Service
104
- #
105
- # # with explicit namespace
106
- # Hanami::Utils::Class.load_from_pattern!('Service', App) # => App::Service
107
- #
108
- # # with pattern
109
- # Hanami::Utils::Class.load_from_pattern!('App::Service(::Endpoint|Endpoint)') # => App::Service::Endpoint
110
- # Hanami::Utils::Class.load_from_pattern!('App::Service(Endpoint|::Endpoint)') # => App::ServiceEndpoint
111
- #
112
- # # with missing constant
113
- # Hanami::Utils::Class.load_from_pattern!('Unknown') # => raises NameError
114
- def self.load_from_pattern!(pattern, namespace = Object)
115
- Deprecation.new("Hanami::Utils::Class.load_from_pattern! is deprecated, please use Hanami::Utils::Class.load! instead") # rubocop:disable Layout/LineLength
116
-
117
- tokenize(pattern) do |token|
118
- begin
119
- return namespace.const_get(token, false)
120
- rescue NameError # rubocop:disable Lint/SuppressedException
121
- end
122
- end
123
-
124
- full_name = [(namespace == Object ? nil : namespace), pattern].compact.join("::")
125
- raise NameError.new("uninitialized constant #{full_name}")
126
- end
127
-
77
+ # rubocop:disable Metrics/MethodLength
128
78
  def self.tokenize(pattern)
129
- if match = TOKENIZE_REGEXP.match(pattern)
79
+ if match = TOKENIZE_REGEXP.match(pattern) # rubocop:disable Lint/AssignmentInCondition
130
80
  pre = match.pre_match
131
81
  post = match.post_match
132
82
  tokens = match[1].split(TOKENIZE_SEPARATOR)
@@ -139,6 +89,7 @@ module Hanami
139
89
 
140
90
  nil
141
91
  end
92
+ # rubocop:enable Metrics/MethodLength
142
93
 
143
94
  # Regexp for .tokenize
144
95
  #