lucky_case 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3a2cb0b71a39713fbfdcf1d1c829a682b2b5c3d3ab3e27848ed10ddb9b17f17c
4
+ data.tar.gz: 47d28a8136f743a4bb8bd6b3687eecf40fd8bddc92554cd093616dc91a81b14a
5
+ SHA512:
6
+ metadata.gz: 3c6f91d4e248c1c54fff4f25c168a34010dcadf12de9dedf488e50e4ca6f9235959990a6d59bd0f69b6cd6e7f5f72ffea2231b83745184e20ca2bcf0e529c22e
7
+ data.tar.gz: c8dadeefe2192286ff3b9f3e756a6fc5fc8b0d640140ae38aaa1a300b526a12e2bc04c43b62b8112ee348b064e7a3348836da3516b188008e0e2ca910d402ac0
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.vscode/
11
+ /.idea/
12
+ *.gem
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at yaml_extend.gemspec@mail.magynhard.de. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in lucky_case.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Matthäus J. N. Beyrle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,128 @@
1
+ # lucky_case
2
+
3
+ The lucky ruby gem to identify and convert strings from any letter case to another. Plus some extra functions.
4
+
5
+ Useful when working with conventions, where class names, method names and file names needs to be converted.
6
+
7
+ * Converters: Only characters, numbers, dashes and underlines are allowed inside a string.
8
+ * Must not start with dash or number, underlines at the beginning are allowed by default and can be allowed/removed/controlled by parameter (when used for private methods for example)
9
+
10
+
11
+
12
+
13
+ # Contents
14
+
15
+ * [Usage](#usage)
16
+ * [Installation](#installation)
17
+ * [Documentation](#documentation)
18
+ * [Contributing](#contributing)
19
+
20
+
21
+
22
+
23
+ <a name="usage"></a>
24
+ ## Usage
25
+
26
+ You can either use the static LuckyCase class with its method or optionally monkey patch the String class.
27
+
28
+ ### Use the static class only
29
+ ```ruby
30
+ require 'lucky_case'
31
+
32
+ # converters
33
+ LuckyCase.snake_case('ExamplePascalString') # => 'example_pascal_string'
34
+ LuckyCase.upper_snake_case('Example-Train-String') # => 'EXAMPLE_TRAIN_STRING'
35
+ LuckyCase.pascal_case('example_snake_string') # => 'ExampleSnakeString'
36
+ LuckyCase.camel_case('example-dash-string') # => 'exampleDashString'
37
+ LuckyCase.dash_case('ExamplePascalString') # => 'example-pascal-string'
38
+ LuckyCase.upper_dash_case('ExamplePascalString') # => 'EXAMPLE-PASCAL-STRING'
39
+ LuckyCase.train_case('example_snake_string') # => 'Example-Snake-String'
40
+ LuckyCase.mixed_case('example_snake_string') # => 'Example-snake_STRING'
41
+ # converter by type
42
+ LuckyCase.convert_case('some_snake', :pascal_case) # => 'SomeSnake'
43
+ # transformers
44
+ LuckyCase.lower_case('Some_FuckingShit') # => 'some_fuckingshit'
45
+ LuckyCase.upper_case('Some_FuckingShit') # => 'SOME_FUCKINGSHIT'
46
+ LuckyCase.swap_case('SomeSwappy_Case-Example') # => 'sOMEsWAPPY-cASE_eXAMPLE'
47
+ LuckyCase.capital('example') # => 'Example'
48
+ LuckyCase.capitalize('example') # => 'Example'
49
+ LuckyCase.constantize('some_constant') # => SomeConstant
50
+ LuckyCase.constantize('SOME_CONSTANT') # => SomeConstant
51
+ LuckyCase.constantize('some/path_example/folder') # => Some::PathExample::Folder
52
+ LuckyCase.deconstantize(SomeConstant) # => 'some_constant'
53
+ LuckyCase.deconstantize(Some::PathExample::Folder, case_type: :camel_case) # => 'some/pathExample/folder'
54
+ # identifier
55
+ LuckyCase.case('this_can_only_be_snake_case') # => :snake_case
56
+ LuckyCase.cases('multiple') # => [ :snake_case, :camel_case, :dash_case ]
57
+ # checkers
58
+ LuckyCase.snake_case?('valid_snake_case') # => true
59
+ LuckyCase.upper_snake_case?('inValidSnakeCase') # => false
60
+ LuckyCase.pascal_case?('PascalCase') # => true
61
+ LuckyCase.camel_case?('camelCase') # => true
62
+ LuckyCase.dash_case?('dash-case') # => true
63
+ LuckyCase.upper_dash_case?('DASH-CASE') # => true
64
+ LuckyCase.train?('Train-Case') # => true
65
+ LuckyCase.mixed_case?('mixed_Case') # => true
66
+ LuckyCase.upper_case?('UPPER50984') # => true
67
+ LuckyCase.lower_case?('mixed_Case') # => true
68
+ LuckyCase.capital?('Some') # => true
69
+ LuckyCase.capitalized?('some') # => false
70
+ ```
71
+
72
+ ### Monkey patch the string class
73
+
74
+ With monkey patching you can access the same methods (except deconstantize) of LuckyCase directly from strings.
75
+ Additionally they provide versions with exclamation mark for direct manipulation.
76
+
77
+ ```ruby
78
+ require 'lucky_case/string'
79
+
80
+ a = 'ExampleString'
81
+
82
+ a.pascal_case? # => true
83
+ a.snake_case # => 'example_string'
84
+ a # => 'ExampleString'
85
+ # string variable manipulation
86
+ a.snake_case! # => 'example_string'
87
+ a # => 'example_string'
88
+ ```
89
+
90
+
91
+
92
+
93
+
94
+ <a name="installation"></a>
95
+ ## Installation
96
+
97
+ Add this line to your application's Gemfile:
98
+
99
+ ```ruby
100
+ gem 'lucky_case'
101
+ ```
102
+
103
+ And then execute:
104
+
105
+ $ bundle install
106
+
107
+ Or install it yourself by:
108
+
109
+ $ gem install yaml_extend
110
+
111
+
112
+
113
+
114
+
115
+ <a name="documentation"></a>
116
+ ## Documentation
117
+ Check out the doc at RubyDoc
118
+ <a href="https://www.rubydoc.info/gems/lucky_case">https://www.rubydoc.info/gems/lucky_case</a>
119
+
120
+
121
+
122
+
123
+
124
+ <a name="contributing"></a>
125
+ ## Contributing
126
+
127
+ Bug reports and pull requests are welcome on GitHub at https://github.com/magynhard/lucky_case. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
128
+
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ #
5
+ # run default task to see tasks to build and publish gem
6
+ #
7
+ task :default do
8
+ system 'rake --tasks'
9
+ end
10
+
11
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lucky_case"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,2 @@
1
+ class InvalidCaseError < StandardError
2
+ end
@@ -0,0 +1,648 @@
1
+ require 'lucky_case/version'
2
+
3
+ require_relative 'custom_errors/invalid_case_error'
4
+
5
+
6
+ # LuckyCase
7
+ #
8
+ # Convert and detect various letter cases in strings
9
+ #
10
+
11
+ module LuckyCase
12
+
13
+ CASES = {
14
+ snake_case: /^[[:lower:]]{1}[[:lower:]_0-9]+$/,
15
+ upper_snake_case: /^[[:upper:]]{1}[[:upper:]_0-9]+$/,
16
+ pascal_case: /^[[:upper:]]{1}[[:upper:][:lower:]0-9]+$/,
17
+ camel_case: /^[[:lower:]]{1}[[:upper:][:lower:]0-9]+$/,
18
+ dash_case: /^([[:lower:]]){1}[[:lower:]\-0-9]*[[:lower:]0-9]+$/,
19
+ upper_dash_case: /^([[:upper:]]){1}[[:upper:]\-0-9]*[[:upper:]0-9]+$/,
20
+ train_case: /^([[:upper:]][[:lower:]0-9]*\-|[0-9]+\-)*([[:upper:]][[:lower:]0-9]*)$/,
21
+ mixed_case: /^[[:upper:][:lower:]][[:upper:][:lower:]_\-0-9]*$/,
22
+ }
23
+
24
+ FORMATS = {
25
+ capital: /^[[:upper:]]{1}.*$/,
26
+ upper_case: /^[^[:lower:]]+$/,
27
+ lower_case: /^[^[:upper:]]+$/,
28
+ }
29
+
30
+ # Get type of case of string (one key of LuckyCase.CASES)
31
+ #
32
+ # If more than one case matches, the first match wins.
33
+ # Match prio is the order of the regex in LuckyCase.CASES
34
+ #
35
+ # If you want or need to know all cases, use plural version of this method
36
+ #
37
+ # If you want to check explicitly for one case, use its check method,
38
+ # e.g. snake_case? for snake_case, etc...
39
+ #
40
+ # @param [String] string
41
+ # @param [Boolean] allow_prefixed_underscores
42
+ # @return [Symbol,nil] symbol of type, nil if no match
43
+ def self.case(string, allow_prefixed_underscores: true)
44
+ s = if allow_prefixed_underscores
45
+ cut_underscores_at_start string
46
+ else
47
+ string
48
+ end
49
+ CASES.each do |case_type, regex|
50
+ if s =~ regex
51
+ return case_type
52
+ end
53
+ end
54
+ nil
55
+ end
56
+
57
+ # Get types of cases of string (keys of LuckyCase.CASES)
58
+ #
59
+ # @param [String] string
60
+ # @param [Boolean] allow_prefixed_underscores
61
+ # @return [Array<Symbol>,nil] symbols of types, nil if no one matches
62
+ def self.cases(string, allow_prefixed_underscores: true)
63
+ s = if allow_prefixed_underscores
64
+ cut_underscores_at_start string
65
+ else
66
+ string
67
+ end
68
+ matched_cases = []
69
+ CASES.each do |case_type, regex|
70
+ if s =~ regex
71
+ matched_cases.push case_type
72
+ end
73
+ end
74
+ if matched_cases.empty?
75
+ nil
76
+ # reject mixed case if there are other matches
77
+ # because it would always be included if one other case matches
78
+ elsif matched_cases.size > 1
79
+ matched_cases.reject { |e| e == :mixed_case }
80
+ else
81
+ matched_cases
82
+ end
83
+ end
84
+
85
+ # Convert a string into the given case type
86
+ #
87
+ # @param [String] string
88
+ # @param [Symbol,String] case_type
89
+ # @param [Boolean] preserve_prefixed_underscores
90
+ # @return [String]
91
+ def self.convert_case(string, case_type, preserve_prefixed_underscores: true)
92
+ type = case_type.to_sym
93
+ if CASES.include? case_type.to_sym
94
+ return self.send type.to_s, string, preserve_prefixed_underscores: preserve_prefixed_underscores
95
+ end
96
+ error_message = "Invalid case type '#{case_type}'. Valid types are: #{CASES.keys.join(', ')}"
97
+ raise InvalidCaseError.new error_message
98
+ end
99
+
100
+ #----------------------------------------------------------------------------------------------------
101
+ # UPPER CASE
102
+ #----------------------------------------------------------------------------------------------------
103
+
104
+ # Converts all characters inside the string
105
+ # into upper case
106
+ #
107
+ # @example conversion
108
+ # 'this-isAnExample_string' => 'THIS-ISANEXAMPLE_STRING'
109
+ #
110
+ # @param [String] string to convert
111
+ # @return [String]
112
+ def self.upper_case(string)
113
+ string.upcase
114
+ end
115
+
116
+ # Checks if all characters inside the string are upper case
117
+ #
118
+ # @param [String] string to check
119
+ # @return [Boolean]
120
+ def self.upper_case?(string)
121
+ string == upper_case(string)
122
+ end
123
+
124
+ #----------------------------------------------------------------------------------------------------
125
+ # LOWER CASE
126
+ #----------------------------------------------------------------------------------------------------
127
+
128
+ # Converts all characters inside the string
129
+ # into lower case
130
+ #
131
+ # @example conversion
132
+ # 'this-isAnExample_string' => 'this-isanexample_string'
133
+ #
134
+ # @param [String] string to convert
135
+ # @return [String]
136
+ def self.lower_case(string)
137
+ string.downcase
138
+ end
139
+
140
+ # Checks if all characters inside the string are lower case
141
+ #
142
+ # @param [String] string to check
143
+ # @return [Boolean]
144
+ def self.lower_case?(string)
145
+ string == lower_case(string)
146
+ end
147
+
148
+ #----------------------------------------------------------------------------------------------------
149
+ # SNAKE CASE
150
+ #----------------------------------------------------------------------------------------------------
151
+
152
+ # Converts the given string from any case
153
+ # into snake case
154
+ #
155
+ # @example conversion
156
+ # 'this-isAnExample_string' => 'this_is_an_example_string'
157
+ #
158
+ # @param [String] string to convert
159
+ # @param [Boolean] preserve_prefixed_underscores
160
+ # @return [String]
161
+ def self.snake_case(string, preserve_prefixed_underscores: true)
162
+ a = split_case_string string
163
+ converted = a.join('_')
164
+ if preserve_prefixed_underscores
165
+ underscores_at_start(string) + converted
166
+ else
167
+ converted
168
+ end
169
+ end
170
+
171
+ # Checks if the string is snake case
172
+ #
173
+ # @param [String] string to check
174
+ # @param [Boolean] allow_prefixed_underscores
175
+ # @return [Boolean]
176
+ def self.snake_case?(string, allow_prefixed_underscores: true)
177
+ s = if allow_prefixed_underscores
178
+ cut_underscores_at_start string
179
+ else
180
+ string
181
+ end
182
+ _case_match? s, :snake_case
183
+ end
184
+
185
+ # Converts the given string from any case
186
+ # into upper snake case
187
+ #
188
+ # @example conversion
189
+ # 'this-isAnExample_string' => 'THIS_IS_AN_EXAMPLE_STRING'
190
+ #
191
+ # @param [String] string to convert
192
+ # @param [Boolean] preserve_prefixed_underscores
193
+ # @return [String]
194
+ def self.upper_snake_case(string, preserve_prefixed_underscores: true)
195
+ a = split_case_string string
196
+ converted = a.map { |e| upper_case e }.join('_')
197
+ if preserve_prefixed_underscores
198
+ underscores_at_start(string) + converted
199
+ else
200
+ converted
201
+ end
202
+ end
203
+
204
+ # Checks if the string is upper snake case
205
+ #
206
+ # @param [String] string to check
207
+ # @param [Boolean] allow_prefixed_underscores
208
+ # @return [Boolean]
209
+ def self.upper_snake_case?(string, allow_prefixed_underscores: true)
210
+ s = if allow_prefixed_underscores
211
+ cut_underscores_at_start string
212
+ else
213
+ string
214
+ end
215
+ _case_match? s, :upper_snake_case
216
+ end
217
+
218
+ #----------------------------------------------------------------------------------------------------
219
+ # PASCAL CASE
220
+ #----------------------------------------------------------------------------------------------------
221
+
222
+ # Converts the given string from any case
223
+ # into pascal case
224
+ #
225
+ # @example conversion
226
+ # 'this-isAnExample_string' => 'ThisIsAnExampleString'
227
+ #
228
+ # @param [String] string to convert
229
+ # @param [Boolean] preserve_prefixed_underscores
230
+ # @return [String]
231
+ def self.pascal_case(string, preserve_prefixed_underscores: true)
232
+ a = split_case_string string
233
+ converted = a.map { |e| capital e }.join('')
234
+ if preserve_prefixed_underscores
235
+ underscores_at_start(string) + converted
236
+ else
237
+ converted
238
+ end
239
+ end
240
+
241
+ # Checks if the string is upper pascal case
242
+ #
243
+ # @param [String] string to check
244
+ # @param [Boolean] allow_prefixed_underscores
245
+ # @return [Boolean]
246
+ def self.pascal_case?(string, allow_prefixed_underscores: true)
247
+ s = if allow_prefixed_underscores
248
+ cut_underscores_at_start string
249
+ else
250
+ string
251
+ end
252
+ _case_match? s, :pascal_case
253
+ end
254
+
255
+ #----------------------------------------------------------------------------------------------------
256
+ # CAMEL CASE
257
+ #----------------------------------------------------------------------------------------------------
258
+
259
+ # Converts the given string from any case
260
+ # into camel case
261
+ #
262
+ # @example conversion
263
+ # 'this-isAnExample_string' => 'thisIsAnExampleString'
264
+ #
265
+ # @param [String] string to convert
266
+ # @param [Boolean] preserve_prefixed_underscores
267
+ # @return [String]
268
+ def self.camel_case(string, preserve_prefixed_underscores: true)
269
+ a = split_case_string string
270
+ converted = ([a[0]] + a[1..-1].map { |e| capital e }).join('')
271
+ if preserve_prefixed_underscores
272
+ underscores_at_start(string) + converted
273
+ else
274
+ converted
275
+ end
276
+ end
277
+
278
+ # Checks if the string is camel case
279
+ #
280
+ # @param [String] string to check
281
+ # @param [Boolean] allow_prefixed_underscores
282
+ # @return [Boolean]
283
+ def self.camel_case?(string, allow_prefixed_underscores: true)
284
+ s = if allow_prefixed_underscores
285
+ cut_underscores_at_start string
286
+ else
287
+ string
288
+ end
289
+ _case_match? s, :camel_case
290
+ end
291
+
292
+ #----------------------------------------------------------------------------------------------------
293
+ # DASH CASE
294
+ #----------------------------------------------------------------------------------------------------
295
+
296
+ # Converts the given string from any case
297
+ # into dash case
298
+ #
299
+ # @example conversion
300
+ # 'this-isAnExample_string' => 'this-is-an-example-string'
301
+ #
302
+ # @param [String] string to convert
303
+ # @param [Boolean] preserve_prefixed_underscores
304
+ # @return [String]
305
+ def self.dash_case(string, preserve_prefixed_underscores: true)
306
+ a = split_case_string string
307
+ converted = a.join('-')
308
+ if preserve_prefixed_underscores
309
+ underscores_at_start(string) + converted
310
+ else
311
+ converted
312
+ end
313
+ end
314
+
315
+ # Checks if the string is dash case
316
+ #
317
+ # @param [String] string to check
318
+ # @param [Boolean] allow_prefixed_underscores
319
+ # @return [Boolean]
320
+ def self.dash_case?(string, allow_prefixed_underscores: true)
321
+ s = if allow_prefixed_underscores
322
+ cut_underscores_at_start string
323
+ else
324
+ string
325
+ end
326
+ _case_match? s, :dash_case
327
+ end
328
+
329
+ # Converts the given string from any case
330
+ # into upper dash case
331
+ #
332
+ # @example conversion
333
+ # 'this-isAnExample_string' => 'THIS-IS-AN-EXAMPLE-STRING'
334
+ #
335
+ # @param [String] string to convert
336
+ # @param [Boolean] preserve_prefixed_underscores
337
+ # @return [String]
338
+ def self.upper_dash_case(string, preserve_prefixed_underscores: true)
339
+ s = dash_case string, preserve_prefixed_underscores: preserve_prefixed_underscores
340
+ upper_case s
341
+ end
342
+
343
+ # Checks if the string is upper dash case
344
+ #
345
+ # @param [String] string to check
346
+ # @param [Boolean] allow_prefixed_underscores
347
+ # @return [Boolean]
348
+ def self.upper_dash_case?(string, allow_prefixed_underscores: true)
349
+ s = if allow_prefixed_underscores
350
+ cut_underscores_at_start string
351
+ else
352
+ string
353
+ end
354
+ _case_match? s, :upper_dash_case
355
+ end
356
+
357
+ #----------------------------------------------------------------------------------------------------
358
+ # TRAIN CASE
359
+ #----------------------------------------------------------------------------------------------------
360
+
361
+ # Converts the given string from any case
362
+ # into train case
363
+ #
364
+ # @example conversion
365
+ # 'this-isAnExample_string' => 'This-Is-An-Example-String'
366
+ #
367
+ # @param [String] string to convert
368
+ # @param [Boolean] preserve_prefixed_underscores
369
+ # @return [String]
370
+ def self.train_case(string, preserve_prefixed_underscores: true)
371
+ a = split_case_string string
372
+ converted = a.map { |e| capital e }.join('-')
373
+ if preserve_prefixed_underscores
374
+ underscores_at_start(string) + converted
375
+ else
376
+ converted
377
+ end
378
+ end
379
+
380
+ # Checks if the string is train case
381
+ #
382
+ # @param [String] string to check
383
+ # @param [Boolean] allow_prefixed_underscores
384
+ # @return [Boolean]
385
+ def self.train_case?(string, allow_prefixed_underscores: true)
386
+ s = if allow_prefixed_underscores
387
+ cut_underscores_at_start string
388
+ else
389
+ string
390
+ end
391
+ _case_match? s, :train_case
392
+ end
393
+
394
+ #----------------------------------------------------------------------------------------------------
395
+ # CAPITALIZE
396
+ #----------------------------------------------------------------------------------------------------
397
+
398
+ # Converts the first character to capital
399
+ #
400
+ # @param [String] string to convert
401
+ # @param [Boolean] skip_prefixed_underscores
402
+ # @return [String]
403
+ def self.capital(string, skip_prefixed_underscores: false)
404
+ return string if string.empty?
405
+ s = if skip_prefixed_underscores
406
+ cut_underscores_at_start string
407
+ else
408
+ string
409
+ end
410
+ s = s[0].upcase + s[1..-1]
411
+ if skip_prefixed_underscores
412
+ underscores_at_start(string) + s
413
+ else
414
+ s
415
+ end
416
+ end
417
+
418
+ # Converts the first character to capital
419
+ #
420
+ # @param [String] string to convert
421
+ # @param [Boolean] skip_prefixed_underscores
422
+ # @return [String]
423
+ def self.capitalize(string, skip_prefixed_underscores: false)
424
+ capital string, skip_prefixed_underscores: skip_prefixed_underscores
425
+ end
426
+
427
+ # Checks if the strings first character is a capital letter
428
+ #
429
+ # @param [String] string to check
430
+ # @param [Boolean] skip_prefixed_underscores
431
+ # @return [Boolean]
432
+ def self.capital?(string, skip_prefixed_underscores: false)
433
+ s = if skip_prefixed_underscores
434
+ cut_underscores_at_start string
435
+ else
436
+ string
437
+ end
438
+ _case_match? s, :capital
439
+ end
440
+
441
+ # Checks if the strings first character is a capital letter
442
+ #
443
+ # @param [String] string to check
444
+ # @param [Boolean] skip_prefixed_underscores
445
+ # @return [Boolean]
446
+ def self.capitalized?(string, skip_prefixed_underscores: false)
447
+ capital? string, skip_prefixed_underscores: skip_prefixed_underscores
448
+ end
449
+
450
+ #----------------------------------------------------------------------------------------------------
451
+ # MIXED CASE
452
+ #----------------------------------------------------------------------------------------------------
453
+
454
+ # Converts the given string from any case
455
+ # into mixed case
456
+ #
457
+ # @example conversion
458
+ # 'this-isAnExample_string' => 'This-Is_anExample-string'
459
+ #
460
+ # @param [String] string to convert
461
+ # @param [Boolean] preserve_prefixed_underscores
462
+ # @return [String]
463
+ def self.mixed_case(string, preserve_prefixed_underscores: true)
464
+ a = split_case_string string
465
+ converted = ''
466
+ a.each do |part|
467
+ converted += self.send random_case, part
468
+ end
469
+ if preserve_prefixed_underscores
470
+ underscores_at_start(string) + converted
471
+ else
472
+ converted
473
+ end
474
+ end
475
+
476
+ # Checks if the string is a valid mixed case (without special characters!)
477
+ #
478
+ # @param [String] string to check
479
+ # @return [Boolean]
480
+ def self.mixed_case?(string)
481
+ _case_match? string, :mixed_case
482
+ end
483
+
484
+ #----------------------------------------------------------------------------------------------------
485
+ # SWAP CASE
486
+ #----------------------------------------------------------------------------------------------------
487
+
488
+ # Swaps character cases in string
489
+ #
490
+ # lower case to upper case
491
+ # upper case to lower case
492
+ # dash to underscore
493
+ # underscore to dash
494
+ #
495
+ # @example conversion
496
+ # 'this-isAnExample_string' => 'THIS_ISaNeXAMPLE-STRING'
497
+ #
498
+ # @param [String] string
499
+ # @param [Boolean] preserve_prefixed_underscores
500
+ # @return [String]
501
+ def self.swap_case(string, preserve_prefixed_underscores: false)
502
+ s = if preserve_prefixed_underscores
503
+ cut_underscores_at_start string
504
+ else
505
+ string
506
+ end
507
+ sp = s.split('')
508
+ sp.each_with_index do |char, i|
509
+ if char == '_'
510
+ sp[i] = '-'
511
+ elsif char == '-'
512
+ sp[i] = '_'
513
+ elsif lower_case? char
514
+ sp[i] = upper_case char
515
+ elsif upper_case? char
516
+ sp[i] = lower_case char
517
+ end
518
+ end
519
+ sp = sp.join('')
520
+ if preserve_prefixed_underscores
521
+ underscores_at_start(string) + sp
522
+ else
523
+ sp
524
+ end
525
+ end
526
+
527
+ #----------------------------------------------------------------------------------------------------
528
+ # CONSTANTIZE
529
+ #----------------------------------------------------------------------------------------------------
530
+
531
+ # Converts the string from any case
532
+ # into pascal case and casts it into a constant
533
+ #
534
+ # @example conversion
535
+ # 'this-isAnExample_string' => ThisIsAnExampleString
536
+ # 'this/is_an/example_path' => This::IsAn::ExamplePath
537
+ #
538
+ # @param [String] string to convert
539
+ # @param [Boolean] preserve_prefixed_underscores
540
+ # @return [Constant]
541
+ def self.constantize(string)
542
+ s = string.gsub('/','::')
543
+ constants = if s.include? '::'
544
+ s.split('::')
545
+ else
546
+ [s]
547
+ end
548
+ final_constant = constants.map { |e| pascal_case(e, preserve_prefixed_underscores: false) }.reject(&:empty?).join('::')
549
+ Object.const_get(final_constant)
550
+ end
551
+
552
+ # Deconverts the constant back into specified target type
553
+ #
554
+ # @example deconversion
555
+ # This::AweSome::Constant => 'this/awe_some/constant'
556
+ #
557
+ # @param [Constant] constant to reconvert
558
+ # @param [Symbol,String] target can be :path, :string
559
+ # @param [Symbol,String] case_type can be any valid case of CASES
560
+ # @return [String]
561
+ def self.deconstantize(constant, target: :path, case_type: nil)
562
+ # defaults if none is set, depending on target
563
+ unless case_type
564
+ case_type = case target.to_sym
565
+ when :path
566
+ :snake_case
567
+ when :string
568
+ :pascal_case
569
+ end
570
+ end
571
+ s = constant.name
572
+ split = if s.include? '::'
573
+ s.split('::')
574
+ else
575
+ [s]
576
+ end
577
+ reconverted_parts = split.map { |e| convert_case e, case_type }
578
+ case target.to_sym
579
+ when :path
580
+ reconverted_parts.join('/')
581
+ when :string
582
+ reconverted_parts.join('::')
583
+ end
584
+ end
585
+
586
+ #----------------------------------------------------------------------------------------------------
587
+ # HELPERS
588
+ #----------------------------------------------------------------------------------------------------
589
+
590
+ # Return string without underscores at the start
591
+ #
592
+ # @param [String] string
593
+ # @return [String] string without prefixed underscores
594
+ def self.cut_underscores_at_start(string)
595
+ underscore_counter = 0
596
+ string.split('').each do |c|
597
+ if c == '_'
598
+ underscore_counter += 1
599
+ else
600
+ break
601
+ end
602
+ end
603
+ string[underscore_counter..-1]
604
+ end
605
+
606
+ # Return the underscores at the start of the string
607
+ #
608
+ # @param [String] string
609
+ # @return [String] string of underscores or empty if none found
610
+ def self.underscores_at_start(string)
611
+ underscore_counter = 0
612
+ string.split('').each do |c|
613
+ if c == '_'
614
+ underscore_counter += 1
615
+ else
616
+ break
617
+ end
618
+ end
619
+ '_' * underscore_counter
620
+ end
621
+
622
+ # Split the string into parts
623
+ # It is splitted by all (different) case separators
624
+ #
625
+ # @param [String] string
626
+ # @return [Array<String>]
627
+ def self.split_case_string(string)
628
+ s = cut_underscores_at_start string
629
+ s = s.gsub(/([[:upper:]])/, '_\1') unless upper_case? s # prepend all upper characters with underscore
630
+ s = s.gsub('-', '_') # replace all dashes with underscore
631
+ s = cut_underscores_at_start s
632
+ s.downcase.split('_').reject(&:empty?) # split everything by underscore
633
+ end
634
+
635
+ private
636
+
637
+ # Check if the given case matches the string
638
+ #
639
+ # @param [String] string
640
+ # @param [Symbol,String] case_to_match
641
+ # @return [Boolean]
642
+ def self._case_match?(string, case_to_match)
643
+ !!(string =~ CASES[case_to_match.to_sym])
644
+ end
645
+
646
+ #----------------------------------------------------------------------------------------------------
647
+
648
+ end