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.
@@ -6,7 +6,7 @@ module Hanami
6
6
  #
7
7
  # @since 0.9.0
8
8
  module FileList
9
- # Return an ordered list of files, consistent across operating systems
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
@@ -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) # rubocop:disable Metrics/AbcSize
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..-1], path, closing)
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
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "transproc"
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 Transproc::Registry
11
- import Transproc::HashTransformations
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
- # Deep symbolize the given hash
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
- # Stringify the given hash
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 stringify the given hash
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) # rubocop:disable Metrics/MethodLength
94
- input.each_with_object({}) do |(key, value), output|
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 duplicate hash values
97
+ # Deep duplicates hash values
110
98
  #
111
- # The output of this function is a shallow duplicate of the input.
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 shallow duplicate of input
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.each_with_object({}) do |(k, v), result|
148
- result[k] = case v
149
- when ::Hash
150
- deep_dup(v)
151
- else
152
- v.dup
153
- end
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 serialize given object into a `Hash`
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) # rubocop:disable Metrics/MethodLength
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
@@ -43,7 +43,7 @@ module Hanami
43
43
  end
44
44
  # rubocop:enable Style/ClassVars
45
45
 
46
- # Parse the given JSON paylod
46
+ # Parses the given JSON paylod
47
47
  #
48
48
  # @param payload [String] a JSON payload
49
49
  #
@@ -9,7 +9,7 @@ require "hanami/utils"
9
9
  require "hanami/utils/string"
10
10
 
11
11
  unless defined?(Boolean)
12
- # Define top level constant Boolean, so it can be easily used by other libraries
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\/\.\+iE]+|NaN|Infinity)\z}.freeze
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) # rubocop:disable Metrics/MethodLength
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) # rubocop:disable Metrics/MethodLength
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 #<DateTime: 1970-02-10T08:45:43+01:00 ((2440628j,27943s,0n),+3600s,2299161j)>
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) # rubocop:disable Metrics/MethodLength
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
- # Check if the given argument is a string representation of a number
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 << " instance "
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 # rubocop:disable Style/AccessModifierDeclarations
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 thru the collection and yields the given block.
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
- alias << push
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
- # Allow subclasses to define their own policy to discover the realpath
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 < Hanami::Utils::String
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
- super(string)
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.
@@ -12,7 +12,7 @@ module Hanami
12
12
  # @api private
13
13
  HASH_SEPARATOR = ","
14
14
 
15
- # Serialize input into a query string
15
+ # Serializes input into a query string
16
16
  #
17
17
  # @param input [Object] the input
18
18
  #
@@ -18,22 +18,22 @@ module Hanami
18
18
  end
19
19
  end
20
20
 
21
- # Escape codes for terminals to output strings in colors
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: 30,
27
- red: 31,
28
- green: 32,
29
- yellow: 33,
30
- blue: 34,
26
+ black: 30,
27
+ red: 31,
28
+ green: 32,
29
+ yellow: 33,
30
+ blue: 34,
31
31
  magenta: 35,
32
- cyan: 36,
33
- gray: 37,
32
+ cyan: 36,
33
+ gray: 37,
34
34
  ].freeze
35
35
 
36
- # Colorize output
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
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "transproc"
3
+ require "dry/transformer"
4
4
  require "concurrent/map"
5
5
 
6
6
  module Hanami
7
7
  module Utils
8
- # String on steroids
8
+ # String utilities
9
9
  #
10
10
  # @since 0.1.0
11
- class String # rubocop:disable Metrics/ClassLength
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 Transproc::Registry
81
- extend Transproc::Composer
68
+ extend Dry::Transformer::Registry
82
69
 
83
- # Apply the given transformation(s) to `input`
70
+ # Applies the given transformation(s) to `input`
84
71
  #
85
- # It performs a pipeline of transformations, by applying the given functions from `Hanami::Utils::String` and `::String`.
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
- compose do |fns|
138
- transformations.each do |transformation, *args|
139
- fns << if transformation.is_a?(Proc)
140
- transformation
141
- elsif contain?(transformation)
142
- self[transformation, *args]
143
- elsif input.respond_to?(transformation)
144
- t(:bind, input, ->(i) { i.public_send(transformation, *args) })
145
- else
146
- raise NoMethodError.new(%(undefined method `#{transformation.inspect}' for #{input.inspect}:#{input.class}))
147
- end
148
- end
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
- # Extracted from `transproc` source code
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
- # Return a capitalized version of the string
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
- # Return a CamelCase version of the string
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
- # Return a downcased and underscore separated version of the string
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:]]|\-/, UNDERSCORE_DIVISION_TARGET)
234
+ string.gsub!(/[[:space:]]|-/, UNDERSCORE_DIVISION_TARGET)
258
235
  string.downcase
259
236
  end
260
237
 
261
- # Return a downcased and dash separated version of the string
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
- # Return the string without the Ruby namespace of the class
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
- # Return the top level namespace name
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) # rubocop:disable Lint/AssignmentInCondition
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