hanami-utils 2.0.0.alpha1 → 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 +4 -5
- data/hanami-utils.gemspec +5 -4
- data/lib/hanami/interactor.rb +64 -32
- data/lib/hanami/logger.rb +13 -13
- data/lib/hanami/logger/colorizer.rb +10 -10
- data/lib/hanami/logger/filter.rb +86 -10
- data/lib/hanami/logger/formatter.rb +4 -4
- data/lib/hanami/utils.rb +4 -4
- data/lib/hanami/utils/basic_object.rb +63 -3
- data/lib/hanami/utils/blank.rb +6 -6
- data/lib/hanami/utils/callbacks.rb +4 -2
- data/lib/hanami/utils/class.rb +1 -5
- data/lib/hanami/utils/escape.rb +172 -170
- data/lib/hanami/utils/file_list.rb +22 -2
- data/lib/hanami/utils/files.rb +13 -2
- data/lib/hanami/utils/hash.rb +20 -32
- data/lib/hanami/utils/json.rb +1 -1
- data/lib/hanami/utils/kernel.rb +12 -13
- data/lib/hanami/utils/load_paths.rb +3 -3
- data/lib/hanami/utils/path_prefix.rb +33 -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 +33 -394
- data/lib/hanami/utils/version.rb +1 -1
- metadata +28 -14
@@ -6,7 +6,7 @@ module Hanami
|
|
6
6
|
#
|
7
7
|
# @since 0.9.0
|
8
8
|
module FileList
|
9
|
-
#
|
9
|
+
# Returns an ordered list of files, consistent across operating systems
|
10
10
|
#
|
11
11
|
# It has the same signature of <tt>Dir.glob</tt>, it just guarantees to
|
12
12
|
# order the results before to return them.
|
@@ -14,8 +14,28 @@ module Hanami
|
|
14
14
|
# @since 0.9.0
|
15
15
|
#
|
16
16
|
# @see https://ruby-doc.org/core/Dir.html#method-c-glob
|
17
|
+
#
|
18
|
+
# @example simple usage
|
19
|
+
# require "hanami/utils/file_list"
|
20
|
+
#
|
21
|
+
# Hanami::Utils::FileList["spec/support/fixtures/file_list/*.rb"]
|
22
|
+
# # => [
|
23
|
+
# "spec/support/fixtures/file_list/a.rb",
|
24
|
+
# "spec/support/fixtures/file_list/aa.rb",
|
25
|
+
# "spec/support/fixtures/file_list/ab.rb"
|
26
|
+
# ]
|
27
|
+
#
|
28
|
+
# @example token usage
|
29
|
+
# require "hanami/utils/file_list"
|
30
|
+
#
|
31
|
+
# Hanami::Utils::FileList["spec", "support", "fixtures", "file_list", "*.rb"]
|
32
|
+
# # => [
|
33
|
+
# "spec/support/fixtures/file_list/a.rb",
|
34
|
+
# "spec/support/fixtures/file_list/aa.rb",
|
35
|
+
# "spec/support/fixtures/file_list/ab.rb"
|
36
|
+
# ]
|
17
37
|
def self.[](*args)
|
18
|
-
Dir.glob(*args).sort!
|
38
|
+
Dir.glob(::File.join(*args)).sort!
|
19
39
|
end
|
20
40
|
end
|
21
41
|
end
|
data/lib/hanami/utils/files.rb
CHANGED
@@ -147,6 +147,7 @@ module Hanami
|
|
147
147
|
mkdir_p(path)
|
148
148
|
|
149
149
|
content = ::File.readlines(path)
|
150
|
+
content << "\n" if _append_newline?(content)
|
150
151
|
content << "#{contents}\n"
|
151
152
|
|
152
153
|
write(path, content)
|
@@ -307,13 +308,13 @@ module Hanami
|
|
307
308
|
#
|
308
309
|
# # class App
|
309
310
|
# # end
|
310
|
-
def self.remove_block(path, target)
|
311
|
+
def self.remove_block(path, target)
|
311
312
|
content = ::File.readlines(path)
|
312
313
|
starting = index(content, path, target)
|
313
314
|
line = content[starting]
|
314
315
|
size = line[/\A[[:space:]]*/].bytesize
|
315
316
|
closing = (" " * size) + (/{/.match?(target) ? "}" : "end")
|
316
|
-
ending = starting + index(content[starting
|
317
|
+
ending = starting + index(content[starting..], path, closing)
|
317
318
|
|
318
319
|
content.slice!(starting..ending)
|
319
320
|
write(path, content)
|
@@ -435,6 +436,16 @@ module Hanami
|
|
435
436
|
end
|
436
437
|
|
437
438
|
private_class_method :line_number
|
439
|
+
|
440
|
+
# @since 1.3.6
|
441
|
+
# @api private
|
442
|
+
def self._append_newline?(content)
|
443
|
+
return false if content.empty?
|
444
|
+
|
445
|
+
!content.last.end_with?("\n")
|
446
|
+
end
|
447
|
+
|
448
|
+
private_class_method :_append_newline?
|
438
449
|
end
|
439
450
|
end
|
440
451
|
end
|
data/lib/hanami/utils/hash.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "dry-transformer"
|
4
4
|
|
5
5
|
module Hanami
|
6
6
|
module Utils
|
7
7
|
# Hash transformations
|
8
8
|
# @since 0.1.0
|
9
9
|
module Hash
|
10
|
-
extend
|
11
|
-
import
|
10
|
+
extend Dry::Transformer::Registry
|
11
|
+
import Dry::Transformer::HashTransformations
|
12
12
|
|
13
13
|
# Symbolize the given hash
|
14
14
|
#
|
@@ -32,7 +32,7 @@ module Hanami
|
|
32
32
|
self[:symbolize_keys].call(input)
|
33
33
|
end
|
34
34
|
|
35
|
-
#
|
35
|
+
# Performs deep symbolize on the given hash
|
36
36
|
#
|
37
37
|
# @param input [::Hash] the input
|
38
38
|
#
|
@@ -54,7 +54,7 @@ module Hanami
|
|
54
54
|
self[:deep_symbolize_keys].call(input)
|
55
55
|
end
|
56
56
|
|
57
|
-
#
|
57
|
+
# Stringifies the given hash
|
58
58
|
#
|
59
59
|
# @param input [::Hash] the input
|
60
60
|
#
|
@@ -74,7 +74,7 @@ module Hanami
|
|
74
74
|
self[:stringify_keys].call(input)
|
75
75
|
end
|
76
76
|
|
77
|
-
# Deeply
|
77
|
+
# Deeply stringifies the given hash
|
78
78
|
#
|
79
79
|
# @param input [::Hash] the input
|
80
80
|
#
|
@@ -90,31 +90,19 @@ module Hanami
|
|
90
90
|
#
|
91
91
|
# hash.class
|
92
92
|
# # => Hash
|
93
|
-
def self.deep_stringify(input)
|
94
|
-
|
95
|
-
output[key.to_s] =
|
96
|
-
case value
|
97
|
-
when ::Hash
|
98
|
-
deep_stringify(value)
|
99
|
-
when Array
|
100
|
-
value.map do |item|
|
101
|
-
item.is_a?(::Hash) ? deep_stringify(item) : item
|
102
|
-
end
|
103
|
-
else
|
104
|
-
value
|
105
|
-
end
|
106
|
-
end
|
93
|
+
def self.deep_stringify(input)
|
94
|
+
self[:deep_stringify_keys].call(input)
|
107
95
|
end
|
108
96
|
|
109
|
-
# Deep
|
97
|
+
# Deep duplicates hash values
|
110
98
|
#
|
111
|
-
# The output of this function is a
|
99
|
+
# The output of this function is a deep duplicate of the input.
|
112
100
|
# Any further modification on the input, won't be reflected on the output
|
113
101
|
# and viceversa.
|
114
102
|
#
|
115
103
|
# @param input [::Hash] the input
|
116
104
|
#
|
117
|
-
# @return [::Hash] the
|
105
|
+
# @return [::Hash] the deep duplicate of input
|
118
106
|
#
|
119
107
|
# @since 1.0.1
|
120
108
|
#
|
@@ -144,17 +132,17 @@ module Hanami
|
|
144
132
|
# input
|
145
133
|
# # => {"a"=>{"b"=>{"c"=>[1,2,3,4]}}}
|
146
134
|
def self.deep_dup(input)
|
147
|
-
input.
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
135
|
+
input.transform_values do |v|
|
136
|
+
case v
|
137
|
+
when ::Hash
|
138
|
+
deep_dup(v)
|
139
|
+
else
|
140
|
+
v.dup
|
141
|
+
end
|
154
142
|
end
|
155
143
|
end
|
156
144
|
|
157
|
-
# Deep
|
145
|
+
# Deep serializes given object into a `Hash`
|
158
146
|
#
|
159
147
|
# Please note that the returning `Hash` will use symbols as keys.
|
160
148
|
#
|
@@ -178,7 +166,7 @@ module Hanami
|
|
178
166
|
#
|
179
167
|
# Hanami::Utils::Hash.deep_serialize(input)
|
180
168
|
# # => {:foo=>"bar", :baz=>[{:hello=>"world"}]}
|
181
|
-
def self.deep_serialize(input)
|
169
|
+
def self.deep_serialize(input)
|
182
170
|
input.to_hash.each_with_object({}) do |(key, value), output|
|
183
171
|
output[key.to_sym] =
|
184
172
|
case value
|
data/lib/hanami/utils/json.rb
CHANGED
data/lib/hanami/utils/kernel.rb
CHANGED
@@ -9,7 +9,7 @@ require "hanami/utils"
|
|
9
9
|
require "hanami/utils/string"
|
10
10
|
|
11
11
|
unless defined?(Boolean)
|
12
|
-
#
|
12
|
+
# Defines top level constant Boolean, so it can be easily used by other libraries
|
13
13
|
# in coercions DSLs
|
14
14
|
#
|
15
15
|
# @since 0.3.0
|
@@ -28,7 +28,7 @@ module Hanami
|
|
28
28
|
# @api private
|
29
29
|
#
|
30
30
|
# @see Hanami::Utils::Kernel.Integer
|
31
|
-
NUMERIC_MATCHER = %r{\A([\d
|
31
|
+
NUMERIC_MATCHER = %r{\A([\d/.+iE]+|NaN|Infinity)\z}.freeze
|
32
32
|
|
33
33
|
# @since 0.8.0
|
34
34
|
# @api private
|
@@ -327,7 +327,7 @@ module Hanami
|
|
327
327
|
# # big complex represented as a string
|
328
328
|
# input = Complex(2, 3)
|
329
329
|
# Hanami::Utils::Kernel.Integer(input) # => TypeError
|
330
|
-
def self.Integer(arg)
|
330
|
+
def self.Integer(arg)
|
331
331
|
super(arg)
|
332
332
|
rescue ArgumentError, TypeError, NoMethodError
|
333
333
|
begin
|
@@ -418,7 +418,6 @@ module Hanami
|
|
418
418
|
# input = BasicObject.new
|
419
419
|
# Hanami::Utils::Kernel.BigDecimal(input) # => TypeError
|
420
420
|
#
|
421
|
-
# rubocop:disable Metrics/MethodLength
|
422
421
|
def self.BigDecimal(arg, precision = ::Float::DIG)
|
423
422
|
case arg
|
424
423
|
when NilClass # This is only needed by Ruby 2.6
|
@@ -435,7 +434,6 @@ module Hanami
|
|
435
434
|
rescue NoMethodError
|
436
435
|
raise TypeError.new "can't convert #{inspect_type_error(arg)}into BigDecimal"
|
437
436
|
end
|
438
|
-
# rubocop:enable Metrics/MethodLength
|
439
437
|
|
440
438
|
# Coerces the argument to be a Float.
|
441
439
|
#
|
@@ -549,7 +547,7 @@ module Hanami
|
|
549
547
|
# # big complex represented as a string
|
550
548
|
# input = Complex(2, 3)
|
551
549
|
# Hanami::Utils::Kernel.Float(input) # => TypeError
|
552
|
-
def self.Float(arg)
|
550
|
+
def self.Float(arg)
|
553
551
|
super(arg)
|
554
552
|
rescue ArgumentError, TypeError
|
555
553
|
begin
|
@@ -738,7 +736,8 @@ module Hanami
|
|
738
736
|
# require 'hanami/utils/kernel'
|
739
737
|
#
|
740
738
|
# Hanami::Utils::Kernel.DateTime(3483943)
|
741
|
-
# # => 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)>
|
742
741
|
#
|
743
742
|
# Hanami::Utils::Kernel.DateTime(DateTime.now)
|
744
743
|
# # => #<DateTime: 2014-04-18T09:33:49+02:00 ((2456766j,27229s,690849000n),+7200s,2299161j)>
|
@@ -898,7 +897,7 @@ module Hanami
|
|
898
897
|
# # Missing #respond_to?
|
899
898
|
# input = BasicObject.new
|
900
899
|
# Hanami::Utils::Kernel.Boolean(input) # => TypeError
|
901
|
-
def self.Boolean(arg)
|
900
|
+
def self.Boolean(arg)
|
902
901
|
case arg
|
903
902
|
when Numeric
|
904
903
|
arg.to_i == BOOLEAN_TRUE_INTEGER
|
@@ -1023,7 +1022,7 @@ module Hanami
|
|
1023
1022
|
raise TypeError.new "can't convert #{inspect_type_error(arg)}into Symbol"
|
1024
1023
|
end
|
1025
1024
|
|
1026
|
-
#
|
1025
|
+
# Checks if the given argument is a string representation of a number
|
1027
1026
|
#
|
1028
1027
|
# @param arg [Object] the input
|
1029
1028
|
#
|
@@ -1044,11 +1043,11 @@ module Hanami
|
|
1044
1043
|
# @since 0.4.3
|
1045
1044
|
# @api private
|
1046
1045
|
def self.inspect_type_error(arg)
|
1047
|
-
(arg.respond_to?(:inspect) ? arg.inspect : arg.to_s)
|
1048
|
-
rescue NoMethodError
|
1046
|
+
"#{(arg.respond_to?(:inspect) ? arg.inspect : arg.to_s)} "
|
1047
|
+
rescue NoMethodError
|
1049
1048
|
# missing the #respond_to? method, fall back to returning the class' name
|
1050
1049
|
begin
|
1051
|
-
arg.class.name
|
1050
|
+
"#{arg.class.name} instance "
|
1052
1051
|
rescue NoMethodError
|
1053
1052
|
# missing the #class method, can't fall back to anything better than nothing
|
1054
1053
|
# Callers will have to guess from their code
|
@@ -1057,7 +1056,7 @@ module Hanami
|
|
1057
1056
|
end
|
1058
1057
|
|
1059
1058
|
class << self
|
1060
|
-
private :inspect_type_error
|
1059
|
+
private :inspect_type_error
|
1061
1060
|
end
|
1062
1061
|
end
|
1063
1062
|
end
|
@@ -50,7 +50,7 @@ module Hanami
|
|
50
50
|
@paths = original.instance_variable_get(:@paths).dup
|
51
51
|
end
|
52
52
|
|
53
|
-
# Iterates
|
53
|
+
# Iterates through the collection and yields the given block.
|
54
54
|
# It skips duplications and raises an error in case one of the paths
|
55
55
|
# doesn't exist.
|
56
56
|
#
|
@@ -117,7 +117,7 @@ module Hanami
|
|
117
117
|
self
|
118
118
|
end
|
119
119
|
|
120
|
-
|
120
|
+
alias_method :<<, :push
|
121
121
|
|
122
122
|
# It freezes the object by preventing further modifications.
|
123
123
|
#
|
@@ -158,7 +158,7 @@ module Hanami
|
|
158
158
|
|
159
159
|
private
|
160
160
|
|
161
|
-
#
|
161
|
+
# Allows subclasses to define their own policy to discover the realpath
|
162
162
|
# of the given path.
|
163
163
|
#
|
164
164
|
# @since 0.2.0
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "hanami/utils/string"
|
4
3
|
require "hanami/utils/kernel"
|
5
4
|
|
6
5
|
module Hanami
|
@@ -8,7 +7,7 @@ module Hanami
|
|
8
7
|
# Prefixed string
|
9
8
|
#
|
10
9
|
# @since 0.1.0
|
11
|
-
class PathPrefix
|
10
|
+
class PathPrefix
|
12
11
|
# Path separator
|
13
12
|
#
|
14
13
|
# @since 0.3.1
|
@@ -26,7 +25,7 @@ module Hanami
|
|
26
25
|
#
|
27
26
|
# @see Hanami::Utils::PathPrefix::DEFAULT_SEPARATOR
|
28
27
|
def initialize(string = nil, separator = DEFAULT_SEPARATOR)
|
29
|
-
|
28
|
+
@string = string.to_s
|
30
29
|
@separator = separator
|
31
30
|
end
|
32
31
|
|
@@ -93,6 +92,37 @@ module Hanami
|
|
93
92
|
).relative!
|
94
93
|
end
|
95
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
|
+
|
96
126
|
protected
|
97
127
|
|
98
128
|
# Modifies the path prefix to have a prepended separator.
|
@@ -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,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "dry/transformer"
|
4
4
|
require "concurrent/map"
|
5
5
|
|
6
6
|
module Hanami
|
7
7
|
module Utils
|
8
|
-
# String
|
8
|
+
# String utilities
|
9
9
|
#
|
10
10
|
# @since 0.1.0
|
11
|
-
|
11
|
+
module String
|
12
12
|
# Empty string for #classify
|
13
13
|
#
|
14
14
|
# @since 0.6.0
|
@@ -27,18 +27,6 @@ module Hanami
|
|
27
27
|
# @api private
|
28
28
|
CLASSIFY_SEPARATOR = "_"
|
29
29
|
|
30
|
-
# Regexp for #tokenize
|
31
|
-
#
|
32
|
-
# @since 0.3.0
|
33
|
-
# @api private
|
34
|
-
TOKENIZE_REGEXP = /\((.*)\)/.freeze
|
35
|
-
|
36
|
-
# Separator for #tokenize
|
37
|
-
#
|
38
|
-
# @since 0.3.0
|
39
|
-
# @api private
|
40
|
-
TOKENIZE_SEPARATOR = "|"
|
41
|
-
|
42
30
|
# Separator for #underscore
|
43
31
|
#
|
44
32
|
# @since 0.3.0
|
@@ -73,16 +61,16 @@ module Hanami
|
|
73
61
|
#
|
74
62
|
# @since 0.3.4
|
75
63
|
# @api private
|
76
|
-
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
|
77
65
|
|
78
66
|
@__transformations__ = Concurrent::Map.new
|
79
67
|
|
80
|
-
extend
|
81
|
-
extend Transproc::Composer
|
68
|
+
extend Dry::Transformer::Registry
|
82
69
|
|
83
|
-
#
|
70
|
+
# Applies the given transformation(s) to `input`
|
84
71
|
#
|
85
|
-
# 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`.
|
86
74
|
# The transformations are applied in the given order.
|
87
75
|
#
|
88
76
|
# It doesn't mutate the input, unless you use destructive methods from `::String`
|
@@ -130,42 +118,31 @@ module Hanami
|
|
130
118
|
# Hanami::Utils::String.transform("Cherry", -> { "blossom" }))
|
131
119
|
# # => ArgumentError: wrong number of arguments (given 1, expected 0)
|
132
120
|
#
|
133
|
-
# rubocop:disable Metrics/AbcSize
|
134
|
-
# rubocop:disable Metrics/MethodLength
|
135
121
|
def self.transform(input, *transformations)
|
136
122
|
fn = @__transformations__.fetch_or_store(transformations.hash) do
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
+
)
|
149
137
|
end
|
138
|
+
|
139
|
+
fns
|
150
140
|
end
|
151
141
|
|
152
142
|
fn.call(input)
|
153
143
|
end
|
154
|
-
# rubocop:enable Metrics/MethodLength
|
155
|
-
# rubocop:enable Metrics/AbcSize
|
156
144
|
|
157
|
-
#
|
158
|
-
#
|
159
|
-
# `transproc` is Copyright 2014 by Piotr Solnica (piotr.solnica@gmail.com),
|
160
|
-
# released under the MIT License
|
161
|
-
#
|
162
|
-
# @since 1.1.0
|
163
|
-
# @api private
|
164
|
-
def self.bind(value, binding, fun)
|
165
|
-
binding.instance_exec(value, &fun)
|
166
|
-
end
|
167
|
-
|
168
|
-
# Return a titleized version of the string
|
145
|
+
# Returns a titleized version of the string
|
169
146
|
#
|
170
147
|
# @param input [::String] the input
|
171
148
|
#
|
@@ -182,7 +159,7 @@ module Hanami
|
|
182
159
|
underscore(string).split(CLASSIFY_SEPARATOR).map(&:capitalize).join(TITLEIZE_SEPARATOR)
|
183
160
|
end
|
184
161
|
|
185
|
-
#
|
162
|
+
# Returns a capitalized version of the string
|
186
163
|
#
|
187
164
|
# @param input [::String] the input
|
188
165
|
#
|
@@ -209,7 +186,7 @@ module Hanami
|
|
209
186
|
tail.unshift(head.capitalize).join(CAPITALIZE_SEPARATOR)
|
210
187
|
end
|
211
188
|
|
212
|
-
#
|
189
|
+
# Returns a CamelCase version of the string
|
213
190
|
#
|
214
191
|
# @param input [::String] the input
|
215
192
|
#
|
@@ -233,7 +210,7 @@ module Hanami
|
|
233
210
|
words.zip(delimiters).join
|
234
211
|
end
|
235
212
|
|
236
|
-
#
|
213
|
+
# Returns a downcased and underscore separated version of the string
|
237
214
|
#
|
238
215
|
# Revised version of `ActiveSupport::Inflector.underscore` implementation
|
239
216
|
# @see https://github.com/rails/rails/blob/feaa6e2048fe86bcf07e967d6e47b865e42e055b/activesupport/lib/active_support/inflector/methods.rb#L90
|
@@ -254,11 +231,11 @@ module Hanami
|
|
254
231
|
string.gsub!(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
|
255
232
|
string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, UNDERSCORE_DIVISION_TARGET)
|
256
233
|
string.gsub!(/([a-z\d])([A-Z])/, UNDERSCORE_DIVISION_TARGET)
|
257
|
-
string.gsub!(/[[:space:]]
|
234
|
+
string.gsub!(/[[:space:]]|-/, UNDERSCORE_DIVISION_TARGET)
|
258
235
|
string.downcase
|
259
236
|
end
|
260
237
|
|
261
|
-
#
|
238
|
+
# Returns a downcased and dash separated version of the string
|
262
239
|
#
|
263
240
|
# @param input [::String] the input
|
264
241
|
#
|
@@ -279,7 +256,7 @@ module Hanami
|
|
279
256
|
underscore(string).split(CLASSIFY_SEPARATOR).join(DASHERIZE_SEPARATOR)
|
280
257
|
end
|
281
258
|
|
282
|
-
#
|
259
|
+
# Returns the string without the Ruby namespace of the class
|
283
260
|
#
|
284
261
|
# @param input [::String] the input
|
285
262
|
#
|
@@ -297,7 +274,7 @@ module Hanami
|
|
297
274
|
::String.new(input.to_s).split(NAMESPACE_SEPARATOR).last
|
298
275
|
end
|
299
276
|
|
300
|
-
#
|
277
|
+
# Returns the top level namespace name
|
301
278
|
#
|
302
279
|
# @param input [::String] the input
|
303
280
|
#
|
@@ -336,7 +313,7 @@ module Hanami
|
|
336
313
|
# # => 'authors/books#index'
|
337
314
|
def self.rsub(input, pattern, replacement)
|
338
315
|
string = ::String.new(input.to_s)
|
339
|
-
if i = string.rindex(pattern)
|
316
|
+
if i = string.rindex(pattern)
|
340
317
|
s = string.dup
|
341
318
|
s[i] = replacement
|
342
319
|
s
|
@@ -344,344 +321,6 @@ module Hanami
|
|
344
321
|
string
|
345
322
|
end
|
346
323
|
end
|
347
|
-
|
348
|
-
# Initialize the string
|
349
|
-
#
|
350
|
-
# @param string [::String, Symbol] the value we want to initialize
|
351
|
-
#
|
352
|
-
# @return [Hanami::Utils::String] self
|
353
|
-
#
|
354
|
-
# @since 0.1.0
|
355
|
-
# @deprecated
|
356
|
-
def initialize(string)
|
357
|
-
@string = string.to_s
|
358
|
-
end
|
359
|
-
|
360
|
-
# Return a titleized version of the string
|
361
|
-
#
|
362
|
-
# @return [Hanami::Utils::String] the transformed string
|
363
|
-
#
|
364
|
-
# @since 0.4.0
|
365
|
-
# @deprecated Use {Hanami::Utils::String.titleize}
|
366
|
-
#
|
367
|
-
# @example
|
368
|
-
# require 'hanami/utils/string'
|
369
|
-
#
|
370
|
-
# string = Hanami::Utils::String.new 'hanami utils'
|
371
|
-
# string.titleize # => "Hanami Utils"
|
372
|
-
def titleize
|
373
|
-
self.class.new underscore.split(CLASSIFY_SEPARATOR).map(&:capitalize).join(TITLEIZE_SEPARATOR)
|
374
|
-
end
|
375
|
-
|
376
|
-
# Return a capitalized version of the string
|
377
|
-
#
|
378
|
-
# @return [Hanami::Utils::String] the transformed string
|
379
|
-
#
|
380
|
-
# @since 0.5.2
|
381
|
-
# @deprecated Use {Hanami::Utils::String.capitalize}
|
382
|
-
#
|
383
|
-
# @example
|
384
|
-
# require 'hanami/utils/string'
|
385
|
-
#
|
386
|
-
# string = Hanami::Utils::String.new 'hanami'
|
387
|
-
# string.capitalize # => "Hanami"
|
388
|
-
#
|
389
|
-
# string = Hanami::Utils::String.new 'hanami utils'
|
390
|
-
# string.capitalize # => "Hanami utils"
|
391
|
-
#
|
392
|
-
# string = Hanami::Utils::String.new 'Hanami Utils'
|
393
|
-
# string.capitalize # => "Hanami utils"
|
394
|
-
#
|
395
|
-
# string = Hanami::Utils::String.new 'hanami_utils'
|
396
|
-
# string.capitalize # => "Hanami utils"
|
397
|
-
#
|
398
|
-
# string = Hanami::Utils::String.new 'hanami-utils'
|
399
|
-
# string.capitalize # => "Hanami utils"
|
400
|
-
def capitalize
|
401
|
-
head, *tail = underscore.split(CLASSIFY_SEPARATOR)
|
402
|
-
|
403
|
-
self.class.new(
|
404
|
-
tail.unshift(head.capitalize).join(CAPITALIZE_SEPARATOR)
|
405
|
-
)
|
406
|
-
end
|
407
|
-
|
408
|
-
# Return a CamelCase version of the string
|
409
|
-
#
|
410
|
-
# @return [Hanami::Utils::String] the transformed string
|
411
|
-
#
|
412
|
-
# @since 0.1.0
|
413
|
-
# @deprecated Use {Hanami::Utils::String.classify}
|
414
|
-
#
|
415
|
-
# @example
|
416
|
-
# require 'hanami/utils/string'
|
417
|
-
#
|
418
|
-
# string = Hanami::Utils::String.new 'hanami_utils'
|
419
|
-
# string.classify # => 'HanamiUtils'
|
420
|
-
def classify
|
421
|
-
words = underscore.split(CLASSIFY_WORD_SEPARATOR).map!(&:capitalize)
|
422
|
-
delimiters = underscore.scan(CLASSIFY_WORD_SEPARATOR)
|
423
|
-
|
424
|
-
delimiters.map! do |delimiter|
|
425
|
-
delimiter == CLASSIFY_SEPARATOR ? EMPTY_STRING : NAMESPACE_SEPARATOR
|
426
|
-
end
|
427
|
-
|
428
|
-
self.class.new words.zip(delimiters).join
|
429
|
-
end
|
430
|
-
|
431
|
-
# Return a downcased and underscore separated version of the string
|
432
|
-
#
|
433
|
-
# Revised version of `ActiveSupport::Inflector.underscore` implementation
|
434
|
-
# @see https://github.com/rails/rails/blob/feaa6e2048fe86bcf07e967d6e47b865e42e055b/activesupport/lib/active_support/inflector/methods.rb#L90
|
435
|
-
#
|
436
|
-
# @return [Hanami::Utils::String] the transformed string
|
437
|
-
# @deprecated Use {Hanami::Utils::String.underscore}
|
438
|
-
#
|
439
|
-
# @since 0.1.0
|
440
|
-
#
|
441
|
-
# @example
|
442
|
-
# require 'hanami/utils/string'
|
443
|
-
#
|
444
|
-
# string = Hanami::Utils::String.new 'HanamiUtils'
|
445
|
-
# string.underscore # => 'hanami_utils'
|
446
|
-
def underscore
|
447
|
-
new_string = gsub(NAMESPACE_SEPARATOR, UNDERSCORE_SEPARATOR)
|
448
|
-
new_string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, UNDERSCORE_DIVISION_TARGET)
|
449
|
-
new_string.gsub!(/([a-z\d])([A-Z])/, UNDERSCORE_DIVISION_TARGET)
|
450
|
-
new_string.gsub!(/[[:space:]]|\-/, UNDERSCORE_DIVISION_TARGET)
|
451
|
-
new_string.downcase!
|
452
|
-
self.class.new new_string
|
453
|
-
end
|
454
|
-
|
455
|
-
# Return a downcased and dash separated version of the string
|
456
|
-
#
|
457
|
-
# @return [Hanami::Utils::String] the transformed string
|
458
|
-
#
|
459
|
-
# @since 0.4.0
|
460
|
-
# @deprecated Use {Hanami::Utils::String.dasherize}
|
461
|
-
#
|
462
|
-
# @example
|
463
|
-
# require 'hanami/utils/string'
|
464
|
-
#
|
465
|
-
# string = Hanami::Utils::String.new 'Hanami Utils'
|
466
|
-
# string.dasherize # => 'hanami-utils'
|
467
|
-
#
|
468
|
-
# string = Hanami::Utils::String.new 'hanami_utils'
|
469
|
-
# string.dasherize # => 'hanami-utils'
|
470
|
-
#
|
471
|
-
# string = Hanami::Utils::String.new 'HanamiUtils'
|
472
|
-
# string.dasherize # => "hanami-utils"
|
473
|
-
def dasherize
|
474
|
-
self.class.new underscore.split(CLASSIFY_SEPARATOR).join(DASHERIZE_SEPARATOR)
|
475
|
-
end
|
476
|
-
|
477
|
-
# Return the string without the Ruby namespace of the class
|
478
|
-
#
|
479
|
-
# @return [Hanami::Utils::String] the transformed string
|
480
|
-
#
|
481
|
-
# @since 0.1.0
|
482
|
-
# @deprecated Use {Hanami::Utils::String.demodulize}
|
483
|
-
#
|
484
|
-
# @example
|
485
|
-
# require 'hanami/utils/string'
|
486
|
-
#
|
487
|
-
# string = Hanami::Utils::String.new 'Hanami::Utils::String'
|
488
|
-
# string.demodulize # => 'String'
|
489
|
-
#
|
490
|
-
# string = Hanami::Utils::String.new 'String'
|
491
|
-
# string.demodulize # => 'String'
|
492
|
-
def demodulize
|
493
|
-
self.class.new split(NAMESPACE_SEPARATOR).last
|
494
|
-
end
|
495
|
-
|
496
|
-
# Return the top level namespace name
|
497
|
-
#
|
498
|
-
# @return [Hanami::Utils::String] the transformed string
|
499
|
-
#
|
500
|
-
# @since 0.1.2
|
501
|
-
# @deprecated Use {Hanami::Utils::String.namespace}
|
502
|
-
#
|
503
|
-
# @example
|
504
|
-
# require 'hanami/utils/string'
|
505
|
-
#
|
506
|
-
# string = Hanami::Utils::String.new 'Hanami::Utils::String'
|
507
|
-
# string.namespace # => 'Hanami'
|
508
|
-
#
|
509
|
-
# string = Hanami::Utils::String.new 'String'
|
510
|
-
# string.namespace # => 'String'
|
511
|
-
def namespace
|
512
|
-
self.class.new split(NAMESPACE_SEPARATOR).first
|
513
|
-
end
|
514
|
-
|
515
|
-
# It iterates through the tokens and calls the given block.
|
516
|
-
# A token is a substring wrapped by `()` and separated by `|`.
|
517
|
-
#
|
518
|
-
# @yield the block that is called for each token.
|
519
|
-
#
|
520
|
-
# @return [void]
|
521
|
-
#
|
522
|
-
# @since 0.1.0
|
523
|
-
# @deprecated
|
524
|
-
#
|
525
|
-
# @example
|
526
|
-
# require 'hanami/utils/string'
|
527
|
-
#
|
528
|
-
# string = Hanami::Utils::String.new 'Hanami::(Utils|App)'
|
529
|
-
# string.tokenize do |token|
|
530
|
-
# puts token
|
531
|
-
# end
|
532
|
-
#
|
533
|
-
# # =>
|
534
|
-
# 'Hanami::Utils'
|
535
|
-
# 'Hanami::App'
|
536
|
-
#
|
537
|
-
# rubocop:disable Metrics/MethodLength
|
538
|
-
def tokenize
|
539
|
-
if match = TOKENIZE_REGEXP.match(@string) # rubocop:disable Lint/AssignmentInCondition
|
540
|
-
pre = match.pre_match
|
541
|
-
post = match.post_match
|
542
|
-
tokens = match[1].split(TOKENIZE_SEPARATOR)
|
543
|
-
tokens.each do |token|
|
544
|
-
yield(self.class.new("#{pre}#{token}#{post}"))
|
545
|
-
end
|
546
|
-
else
|
547
|
-
yield(self.class.new(@string))
|
548
|
-
end
|
549
|
-
|
550
|
-
nil
|
551
|
-
end
|
552
|
-
# rubocop:enable Metrics/MethodLength
|
553
|
-
|
554
|
-
# Returns the hash of the internal string
|
555
|
-
#
|
556
|
-
# @return [Integer]
|
557
|
-
#
|
558
|
-
# @since 0.3.0
|
559
|
-
# @deprecated
|
560
|
-
def hash
|
561
|
-
@string.hash
|
562
|
-
end
|
563
|
-
|
564
|
-
# Returns a string representation
|
565
|
-
#
|
566
|
-
# @return [::String]
|
567
|
-
#
|
568
|
-
# @since 0.3.0
|
569
|
-
# @deprecated
|
570
|
-
def to_s
|
571
|
-
@string
|
572
|
-
end
|
573
|
-
|
574
|
-
alias to_str to_s
|
575
|
-
|
576
|
-
# Equality
|
577
|
-
#
|
578
|
-
# @return [TrueClass,FalseClass]
|
579
|
-
#
|
580
|
-
# @since 0.3.0
|
581
|
-
# @deprecated
|
582
|
-
def ==(other)
|
583
|
-
to_s == other
|
584
|
-
end
|
585
|
-
|
586
|
-
alias eql? ==
|
587
|
-
|
588
|
-
# Split the string with the given pattern
|
589
|
-
#
|
590
|
-
# @return [Array<::String>]
|
591
|
-
#
|
592
|
-
# @see http://www.ruby-doc.org/core/String.html#method-i-split
|
593
|
-
#
|
594
|
-
# @since 0.3.0
|
595
|
-
# @deprecated
|
596
|
-
def split(pattern, limit = 0)
|
597
|
-
@string.split(pattern, limit)
|
598
|
-
end
|
599
|
-
|
600
|
-
# Replace the given pattern with the given replacement
|
601
|
-
#
|
602
|
-
# @return [::String]
|
603
|
-
#
|
604
|
-
# @see http://www.ruby-doc.org/core/String.html#method-i-gsub
|
605
|
-
#
|
606
|
-
# @since 0.3.0
|
607
|
-
# @deprecated
|
608
|
-
def gsub(pattern, replacement = nil, &blk)
|
609
|
-
if block_given?
|
610
|
-
@string.gsub(pattern, &blk)
|
611
|
-
else
|
612
|
-
@string.gsub(pattern, replacement)
|
613
|
-
end
|
614
|
-
end
|
615
|
-
|
616
|
-
# Iterate through the string, matching the pattern.
|
617
|
-
# Either return all those patterns, or pass them to the block.
|
618
|
-
#
|
619
|
-
# @return [Array<::String>]
|
620
|
-
#
|
621
|
-
# @see http://www.ruby-doc.org/core/String.html#method-i-scan
|
622
|
-
#
|
623
|
-
# @since 0.6.0
|
624
|
-
# @deprecated
|
625
|
-
def scan(pattern, &blk)
|
626
|
-
@string.scan(pattern, &blk)
|
627
|
-
end
|
628
|
-
|
629
|
-
# Replace the rightmost match of `pattern` with `replacement`
|
630
|
-
#
|
631
|
-
# If the pattern cannot be matched, it returns the original string.
|
632
|
-
#
|
633
|
-
# This method does NOT mutate the original string.
|
634
|
-
#
|
635
|
-
# @param pattern [Regexp, String] the pattern to find
|
636
|
-
# @param replacement [String, Hanami::Utils::String] the string to replace
|
637
|
-
#
|
638
|
-
# @return [Hanami::Utils::String] the replaced string
|
639
|
-
#
|
640
|
-
# @since 0.6.0
|
641
|
-
# @deprecated Use {Hanami::Utils::String.rsub}
|
642
|
-
#
|
643
|
-
# @example
|
644
|
-
# require 'hanami/utils/string'
|
645
|
-
#
|
646
|
-
# string = Hanami::Utils::String.new('authors/books/index')
|
647
|
-
# result = string.rsub(/\//, '#')
|
648
|
-
#
|
649
|
-
# puts string
|
650
|
-
# # => #<Hanami::Utils::String:0x007fdb41233ad8 @string="authors/books/index">
|
651
|
-
#
|
652
|
-
# puts result
|
653
|
-
# # => #<Hanami::Utils::String:0x007fdb41232ed0 @string="authors/books#index">
|
654
|
-
def rsub(pattern, replacement)
|
655
|
-
if i = rindex(pattern) # rubocop:disable Lint/AssignmentInCondition
|
656
|
-
s = @string.dup
|
657
|
-
s[i] = replacement
|
658
|
-
self.class.new s
|
659
|
-
else
|
660
|
-
self
|
661
|
-
end
|
662
|
-
end
|
663
|
-
|
664
|
-
# Override Ruby's method_missing in order to provide ::String interface
|
665
|
-
#
|
666
|
-
# @api private
|
667
|
-
# @since 0.3.0
|
668
|
-
#
|
669
|
-
# @raise [NoMethodError] If doesn't respond to the given method
|
670
|
-
def method_missing(method_name, *args, &blk)
|
671
|
-
raise NoMethodError.new(%(undefined method `#{method_name}' for "#{@string}":#{self.class})) unless respond_to?(method_name)
|
672
|
-
|
673
|
-
s = @string.__send__(method_name, *args, &blk)
|
674
|
-
s = self.class.new(s) if s.is_a?(::String)
|
675
|
-
s
|
676
|
-
end
|
677
|
-
|
678
|
-
# Override Ruby's respond_to_missing? in order to support ::String interface
|
679
|
-
#
|
680
|
-
# @api private
|
681
|
-
# @since 0.3.0
|
682
|
-
def respond_to_missing?(method_name, include_private = false)
|
683
|
-
@string.respond_to?(method_name, include_private)
|
684
|
-
end
|
685
324
|
end
|
686
325
|
end
|
687
326
|
end
|