cliutils 2.1.4 → 2.2.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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +3 -2
  4. data/Gemfile +7 -0
  5. data/HISTORY.md +7 -0
  6. data/README.md +3 -1
  7. data/Rakefile +8 -1
  8. data/cliutils.gemspec +1 -0
  9. data/lib/cliutils/configuration.rb +1 -1
  10. data/lib/cliutils/constants.rb +1 -1
  11. data/lib/cliutils/ext/hash_extensions.rb +16 -12
  12. data/lib/cliutils/messaging.rb +2 -116
  13. data/lib/cliutils/messenger.rb +109 -0
  14. data/lib/cliutils/prefs/pref.rb +10 -10
  15. data/lib/cliutils/prefs/pref_actions/open_url_action.rb +1 -1
  16. data/lib/cliutils/prefs/pref_validators/filepath_exists_validator.rb +2 -0
  17. data/lib/cliutils/prefs/pref_validators/url_validator.rb +1 -1
  18. data/lib/cliutils/prefs.rb +1 -1
  19. data/lib/cliutils/pretty_io.rb +0 -10
  20. data/lib/cliutils.rb +1 -1
  21. data/spec/action/open_url_action_spec.rb +20 -0
  22. data/spec/action/pref_action_spec.rb +11 -0
  23. data/spec/behavior/capitalize_behavior_spec.rb +11 -0
  24. data/spec/behavior/expand_filepath_behavior_spec.rb +11 -0
  25. data/spec/behavior/lowercase_behavior_spec.rb +11 -0
  26. data/spec/behavior/pref_behavior_spec.rb +11 -0
  27. data/spec/behavior/prefix_behavior_spec.rb +12 -0
  28. data/spec/behavior/suffix_behavior_spec.rb +12 -0
  29. data/spec/behavior/titlecase_behavior_spec.rb +10 -0
  30. data/spec/behavior/uppercase_behavior_spec.rb +11 -0
  31. data/spec/configuration_spec.rb +37 -0
  32. data/spec/configurator_spec.rb +104 -0
  33. data/spec/ext/hash_extensions_spec.rb +54 -0
  34. data/spec/ext/logger_extensions_spec.rb +20 -0
  35. data/spec/ext/string_extensions_spec.rb +26 -0
  36. data/spec/messaging_spec.rb +91 -0
  37. data/spec/pref_spec.rb +144 -0
  38. data/spec/prefs_spec.rb +150 -0
  39. data/spec/spec_helper.rb +16 -0
  40. data/spec/validator/alphabetic_validator_spec.rb +20 -0
  41. data/spec/validator/alphanumeric_validator_spec.rb +20 -0
  42. data/spec/validator/date_validator_spec.rb +20 -0
  43. data/spec/validator/datetime_validator_spec.rb +20 -0
  44. data/spec/validator/filepath_exists_validator_spec.rb +20 -0
  45. data/spec/validator/non_nil_validator_spec.rb +24 -0
  46. data/spec/validator/number_validator_spec.rb +20 -0
  47. data/spec/validator/pref_validator_spec.rb +11 -0
  48. data/spec/validator/time_validator_spec.rb +20 -0
  49. data/spec/validator/url_validator_spec.rb +20 -0
  50. data/{test/test_files → support}/configuration.yaml +1 -1
  51. data/support/prefstest.yaml +27 -0
  52. data/{test/test_files → support}/test_action.rb +0 -0
  53. data/support/test_action_empty.rb +7 -0
  54. data/{test/test_files → support}/test_behavior.rb +2 -2
  55. data/support/test_behavior_empty.rb +6 -0
  56. data/{test/test_files → support}/test_validator.rb +0 -2
  57. data/support/test_validator_empty.rb +7 -0
  58. data/test/pref_test.rb +0 -1
  59. data/test/prefs_test.rb +64 -1
  60. data/test/test_helper.rb +2 -2
  61. metadata +91 -67
  62. data/lib/cliutils/logger_delegator.rb +0 -49
  63. data/test/action_tests/open_url_action_test.rb +0 -12
  64. data/test/behavior_tests/capitalize_behavior_test.rb +0 -11
  65. data/test/behavior_tests/expand_filepath_behavior_test.rb +0 -11
  66. data/test/behavior_tests/lowercase_behavior_test.rb +0 -11
  67. data/test/behavior_tests/prefix_behavior_test.rb +0 -12
  68. data/test/behavior_tests/suffix_behavior_test.rb +0 -12
  69. data/test/behavior_tests/titlecase_behavior_test.rb +0 -11
  70. data/test/behavior_tests/uppercase_behavior_test.rb +0 -11
  71. data/test/configuration_test.rb +0 -49
  72. data/test/configurator_test.rb +0 -63
  73. data/test/hash_extensions_test.rb +0 -51
  74. data/test/logger_extensions_test.rb +0 -17
  75. data/test/messaging_test.rb +0 -53
  76. data/test/string_extesions_test.rb +0 -28
  77. data/test/test_files/prefstest.yaml +0 -38
  78. data/test/validator_tests/alphabetic_validator_test.rb +0 -22
  79. data/test/validator_tests/alphanumeric_validator_test.rb +0 -22
  80. data/test/validator_tests/date_validator_test.rb +0 -22
  81. data/test/validator_tests/datetime_validator_test.rb +0 -22
  82. data/test/validator_tests/filepath_exists_validator_test.rb +0 -22
  83. data/test/validator_tests/non_nil_validator_test.rb +0 -30
  84. data/test/validator_tests/number_validator_test.rb +0 -22
  85. data/test/validator_tests/time_validator_test.rb +0 -22
  86. data/test/validator_tests/url_validator_test.rb +0 -22
@@ -9,7 +9,7 @@ module CLIUtils
9
9
  def run
10
10
  url = @parameters[:url]
11
11
  Launchy.open(url) do |exception|
12
- puts "Failed to open #{ url }: #{ exception }"
12
+ fail "Failed to open URL: #{ exception }" if exception
13
13
  end
14
14
  end
15
15
  end
@@ -1,3 +1,5 @@
1
+ require 'pathname'
2
+
1
3
  module CLIUtils
2
4
  # A Validator to verify whether a Pref answer
3
5
  # is a local filepath that exists.
@@ -9,7 +9,7 @@ module CLIUtils
9
9
  # @return [String]
10
10
  def validate(text)
11
11
  @is_valid = text.to_s =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]
12
- @message = "Response is not a url: #{ text }"
12
+ @message = "Response is not a URL: #{ text }"
13
13
  end
14
14
  end
15
15
  end
@@ -54,7 +54,7 @@ module CLIUtils
54
54
  data = YAML.load_file(data).deep_symbolize_keys
55
55
  @prompts = _generate_prefs(data)
56
56
  else
57
- fail "Invalid configuration file: #{ data }"
57
+ fail "Invalid configuration file: #{ data }"
58
58
  end
59
59
  when Hash
60
60
  @config_path = nil
@@ -1,13 +1,3 @@
1
- begin
2
- unless (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM).nil?
3
- require 'Win32/Console/ANSI'
4
- end
5
- rescue LoadError
6
- raise 'You must run `gem install win32console` to use CLIMessage on Windows'
7
- end
8
-
9
- require 'readline'
10
-
11
1
  module CLIUtils
12
2
  # CLIMessenger Module
13
3
  # Outputs color-coordinated messages to a CLI
data/lib/cliutils.rb CHANGED
@@ -6,7 +6,7 @@ require 'cliutils/constants'
6
6
  require 'cliutils/pretty_io'
7
7
  require 'cliutils/configurator'
8
8
  require 'cliutils/configuration'
9
- require 'cliutils/logger_delegator'
9
+ require 'cliutils/messenger'
10
10
  require 'cliutils/messaging'
11
11
  require 'cliutils/prefs'
12
12
  require 'cliutils/prefs/pref'
@@ -0,0 +1,20 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_actions/pref_action'
4
+ require 'cliutils/prefs/pref_actions/open_url_action'
5
+
6
+ describe CLIUtils::OpenUrlAction do
7
+ it 'opens a website with the specified parameter' do
8
+ a = CLIUtils::OpenUrlAction.new
9
+ a.parameters = { url: 'http://www.google.com' }
10
+ expect(Launchy).to receive(:open).with('http://www.google.com')
11
+ a.run
12
+ end
13
+
14
+ it 'throws an exception with a bad URL' do
15
+ a = CLIUtils::OpenUrlAction.new
16
+ a.parameters = { url: 'bachya' }
17
+ m = "Failed to open URL: No application found to handle 'bachya'"
18
+ expect { a.run }.to raise_error(RuntimeError, m)
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_actions/pref_action'
4
+ require File.join(File.dirname(__FILE__), '..', '..', 'support/test_action_empty')
5
+
6
+ describe CLIUtils::TestActionEmpty do
7
+ it 'raises an exception if `run` is not implemented' do
8
+ m = '`run` method not implemented on caller: CLIUtils::TestActionEmpty'
9
+ expect { CLIUtils::TestActionEmpty.new.run }.to raise_error(RuntimeError, m)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require 'cliutils/prefs/pref_behaviors/capitalize_behavior'
5
+
6
+ describe CLIUtils::CapitalizeBehavior do
7
+ it 'capitalizes its input' do
8
+ b = CLIUtils::CapitalizeBehavior.new
9
+ expect(b.evaluate('bachya')).to eq('Bachya')
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require 'cliutils/prefs/pref_behaviors/expand_filepath_behavior'
5
+
6
+ describe CLIUtils::ExpandFilepathBehavior do
7
+ it 'runs File.expand_path on its input' do
8
+ b = CLIUtils::ExpandFilepathBehavior.new
9
+ expect(b.evaluate('~/test')).to eq("#{ ENV['HOME'] }/test")
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require 'cliutils/prefs/pref_behaviors/lowercase_behavior'
5
+
6
+ describe CLIUtils::LowercaseBehavior do
7
+ it 'lowercases its input' do
8
+ b = CLIUtils::LowercaseBehavior.new
9
+ expect(b.evaluate('BaChYa')).to eq('bachya')
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require File.join(File.dirname(__FILE__), '..', '..', 'support/test_behavior_empty')
5
+
6
+ describe CLIUtils::TestBehaviorEmpty do
7
+ it 'raises an exception if `evaluate` is not implemented' do
8
+ m = '`evaluate` method not implemented on caller: CLIUtils::TestBehaviorEmpty'
9
+ expect { CLIUtils::TestBehaviorEmpty.new.evaluate('') }.to raise_error(RuntimeError, m)
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require 'cliutils/prefs/pref_behaviors/prefix_behavior'
5
+
6
+ describe CLIUtils::PrefixBehavior do
7
+ it 'prefixes its input' do
8
+ b = CLIUtils::PrefixBehavior.new
9
+ b.parameters = { prefix: 'Starting up: ' }
10
+ expect(b.evaluate('bachya')).to eq('Starting up: bachya')
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require 'cliutils/prefs/pref_behaviors/suffix_behavior'
5
+
6
+ describe CLIUtils::SuffixBehavior do
7
+ it 'prefixes its input' do
8
+ b = CLIUtils::SuffixBehavior.new
9
+ b.parameters = { suffix: ' - signing off!' }
10
+ expect(b.evaluate('bachya')).to eq('bachya - signing off!')
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ require 'cliutils/messaging'
2
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
3
+ require 'cliutils/prefs/pref_behaviors/titlecase_behavior'
4
+
5
+ describe CLIUtils::TitlecaseBehavior do
6
+ it 'titlecases its input' do
7
+ b = CLIUtils::TitlecaseBehavior.new
8
+ expect(b.evaluate('my sentence is here')).to eq('My Sentence Is Here')
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/prefs/pref_behaviors/pref_behavior'
4
+ require 'cliutils/prefs/pref_behaviors/uppercase_behavior'
5
+
6
+ describe CLIUtils::UppercaseBehavior do
7
+ it 'uppercases its input' do
8
+ b = CLIUtils::UppercaseBehavior.new
9
+ expect(b.evaluate('bachya')).to eq('BACHYA')
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ require_relative 'spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/configuration'
4
+ require 'cliutils/configurator'
5
+
6
+ describe CLIUtils::Configuration do
7
+ include CLIUtils::Configuration
8
+
9
+ it 'raises an exception if not loaded properly' do
10
+ m = 'Attempted to access `configuration` before executing `load_configuration`'
11
+ expect { configuration }.to raise_error(RuntimeError, m)
12
+ end
13
+
14
+ let(:config_path_new) { File.expand_path('support/configuration2.yaml') }
15
+ it 'initializies configuration from scratch' do
16
+ load_configuration(config_path_new)
17
+ expect(configuration.class).to eq(CLIUtils::Configurator)
18
+ expect(configuration.config_path).to eq(config_path_new)
19
+ expect(configuration.data).to eq({})
20
+ end
21
+
22
+ let(:config_path_existing) { File.expand_path('support/configuration.yaml') }
23
+ let(:existing_data) { { my_app: {
24
+ config_location: '/Users/bob/.my-app-config',
25
+ log_level: 'WARN',
26
+ version: '1.0.0' },
27
+ user_data: {
28
+ username: 'bob',
29
+ age: 45 } } }
30
+
31
+ it 'works with existing configuration data' do
32
+ load_configuration(config_path_existing)
33
+ expect(configuration.class).to eq(CLIUtils::Configurator)
34
+ expect(configuration.config_path).to eq(config_path_existing)
35
+ expect(configuration.data).to eq(existing_data)
36
+ end
37
+ end
@@ -0,0 +1,104 @@
1
+ require_relative 'spec_helper'
2
+ require 'cliutils/messaging'
3
+ require 'cliutils/configurator'
4
+ require 'cliutils/ext/hash_extensions'
5
+ require 'cliutils/prefs'
6
+ require 'yaml'
7
+
8
+ describe CLIUtils::Configuration do
9
+ include CLIUtils::Configuration
10
+
11
+ let(:config_path) { File.expand_path('support/configuration.yaml') }
12
+ let(:prefs_path) { File.expand_path('support/prefstest.yaml') }
13
+ let(:config) { CLIUtils::Configurator.new(config_path)}
14
+ let(:existing_data) { { my_app: {
15
+ config_location: '/Users/bob/.my-app-config',
16
+ log_level: 'WARN',
17
+ version: '1.0.0' },
18
+ user_data: {
19
+ username: 'bob',
20
+ age: 45 } } }
21
+
22
+ it 'adds a section to the config data' do
23
+ config.add_section(:test)
24
+ expect(config.data).to eq(existing_data.merge!(test: {}))
25
+ end
26
+
27
+ it 'raises an exception when trying to add an already-existing section' do
28
+ config.add_section(:test)
29
+ m = 'Section already exists: test'
30
+ expect { config.add_section(:test) }.to raise_error(RuntimeError, m)
31
+ end
32
+
33
+ it 'backs up the configuration file' do
34
+ backup_path = config.backup
35
+ expect(backup_path).to eq("#{ config_path }-#{ Time.now.to_i }")
36
+ FileUtils.rm(backup_path)
37
+ end
38
+
39
+ it 'deletes a section from the config data' do
40
+ config.add_section(:test)
41
+ config.add_section(:test2)
42
+ config.delete_section(:test)
43
+ expect(config.data).to eq(existing_data.merge!(test2: {}))
44
+ end
45
+
46
+ it 'raises an exception when trying to delete a nonexistent section' do
47
+ m = 'Cannot delete nonexistent section: test'
48
+ expect { config.delete_section(:test) }.to raise_error(RuntimeError, m)
49
+ end
50
+
51
+ it 'allows data retrieval via a hash or magic methods' do
52
+ config.add_section(:test)
53
+ config.data[:test].merge!(name: 'Bob')
54
+ expect(config.data[:test][:name]).to eq('Bob')
55
+ expect(config.test[:name]).to eq('Bob')
56
+ end
57
+
58
+ it 'resets the entire data collection' do
59
+ config.add_section(:test)
60
+ config.data[:test].merge!(name: 'Bob')
61
+ config.reset
62
+ expect(config.data).to eq({})
63
+ end
64
+
65
+ it 'saves its data to a file' do
66
+ config.add_section(:section1)
67
+ config.section1.merge!(a: 'test', b: 'test')
68
+ config.save
69
+
70
+ saved_data = YAML.load_file(config.config_path).deep_symbolize_keys
71
+ expect(saved_data).to eq(config.data)
72
+
73
+ config.delete_section(:section1)
74
+ config.save
75
+ end
76
+
77
+ it 'compares versions' do
78
+ config.add_section(:app_data)
79
+ config.app_data.merge!(VERSION: '1.0.0')
80
+ config.current_version = config.app_data[:VERSION]
81
+ config.last_version = '1.0.8'
82
+ config.compare_version do |c, l|
83
+ expect(c).to be < l
84
+ end
85
+ end
86
+
87
+ it 'successfully ingests Prefs into its data' do
88
+ config.ingest_prefs(CLIUtils::Prefs.new(prefs_path))
89
+ h = {
90
+ personal_info: {
91
+ superhero: nil,
92
+ batman_answer: nil,
93
+ superman_answer: nil,
94
+ no_clue: nil
95
+ }
96
+ }
97
+ expect(existing_data.merge!(h)).to eq(config.data)
98
+ end
99
+
100
+ it 'raises an exception when attempting to ingest invalid Prefs' do
101
+ m = 'Invaid Prefs class'
102
+ expect { config.ingest_prefs(123) }.to raise_error(RuntimeError, m)
103
+ end
104
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/ext/hash_extensions'
3
+
4
+ describe Hash do
5
+ it 'allows for deep merging' do
6
+ h1 = { key: 'value', key2: %w(value1, value2) }
7
+ h2 = { key: 'another_value', key3: { subkey1: 'value' } }
8
+ exp_result = { key: 'another_value', key2: ['value1,', 'value2'], key3: { subkey1: 'value' } }
9
+ actual_result = h1.deep_merge!(h2)
10
+
11
+ expect(actual_result).to eq(exp_result)
12
+ end
13
+
14
+ it 'allows for a new hash to be created with stringified keys' do
15
+ h = { key: { subkey1: 'value1', subkey2: { subsubkey1: 'value' } } }
16
+ exp_result = { 'key' => { 'subkey1' => 'value1', 'subkey2' => { 'subsubkey1' => 'value' } } }
17
+ actual_result = h.deep_stringify_keys
18
+
19
+ expect(actual_result).to_not eq(h)
20
+ expect(actual_result).to eq(exp_result)
21
+ end
22
+
23
+ it 'allows for inline key stringification' do
24
+ h = {key: {subkey1: 'value1', subkey2: {subsubkey1: 'value'}}}
25
+ exp_result = { 'key' => { 'subkey1' => 'value1', 'subkey2' => { 'subsubkey1' => 'value' } } }
26
+ actual_result = h.deep_stringify_keys!
27
+
28
+ expect(actual_result).to eq(h)
29
+ expect(actual_result).to eq(exp_result)
30
+ end
31
+
32
+ it 'allows for a new hash to be created with symbolized keys' do
33
+ h = { 'key' => { 'subkey1' => 'value1', 'subkey2' => { 'subsubkey1' => ['value1', 'value2']} } }
34
+ exp_result = { key: { subkey1: 'value1', subkey2: { subsubkey1: ['value1', 'value2']} } }
35
+ actual_result = h.deep_symbolize_keys
36
+
37
+ expect(actual_result).to_not eq(h)
38
+ expect(actual_result).to eq(exp_result)
39
+ end
40
+
41
+ it 'allows for inline key symbolization' do
42
+ h = { 'key' => { 'subkey1' => 'value1', 'subkey2' => { 'subsubkey1' => ['value1', 'value2']} } }
43
+ exp_result = { key: { subkey1: 'value1', subkey2: { subsubkey1: ['value1', 'value2']} } }
44
+ actual_result = h.deep_symbolize_keys!
45
+
46
+ expect(actual_result).to eq(h)
47
+ expect(actual_result).to eq(exp_result)
48
+ end
49
+
50
+ it 'can find a nested value by key' do
51
+ h = { key: { subkey1: 'value1', subkey2: { subsubkey1: 'subvalue1'} } }
52
+ h.recursive_find_by_key(:subsubkey1).should == 'subvalue1'
53
+ end
54
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/ext/logger_extensions'
3
+
4
+ describe Logger do
5
+ it 'allows custom levels to be attached' do
6
+ l = Logger.new(STDOUT)
7
+ l.formatter = proc do |severity, datetime, progname, msg|
8
+ puts "#{ severity }: #{ msg }"
9
+ end
10
+
11
+ out = capture_stdout { l.prompt('test') }
12
+ expect(out).to eq("PROMPT: test\n")
13
+
14
+ out = capture_stdout { l.section('test') }
15
+ expect(out).to eq("SECTION: test\n")
16
+
17
+ out = capture_stdout { l.success('test') }
18
+ expect(out).to eq("SUCCESS: test\n")
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../spec_helper'
2
+ require 'cliutils/ext/string_extensions'
3
+
4
+ describe String do
5
+ it 'outputs strings with preset custom colors' do
6
+ expect('blue string'.blue).to eq("\e[34mblue string\e[0m")
7
+ expect('cyan string'.cyan).to eq("\e[36mcyan string\e[0m")
8
+ expect('green string'.green).to eq("\e[32mgreen string\e[0m")
9
+ expect('purple string'.purple).to eq("\e[35mpurple string\e[0m")
10
+ expect('red string'.red).to eq("\e[31mred string\e[0m")
11
+ expect('white string'.white).to eq("\e[37mwhite string\e[0m")
12
+ expect('yellow string'.yellow).to eq("\e[33myellow string\e[0m")
13
+ end
14
+
15
+ it 'outputs strings with configurable custom colors' do
16
+ expect('crazy string'.colorize('34,42')).to eq("\e[34,42mcrazy string\e[0m")
17
+ end
18
+
19
+ it 'camel-cases strings' do
20
+ expect('my_long_snake_name'.camelize).to eq('MyLongSnakeName')
21
+ end
22
+
23
+ it 'snake-cases strings' do
24
+ expect('MyLongCamelName'.snakify).to eq('my_long_camel_name')
25
+ end
26
+ end