Module: Hanami::Utils::String

Extended by:
Dry::Transformer::Registry
Defined in:
lib/hanami/utils/string.rb

Overview

String utilities

Since:

  • 0.1.0

Constant Summary collapse

EMPTY_STRING =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Empty string for #classify

Since:

  • 0.6.0

""
NAMESPACE_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Separator between Ruby namespaces

Since:

  • 0.1.0

"::"
CLASSIFY_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Separator for #classify

Since:

  • 0.3.0

"_"
UNDERSCORE_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Separator for #underscore

Since:

  • 0.3.0

"/"
UNDERSCORE_DIVISION_TARGET =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

gsub second parameter used in #underscore

Since:

  • 0.3.0

'\1_\2'
TITLEIZE_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Separator for #titleize

Since:

  • 0.4.0

" "
CAPITALIZE_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Separator for #capitalize

Since:

  • 0.5.2

" "
DASHERIZE_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Separator for #dasherize

Since:

  • 0.4.0

"-"
CLASSIFY_WORD_SEPARATOR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Regexp for #classify

Since:

  • 0.3.4

/#{CLASSIFY_SEPARATOR}|#{NAMESPACE_SEPARATOR}|#{UNDERSCORE_SEPARATOR}|#{DASHERIZE_SEPARATOR}/

Class Method Summary collapse

Class Method Details

.capitalize(input) ⇒ ::String

Returns a capitalized version of the string

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.capitalize('hanami') # => "Hanami"

Hanami::Utils::String.capitalize('hanami utils') # => "Hanami utils"

Hanami::Utils::String.capitalize('Hanami Utils') # => "Hanami utils"

Hanami::Utils::String.capitalize('hanami_utils') # => "Hanami utils"

Hanami::Utils::String.capitalize('hanami-utils') # => "Hanami utils"

Parameters:

  • input (::String)

    the input

Returns:

  • (::String)

    the transformed string

Since:

  • 1.1.0



182
183
184
185
186
187
# File 'lib/hanami/utils/string.rb', line 182

def self.capitalize(input)
  string = ::String.new(input.to_s)
  head, *tail = underscore(string).split(CLASSIFY_SEPARATOR)

  tail.unshift(head.capitalize).join(CAPITALIZE_SEPARATOR)
end

.classify(input) ⇒ ::String

Returns a CamelCase version of the string

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.classify('hanami_utils') # => 'HanamiUtils'

Parameters:

  • input (::String)

    the input

Returns:

  • (::String)

    the transformed string

Since:

  • 1.1.0



201
202
203
204
205
206
207
208
209
210
211
# File 'lib/hanami/utils/string.rb', line 201

def self.classify(input)
  string = ::String.new(input.to_s)
  words = underscore(string).split(CLASSIFY_WORD_SEPARATOR).map!(&:capitalize)
  delimiters = underscore(string).scan(CLASSIFY_WORD_SEPARATOR)

  delimiters.map! do |delimiter|
    delimiter == CLASSIFY_SEPARATOR ? EMPTY_STRING : NAMESPACE_SEPARATOR
  end

  words.zip(delimiters).join
end

.dasherize(input) ⇒ Object

Hanami::Utils::String.dasherize(‘hanami_utils’) # => ‘hanami-utils’

Hanami::Utils::String.dasherize('HanamiUtils') # => "hanami-utils"

Since:

  • 0.1.0



254
255
256
257
# File 'lib/hanami/utils/string.rb', line 254

def self.dasherize(input)
  string = ::String.new(input.to_s)
  underscore(string).split(CLASSIFY_SEPARATOR).join(DASHERIZE_SEPARATOR)
end

.demodulize(input) ⇒ ::String

Returns the string without the Ruby namespace of the class

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.demodulize('Hanami::Utils::String') # => 'String'

Hanami::Utils::String.demodulize('String') # => 'String'

Parameters:

  • input (::String)

    the input

Returns:

  • (::String)

    the transformed string

Since:

  • 1.1.0



273
274
275
# File 'lib/hanami/utils/string.rb', line 273

def self.demodulize(input)
  ::String.new(input.to_s).split(NAMESPACE_SEPARATOR).last
end

.namespace(input) ⇒ ::String

Returns the top level namespace name

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.namespace('Hanami::Utils::String') # => 'Hanami'

Hanami::Utils::String.namespace('String') # => 'String'

Parameters:

  • input (::String)

    the input

Returns:

  • (::String)

    the transformed string

Since:

  • 1.1.0



291
292
293
# File 'lib/hanami/utils/string.rb', line 291

def self.namespace(input)
  ::String.new(input.to_s).split(NAMESPACE_SEPARATOR).first
end

.rsub(input, pattern, replacement) ⇒ ::String

Replace the rightmost match of ‘pattern` with `replacement`

If the pattern cannot be matched, it returns the original string.

This method does NOT mutate the original string.

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.rsub('authors/books/index', %r{/}, '#')
  # => 'authors/books#index'

Parameters:

  • input (::String)

    the input

  • pattern (Regexp, ::String)

    the pattern to find

  • replacement (String)

    the string to replace

Returns:

  • (::String)

    the replaced string

Since:

  • 1.1.0



314
315
316
317
318
319
320
321
322
323
# File 'lib/hanami/utils/string.rb', line 314

def self.rsub(input, pattern, replacement)
  string = ::String.new(input.to_s)
  if i = string.rindex(pattern)
    s = string.dup
    s[i] = replacement
    s
  else
    string
  end
end

.titleize(input) ⇒ ::String

Returns a titleized version of the string

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.titleize('hanami utils') # => "Hanami Utils"

Parameters:

  • input (::String)

    the input

Returns:

  • (::String)

    the transformed string

Since:

  • 1.1.0



157
158
159
160
# File 'lib/hanami/utils/string.rb', line 157

def self.titleize(input)
  string = ::String.new(input.to_s)
  underscore(string).split(CLASSIFY_SEPARATOR).map(&:capitalize).join(TITLEIZE_SEPARATOR)
end

.transform(input, *transformations) ⇒ ::String

Applies the given transformation(s) to ‘input`

It performs a pipeline of transformations, by applying the given functions from ‘Hanami::Utils::String` and `::String`. The transformations are applied in the given order.

It doesn’t mutate the input, unless you use destructive methods from ‘::String`

Examples:

Basic usage

require "hanami/utils/string"

Hanami::Utils::String.transform("hanami/utils", :underscore, :classify)
  # => "Hanami::Utils"

Hanami::Utils::String.transform("Hanami::Utils::String", [:gsub, /[aeiouy]/, "*"], :demodulize)
  # => "H*n*m*"

Hanami::Utils::String.transform("Hanami", ->(s) { s.upcase })
  # => "HANAMI"

Unkown transformation

require "hanami/utils/string"

Hanami::Utils::String.transform("Sakura", :foo)
  # => NoMethodError: undefined method `:foo' for "Sakura":String

Proc with arity not equal to 1

require "hanami/utils/string"

Hanami::Utils::String.transform("Cherry", -> { "blossom" }))
  # => ArgumentError: wrong number of arguments (given 1, expected 0)

Parameters:

  • input (::String)

    the string to be transformed

  • transformations (Array<Symbol,Proc,Array>)

    one or many transformations expressed as:

    * `Symbol` to reference a function from `Hanami::Utils::String` or `String`.
    * `Proc` an anonymous function that MUST accept one input
    * `Array` where the first element is a `Symbol` to reference a
      function from `Hanami::Utils::String` or `String` and the rest of
      the elements are the arguments to pass
    

Returns:

  • (::String)

    the result of the transformations

Raises:

  • (NoMethodError)

    if a ‘Hanami::Utils::String` and `::String` don’t respond to a given method name

  • (ArgumentError)

    if a Proc transformation has an arity not equal to 1

Since:

  • 1.1.0



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/hanami/utils/string.rb', line 121

def self.transform(input, *transformations)
  fn = @__transformations__.fetch_or_store(transformations.hash) do
    fns = Dry::Transformer::Function.new(->(object) { object })

    transformations.each do |transformation, *args|
      fns = fns.compose(
        if transformation.is_a?(Proc)
          transformation
        elsif contain?(transformation)
          self[transformation, *args]
        elsif input.respond_to?(transformation)
          ->(i) { i.public_send(transformation, *args) }
        else
          raise NoMethodError.new(%(undefined method `#{transformation.inspect}' for #{input.inspect}:#{input.class})) # rubocop:disable Layout/LineLength
        end
      )
    end

    fns
  end

  fn.call(input)
end

.underscore(input) ⇒ ::String

Returns a downcased and underscore separated version of the string

Revised version of ‘ActiveSupport::Inflector.underscore` implementation

Examples:

require 'hanami/utils/string'

Hanami::Utils::String.underscore('HanamiUtils') # => 'hanami_utils'

Parameters:

  • input (::String)

    the input

Returns:

  • (::String)

    the transformed string

See Also:

Since:

  • 1.1.0



228
229
230
231
232
233
234
235
236
# File 'lib/hanami/utils/string.rb', line 228

def self.underscore(input)
  string = ::String.new(input.to_s)
  string.gsub!(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
  string.gsub!(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
  string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, UNDERSCORE_DIVISION_TARGET)
  string.gsub!(/([a-z\d])([A-Z])/, UNDERSCORE_DIVISION_TARGET)
  string.gsub!(/[[:space:]]|-|\./, UNDERSCORE_DIVISION_TARGET)
  string.downcase
end