hanami-utils 2.0.0.alpha1 → 2.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|