hanami-utils 1.3.7 → 2.0.0.alpha1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -29
- data/README.md +5 -13
- data/hanami-utils.gemspec +3 -4
- data/lib/hanami/interactor.rb +29 -53
- data/lib/hanami/logger.rb +12 -12
- data/lib/hanami/logger/colorizer.rb +10 -10
- data/lib/hanami/logger/filter.rb +10 -89
- data/lib/hanami/logger/formatter.rb +7 -7
- data/lib/hanami/middleware.rb +11 -0
- data/lib/hanami/utils.rb +3 -19
- data/lib/hanami/utils/basic_object.rb +3 -63
- data/lib/hanami/utils/blank.rb +6 -8
- data/lib/hanami/utils/callbacks.rb +20 -5
- data/lib/hanami/utils/class.rb +3 -52
- data/lib/hanami/utils/class_attribute.rb +22 -13
- data/lib/hanami/utils/class_attribute/attributes.rb +45 -0
- data/lib/hanami/utils/escape.rb +170 -172
- data/lib/hanami/utils/file_list.rb +1 -1
- data/lib/hanami/utils/files.rb +2 -31
- data/lib/hanami/utils/hash.rb +12 -341
- data/lib/hanami/utils/json.rb +1 -1
- data/lib/hanami/utils/kernel.rb +12 -11
- data/lib/hanami/utils/load_paths.rb +3 -3
- data/lib/hanami/utils/query_string.rb +1 -1
- data/lib/hanami/utils/shell_color.rb +9 -9
- data/lib/hanami/utils/string.rb +38 -102
- data/lib/hanami/utils/version.rb +1 -1
- metadata +15 -29
- data/lib/hanami/utils/duplicable.rb +0 -82
- data/lib/hanami/utils/inflector.rb +0 -493
| @@ -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: | 
| 111 | 
            +
                      ::Hash[
         | 
| 112 | 
            +
                        message:   message.message,
         | 
| 113 113 | 
             
                        backtrace: message.backtrace || [],
         | 
| 114 | 
            -
                        error: | 
| 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)}"
         | 
| 125 125 | 
             
                  end
         | 
| 126 126 |  | 
| 127 127 | 
             
                  # @since 1.2.0
         | 
    
        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]  | 
| 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]  | 
| 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  | 
| 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 | 
            -
                  #  | 
| 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 | 
             
                  #
         | 
    
        data/lib/hanami/utils/blank.rb
    CHANGED
    
    | @@ -13,7 +13,7 @@ module Hanami | |
| 13 13 | 
             
                  # @api private
         | 
| 14 14 | 
             
                  STRING_MATCHER = /\A[[:space:]]*\z/.freeze
         | 
| 15 15 |  | 
| 16 | 
            -
                  # Checks  | 
| 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] | 
| 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  | 
| 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  | 
| 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] | 
| 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 | 
            -
                    #  | 
| 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
         | 
    
        data/lib/hanami/utils/class.rb
    CHANGED
    
    | @@ -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 | 
            -
                  #  | 
| 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 | 
             
                  #
         | 
| @@ -1,8 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "set"
         | 
| 4 | 
            -
            require "hanami/utils/duplicable"
         | 
| 5 | 
            -
             | 
| 6 3 | 
             
            module Hanami
         | 
| 7 4 | 
             
              module Utils
         | 
| 8 5 | 
             
                # Inheritable class level variable accessors.
         | 
| @@ -10,6 +7,8 @@ module Hanami | |
| 10 7 | 
             
                #
         | 
| 11 8 | 
             
                # @see Hanami::Utils::ClassAttribute::ClassMethods
         | 
| 12 9 | 
             
                module ClassAttribute
         | 
| 10 | 
            +
                  require "hanami/utils/class_attribute/attributes"
         | 
| 11 | 
            +
             | 
| 13 12 | 
             
                  # @api private
         | 
| 14 13 | 
             
                  def self.included(base)
         | 
| 15 14 | 
             
                    base.extend ClassMethods
         | 
| @@ -18,6 +17,12 @@ module Hanami | |
| 18 17 | 
             
                  # @since 0.1.0
         | 
| 19 18 | 
             
                  # @api private
         | 
| 20 19 | 
             
                  module ClassMethods
         | 
| 20 | 
            +
                    def self.extended(base)
         | 
| 21 | 
            +
                      base.class_eval do
         | 
| 22 | 
            +
                        @__class_attributes = Attributes.new unless defined?(@__class_attributes)
         | 
| 23 | 
            +
                      end
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
             | 
| 21 26 | 
             
                    # Defines a class level accessor for the given attribute(s).
         | 
| 22 27 | 
             
                    #
         | 
| 23 28 | 
             
                    # A value set for a superclass is automatically available by their
         | 
| @@ -68,11 +73,17 @@ module Hanami | |
| 68 73 | 
             
                    #   SmallAirplane.engines # => 2
         | 
| 69 74 | 
             
                    #   SmallAirplane.wheels  # => 8
         | 
| 70 75 | 
             
                    def class_attribute(*attributes)
         | 
| 71 | 
            -
                       | 
| 72 | 
            -
                         | 
| 73 | 
            -
             | 
| 76 | 
            +
                      attributes.each do |attr|
         | 
| 77 | 
            +
                        singleton_class.class_eval %(
         | 
| 78 | 
            +
                          def #{attr}
         | 
| 79 | 
            +
                            class_attributes[:#{attr}]
         | 
| 80 | 
            +
                          end
         | 
| 74 81 |  | 
| 75 | 
            -
             | 
| 82 | 
            +
                          def #{attr}=(value)
         | 
| 83 | 
            +
                            class_attributes[:#{attr}] = value
         | 
| 84 | 
            +
                          end
         | 
| 85 | 
            +
                        ), __FILE__, __LINE__ - 8
         | 
| 86 | 
            +
                      end
         | 
| 76 87 | 
             
                    end
         | 
| 77 88 |  | 
| 78 89 | 
             
                    protected
         | 
| @@ -80,11 +91,9 @@ module Hanami | |
| 80 91 | 
             
                    # @see Class#inherited
         | 
| 81 92 | 
             
                    # @api private
         | 
| 82 93 | 
             
                    def inherited(subclass)
         | 
| 83 | 
            -
                      class_attributes. | 
| 84 | 
            -
             | 
| 85 | 
            -
                         | 
| 86 | 
            -
                        subclass.class_attribute attr
         | 
| 87 | 
            -
                        subclass.send("#{attr}=", value)
         | 
| 94 | 
            +
                      ca = class_attributes.dup
         | 
| 95 | 
            +
                      subclass.class_eval do
         | 
| 96 | 
            +
                        @__class_attributes = ca
         | 
| 88 97 | 
             
                      end
         | 
| 89 98 |  | 
| 90 99 | 
             
                      super
         | 
| @@ -95,7 +104,7 @@ module Hanami | |
| 95 104 | 
             
                    # Class accessor for class attributes.
         | 
| 96 105 | 
             
                    # @api private
         | 
| 97 106 | 
             
                    def class_attributes
         | 
| 98 | 
            -
                      @ | 
| 107 | 
            +
                      @__class_attributes
         | 
| 99 108 | 
             
                    end
         | 
| 100 109 | 
             
                  end
         | 
| 101 110 | 
             
                end
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "concurrent/map"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Hanami
         | 
| 6 | 
            +
              module Utils
         | 
| 7 | 
            +
                module ClassAttribute
         | 
| 8 | 
            +
                  # Class attributes set
         | 
| 9 | 
            +
                  #
         | 
| 10 | 
            +
                  # @since 2.0.0
         | 
| 11 | 
            +
                  # @api private
         | 
| 12 | 
            +
                  class Attributes
         | 
| 13 | 
            +
                    # @since 2.0.0
         | 
| 14 | 
            +
                    # @api private
         | 
| 15 | 
            +
                    def initialize(attributes: Concurrent::Map.new)
         | 
| 16 | 
            +
                      @attributes = attributes
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    # @since 2.0.0
         | 
| 20 | 
            +
                    # @api private
         | 
| 21 | 
            +
                    def []=(key, value)
         | 
| 22 | 
            +
                      @attributes[key.to_sym] = value
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    # @since 2.0.0
         | 
| 26 | 
            +
                    # @api private
         | 
| 27 | 
            +
                    def [](key)
         | 
| 28 | 
            +
                      @attributes.fetch(key, nil)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    # @since 2.0.0
         | 
| 32 | 
            +
                    # @api private
         | 
| 33 | 
            +
                    def dup
         | 
| 34 | 
            +
                      attributes = Concurrent::Map.new.tap do |attrs|
         | 
| 35 | 
            +
                        @attributes.each do |key, value|
         | 
| 36 | 
            +
                          attrs[key.to_sym] = value.dup
         | 
| 37 | 
            +
                        end
         | 
| 38 | 
            +
                      end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                      self.class.new(attributes: attributes)
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         |