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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/README.md +5 -15
- data/hanami-utils.gemspec +19 -16
- data/lib/hanami-utils.rb +3 -1
- data/lib/hanami/interactor.rb +70 -36
- data/lib/hanami/logger.rb +13 -13
- data/lib/hanami/logger/colorizer.rb +10 -10
- data/lib/hanami/logger/filter.rb +74 -9
- data/lib/hanami/logger/formatter.rb +7 -7
- data/lib/hanami/middleware.rb +11 -0
- data/lib/hanami/utils.rb +12 -26
- data/lib/hanami/utils/basic_object.rb +7 -7
- data/lib/hanami/utils/blank.rb +9 -9
- data/lib/hanami/utils/callbacks.rb +24 -3
- data/lib/hanami/utils/class.rb +3 -56
- data/lib/hanami/utils/class_attribute.rb +23 -12
- data/lib/hanami/utils/class_attribute/attributes.rb +45 -0
- data/lib/hanami/utils/deprecation.rb +3 -1
- data/lib/hanami/utils/escape.rb +275 -271
- data/lib/hanami/utils/file_list.rb +24 -2
- data/lib/hanami/utils/files.rb +16 -22
- data/lib/hanami/utils/hash.rb +24 -363
- data/lib/hanami/utils/io.rb +2 -0
- data/lib/hanami/utils/json.rb +5 -3
- data/lib/hanami/utils/kernel.rb +22 -21
- data/lib/hanami/utils/load_paths.rb +6 -4
- data/lib/hanami/utils/path_prefix.rb +38 -6
- data/lib/hanami/utils/query_string.rb +1 -1
- data/lib/hanami/utils/shell_color.rb +9 -9
- data/lib/hanami/utils/string.rb +44 -470
- data/lib/hanami/utils/version.rb +3 -1
- metadata +30 -16
- data/lib/hanami/utils/duplicable.rb +0 -80
- data/lib/hanami/utils/inflector.rb +0 -494
data/lib/hanami/utils/io.rb
CHANGED
data/lib/hanami/utils/json.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
|
-
require
|
4
|
+
require "multi_json"
|
3
5
|
rescue LoadError
|
4
|
-
require
|
6
|
+
require "json"
|
5
7
|
end
|
6
8
|
|
7
9
|
module Hanami
|
@@ -41,7 +43,7 @@ module Hanami
|
|
41
43
|
end
|
42
44
|
# rubocop:enable Style/ClassVars
|
43
45
|
|
44
|
-
#
|
46
|
+
# Parses the given JSON paylod
|
45
47
|
#
|
46
48
|
# @param payload [String] a JSON payload
|
47
49
|
#
|
data/lib/hanami/utils/kernel.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "date"
|
5
|
+
require "time"
|
6
|
+
require "pathname"
|
7
|
+
require "bigdecimal"
|
8
|
+
require "hanami/utils"
|
9
|
+
require "hanami/utils/string"
|
8
10
|
|
9
11
|
unless defined?(Boolean)
|
10
|
-
#
|
12
|
+
# Defines top level constant Boolean, so it can be easily used by other libraries
|
11
13
|
# in coercions DSLs
|
12
14
|
#
|
13
15
|
# @since 0.3.0
|
@@ -26,11 +28,11 @@ module Hanami
|
|
26
28
|
# @api private
|
27
29
|
#
|
28
30
|
# @see Hanami::Utils::Kernel.Integer
|
29
|
-
NUMERIC_MATCHER = %r{\A([\d
|
31
|
+
NUMERIC_MATCHER = %r{\A([\d/.+iE]+|NaN|Infinity)\z}.freeze
|
30
32
|
|
31
33
|
# @since 0.8.0
|
32
34
|
# @api private
|
33
|
-
BOOLEAN_FALSE_STRING =
|
35
|
+
BOOLEAN_FALSE_STRING = "0"
|
34
36
|
|
35
37
|
# @since 0.8.0
|
36
38
|
# @api private
|
@@ -325,7 +327,7 @@ module Hanami
|
|
325
327
|
# # big complex represented as a string
|
326
328
|
# input = Complex(2, 3)
|
327
329
|
# Hanami::Utils::Kernel.Integer(input) # => TypeError
|
328
|
-
def self.Integer(arg)
|
330
|
+
def self.Integer(arg)
|
329
331
|
super(arg)
|
330
332
|
rescue ArgumentError, TypeError, NoMethodError
|
331
333
|
begin
|
@@ -416,7 +418,6 @@ module Hanami
|
|
416
418
|
# input = BasicObject.new
|
417
419
|
# Hanami::Utils::Kernel.BigDecimal(input) # => TypeError
|
418
420
|
#
|
419
|
-
# rubocop:disable Metrics/MethodLength
|
420
421
|
def self.BigDecimal(arg, precision = ::Float::DIG)
|
421
422
|
case arg
|
422
423
|
when NilClass # This is only needed by Ruby 2.6
|
@@ -433,7 +434,6 @@ module Hanami
|
|
433
434
|
rescue NoMethodError
|
434
435
|
raise TypeError.new "can't convert #{inspect_type_error(arg)}into BigDecimal"
|
435
436
|
end
|
436
|
-
# rubocop:enable Metrics/MethodLength
|
437
437
|
|
438
438
|
# Coerces the argument to be a Float.
|
439
439
|
#
|
@@ -547,7 +547,7 @@ module Hanami
|
|
547
547
|
# # big complex represented as a string
|
548
548
|
# input = Complex(2, 3)
|
549
549
|
# Hanami::Utils::Kernel.Float(input) # => TypeError
|
550
|
-
def self.Float(arg)
|
550
|
+
def self.Float(arg)
|
551
551
|
super(arg)
|
552
552
|
rescue ArgumentError, TypeError
|
553
553
|
begin
|
@@ -736,7 +736,8 @@ module Hanami
|
|
736
736
|
# require 'hanami/utils/kernel'
|
737
737
|
#
|
738
738
|
# Hanami::Utils::Kernel.DateTime(3483943)
|
739
|
-
# # => Time.at(3483943).to_datetime
|
739
|
+
# # => Time.at(3483943).to_datetime
|
740
|
+
# # #<DateTime: 1970-02-10T08:45:43+01:00 ((2440628j,27943s,0n),+3600s,2299161j)>
|
740
741
|
#
|
741
742
|
# Hanami::Utils::Kernel.DateTime(DateTime.now)
|
742
743
|
# # => #<DateTime: 2014-04-18T09:33:49+02:00 ((2456766j,27229s,690849000n),+7200s,2299161j)>
|
@@ -896,7 +897,7 @@ module Hanami
|
|
896
897
|
# # Missing #respond_to?
|
897
898
|
# input = BasicObject.new
|
898
899
|
# Hanami::Utils::Kernel.Boolean(input) # => TypeError
|
899
|
-
def self.Boolean(arg)
|
900
|
+
def self.Boolean(arg)
|
900
901
|
case arg
|
901
902
|
when Numeric
|
902
903
|
arg.to_i == BOOLEAN_TRUE_INTEGER
|
@@ -1012,7 +1013,7 @@ module Hanami
|
|
1012
1013
|
# Hanami::Utils::Kernel.Symbol(input) # => TypeError
|
1013
1014
|
def self.Symbol(arg)
|
1014
1015
|
case arg
|
1015
|
-
when
|
1016
|
+
when "" then raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
|
1016
1017
|
when ->(a) { a.respond_to?(:to_sym) } then arg.to_sym
|
1017
1018
|
else
|
1018
1019
|
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
|
@@ -1021,7 +1022,7 @@ module Hanami
|
|
1021
1022
|
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
|
1022
1023
|
end
|
1023
1024
|
|
1024
|
-
#
|
1025
|
+
# Checks if the given argument is a string representation of a number
|
1025
1026
|
#
|
1026
1027
|
# @param arg [Object] the input
|
1027
1028
|
#
|
@@ -1042,11 +1043,11 @@ module Hanami
|
|
1042
1043
|
# @since 0.4.3
|
1043
1044
|
# @api private
|
1044
1045
|
def self.inspect_type_error(arg)
|
1045
|
-
(arg.respond_to?(:inspect) ? arg.inspect : arg.to_s)
|
1046
|
+
"#{(arg.respond_to?(:inspect) ? arg.inspect : arg.to_s)} "
|
1046
1047
|
rescue NoMethodError
|
1047
1048
|
# missing the #respond_to? method, fall back to returning the class' name
|
1048
1049
|
begin
|
1049
|
-
arg.class.name
|
1050
|
+
"#{arg.class.name} instance "
|
1050
1051
|
rescue NoMethodError
|
1051
1052
|
# missing the #class method, can't fall back to anything better than nothing
|
1052
1053
|
# Callers will have to guess from their code
|
@@ -1055,7 +1056,7 @@ module Hanami
|
|
1055
1056
|
end
|
1056
1057
|
|
1057
1058
|
class << self
|
1058
|
-
private :inspect_type_error
|
1059
|
+
private :inspect_type_error
|
1059
1060
|
end
|
1060
1061
|
end
|
1061
1062
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/utils/kernel"
|
2
4
|
|
3
5
|
module Hanami
|
4
6
|
module Utils
|
@@ -48,7 +50,7 @@ module Hanami
|
|
48
50
|
@paths = original.instance_variable_get(:@paths).dup
|
49
51
|
end
|
50
52
|
|
51
|
-
# Iterates
|
53
|
+
# Iterates through the collection and yields the given block.
|
52
54
|
# It skips duplications and raises an error in case one of the paths
|
53
55
|
# doesn't exist.
|
54
56
|
#
|
@@ -115,7 +117,7 @@ module Hanami
|
|
115
117
|
self
|
116
118
|
end
|
117
119
|
|
118
|
-
|
120
|
+
alias_method :<<, :push
|
119
121
|
|
120
122
|
# It freezes the object by preventing further modifications.
|
121
123
|
#
|
@@ -156,7 +158,7 @@ module Hanami
|
|
156
158
|
|
157
159
|
private
|
158
160
|
|
159
|
-
#
|
161
|
+
# Allows subclasses to define their own policy to discover the realpath
|
160
162
|
# of the given path.
|
161
163
|
#
|
162
164
|
# @since 0.2.0
|
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/utils/kernel"
|
3
4
|
|
4
5
|
module Hanami
|
5
6
|
module Utils
|
6
7
|
# Prefixed string
|
7
8
|
#
|
8
9
|
# @since 0.1.0
|
9
|
-
class PathPrefix
|
10
|
+
class PathPrefix
|
10
11
|
# Path separator
|
11
12
|
#
|
12
13
|
# @since 0.3.1
|
13
14
|
# @api private
|
14
|
-
DEFAULT_SEPARATOR =
|
15
|
+
DEFAULT_SEPARATOR = "/"
|
15
16
|
|
16
17
|
# Initialize the path prefix
|
17
18
|
#
|
@@ -24,7 +25,7 @@ module Hanami
|
|
24
25
|
#
|
25
26
|
# @see Hanami::Utils::PathPrefix::DEFAULT_SEPARATOR
|
26
27
|
def initialize(string = nil, separator = DEFAULT_SEPARATOR)
|
27
|
-
|
28
|
+
@string = string.to_s
|
28
29
|
@separator = separator
|
29
30
|
end
|
30
31
|
|
@@ -91,6 +92,37 @@ module Hanami
|
|
91
92
|
).relative!
|
92
93
|
end
|
93
94
|
|
95
|
+
# Returns the hash of the internal string
|
96
|
+
#
|
97
|
+
# @return [Integer]
|
98
|
+
#
|
99
|
+
# @since 0.3.0
|
100
|
+
def hash
|
101
|
+
@string.hash
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns a string representation
|
105
|
+
#
|
106
|
+
# @return [::String]
|
107
|
+
#
|
108
|
+
# @since 0.3.0
|
109
|
+
def to_s
|
110
|
+
@string
|
111
|
+
end
|
112
|
+
|
113
|
+
alias_method :to_str, :to_s
|
114
|
+
|
115
|
+
# Equality
|
116
|
+
#
|
117
|
+
# @return [TrueClass,FalseClass]
|
118
|
+
#
|
119
|
+
# @since 0.3.0
|
120
|
+
def ==(other)
|
121
|
+
to_s == other
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :eql?, :==
|
125
|
+
|
94
126
|
protected
|
95
127
|
|
96
128
|
# Modifies the path prefix to have a prepended separator.
|
@@ -133,7 +165,7 @@ module Hanami
|
|
133
165
|
# @see #relative
|
134
166
|
def relative!
|
135
167
|
@string.gsub!(/(?<!:)#{separator * 2}/, separator)
|
136
|
-
@string[/\A#{separator}|^/] =
|
168
|
+
@string[/\A#{separator}|^/] = ""
|
137
169
|
|
138
170
|
self
|
139
171
|
end
|
@@ -18,22 +18,22 @@ module Hanami
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
#
|
21
|
+
# Escapes codes for terminals to output strings in colors
|
22
22
|
#
|
23
23
|
# @since 1.2.0
|
24
24
|
# @api private
|
25
25
|
COLORS = ::Hash[
|
26
|
-
black:
|
27
|
-
red:
|
28
|
-
green:
|
29
|
-
yellow:
|
30
|
-
blue:
|
26
|
+
black: 30,
|
27
|
+
red: 31,
|
28
|
+
green: 32,
|
29
|
+
yellow: 33,
|
30
|
+
blue: 34,
|
31
31
|
magenta: 35,
|
32
|
-
cyan:
|
33
|
-
gray:
|
32
|
+
cyan: 36,
|
33
|
+
gray: 37,
|
34
34
|
].freeze
|
35
35
|
|
36
|
-
#
|
36
|
+
# Colorizes output
|
37
37
|
# 8 colors available: black, red, green, yellow, blue, magenta, cyan, and gray
|
38
38
|
#
|
39
39
|
# @param input [#to_s] the string to colorize
|
data/lib/hanami/utils/string.rb
CHANGED
@@ -1,87 +1,76 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/transformer"
|
4
|
+
require "concurrent/map"
|
4
5
|
|
5
6
|
module Hanami
|
6
7
|
module Utils
|
7
|
-
# String
|
8
|
+
# String utilities
|
8
9
|
#
|
9
10
|
# @since 0.1.0
|
10
|
-
|
11
|
+
module String
|
11
12
|
# Empty string for #classify
|
12
13
|
#
|
13
14
|
# @since 0.6.0
|
14
15
|
# @api private
|
15
|
-
EMPTY_STRING =
|
16
|
+
EMPTY_STRING = ""
|
16
17
|
|
17
18
|
# Separator between Ruby namespaces
|
18
19
|
#
|
19
20
|
# @since 0.1.0
|
20
21
|
# @api private
|
21
|
-
NAMESPACE_SEPARATOR =
|
22
|
+
NAMESPACE_SEPARATOR = "::"
|
22
23
|
|
23
24
|
# Separator for #classify
|
24
25
|
#
|
25
26
|
# @since 0.3.0
|
26
27
|
# @api private
|
27
|
-
CLASSIFY_SEPARATOR =
|
28
|
-
|
29
|
-
# Regexp for #tokenize
|
30
|
-
#
|
31
|
-
# @since 0.3.0
|
32
|
-
# @api private
|
33
|
-
TOKENIZE_REGEXP = /\((.*)\)/.freeze
|
34
|
-
|
35
|
-
# Separator for #tokenize
|
36
|
-
#
|
37
|
-
# @since 0.3.0
|
38
|
-
# @api private
|
39
|
-
TOKENIZE_SEPARATOR = '|'.freeze
|
28
|
+
CLASSIFY_SEPARATOR = "_"
|
40
29
|
|
41
30
|
# Separator for #underscore
|
42
31
|
#
|
43
32
|
# @since 0.3.0
|
44
33
|
# @api private
|
45
|
-
UNDERSCORE_SEPARATOR =
|
34
|
+
UNDERSCORE_SEPARATOR = "/"
|
46
35
|
|
47
36
|
# gsub second parameter used in #underscore
|
48
37
|
#
|
49
38
|
# @since 0.3.0
|
50
39
|
# @api private
|
51
|
-
UNDERSCORE_DIVISION_TARGET = '\1_\2'
|
40
|
+
UNDERSCORE_DIVISION_TARGET = '\1_\2'
|
52
41
|
|
53
42
|
# Separator for #titleize
|
54
43
|
#
|
55
44
|
# @since 0.4.0
|
56
45
|
# @api private
|
57
|
-
TITLEIZE_SEPARATOR =
|
46
|
+
TITLEIZE_SEPARATOR = " "
|
58
47
|
|
59
48
|
# Separator for #capitalize
|
60
49
|
#
|
61
50
|
# @since 0.5.2
|
62
51
|
# @api private
|
63
|
-
CAPITALIZE_SEPARATOR =
|
52
|
+
CAPITALIZE_SEPARATOR = " "
|
64
53
|
|
65
54
|
# Separator for #dasherize
|
66
55
|
#
|
67
56
|
# @since 0.4.0
|
68
57
|
# @api private
|
69
|
-
DASHERIZE_SEPARATOR =
|
58
|
+
DASHERIZE_SEPARATOR = "-"
|
70
59
|
|
71
60
|
# Regexp for #classify
|
72
61
|
#
|
73
62
|
# @since 0.3.4
|
74
63
|
# @api private
|
75
|
-
CLASSIFY_WORD_SEPARATOR = /#{CLASSIFY_SEPARATOR}|#{NAMESPACE_SEPARATOR}|#{UNDERSCORE_SEPARATOR}|#{DASHERIZE_SEPARATOR}/.freeze
|
64
|
+
CLASSIFY_WORD_SEPARATOR = /#{CLASSIFY_SEPARATOR}|#{NAMESPACE_SEPARATOR}|#{UNDERSCORE_SEPARATOR}|#{DASHERIZE_SEPARATOR}/.freeze # rubocop:disable Layout/LineLength
|
76
65
|
|
77
66
|
@__transformations__ = Concurrent::Map.new
|
78
67
|
|
79
|
-
extend
|
80
|
-
extend Transproc::Composer
|
68
|
+
extend Dry::Transformer::Registry
|
81
69
|
|
82
|
-
#
|
70
|
+
# Applies the given transformation(s) to `input`
|
83
71
|
#
|
84
|
-
# It performs a pipeline of transformations, by applying the given
|
72
|
+
# It performs a pipeline of transformations, by applying the given
|
73
|
+
# functions from `Hanami::Utils::String` and `::String`.
|
85
74
|
# The transformations are applied in the given order.
|
86
75
|
#
|
87
76
|
# It doesn't mutate the input, unless you use destructive methods from `::String`
|
@@ -129,42 +118,31 @@ module Hanami
|
|
129
118
|
# Hanami::Utils::String.transform("Cherry", -> { "blossom" }))
|
130
119
|
# # => ArgumentError: wrong number of arguments (given 1, expected 0)
|
131
120
|
#
|
132
|
-
# rubocop:disable Metrics/AbcSize
|
133
|
-
# rubocop:disable Metrics/MethodLength
|
134
121
|
def self.transform(input, *transformations)
|
135
122
|
fn = @__transformations__.fetch_or_store(transformations.hash) do
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
123
|
+
fns = Dry::Transformer::Function.new(->(object) { object })
|
124
|
+
|
125
|
+
transformations.each do |transformation, *args|
|
126
|
+
fns = fns.compose(
|
127
|
+
if transformation.is_a?(Proc)
|
128
|
+
transformation
|
129
|
+
elsif contain?(transformation)
|
130
|
+
self[transformation, *args]
|
131
|
+
elsif input.respond_to?(transformation)
|
132
|
+
->(i) { i.public_send(transformation, *args) }
|
133
|
+
else
|
134
|
+
raise NoMethodError.new(%(undefined method `#{transformation.inspect}' for #{input.inspect}:#{input.class})) # rubocop:disable Layout/LineLength
|
135
|
+
end
|
136
|
+
)
|
148
137
|
end
|
138
|
+
|
139
|
+
fns
|
149
140
|
end
|
150
141
|
|
151
142
|
fn.call(input)
|
152
143
|
end
|
153
|
-
# rubocop:enable Metrics/MethodLength
|
154
|
-
# rubocop:enable Metrics/AbcSize
|
155
|
-
|
156
|
-
# Extracted from `transproc` source code
|
157
|
-
#
|
158
|
-
# `transproc` is Copyright 2014 by Piotr Solnica (piotr.solnica@gmail.com),
|
159
|
-
# released under the MIT License
|
160
|
-
#
|
161
|
-
# @since 1.1.0
|
162
|
-
# @api private
|
163
|
-
def self.bind(value, binding, fun)
|
164
|
-
binding.instance_exec(value, &fun)
|
165
|
-
end
|
166
144
|
|
167
|
-
#
|
145
|
+
# Returns a titleized version of the string
|
168
146
|
#
|
169
147
|
# @param input [::String] the input
|
170
148
|
#
|
@@ -181,7 +159,7 @@ module Hanami
|
|
181
159
|
underscore(string).split(CLASSIFY_SEPARATOR).map(&:capitalize).join(TITLEIZE_SEPARATOR)
|
182
160
|
end
|
183
161
|
|
184
|
-
#
|
162
|
+
# Returns a capitalized version of the string
|
185
163
|
#
|
186
164
|
# @param input [::String] the input
|
187
165
|
#
|
@@ -208,7 +186,7 @@ module Hanami
|
|
208
186
|
tail.unshift(head.capitalize).join(CAPITALIZE_SEPARATOR)
|
209
187
|
end
|
210
188
|
|
211
|
-
#
|
189
|
+
# Returns a CamelCase version of the string
|
212
190
|
#
|
213
191
|
# @param input [::String] the input
|
214
192
|
#
|
@@ -232,7 +210,7 @@ module Hanami
|
|
232
210
|
words.zip(delimiters).join
|
233
211
|
end
|
234
212
|
|
235
|
-
#
|
213
|
+
# Returns a downcased and underscore separated version of the string
|
236
214
|
#
|
237
215
|
# Revised version of `ActiveSupport::Inflector.underscore` implementation
|
238
216
|
# @see https://github.com/rails/rails/blob/feaa6e2048fe86bcf07e967d6e47b865e42e055b/activesupport/lib/active_support/inflector/methods.rb#L90
|
@@ -253,11 +231,11 @@ module Hanami
|
|
253
231
|
string.gsub!(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
|
254
232
|
string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, UNDERSCORE_DIVISION_TARGET)
|
255
233
|
string.gsub!(/([a-z\d])([A-Z])/, UNDERSCORE_DIVISION_TARGET)
|
256
|
-
string.gsub!(/[[:space:]]
|
234
|
+
string.gsub!(/[[:space:]]|-/, UNDERSCORE_DIVISION_TARGET)
|
257
235
|
string.downcase
|
258
236
|
end
|
259
237
|
|
260
|
-
#
|
238
|
+
# Returns a downcased and dash separated version of the string
|
261
239
|
#
|
262
240
|
# @param input [::String] the input
|
263
241
|
#
|
@@ -278,7 +256,7 @@ module Hanami
|
|
278
256
|
underscore(string).split(CLASSIFY_SEPARATOR).join(DASHERIZE_SEPARATOR)
|
279
257
|
end
|
280
258
|
|
281
|
-
#
|
259
|
+
# Returns the string without the Ruby namespace of the class
|
282
260
|
#
|
283
261
|
# @param input [::String] the input
|
284
262
|
#
|
@@ -296,7 +274,7 @@ module Hanami
|
|
296
274
|
::String.new(input.to_s).split(NAMESPACE_SEPARATOR).last
|
297
275
|
end
|
298
276
|
|
299
|
-
#
|
277
|
+
# Returns the top level namespace name
|
300
278
|
#
|
301
279
|
# @param input [::String] the input
|
302
280
|
#
|
@@ -314,46 +292,6 @@ module Hanami
|
|
314
292
|
::String.new(input.to_s).split(NAMESPACE_SEPARATOR).first
|
315
293
|
end
|
316
294
|
|
317
|
-
# Return a pluralized version of self.
|
318
|
-
#
|
319
|
-
# @param input [::String] the input
|
320
|
-
#
|
321
|
-
# @return [::String] the pluralized string.
|
322
|
-
#
|
323
|
-
# @since 1.1.0
|
324
|
-
#
|
325
|
-
# @see Hanami::Utils::Inflector
|
326
|
-
# @deprecated
|
327
|
-
#
|
328
|
-
# @example
|
329
|
-
# require 'hanami/utils/string'
|
330
|
-
#
|
331
|
-
# Hanami::Utils::String.pluralize('book') # => 'books'
|
332
|
-
def self.pluralize(input)
|
333
|
-
string = ::String.new(input.to_s)
|
334
|
-
Inflector.pluralize(string)
|
335
|
-
end
|
336
|
-
|
337
|
-
# Return a singularized version of self.
|
338
|
-
#
|
339
|
-
# @param input [::String] the input
|
340
|
-
#
|
341
|
-
# @return [::String] the singularized string.
|
342
|
-
#
|
343
|
-
# @since 1.1.0
|
344
|
-
# @deprecated
|
345
|
-
#
|
346
|
-
# @see Hanami::Utils::Inflector
|
347
|
-
#
|
348
|
-
# @example
|
349
|
-
# require 'hanami/utils/string'
|
350
|
-
#
|
351
|
-
# Hanami::Utils::String.singularize('books') # => 'book'
|
352
|
-
def self.singularize(input)
|
353
|
-
string = ::String.new(input.to_s)
|
354
|
-
Inflector.singularize(string)
|
355
|
-
end
|
356
|
-
|
357
295
|
# Replace the rightmost match of `pattern` with `replacement`
|
358
296
|
#
|
359
297
|
# If the pattern cannot be matched, it returns the original string.
|
@@ -375,7 +313,7 @@ module Hanami
|
|
375
313
|
# # => 'authors/books#index'
|
376
314
|
def self.rsub(input, pattern, replacement)
|
377
315
|
string = ::String.new(input.to_s)
|
378
|
-
if i = string.rindex(pattern)
|
316
|
+
if i = string.rindex(pattern)
|
379
317
|
s = string.dup
|
380
318
|
s[i] = replacement
|
381
319
|
s
|
@@ -383,370 +321,6 @@ module Hanami
|
|
383
321
|
string
|
384
322
|
end
|
385
323
|
end
|
386
|
-
|
387
|
-
# Initialize the string
|
388
|
-
#
|
389
|
-
# @param string [::String, Symbol] the value we want to initialize
|
390
|
-
#
|
391
|
-
# @return [Hanami::Utils::String] self
|
392
|
-
#
|
393
|
-
# @since 0.1.0
|
394
|
-
# @deprecated
|
395
|
-
def initialize(string)
|
396
|
-
@string = string.to_s
|
397
|
-
end
|
398
|
-
|
399
|
-
# Return a titleized version of the string
|
400
|
-
#
|
401
|
-
# @return [Hanami::Utils::String] the transformed string
|
402
|
-
#
|
403
|
-
# @since 0.4.0
|
404
|
-
# @deprecated Use {Hanami::Utils::String.titleize}
|
405
|
-
#
|
406
|
-
# @example
|
407
|
-
# require 'hanami/utils/string'
|
408
|
-
#
|
409
|
-
# string = Hanami::Utils::String.new 'hanami utils'
|
410
|
-
# string.titleize # => "Hanami Utils"
|
411
|
-
def titleize
|
412
|
-
self.class.new underscore.split(CLASSIFY_SEPARATOR).map(&:capitalize).join(TITLEIZE_SEPARATOR)
|
413
|
-
end
|
414
|
-
|
415
|
-
# Return a capitalized version of the string
|
416
|
-
#
|
417
|
-
# @return [Hanami::Utils::String] the transformed string
|
418
|
-
#
|
419
|
-
# @since 0.5.2
|
420
|
-
# @deprecated Use {Hanami::Utils::String.capitalize}
|
421
|
-
#
|
422
|
-
# @example
|
423
|
-
# require 'hanami/utils/string'
|
424
|
-
#
|
425
|
-
# string = Hanami::Utils::String.new 'hanami'
|
426
|
-
# string.capitalize # => "Hanami"
|
427
|
-
#
|
428
|
-
# string = Hanami::Utils::String.new 'hanami utils'
|
429
|
-
# string.capitalize # => "Hanami utils"
|
430
|
-
#
|
431
|
-
# string = Hanami::Utils::String.new 'Hanami Utils'
|
432
|
-
# string.capitalize # => "Hanami utils"
|
433
|
-
#
|
434
|
-
# string = Hanami::Utils::String.new 'hanami_utils'
|
435
|
-
# string.capitalize # => "Hanami utils"
|
436
|
-
#
|
437
|
-
# string = Hanami::Utils::String.new 'hanami-utils'
|
438
|
-
# string.capitalize # => "Hanami utils"
|
439
|
-
def capitalize
|
440
|
-
head, *tail = underscore.split(CLASSIFY_SEPARATOR)
|
441
|
-
|
442
|
-
self.class.new(
|
443
|
-
tail.unshift(head.capitalize).join(CAPITALIZE_SEPARATOR)
|
444
|
-
)
|
445
|
-
end
|
446
|
-
|
447
|
-
# Return a CamelCase version of the string
|
448
|
-
#
|
449
|
-
# @return [Hanami::Utils::String] the transformed string
|
450
|
-
#
|
451
|
-
# @since 0.1.0
|
452
|
-
# @deprecated Use {Hanami::Utils::String.classify}
|
453
|
-
#
|
454
|
-
# @example
|
455
|
-
# require 'hanami/utils/string'
|
456
|
-
#
|
457
|
-
# string = Hanami::Utils::String.new 'hanami_utils'
|
458
|
-
# string.classify # => 'HanamiUtils'
|
459
|
-
def classify
|
460
|
-
words = underscore.split(CLASSIFY_WORD_SEPARATOR).map!(&:capitalize)
|
461
|
-
delimiters = underscore.scan(CLASSIFY_WORD_SEPARATOR)
|
462
|
-
|
463
|
-
delimiters.map! do |delimiter|
|
464
|
-
delimiter == CLASSIFY_SEPARATOR ? EMPTY_STRING : NAMESPACE_SEPARATOR
|
465
|
-
end
|
466
|
-
|
467
|
-
self.class.new words.zip(delimiters).join
|
468
|
-
end
|
469
|
-
|
470
|
-
# Return a downcased and underscore separated version of the string
|
471
|
-
#
|
472
|
-
# Revised version of `ActiveSupport::Inflector.underscore` implementation
|
473
|
-
# @see https://github.com/rails/rails/blob/feaa6e2048fe86bcf07e967d6e47b865e42e055b/activesupport/lib/active_support/inflector/methods.rb#L90
|
474
|
-
#
|
475
|
-
# @return [Hanami::Utils::String] the transformed string
|
476
|
-
# @deprecated Use {Hanami::Utils::String.underscore}
|
477
|
-
#
|
478
|
-
# @since 0.1.0
|
479
|
-
#
|
480
|
-
# @example
|
481
|
-
# require 'hanami/utils/string'
|
482
|
-
#
|
483
|
-
# string = Hanami::Utils::String.new 'HanamiUtils'
|
484
|
-
# string.underscore # => 'hanami_utils'
|
485
|
-
def underscore
|
486
|
-
new_string = gsub(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
|
487
|
-
new_string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, UNDERSCORE_DIVISION_TARGET)
|
488
|
-
new_string.gsub!(/([a-z\d])([A-Z])/, UNDERSCORE_DIVISION_TARGET)
|
489
|
-
new_string.gsub!(/[[:space:]]|\-/, UNDERSCORE_DIVISION_TARGET)
|
490
|
-
new_string.downcase!
|
491
|
-
self.class.new new_string
|
492
|
-
end
|
493
|
-
|
494
|
-
# Return a downcased and dash separated version of the string
|
495
|
-
#
|
496
|
-
# @return [Hanami::Utils::String] the transformed string
|
497
|
-
#
|
498
|
-
# @since 0.4.0
|
499
|
-
# @deprecated Use {Hanami::Utils::String.dasherize}
|
500
|
-
#
|
501
|
-
# @example
|
502
|
-
# require 'hanami/utils/string'
|
503
|
-
#
|
504
|
-
# string = Hanami::Utils::String.new 'Hanami Utils'
|
505
|
-
# string.dasherize # => 'hanami-utils'
|
506
|
-
#
|
507
|
-
# string = Hanami::Utils::String.new 'hanami_utils'
|
508
|
-
# string.dasherize # => 'hanami-utils'
|
509
|
-
#
|
510
|
-
# string = Hanami::Utils::String.new 'HanamiUtils'
|
511
|
-
# string.dasherize # => "hanami-utils"
|
512
|
-
def dasherize
|
513
|
-
self.class.new underscore.split(CLASSIFY_SEPARATOR).join(DASHERIZE_SEPARATOR)
|
514
|
-
end
|
515
|
-
|
516
|
-
# Return the string without the Ruby namespace of the class
|
517
|
-
#
|
518
|
-
# @return [Hanami::Utils::String] the transformed string
|
519
|
-
#
|
520
|
-
# @since 0.1.0
|
521
|
-
# @deprecated Use {Hanami::Utils::String.demodulize}
|
522
|
-
#
|
523
|
-
# @example
|
524
|
-
# require 'hanami/utils/string'
|
525
|
-
#
|
526
|
-
# string = Hanami::Utils::String.new 'Hanami::Utils::String'
|
527
|
-
# string.demodulize # => 'String'
|
528
|
-
#
|
529
|
-
# string = Hanami::Utils::String.new 'String'
|
530
|
-
# string.demodulize # => 'String'
|
531
|
-
def demodulize
|
532
|
-
self.class.new split(NAMESPACE_SEPARATOR).last
|
533
|
-
end
|
534
|
-
|
535
|
-
# Return the top level namespace name
|
536
|
-
#
|
537
|
-
# @return [Hanami::Utils::String] the transformed string
|
538
|
-
#
|
539
|
-
# @since 0.1.2
|
540
|
-
# @deprecated Use {Hanami::Utils::String.namespace}
|
541
|
-
#
|
542
|
-
# @example
|
543
|
-
# require 'hanami/utils/string'
|
544
|
-
#
|
545
|
-
# string = Hanami::Utils::String.new 'Hanami::Utils::String'
|
546
|
-
# string.namespace # => 'Hanami'
|
547
|
-
#
|
548
|
-
# string = Hanami::Utils::String.new 'String'
|
549
|
-
# string.namespace # => 'String'
|
550
|
-
def namespace
|
551
|
-
self.class.new split(NAMESPACE_SEPARATOR).first
|
552
|
-
end
|
553
|
-
|
554
|
-
# It iterates through the tokens and calls the given block.
|
555
|
-
# A token is a substring wrapped by `()` and separated by `|`.
|
556
|
-
#
|
557
|
-
# @yield the block that is called for each token.
|
558
|
-
#
|
559
|
-
# @return [void]
|
560
|
-
#
|
561
|
-
# @since 0.1.0
|
562
|
-
# @deprecated
|
563
|
-
#
|
564
|
-
# @example
|
565
|
-
# require 'hanami/utils/string'
|
566
|
-
#
|
567
|
-
# string = Hanami::Utils::String.new 'Hanami::(Utils|App)'
|
568
|
-
# string.tokenize do |token|
|
569
|
-
# puts token
|
570
|
-
# end
|
571
|
-
#
|
572
|
-
# # =>
|
573
|
-
# 'Hanami::Utils'
|
574
|
-
# 'Hanami::App'
|
575
|
-
#
|
576
|
-
# rubocop:disable Metrics/MethodLength
|
577
|
-
def tokenize
|
578
|
-
if match = TOKENIZE_REGEXP.match(@string) # rubocop:disable Lint/AssignmentInCondition
|
579
|
-
pre = match.pre_match
|
580
|
-
post = match.post_match
|
581
|
-
tokens = match[1].split(TOKENIZE_SEPARATOR)
|
582
|
-
tokens.each do |token|
|
583
|
-
yield(self.class.new("#{pre}#{token}#{post}"))
|
584
|
-
end
|
585
|
-
else
|
586
|
-
yield(self.class.new(@string))
|
587
|
-
end
|
588
|
-
|
589
|
-
nil
|
590
|
-
end
|
591
|
-
# rubocop:enable Metrics/MethodLength
|
592
|
-
|
593
|
-
# Return a pluralized version of self.
|
594
|
-
#
|
595
|
-
# @return [Hanami::Utils::String] the pluralized string.
|
596
|
-
#
|
597
|
-
# @api private
|
598
|
-
# @since 0.4.1
|
599
|
-
# @deprecated
|
600
|
-
#
|
601
|
-
# @see Hanami::Utils::Inflector
|
602
|
-
def pluralize
|
603
|
-
self.class.new Inflector.pluralize(self)
|
604
|
-
end
|
605
|
-
|
606
|
-
# Return a singularized version of self.
|
607
|
-
#
|
608
|
-
# @return [Hanami::Utils::String] the singularized string.
|
609
|
-
#
|
610
|
-
# @api private
|
611
|
-
# @since 0.4.1
|
612
|
-
# @deprecated
|
613
|
-
#
|
614
|
-
# @see Hanami::Utils::Inflector
|
615
|
-
def singularize
|
616
|
-
self.class.new Inflector.singularize(self)
|
617
|
-
end
|
618
|
-
|
619
|
-
# Returns the hash of the internal string
|
620
|
-
#
|
621
|
-
# @return [Integer]
|
622
|
-
#
|
623
|
-
# @since 0.3.0
|
624
|
-
# @deprecated
|
625
|
-
def hash
|
626
|
-
@string.hash
|
627
|
-
end
|
628
|
-
|
629
|
-
# Returns a string representation
|
630
|
-
#
|
631
|
-
# @return [::String]
|
632
|
-
#
|
633
|
-
# @since 0.3.0
|
634
|
-
# @deprecated
|
635
|
-
def to_s
|
636
|
-
@string
|
637
|
-
end
|
638
|
-
|
639
|
-
alias to_str to_s
|
640
|
-
|
641
|
-
# Equality
|
642
|
-
#
|
643
|
-
# @return [TrueClass,FalseClass]
|
644
|
-
#
|
645
|
-
# @since 0.3.0
|
646
|
-
# @deprecated
|
647
|
-
def ==(other)
|
648
|
-
to_s == other
|
649
|
-
end
|
650
|
-
|
651
|
-
alias eql? ==
|
652
|
-
|
653
|
-
# Split the string with the given pattern
|
654
|
-
#
|
655
|
-
# @return [Array<::String>]
|
656
|
-
#
|
657
|
-
# @see http://www.ruby-doc.org/core/String.html#method-i-split
|
658
|
-
#
|
659
|
-
# @since 0.3.0
|
660
|
-
# @deprecated
|
661
|
-
def split(pattern, limit = 0)
|
662
|
-
@string.split(pattern, limit)
|
663
|
-
end
|
664
|
-
|
665
|
-
# Replace the given pattern with the given replacement
|
666
|
-
#
|
667
|
-
# @return [::String]
|
668
|
-
#
|
669
|
-
# @see http://www.ruby-doc.org/core/String.html#method-i-gsub
|
670
|
-
#
|
671
|
-
# @since 0.3.0
|
672
|
-
# @deprecated
|
673
|
-
def gsub(pattern, replacement = nil, &blk)
|
674
|
-
if block_given?
|
675
|
-
@string.gsub(pattern, &blk)
|
676
|
-
else
|
677
|
-
@string.gsub(pattern, replacement)
|
678
|
-
end
|
679
|
-
end
|
680
|
-
|
681
|
-
# Iterate through the string, matching the pattern.
|
682
|
-
# Either return all those patterns, or pass them to the block.
|
683
|
-
#
|
684
|
-
# @return [Array<::String>]
|
685
|
-
#
|
686
|
-
# @see http://www.ruby-doc.org/core/String.html#method-i-scan
|
687
|
-
#
|
688
|
-
# @since 0.6.0
|
689
|
-
# @deprecated
|
690
|
-
def scan(pattern, &blk)
|
691
|
-
@string.scan(pattern, &blk)
|
692
|
-
end
|
693
|
-
|
694
|
-
# Replace the rightmost match of `pattern` with `replacement`
|
695
|
-
#
|
696
|
-
# If the pattern cannot be matched, it returns the original string.
|
697
|
-
#
|
698
|
-
# This method does NOT mutate the original string.
|
699
|
-
#
|
700
|
-
# @param pattern [Regexp, String] the pattern to find
|
701
|
-
# @param replacement [String, Hanami::Utils::String] the string to replace
|
702
|
-
#
|
703
|
-
# @return [Hanami::Utils::String] the replaced string
|
704
|
-
#
|
705
|
-
# @since 0.6.0
|
706
|
-
# @deprecated Use {Hanami::Utils::String.rsub}
|
707
|
-
#
|
708
|
-
# @example
|
709
|
-
# require 'hanami/utils/string'
|
710
|
-
#
|
711
|
-
# string = Hanami::Utils::String.new('authors/books/index')
|
712
|
-
# result = string.rsub(/\//, '#')
|
713
|
-
#
|
714
|
-
# puts string
|
715
|
-
# # => #<Hanami::Utils::String:0x007fdb41233ad8 @string="authors/books/index">
|
716
|
-
#
|
717
|
-
# puts result
|
718
|
-
# # => #<Hanami::Utils::String:0x007fdb41232ed0 @string="authors/books#index">
|
719
|
-
def rsub(pattern, replacement)
|
720
|
-
if i = rindex(pattern) # rubocop:disable Lint/AssignmentInCondition
|
721
|
-
s = @string.dup
|
722
|
-
s[i] = replacement
|
723
|
-
self.class.new s
|
724
|
-
else
|
725
|
-
self
|
726
|
-
end
|
727
|
-
end
|
728
|
-
|
729
|
-
# Override Ruby's method_missing in order to provide ::String interface
|
730
|
-
#
|
731
|
-
# @api private
|
732
|
-
# @since 0.3.0
|
733
|
-
#
|
734
|
-
# @raise [NoMethodError] If doesn't respond to the given method
|
735
|
-
def method_missing(method_name, *args, &blk)
|
736
|
-
raise NoMethodError.new(%(undefined method `#{method_name}' for "#{@string}":#{self.class})) unless respond_to?(method_name)
|
737
|
-
|
738
|
-
s = @string.__send__(method_name, *args, &blk)
|
739
|
-
s = self.class.new(s) if s.is_a?(::String)
|
740
|
-
s
|
741
|
-
end
|
742
|
-
|
743
|
-
# Override Ruby's respond_to_missing? in order to support ::String interface
|
744
|
-
#
|
745
|
-
# @api private
|
746
|
-
# @since 0.3.0
|
747
|
-
def respond_to_missing?(method_name, include_private = false)
|
748
|
-
@string.respond_to?(method_name, include_private)
|
749
|
-
end
|
750
324
|
end
|
751
325
|
end
|
752
326
|
end
|