lucky_case 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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