hanami-utils 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@ module Hanami
10
10
  #
11
11
  # @see http://ruby-doc.org/core/Object.html#method-i-class
12
12
  def class
13
- (class << self; self end).superclass
13
+ (class << self; self; end).superclass
14
14
  end
15
15
 
16
16
  # Bare minimum inspect for debugging purposes.
@@ -21,7 +21,7 @@ module Hanami
21
21
  #
22
22
  # @see http://ruby-doc.org/core/Object.html#method-i-inspect
23
23
  def inspect
24
- "#<#{ self.class }:#{'%x' % (__id__ << 1)}#{ __inspect }>"
24
+ "#<#{self.class}:#{'%x' % (__id__ << 1)}#{__inspect}>" # rubocop:disable Style/FormatString
25
25
  end
26
26
 
27
27
  # Returns true if responds to the given method.
@@ -36,11 +36,12 @@ module Hanami
36
36
  end
37
37
 
38
38
  private
39
+
39
40
  # Must be overridden by descendants
40
41
  #
41
42
  # @since 0.3.5
42
43
  # @api private
43
- def respond_to_missing?(method_name, include_all)
44
+ def respond_to_missing?(_method_name, _include_all)
44
45
  ::Kernel.raise ::NotImplementedError
45
46
  end
46
47
 
@@ -0,0 +1,45 @@
1
+ module Hanami
2
+ module Utils
3
+ # Checks for blank
4
+ # @since 0.8.0
5
+ class Blank
6
+ # Matcher for blank strings
7
+ #
8
+ # @since 0.8.0
9
+ # @api private
10
+ STRING_MATCHER = /\A[[:space:]]*\z/
11
+
12
+ # Checks object is blank
13
+ #
14
+ # @example Basic Usage
15
+ # require 'hanami/utils/blank'
16
+ #
17
+ # Hanami::Utils::Blank.blank?(Hanami::Utils::String.new('')) # => true
18
+ # Hanami::Utils::Blank.blank?(' ') # => true
19
+ # Hanami::Utils::Blank.blank?(nil) # => true
20
+ # Hanami::Utils::Blank.blank?(Hanami::Utils::Hash.new({})) # => true
21
+ # Hanami::Utils::Blank.blank?(true) # => false
22
+ # Hanami::Utils::Blank.blank?(1) # => false
23
+ #
24
+ # @param object the argument
25
+ #
26
+ # @return [TrueClass,FalseClass]
27
+ #
28
+ # @since 0.8.0
29
+ def self.blank?(object) # rubocop:disable Metrics/MethodLength
30
+ case object
31
+ when String, ::String
32
+ STRING_MATCHER === object # rubocop:disable Style/CaseEquality
33
+ when Hash, ::Hash, ::Array
34
+ object.empty?
35
+ when TrueClass, Numeric
36
+ false
37
+ when FalseClass, NilClass
38
+ true
39
+ else
40
+ object.respond_to?(:empty?) ? !!object.empty? : !self
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -16,7 +16,7 @@ module Hanami
16
16
  #
17
17
  # @since 0.2.0
18
18
  def initialize
19
- @chain = Array.new
19
+ @chain = []
20
20
  end
21
21
 
22
22
  # Appends the given callbacks to the end of the chain.
@@ -168,14 +168,12 @@ module Hanami
168
168
  @chain.freeze
169
169
  end
170
170
 
171
-
172
171
  private
173
172
 
174
173
  def callables(callbacks, block)
175
174
  callbacks.push(block) if block
176
175
  callbacks.map { |c| Factory.fabricate(c) }
177
176
  end
178
-
179
177
  end
180
178
 
181
179
  # Callback factory
@@ -41,6 +41,37 @@ module Hanami
41
41
  namespace.const_get(name.to_s)
42
42
  end
43
43
 
44
+ # Loads a class for the given name, only if it's defined.
45
+ #
46
+ # @param name [String, Class] the specific class name
47
+ # @param namespace [Class, Module] the Ruby namespace where we want to perform the lookup.
48
+ # @return [Class, Module, NilClass] the Ruby constant, or nil if not found.
49
+ #
50
+ # @since 0.8.0
51
+ #
52
+ # @example
53
+ # require 'hanami/utils/class'
54
+ #
55
+ # module App
56
+ # module Service
57
+ # class Endpoint
58
+ # end
59
+ # end
60
+ #
61
+ # class ServiceEndpoint
62
+ # end
63
+ # end
64
+ #
65
+ # # basic usage
66
+ # Hanami::Utils::Class.load('App::Service') # => App::Service
67
+ # Hanami::Utils::Class.load(App::Service) # => App::Service
68
+ #
69
+ # # with explicit namespace
70
+ # Hanami::Utils::Class.load('Service', App) # => App::Service
71
+ def self.load(name, namespace = Object)
72
+ load!(name, namespace) if namespace.const_defined?(name.to_s)
73
+ end
74
+
44
75
  # Loads a class from the given pattern name and namespace
45
76
  #
46
77
  # @param pattern [String] the class name pattern
@@ -82,12 +113,12 @@ module Hanami
82
113
  String.new(pattern).tokenize do |token|
83
114
  begin
84
115
  return namespace.const_get(token)
85
- rescue NameError
116
+ rescue NameError # rubocop:disable Lint/HandleExceptions
86
117
  end
87
118
  end
88
119
 
89
- full_name = [ (namespace == Object ? nil : namespace), pattern ].compact.join('::')
90
- raise NameError.new("uninitialized constant #{ full_name }")
120
+ full_name = [(namespace == Object ? nil : namespace), pattern].compact.join('::')
121
+ raise NameError.new("uninitialized constant #{full_name}")
91
122
  end
92
123
  end
93
124
  end
@@ -12,6 +12,8 @@ module Hanami
12
12
  base.extend ClassMethods
13
13
  end
14
14
 
15
+ # @since 0.1.0
16
+ # @api private
15
17
  module ClassMethods
16
18
  # Defines a class level accessor for the given attribute(s).
17
19
  #
@@ -64,13 +66,14 @@ module Hanami
64
66
  # SmallAirplane.wheels # => 8
65
67
  def class_attribute(*attributes)
66
68
  singleton_class.class_eval do
67
- attr_accessor *attributes
69
+ attr_accessor(*attributes)
68
70
  end
69
71
 
70
72
  class_attributes.merge(attributes)
71
73
  end
72
74
 
73
75
  protected
76
+
74
77
  # @see Class#inherited
75
78
  def inherited(subclass)
76
79
  class_attributes.each do |attr|
@@ -84,6 +87,7 @@ module Hanami
84
87
  end
85
88
 
86
89
  private
90
+
87
91
  # Class accessor for class attributes.
88
92
  # @private
89
93
  def class_attributes
@@ -58,10 +58,11 @@ module Hanami
58
58
  # # => old_method is deprecated, please use new_method - called from: test.rb:20:in `start'.
59
59
  # # => started
60
60
  def initialize(message)
61
- ::Kernel.warn("#{ message } - called from: #{ caller[caller_index] }.")
61
+ ::Kernel.warn("#{message} - called from: #{caller[caller_index]}.")
62
62
  end
63
63
 
64
64
  private
65
+
65
66
  def caller_index
66
67
  Utils.jruby? || Utils.rubinius? ? 1 : 2
67
68
  end
@@ -45,7 +45,7 @@ module Hanami
45
45
  # result = Hanami::Utils::Duplicable.dup(object)
46
46
  #
47
47
  # puts result # => "hello"
48
- # puts result.object_id # => 70172671467020 Different object
48
+ # puts result.object_id # => 70172671467020 - Different object
49
49
  #
50
50
  # @example Custom Logic
51
51
  # require 'hanami/utils/duplicable'
@@ -64,7 +64,7 @@ module Hanami
64
64
  # end
65
65
  #
66
66
  # puts result # => "{:a=>1}"
67
- # puts result.object_id # => 70207105185500 Different object
67
+ # puts result.object_id # => 70207105185500 - Different object
68
68
  def self.dup(value, &blk)
69
69
  case value
70
70
  when NilClass, FalseClass, TrueClass, Symbol, Numeric
@@ -11,7 +11,7 @@ module Hanami
11
11
  # @see https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
12
12
  # @see https://www.owasp.org/index.php/ESAPI
13
13
  # @see https://github.com/ESAPI/esapi-java-legacy
14
- module Escape
14
+ module Escape # rubocop:disable Metrics/ModuleLength
15
15
  # Hex base for base 10 integer conversion
16
16
  #
17
17
  # @since 0.4.0
@@ -30,14 +30,14 @@ module Hanami
30
30
  #
31
31
  # @since 0.4.0
32
32
  # @api private
33
- REPLACEMENT_HEX = "fffd".freeze
33
+ REPLACEMENT_HEX = 'fffd'.freeze
34
34
 
35
35
  # Low hex codes lookup table
36
36
  #
37
37
  # @since 0.4.0
38
38
  # @api private
39
39
  HEX_CODES = (0..255).each_with_object({}) do |c, codes|
40
- if (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A)
40
+ if (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A) # rubocop:disable Style/ConditionalAssignment
41
41
  codes[c] = nil
42
42
  else
43
43
  codes[c] = c.to_s(HEX_BASE)
@@ -362,7 +362,7 @@ module Hanami
362
362
  # @api private
363
363
  #
364
364
  # @see Hanami::Utils::Escape.url
365
- DEFAULT_URL_SCHEMES = ['http', 'https', 'mailto'].freeze
365
+ DEFAULT_URL_SCHEMES = %w(http https mailto).freeze
366
366
 
367
367
  # The output of an escape.
368
368
  #
@@ -511,65 +511,66 @@ module Hanami
511
511
  return input if input.is_a?(SafeString)
512
512
 
513
513
  SafeString.new(
514
- URI.extract(
515
- URI.decode(input),
514
+ URI::Parser.new.extract(
515
+ URI.decode_www_form_component(input),
516
516
  schemes
517
517
  ).first.to_s
518
518
  )
519
519
  end
520
520
 
521
- private
522
- # Encode the given string into UTF-8
523
- #
524
- # @param input [String] the input
525
- #
526
- # @return [String] an UTF-8 encoded string
527
- #
528
- # @since 0.4.0
529
- # @api private
530
- def self.encode(input)
531
- return '' if input.nil?
532
- input.to_s.encode(Encoding::UTF_8)
533
- rescue Encoding::UndefinedConversionError
534
- input.dup.force_encoding(Encoding::UTF_8)
535
- end
521
+ class << self
522
+ private
536
523
 
537
- # Encode the given UTF-8 char.
538
- #
539
- # @param char [String] an UTF-8 char
540
- # @param safe_chars [Hash] a table of safe chars
541
- #
542
- # @return [String] an HTML encoded string
543
- #
544
- # @since 0.4.0
545
- # @api private
546
- def self.encode_char(char, safe_chars = {})
547
- return char if safe_chars[char]
524
+ # Encode the given string into UTF-8
525
+ #
526
+ # @param input [String] the input
527
+ #
528
+ # @return [String] an UTF-8 encoded string
529
+ #
530
+ # @since 0.4.0
531
+ # @api private
532
+ def encode(input)
533
+ return '' if input.nil?
534
+ input.to_s.encode(Encoding::UTF_8)
535
+ rescue Encoding::UndefinedConversionError
536
+ input.dup.force_encoding(Encoding::UTF_8)
537
+ end
548
538
 
549
- code = char.ord
550
- hex = hex_for_non_alphanumeric_code(code)
551
- return char if hex.nil?
539
+ # Encode the given UTF-8 char.
540
+ #
541
+ # @param char [String] an UTF-8 char
542
+ # @param safe_chars [Hash] a table of safe chars
543
+ #
544
+ # @return [String] an HTML encoded string
545
+ #
546
+ # @since 0.4.0
547
+ # @api private
548
+ def encode_char(char, safe_chars = {})
549
+ return char if safe_chars[char]
552
550
 
553
- if NON_PRINTABLE_CHARS[code]
554
- hex = REPLACEMENT_HEX
555
- end
551
+ code = char.ord
552
+ hex = hex_for_non_alphanumeric_code(code)
553
+ return char if hex.nil?
556
554
 
557
- if entity = HTML_ENTITIES[code]
558
- "&#{ entity };"
559
- else
560
- "&#x#{ hex };"
555
+ hex = REPLACEMENT_HEX if NON_PRINTABLE_CHARS[code]
556
+
557
+ if entity = HTML_ENTITIES[code] # rubocop:disable Lint/AssignmentInCondition
558
+ "&#{entity};"
559
+ else
560
+ "&#x#{hex};"
561
+ end
561
562
  end
562
- end
563
563
 
564
- # Transforms the given char code
565
- #
566
- # @since 0.4.0
567
- # @api private
568
- def self.hex_for_non_alphanumeric_code(input)
569
- if input < LOW_HEX_CODE_LIMIT
570
- HEX_CODES[input]
571
- else
572
- input.to_s(HEX_BASE)
564
+ # Transforms the given char code
565
+ #
566
+ # @since 0.4.0
567
+ # @api private
568
+ def hex_for_non_alphanumeric_code(input)
569
+ if input < LOW_HEX_CODE_LIMIT
570
+ HEX_CODES[input]
571
+ else
572
+ input.to_s(HEX_BASE)
573
+ end
573
574
  end
574
575
  end
575
576
  end
@@ -10,7 +10,7 @@ module Hanami
10
10
  #
11
11
  # @see Hanami::Utils::Hash#deep_dup
12
12
  # @see Hanami::Utils::Duplicable
13
- DUPLICATE_LOGIC = Proc.new do |value|
13
+ DUPLICATE_LOGIC = proc do |value|
14
14
  case value
15
15
  when Hash
16
16
  value.deep_dup
@@ -65,7 +65,7 @@ module Hanami
65
65
  def symbolize!
66
66
  keys.each do |k|
67
67
  v = delete(k)
68
- v = Hash.new(v).symbolize! if v.is_a?(::Hash)
68
+ v = self.class.new(v).symbolize! if v.is_a?(::Hash) || v.is_a?(self.class)
69
69
 
70
70
  self[k.to_sym] = v
71
71
  end
@@ -90,7 +90,7 @@ module Hanami
90
90
  def stringify!
91
91
  keys.each do |k|
92
92
  v = delete(k)
93
- v = Hash.new(v).stringify! if v.is_a?(::Hash)
93
+ v = self.class.new(v).stringify! if v.is_a?(::Hash) || v.is_a?(self.class)
94
94
 
95
95
  self[k.to_s] = v
96
96
  end
@@ -160,8 +160,8 @@ module Hanami
160
160
  # # it deeply duplicates Hanami::Utils::Hash, by preserving the class
161
161
  # duped['u_hash'].class # => Hanami::Utils::Hash
162
162
  def deep_dup
163
- Hash.new.tap do |result|
164
- @hash.each {|k, v| result[k] = Duplicable.dup(v, &DUPLICATE_LOGIC) }
163
+ self.class.new.tap do |result|
164
+ @hash.each { |k, v| result[k] = Duplicable.dup(v, &DUPLICATE_LOGIC) }
165
165
  end
166
166
  end
167
167
 
@@ -229,7 +229,7 @@ module Hanami
229
229
  end
230
230
  end
231
231
 
232
- alias_method :to_hash, :to_h
232
+ alias to_hash to_h
233
233
 
234
234
  # Converts into a nested array of [ key, value ] arrays.
235
235
  #
@@ -251,7 +251,7 @@ module Hanami
251
251
  @hash == other.to_h
252
252
  end
253
253
 
254
- alias_method :eql?, :==
254
+ alias eql? ==
255
255
 
256
256
  # Returns the hash of the internal @hash
257
257
  #
@@ -283,7 +283,7 @@ module Hanami
283
283
  h = self.class.new(h) if h.is_a?(::Hash)
284
284
  h
285
285
  else
286
- raise NoMethodError.new(%(undefined method `#{ m }' for #{ @hash }:#{ self.class }))
286
+ raise NoMethodError.new(%(undefined method `#{m}' for #{@hash}:#{self.class}))
287
287
  end
288
288
  end
289
289
 
@@ -291,7 +291,7 @@ module Hanami
291
291
  #
292
292
  # @api private
293
293
  # @since 0.3.0
294
- def respond_to_missing?(m, include_private=false)
294
+ def respond_to_missing?(m, include_private = false)
295
295
  @hash.respond_to?(m, include_private)
296
296
  end
297
297
  end
@@ -1,11 +1,14 @@
1
1
  require 'hanami/utils/class_attribute'
2
+ require 'hanami/utils/blank'
2
3
 
3
4
  module Hanami
4
5
  module Utils
5
6
  # String inflector
6
7
  #
7
8
  # @since 0.4.1
8
- module Inflector
9
+ #
10
+ # rubocop:disable Style/PerlBackrefs
11
+ module Inflector # rubocop:disable Metrics/ModuleLength
9
12
  # Rules for irregular plurals
10
13
  #
11
14
  # @since 0.6.0
@@ -40,12 +43,6 @@ module Hanami
40
43
  end
41
44
  end
42
45
 
43
- # Matcher for blank strings
44
- #
45
- # @since 0.4.1
46
- # @api private
47
- BLANK_STRING_MATCHER = /\A[[:space:]]*\z/.freeze
48
-
49
46
  # @since 0.4.1
50
47
  # @api private
51
48
  A = 'a'.freeze
@@ -142,6 +139,14 @@ module Hanami
142
139
  # @api private
143
140
  OUSE = 'ouse'.freeze
144
141
 
142
+ # @since 0.4.1
143
+ # @api private
144
+ RSE = 'rse'.freeze
145
+
146
+ # @since 0.4.1
147
+ # @api private
148
+ RSES = 'rses'.freeze
149
+
145
150
  # @since 0.4.1
146
151
  # @api private
147
152
  S = 's'.freeze
@@ -193,61 +198,66 @@ module Hanami
193
198
  # @since 0.6.0
194
199
  # @api private
195
200
  class_attribute :plurals
196
- self.plurals = IrregularRules.new({
201
+ self.plurals = IrregularRules.new(
197
202
  # irregular
198
- 'cactus' => 'cacti',
199
- 'child' => 'children',
200
- 'corpus' => 'corpora',
201
- 'foot' => 'feet',
202
- 'genus' => 'genera',
203
- 'goose' => 'geese',
204
- 'man' => 'men',
205
- 'ox' => 'oxen',
206
- 'person' => 'people',
207
- 'quiz' => 'quizzes',
208
- 'sex' => 'sexes',
209
- 'testis' => 'testes',
210
- 'tooth' => 'teeth',
211
- 'woman' => 'women',
203
+ 'cactus' => 'cacti',
204
+ 'child' => 'children',
205
+ 'corpus' => 'corpora',
206
+ 'foot' => 'feet',
207
+ 'genus' => 'genera',
208
+ 'goose' => 'geese',
209
+ 'louse' => 'lice',
210
+ 'man' => 'men',
211
+ 'mouse' => 'mice',
212
+ 'ox' => 'oxen',
213
+ 'person' => 'people',
214
+ 'quiz' => 'quizzes',
215
+ 'sex' => 'sexes',
216
+ 'testis' => 'testes',
217
+ 'tooth' => 'teeth',
218
+ 'woman' => 'women',
212
219
  # uncountable
213
- 'deer' => 'deer',
214
- 'equipment' => 'equipment',
215
- 'fish' => 'fish',
216
- 'information' => 'information',
217
- 'means' => 'means',
218
- 'money' => 'money',
219
- 'news' => 'news',
220
- 'offspring' => 'offspring',
221
- 'rice' => 'rice',
222
- 'series' => 'series',
223
- 'sheep' => 'sheep',
224
- 'species' => 'species',
220
+ 'deer' => 'deer',
221
+ 'equipment' => 'equipment',
222
+ 'fish' => 'fish',
223
+ 'information' => 'information',
224
+ 'means' => 'means',
225
+ 'money' => 'money',
226
+ 'news' => 'news',
227
+ 'offspring' => 'offspring',
228
+ 'rice' => 'rice',
229
+ 'series' => 'series',
230
+ 'sheep' => 'sheep',
231
+ 'species' => 'species',
232
+ 'police' => 'police',
225
233
  # regressions
226
234
  # https://github.com/hanami/utils/issues/106
227
- 'album' => 'albums',
228
- })
235
+ 'album' => 'albums'
236
+ )
229
237
 
230
238
  # Irregular rules for singulars
231
239
  #
232
240
  # @since 0.6.0
233
241
  # @api private
234
242
  class_attribute :singulars
235
- self.singulars = IrregularRules.new({
243
+ self.singulars = IrregularRules.new(
236
244
  # irregular
237
- 'cacti' => 'cactus',
238
- 'children'=> 'child',
239
- 'corpora' => 'corpus',
240
- 'feet' => 'foot',
241
- 'genera' => 'genus',
242
- 'geese' => 'goose',
243
- 'men' => 'man',
244
- 'oxen' => 'ox',
245
- 'people' => 'person',
246
- 'quizzes' => 'quiz',
247
- 'sexes' => 'sex',
248
- 'testes' => 'testis',
249
- 'teeth' => 'tooth',
250
- 'women' => 'woman',
245
+ 'cacti' => 'cactus',
246
+ 'children' => 'child',
247
+ 'corpora' => 'corpus',
248
+ 'feet' => 'foot',
249
+ 'genera' => 'genus',
250
+ 'geese' => 'goose',
251
+ 'lice' => 'louse',
252
+ 'men' => 'man',
253
+ 'mice' => 'mouse',
254
+ 'oxen' => 'ox',
255
+ 'people' => 'person',
256
+ 'quizzes' => 'quiz',
257
+ 'sexes' => 'sex',
258
+ 'testes' => 'testis',
259
+ 'teeth' => 'tooth',
260
+ 'women' => 'woman',
251
261
  # uncountable
252
262
  'deer' => 'deer',
253
263
  'equipment' => 'equipment',
@@ -263,9 +273,8 @@ module Hanami
263
273
  'species' => 'species',
264
274
  'police' => 'police',
265
275
  # fallback
266
- 'hives' => 'hive',
267
- 'horses' => 'horse',
268
- })
276
+ 'hives' => 'hive'
277
+ )
269
278
 
270
279
  # Block for custom inflection rules.
271
280
  #
@@ -338,8 +347,12 @@ module Hanami
338
347
  #
339
348
  # @api private
340
349
  # @since 0.4.1
350
+ #
351
+ # rubocop:disable Metrics/AbcSize
352
+ # rubocop:disable Metrics/CyclomaticComplexity
353
+ # rubocop:disable Metrics/MethodLength
341
354
  def self.pluralize(string)
342
- return string if string.nil? || string.match(BLANK_STRING_MATCHER)
355
+ return string if string.nil? || string =~ Utils::Blank::STRING_MATCHER
343
356
 
344
357
  case string
345
358
  when plurals
@@ -358,8 +371,6 @@ module Hanami
358
371
  string + TA
359
372
  when /\A(.*)(um|#{ A })\z/
360
373
  $1 + A
361
- when /\A(.*)(ouse|#{ ICE })\z/
362
- $1 + ICE
363
374
  when /\A(buffal|domin|ech|embarg|her|mosquit|potat|tomat)#{ O }\z/i
364
375
  $1 + OES
365
376
  when /\A(.*)(en|#{ INA })\z/
@@ -380,6 +391,9 @@ module Hanami
380
391
  string + S
381
392
  end
382
393
  end
394
+ # rubocop:enable Metrics/AbcSize
395
+ # rubocop:enable Metrics/CyclomaticComplexity
396
+ # rubocop:enable Metrics/MethodLength
383
397
 
384
398
  # Singularize the given string
385
399
  #
@@ -389,8 +403,13 @@ module Hanami
389
403
  #
390
404
  # @api private
391
405
  # @since 0.4.1
406
+ #
407
+ # rubocop:disable Metrics/AbcSize
408
+ # rubocop:disable Metrics/CyclomaticComplexity
409
+ # rubocop:disable Metrics/MethodLength
410
+ # rubocop:disable Metrics/PerceivedComplexity
392
411
  def self.singularize(string)
393
- return string if string.nil? || string.match(BLANK_STRING_MATCHER)
412
+ return string if string.nil? || string =~ Utils::Blank::STRING_MATCHER
394
413
 
395
414
  case string
396
415
  when singulars
@@ -399,18 +418,16 @@ module Hanami
399
418
  string.sub(CHES, CH)
400
419
  when /\A.*[^aeiou]#{IES}\z/
401
420
  string.sub(IES, Y)
402
- when /\A(.*)#{ICE}\z/
403
- $1 + OUSE
404
421
  when /\A.*#{EAUX}\z/
405
422
  string.chop
406
423
  when /\A(.*)#{IDES}\z/
407
424
  $1 + IS
408
425
  when /\A(.*)#{US}\z/
409
426
  $1 + I
427
+ when /\A(.*)#{RSES}\z/
428
+ $1 + RSE
410
429
  when /\A(.*)#{SES}\z/
411
430
  $1 + S
412
- when /\A(.*)#{OUSE}\z/
413
- $1 + ICE
414
431
  when /\A(.*)#{MATA}\z/
415
432
  $1 + MA
416
433
  when /\A(.*)#{OES}\z/
@@ -437,6 +454,11 @@ module Hanami
437
454
  string.chop
438
455
  end
439
456
  end
457
+ # rubocop:enable Metrics/AbcSize
458
+ # rubocop:enable Metrics/CyclomaticComplexity
459
+ # rubocop:enable Metrics/MethodLength
460
+ # rubocop:enable Metrics/PerceivedComplexity
440
461
  end
462
+ # rubocop:enable Style/PerlBackrefs
441
463
  end
442
464
  end