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