sleeping_king_studios-tools 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +32 -3
- data/DEVELOPMENT.md +5 -7
- data/README.md +3 -64
- data/lib/sleeping_king_studios/tools.rb +12 -6
- data/lib/sleeping_king_studios/tools/all.rb +8 -3
- data/lib/sleeping_king_studios/tools/array_tools.rb +83 -58
- data/lib/sleeping_king_studios/tools/base.rb +18 -0
- data/lib/sleeping_king_studios/tools/core_tools.rb +68 -22
- data/lib/sleeping_king_studios/tools/enumerable_tools.rb +6 -3
- data/lib/sleeping_king_studios/tools/hash_tools.rb +59 -47
- data/lib/sleeping_king_studios/tools/integer_tools.rb +97 -55
- data/lib/sleeping_king_studios/tools/object_tools.rb +67 -50
- data/lib/sleeping_king_studios/tools/string_tools.rb +81 -63
- data/lib/sleeping_king_studios/tools/toolbelt.rb +46 -22
- data/lib/sleeping_king_studios/tools/toolbox.rb +2 -2
- data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +197 -122
- data/lib/sleeping_king_studios/tools/toolbox/constant_map.rb +24 -51
- data/lib/sleeping_king_studios/tools/toolbox/delegator.rb +50 -29
- data/lib/sleeping_king_studios/tools/toolbox/inflector.rb +130 -0
- data/lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb +171 -0
- data/lib/sleeping_king_studios/tools/toolbox/mixin.rb +10 -10
- data/lib/sleeping_king_studios/tools/toolbox/semantic_version.rb +15 -14
- data/lib/sleeping_king_studios/tools/version.rb +6 -8
- metadata +84 -26
- data/lib/sleeping_king_studios/tools/semantic_version.rb +0 -15
- data/lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb +0 -185
@@ -1,26 +1,21 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'sleeping_king_studios/tools/string_tools'
|
4
4
|
require 'sleeping_king_studios/tools/toolbox'
|
5
5
|
|
6
6
|
module SleepingKingStudios::Tools::Toolbox
|
7
7
|
# Provides an enumerable interface for defining a group of constants.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# @param constants [Hash] The constants to define.
|
13
|
-
def new constants
|
14
|
-
mod = Module.new
|
15
|
-
mod.extend self
|
8
|
+
class ConstantMap < Module
|
9
|
+
# @param constants [Hash] The constants to define.
|
10
|
+
def initialize(constants)
|
11
|
+
super()
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
end # each
|
13
|
+
constants.each do |const_name, const_value|
|
14
|
+
const_set(const_name, const_value)
|
20
15
|
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
16
|
+
define_reader(const_name)
|
17
|
+
end
|
18
|
+
end
|
24
19
|
|
25
20
|
# Returns a hash with the names and values of the defined constants.
|
26
21
|
#
|
@@ -28,17 +23,17 @@ module SleepingKingStudios::Tools::Toolbox
|
|
28
23
|
def all
|
29
24
|
constants.each.with_object({}) do |const_name, hsh|
|
30
25
|
hsh[const_name] = const_get(const_name)
|
31
|
-
end
|
32
|
-
end
|
26
|
+
end
|
27
|
+
end
|
33
28
|
|
34
29
|
# Iterates through the defined constants, yielding the name and value of
|
35
30
|
# each constant to the block.
|
36
31
|
#
|
37
32
|
# @yieldparam key [Symbol] The name of the symbol.
|
38
33
|
# @yieldparam value [Object] The value of the symbol.
|
39
|
-
def each
|
34
|
+
def each(&block)
|
40
35
|
all.each(&block)
|
41
|
-
end
|
36
|
+
end
|
42
37
|
|
43
38
|
# Freezes the constant map and recursively freezes every constant value
|
44
39
|
# using ObjectTools#deep_freeze. Also pre-emptively defines any reader
|
@@ -47,48 +42,26 @@ module SleepingKingStudios::Tools::Toolbox
|
|
47
42
|
# @see ObjectTools#deep_freeze
|
48
43
|
def freeze
|
49
44
|
constants.each do |const_name|
|
50
|
-
reader_name = const_name.downcase
|
51
|
-
|
52
|
-
define_reader(const_name, reader_name) unless methods.include?(reader_name)
|
53
|
-
|
54
45
|
object_tools.deep_freeze const_get(const_name)
|
55
|
-
end
|
46
|
+
end
|
56
47
|
|
57
48
|
super
|
58
|
-
end
|
49
|
+
end
|
59
50
|
|
60
51
|
private
|
61
52
|
|
62
|
-
def define_reader
|
63
|
-
reader_name ||= const_name.
|
64
|
-
|
65
|
-
define_singleton_method reader_name, ->() { const_get const_name }
|
66
|
-
end # method define_reader
|
67
|
-
|
68
|
-
def method_missing symbol, *args, &block
|
69
|
-
const_name = string_tools.underscore(symbol.to_s).upcase.intern
|
70
|
-
|
71
|
-
if constants.include?(const_name)
|
72
|
-
define_reader(const_name, symbol)
|
53
|
+
def define_reader(const_name, reader_name = nil)
|
54
|
+
reader_name ||= string_tools.underscore(const_name.to_s).intern
|
73
55
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
super
|
78
|
-
end # method method_missing
|
56
|
+
define_singleton_method(reader_name) { const_get const_name }
|
57
|
+
end
|
79
58
|
|
80
59
|
def object_tools
|
81
60
|
::SleepingKingStudios::Tools::ObjectTools
|
82
|
-
end
|
83
|
-
|
84
|
-
def respond_to_missing? symbol, include_all = false
|
85
|
-
const_name = string_tools.underscore(symbol.to_s).upcase.intern
|
86
|
-
|
87
|
-
constants.include?(const_name) || super
|
88
|
-
end # method respond_to_missing?
|
61
|
+
end
|
89
62
|
|
90
63
|
def string_tools
|
91
64
|
::SleepingKingStudios::Tools::StringTools
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,7 +1,12 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'sleeping_king_studios/tools/core_tools'
|
3
4
|
require 'sleeping_king_studios/tools/toolbox'
|
4
5
|
|
6
|
+
# rubocop:disable Metrics/AbcSize
|
7
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
9
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
5
10
|
module SleepingKingStudios::Tools::Toolbox
|
6
11
|
# Module for extending classes with basic delegation. Supports passing
|
7
12
|
# arguments, keywords, and blocks to the delegated method.
|
@@ -13,6 +18,15 @@ module SleepingKingStudios::Tools::Toolbox
|
|
13
18
|
# delegate :my_method, :to => MyService
|
14
19
|
# end # class
|
15
20
|
module Delegator
|
21
|
+
def self.extended(_module)
|
22
|
+
super
|
23
|
+
|
24
|
+
SleepingKingStudios::Tools::CoreTools.deprecate(
|
25
|
+
'SleepingKingStudios::Tools::Toolbox::Delegator',
|
26
|
+
message: 'Use Ruby stdlib Forwardable instead.'
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
16
30
|
# Defines a wrapper method to delegate implementation of the specified
|
17
31
|
# method or methods to an object, to the object at another specified method,
|
18
32
|
# or to the object at a specified instance variable.
|
@@ -58,13 +72,13 @@ module SleepingKingStudios::Tools::Toolbox
|
|
58
72
|
# variable of that name and call `method_name` on the result.
|
59
73
|
#
|
60
74
|
# @raise ArgumentError if no delegate is specified.
|
61
|
-
def delegate
|
62
|
-
raise ArgumentError
|
75
|
+
def delegate(*method_names, to: nil, allow_nil: false)
|
76
|
+
raise ArgumentError, 'must specify a delegate' if to.nil? && !allow_nil
|
63
77
|
|
64
78
|
method_names.each do |method_name|
|
65
|
-
delegate_method method_name, to, { :
|
66
|
-
end
|
67
|
-
end
|
79
|
+
delegate_method method_name, to, { allow_nil: !!allow_nil }
|
80
|
+
end
|
81
|
+
end
|
68
82
|
|
69
83
|
# Wraps a delegate object by automatically delegating each method that is
|
70
84
|
# defined on the delegate class from the instance to the delegate. The
|
@@ -79,7 +93,10 @@ module SleepingKingStudios::Tools::Toolbox
|
|
79
93
|
# class Errors
|
80
94
|
# extend SleepingKingStudios::Tools::Delegator
|
81
95
|
#
|
82
|
-
# wrap_delegate
|
96
|
+
# wrap_delegate(
|
97
|
+
# Hash.new { |hsh, key| hsh[key] = Errors.new },
|
98
|
+
# :klass => Hash
|
99
|
+
# )
|
83
100
|
#
|
84
101
|
# def messages
|
85
102
|
# @messages ||= []
|
@@ -116,33 +133,33 @@ module SleepingKingStudios::Tools::Toolbox
|
|
116
133
|
# belong to the specified klass.
|
117
134
|
#
|
118
135
|
# @see #delegate
|
119
|
-
def wrap_delegate
|
136
|
+
def wrap_delegate(target, klass: nil, except: [], only: [])
|
120
137
|
if klass.is_a?(Module)
|
121
|
-
unless target.is_a?(String) ||
|
122
|
-
|
123
|
-
|
138
|
+
unless target.is_a?(String) ||
|
139
|
+
target.is_a?(Symbol) ||
|
140
|
+
target.is_a?(klass)
|
141
|
+
raise ArgumentError, "expected delegate to be a #{klass.name}"
|
142
|
+
end
|
124
143
|
|
125
144
|
method_names = klass.instance_methods - Object.instance_methods
|
126
145
|
elsif target.is_a?(String) || target.is_a?(Symbol)
|
127
|
-
raise ArgumentError
|
146
|
+
raise ArgumentError, 'must specify a delegate class'
|
128
147
|
else
|
129
148
|
method_names = target.methods - Object.new.methods
|
130
|
-
end
|
149
|
+
end
|
131
150
|
|
132
151
|
if except.is_a?(Array) && !except.empty?
|
133
|
-
method_names
|
134
|
-
end
|
152
|
+
method_names -= except.map(&:intern)
|
153
|
+
end
|
135
154
|
|
136
|
-
if only.is_a?(Array) && !only.empty?
|
137
|
-
method_names = method_names & only.map(&:intern)
|
138
|
-
end # if
|
155
|
+
method_names &= only.map(&:intern) if only.is_a?(Array) && !only.empty?
|
139
156
|
|
140
|
-
delegate
|
141
|
-
end
|
157
|
+
delegate(*method_names, to: target)
|
158
|
+
end
|
142
159
|
|
143
160
|
private
|
144
161
|
|
145
|
-
def delegate_method
|
162
|
+
def delegate_method(method_name, target, options = {})
|
146
163
|
if target.is_a?(String) || target.is_a?(Symbol)
|
147
164
|
target = target.intern
|
148
165
|
|
@@ -153,7 +170,7 @@ module SleepingKingStudios::Tools::Toolbox
|
|
153
170
|
return nil if receiver.nil? && options[:allow_nil]
|
154
171
|
|
155
172
|
receiver.send(method_name, *args, &block)
|
156
|
-
end
|
173
|
+
end
|
157
174
|
else
|
158
175
|
define_method method_name do |*args, &block|
|
159
176
|
receiver = send(target)
|
@@ -161,15 +178,19 @@ module SleepingKingStudios::Tools::Toolbox
|
|
161
178
|
return nil if receiver.nil? && options[:allow_nil]
|
162
179
|
|
163
180
|
receiver.send(method_name, *args, &block)
|
164
|
-
end
|
165
|
-
end
|
181
|
+
end
|
182
|
+
end
|
166
183
|
else
|
167
184
|
define_method method_name do |*args, &block|
|
168
185
|
return nil if target.nil? && options[:allow_nil]
|
169
186
|
|
170
187
|
target.send(method_name, *args, &block)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
# rubocop:enable Metrics/AbcSize
|
194
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
195
|
+
# rubocop:enable Metrics/MethodLength
|
196
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
require 'sleeping_king_studios/tools/toolbox'
|
6
|
+
|
7
|
+
module SleepingKingStudios::Tools::Toolbox
|
8
|
+
# Transforms words (e.g. from singular to plural).
|
9
|
+
#
|
10
|
+
# Should maintain the same interface as ActiveSupport::Inflector.
|
11
|
+
class Inflector
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
autoload :Rules, 'sleeping_king_studios/tools/toolbox/inflector/rules'
|
15
|
+
|
16
|
+
def_delegators :@rules,
|
17
|
+
:irregular_words,
|
18
|
+
:irregular_words_reversed,
|
19
|
+
:plural_rules,
|
20
|
+
:singular_rules,
|
21
|
+
:uncountable_words
|
22
|
+
|
23
|
+
private \
|
24
|
+
:irregular_words,
|
25
|
+
:irregular_words_reversed,
|
26
|
+
:plural_rules,
|
27
|
+
:singular_rules,
|
28
|
+
:uncountable_words
|
29
|
+
|
30
|
+
# @return [Rules] An object defining the transformation rules.
|
31
|
+
def initialize(rules: nil)
|
32
|
+
@rules = rules || Rules.new
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Rules] The defined rules object for the inflector.
|
36
|
+
attr_reader :rules
|
37
|
+
|
38
|
+
# Transforms the word to CamelCase.
|
39
|
+
#
|
40
|
+
# @param word [String] The word to transform.
|
41
|
+
# @param uppercase_first_letter [Boolean] If true, the first letter is
|
42
|
+
# capitalized. Defaults to true.
|
43
|
+
#
|
44
|
+
# @return [String] The word in CamelCase.
|
45
|
+
def camelize(word, uppercase_first_letter = true)
|
46
|
+
return '' if word.nil? || word.empty?
|
47
|
+
|
48
|
+
word = word.to_s.gsub(/(\b|[_-])([a-z])/) { Regexp.last_match(2).upcase }
|
49
|
+
|
50
|
+
(uppercase_first_letter ? word[0].upcase : word[0].downcase) + word[1..-1]
|
51
|
+
end
|
52
|
+
|
53
|
+
# rubocop:disable Metrics/AbcSize
|
54
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
55
|
+
|
56
|
+
# Transforms the word to a plural, lowercase form.
|
57
|
+
#
|
58
|
+
# @param word [String] The word to transform.
|
59
|
+
#
|
60
|
+
# @return [String] The word in plural form.
|
61
|
+
def pluralize(word)
|
62
|
+
return '' if word.nil? || word.empty?
|
63
|
+
|
64
|
+
normalized = word.to_s.strip.downcase
|
65
|
+
|
66
|
+
return normalized if uncountable_words.include?(normalized)
|
67
|
+
|
68
|
+
return normalized if irregular_words_reversed.key?(normalized)
|
69
|
+
|
70
|
+
return irregular_words[normalized] if irregular_words.key?(normalized)
|
71
|
+
|
72
|
+
plural_rules.each do |match, replace|
|
73
|
+
next unless normalized =~ match
|
74
|
+
|
75
|
+
return normalized.sub(match, replace)
|
76
|
+
end
|
77
|
+
|
78
|
+
word
|
79
|
+
end
|
80
|
+
# rubocop:enable Metrics/AbcSize
|
81
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
82
|
+
|
83
|
+
# rubocop:disable Metrics/AbcSize
|
84
|
+
# rubocop:disable Metrics/MethodLength
|
85
|
+
|
86
|
+
# Transforms the word to a singular, lowercase form.
|
87
|
+
#
|
88
|
+
# @param word [String] The word to transform.
|
89
|
+
#
|
90
|
+
# @return [String] The word in singular form.
|
91
|
+
def singularize(word)
|
92
|
+
return '' if word.nil? || word.empty?
|
93
|
+
|
94
|
+
normalized = word.to_s.strip.downcase
|
95
|
+
|
96
|
+
return normalized if irregular_words.key?(normalized)
|
97
|
+
|
98
|
+
if irregular_words_reversed.key?(normalized)
|
99
|
+
return irregular_words_reversed[normalized]
|
100
|
+
end
|
101
|
+
|
102
|
+
singular_rules.each do |match, replace|
|
103
|
+
next unless normalized =~ match
|
104
|
+
|
105
|
+
return normalized.sub(match, replace)
|
106
|
+
end
|
107
|
+
|
108
|
+
word
|
109
|
+
end
|
110
|
+
|
111
|
+
# rubocop:enable Metrics/AbcSize
|
112
|
+
# rubocop:enable Metrics/MethodLength
|
113
|
+
|
114
|
+
# Transforms the word to a lowercase, underscore-separated form.
|
115
|
+
#
|
116
|
+
# @params word [String] the word to transform.
|
117
|
+
#
|
118
|
+
# @return [String] The word in underscored form.
|
119
|
+
def underscore(word)
|
120
|
+
return '' if word.nil? || word.empty?
|
121
|
+
|
122
|
+
word = word.to_s.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
123
|
+
|
124
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
125
|
+
word.tr!('-', '_')
|
126
|
+
word.downcase!
|
127
|
+
word
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/toolbox'
|
4
|
+
|
5
|
+
class SleepingKingStudios::Tools::Toolbox::Inflector
|
6
|
+
# Rules for inflecting words.
|
7
|
+
class Rules
|
8
|
+
# @param irregular_words [Hash<String, String>] Hash of irregular word
|
9
|
+
# pairs in singular => plural order, e.g. "child" => "children".
|
10
|
+
# @param plural_rules [Array<Array<(Regexp, String)>>] Rules for
|
11
|
+
# pluralizing words.
|
12
|
+
# @param singular_rules [Array<Array<(Regexp, String)>>] Rules for
|
13
|
+
# singularizing words.
|
14
|
+
# @param uncountable_words [Array<String>] List of uncountable words,
|
15
|
+
# e.g. "data".
|
16
|
+
def initialize(
|
17
|
+
irregular_words: nil,
|
18
|
+
plural_rules: nil,
|
19
|
+
singular_rules: nil,
|
20
|
+
uncountable_words: nil
|
21
|
+
)
|
22
|
+
@plural_rules = plural_rules || default_plural_rules
|
23
|
+
@singular_rules = singular_rules || default_singular_rules
|
24
|
+
@irregular_words = irregular_words || default_irregular_words
|
25
|
+
@uncountable_words =
|
26
|
+
Set.new(uncountable_words || default_uncountable_words)
|
27
|
+
|
28
|
+
@irregular_words_reversed = reverse_hash(@irregular_words)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Array<Array<(String, String)>] Hash of irregular word pairs in
|
32
|
+
# singular => plural order.
|
33
|
+
attr_reader :irregular_words
|
34
|
+
|
35
|
+
# @return [Array<Array<(String, String)>] Hash of irregular word pairs in
|
36
|
+
# plural => singular order.
|
37
|
+
attr_reader :irregular_words_reversed
|
38
|
+
|
39
|
+
# @return [Array<Array<(Regexp, String)>>] Rules for pluralizing words.
|
40
|
+
attr_reader :plural_rules
|
41
|
+
|
42
|
+
# @return [Array<Array<(Regexp, String)>>] Rules for singularizing words.
|
43
|
+
attr_reader :singular_rules
|
44
|
+
|
45
|
+
# @return [Array<String>] List of uncountable words.
|
46
|
+
attr_reader :uncountable_words
|
47
|
+
|
48
|
+
# Defines an irregular word pair.
|
49
|
+
#
|
50
|
+
# @param singular [String] The singular form of the word.
|
51
|
+
# @param plural [String] The plural form of the word.
|
52
|
+
#
|
53
|
+
# @return [Rules] The rules object.
|
54
|
+
def define_irregular_word(singular, plural)
|
55
|
+
validate_string(singular)
|
56
|
+
validate_string(plural)
|
57
|
+
|
58
|
+
@irregular_words[singular] = plural
|
59
|
+
@irregular_words_reversed[plural] = singular
|
60
|
+
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Defines a pluralization rule.
|
65
|
+
#
|
66
|
+
# @param pattern [Regexp] The pattern to match.
|
67
|
+
# @param replace [String] The string to replace.
|
68
|
+
#
|
69
|
+
# @return [Rules] The rules object.
|
70
|
+
def define_plural_rule(pattern, replace)
|
71
|
+
validate_pattern(pattern)
|
72
|
+
validate_string(replace, as: 'replace')
|
73
|
+
|
74
|
+
@plural_rules.unshift([pattern, replace])
|
75
|
+
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Defines a singularization rule.
|
80
|
+
#
|
81
|
+
# @param pattern [Regexp] The pattern to match.
|
82
|
+
# @param replace [String] The string to replace.
|
83
|
+
#
|
84
|
+
# @return [Rules] The rules object.
|
85
|
+
def define_singular_rule(pattern, replace)
|
86
|
+
validate_pattern(pattern)
|
87
|
+
validate_string(replace, as: 'replace')
|
88
|
+
|
89
|
+
@singular_rules.unshift([pattern, replace])
|
90
|
+
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
# Defines an uncountable word.
|
95
|
+
#
|
96
|
+
# @param word [String] The uncountable word.
|
97
|
+
#
|
98
|
+
# @return [Rules] The rules object.
|
99
|
+
def define_uncountable_word(word)
|
100
|
+
validate_string(word)
|
101
|
+
|
102
|
+
@uncountable_words << word
|
103
|
+
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [String] A human-readable representation of the rules object.
|
108
|
+
def inspect
|
109
|
+
"#<SleepingKingStudios::Tools::Toolbox::Inflector::Rules:#{object_id}>"
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def default_irregular_words
|
115
|
+
{
|
116
|
+
'child' => 'children',
|
117
|
+
'person' => 'people'
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def default_plural_rules
|
122
|
+
[
|
123
|
+
[/([^aeiouy])y$/i, '\1ies'], # Winery => Wineries
|
124
|
+
[/([^aeiouy]o)$/i, '\1es'], # Halo => Haloes
|
125
|
+
[/(ss|[xz]|[cs]h)$/i, '\1es'], # Truss => Trusses
|
126
|
+
[/s$/i, 's'], # Words => Words
|
127
|
+
[/$/, 's'] # Word => Words
|
128
|
+
]
|
129
|
+
end
|
130
|
+
|
131
|
+
def default_singular_rules
|
132
|
+
[
|
133
|
+
[/([^aeiouy])ies$/i, '\1y'], # Wineries => Winery
|
134
|
+
[/([^aeiouy]o)es$/, '\1'], # Haloes => Halo
|
135
|
+
[/(ss|[sxz]|[cs]h)es$/, '\1'], # Torches => Torch
|
136
|
+
[/ss$/i, 'ss'], # Truss => Truss
|
137
|
+
[/s$/i, ''] # Words => Word
|
138
|
+
]
|
139
|
+
end
|
140
|
+
|
141
|
+
def default_uncountable_words
|
142
|
+
%w[data]
|
143
|
+
end
|
144
|
+
|
145
|
+
def reverse_hash(hsh)
|
146
|
+
hsh.each.with_object({}) do |(key, value), reversed|
|
147
|
+
reversed[value] = key
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def validate_pattern(rxp)
|
152
|
+
raise ArgumentError, "pattern can't be blank", caller(1..-1) if rxp.nil?
|
153
|
+
|
154
|
+
return if rxp.is_a?(Regexp)
|
155
|
+
|
156
|
+
raise ArgumentError, 'pattern must be a Regexp', caller(1..-1)
|
157
|
+
end
|
158
|
+
|
159
|
+
def validate_string(word, as: 'word')
|
160
|
+
raise ArgumentError, "#{as} can't be blank", caller(1..-1) if word.nil?
|
161
|
+
|
162
|
+
unless word.is_a?(String)
|
163
|
+
raise ArgumentError, "#{as} must be a String", caller(1..-1)
|
164
|
+
end
|
165
|
+
|
166
|
+
return unless word.empty?
|
167
|
+
|
168
|
+
raise ArgumentError, "#{as} can't be blank", caller(1..-1)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|