hanami-utils 1.3.5 → 2.0.0.alpha2

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