From edd0e8032cf03c8dcf1a9d45948636fc018c7077 Mon Sep 17 00:00:00 2001 From: alexo Date: Wed, 27 Aug 2025 12:46:58 +0100 Subject: [PATCH 1/2] [5.0.0] feat: added support for camelCase acronyms --- .rubocop.yml | 19 +--- Gemfile | 2 +- bin/console | 1 - lib/simple_symbolize.rb | 44 +++++--- lib/simple_symbolize/translations.rb | 67 +++++++----- lib/simple_symbolize/version.rb | 2 +- simple_symbolize.gemspec | 2 +- spec/camelize_spec.rb | 7 ++ spec/{ => core_ext}/string_spec.rb | 0 spec/core_ext/symbol_spec.rb | 43 ++++++++ spec/simple_symbolize_spec.rb | 28 +++-- spec/translations_spec.rb | 150 +++++++++++++++++++++++++++ 12 files changed, 289 insertions(+), 76 deletions(-) rename spec/{ => core_ext}/string_spec.rb (100%) create mode 100644 spec/core_ext/symbol_spec.rb create mode 100644 spec/translations_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 1ba4d64..2cd31fb 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,7 @@ AllCops: NewCops: enable SuggestExtensions: false - TargetRubyVersion: 3.0 + TargetRubyVersion: 3.2 Gemspec/DevelopmentDependencies: EnforcedStyle: gemspec @@ -15,19 +15,4 @@ Metrics/BlockLength: - spec/**/*.rb Style/MixinUsage: - Enabled: false - -Lint/BooleanSymbol: - Enabled: false - -Metrics/AbcSize: - Enabled: false - -Metrics/MethodLength: - Max: 25 - -Layout/LineLength: - Max: 130 - -Metrics/CyclomaticComplexity: - Max: 8 \ No newline at end of file + Enabled: false \ No newline at end of file diff --git a/Gemfile b/Gemfile index bc8c38f..05f5590 100644 --- a/Gemfile +++ b/Gemfile @@ -7,5 +7,5 @@ gemspec gem 'rake', '~> 13.3' gem 'rspec', '~> 3.13' -gem 'rubocop', '~> 1.79' +gem 'rubocop', '~> 1.80' gem 'simplecov', '~> 0.22' diff --git a/bin/console b/bin/console index 8fcd90c..3d9af4c 100755 --- a/bin/console +++ b/bin/console @@ -3,7 +3,6 @@ require 'bundler/setup' require 'simple_symbolize' -require 'pry' # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. diff --git a/lib/simple_symbolize.rb b/lib/simple_symbolize.rb index 97c2b60..e07453f 100644 --- a/lib/simple_symbolize.rb +++ b/lib/simple_symbolize.rb @@ -32,9 +32,7 @@ def self.translate # @example Symbolize a string using the symbolize method # SimpleSymbolize.symbolize("hello world!") #=> :hello_world def self.symbolize(obj) - return obj unless obj.respond_to?(:to_s) - return obj if [Hash, Array, NilClass].include?(obj.class) - return obj if obj.respond_to?(:empty?) && obj.empty? + return obj unless valid_input?(obj) obj = if SimpleSymbolize.translations.handle_camel_case snakeize(obj) @@ -54,9 +52,7 @@ def self.symbolize(obj) # @example Elementize a string using the elementize method # SimpleSymbolize.elementize("hello world!") #=> "helloWorld" def self.elementize(obj) - return obj unless obj.respond_to?(:to_s) - return obj if [Hash, Array, NilClass].include?(obj.class) - return obj if obj.respond_to?(:empty?) && obj.empty? + return obj unless valid_input?(obj) symbolize(obj).to_s end @@ -68,14 +64,24 @@ def self.elementize(obj) # @example Camelize a string using the camelize method # SimpleSymbolize.camelize("hello world!") #=> :helloWorld def self.camelize(obj) - return obj unless obj.respond_to?(:to_s) - return obj if [Hash, Array, NilClass].include?(obj.class) - return obj if obj.respond_to?(:empty?) && obj.empty? + return obj unless valid_input?(obj) first, *rest = elementize(obj).split('_') return obj if first.nil? - rest.size.positive? ? (first << rest.map(&:capitalize).join).to_sym : symbolize(first) + if rest.size.positive? + acronyms = SimpleSymbolize.translations.camel_case_acronyms + rest = if acronyms.empty? + rest.map(&:capitalize) + else + rest.map { |word| acronyms.include?(word) ? word.upcase : word.capitalize } + end + + word = first + rest.join + word.to_sym + else + symbolize(first) + end end # Turns a String || Symbol into a snake_case Symbol @@ -85,9 +91,7 @@ def self.camelize(obj) # @example Snakeize an object using the snakeize method # SimpleSymbolize.snakeize('Hello World!') #=> :hello_world def self.snakeize(obj) - return obj unless obj.respond_to?(:to_s) - return obj if [Hash, Array, NilClass].include?(obj.class) - return obj if obj.respond_to?(:empty?) && obj.empty? + return obj unless valid_input?(obj) obj.to_s .gsub(Regexp.union(SimpleSymbolize.translations.underscore), '_') @@ -97,4 +101,18 @@ def self.snakeize(obj) .downcase .to_sym end + + # Validates if the input object should be processed + # + # @param obj [Object] the object to validate + # @return [Boolean] true if the object should be processed, false otherwise + def self.valid_input?(obj) + return false unless [String, Symbol].include?(obj.class) + return false unless obj.respond_to?(:to_s) + return false if obj.to_s.empty? + + true + end + + private_class_method :valid_input? end diff --git a/lib/simple_symbolize/translations.rb b/lib/simple_symbolize/translations.rb index 24739b1..164af07 100644 --- a/lib/simple_symbolize/translations.rb +++ b/lib/simple_symbolize/translations.rb @@ -10,8 +10,10 @@ class Translations attr_reader :remove # @return [Array] the characters to be untouched from the String. attr_reader :omit - + # @return [Boolean] whether to handle camelCase strings during symbolisation. attr_reader :handle_camel_case + # @return [Array] the characters to be transformed into uppercase during camelisation. + attr_reader :camel_case_acronyms # Creates an instance of the Translations class. # @@ -21,44 +23,44 @@ def initialize end # Merges the String passed with the @underscore Array omitting duplicates. - # Removes those characters from the @remove and @omit Arrays to avoid the change being over-written. + # Removes those characters from @remove and @omit Arrays to avoid the change being over-written. # - # @param chars [Array] an object containing characters to be underscored. + # @param input [Array] an object containing characters to be underscored. # # @return [Array] the Array of characters to be underscored. - def to_underscore=(chars) - chars = sanitise_chars(chars) + def to_underscore=(input) + arr = sanitise(input) - @remove -= chars - @omit -= chars - @underscore |= chars + @remove -= arr + @omit -= arr + @underscore |= arr end # Merges the String passed with the @remove Array omitting duplicates. - # Removes those characters from the @underscore and @omit Arrays to avoid the change being over-written. + # Removes those characters from @underscore and @omit Arrays to avoid the change being over-written. # - # @param chars [String] a String object containing characters to be removed. + # @param input [String] a String object containing characters to be removed. # # @return [Array] the Array of characters to be removed. - def to_remove=(chars) - chars = sanitise_chars(chars) + def to_remove=(input) + arr = sanitise(input) - @underscore -= chars - @omit -= chars - @remove |= chars + @underscore -= arr + @omit -= arr + @remove |= arr end - # Removes characters within the String passed from the @remove and @underscore Arrays. + # Removes characters within the String passed from @remove and @underscore Arrays. # - # @param chars [String] a String object containing characters to be removed. + # @param input [String] a String object containing characters to be removed. # # @return [Array] the Array of characters to be omitted. - def to_omit=(chars) - chars = sanitise_chars(chars) + def to_omit=(input) + arr = sanitise(input) - @underscore -= chars - @remove -= chars - @omit += chars + @underscore -= arr + @remove -= arr + @omit += arr end def handle_camel_case=(handle) @@ -68,26 +70,37 @@ def handle_camel_case=(handle) @handle_camel_case = handle.eql?('true') end + def camel_case_acronyms=(input) + arr = sanitise(input) + + @camel_case_acronyms = arr.map { |word| word.is_a?(String) ? word.to_s.downcase : nil }.compact.uniq + end + def reset! @underscore = [' ', '::', '-'] @remove = %w[' ( ) , . : " ! @ £ $ % ^ & * / { } [ ] < > ; = #] @omit = [] @handle_camel_case = true + @camel_case_acronyms = [] end private - # Converts chars into Array of Strings + # Sanitises the input into an Array of Strings # - # @param arg Arg to be converted + # @param input [String, Array] to be converted # # @return Array of Strings # # @raise [ArgumentError] if the arg is not either a String or an Array. - def sanitise_chars(arg) - raise ArgumentError 'needs to be a String or an Array of characters' unless [String, Array].include?(arg.class) + def sanitise(input) + raise ArgumentError 'needs to be a String or an Array' unless [String, Array].include?(input.class) - arg.respond_to?(:chars) ? arg.chars : arg.map(&:to_s) + if input.respond_to?(:chars) + input.chars + else + input.map { |obj| obj.respond_to?(:to_s) ? obj.to_s.downcase : nil }.compact.uniq + end end end end diff --git a/lib/simple_symbolize/version.rb b/lib/simple_symbolize/version.rb index 8cc08a8..25748fc 100644 --- a/lib/simple_symbolize/version.rb +++ b/lib/simple_symbolize/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module SimpleSymbolize - VERSION = '4.1.0' + VERSION = '5.0.0' end diff --git a/simple_symbolize.gemspec b/simple_symbolize.gemspec index 75541d5..dbf2e38 100644 --- a/simple_symbolize.gemspec +++ b/simple_symbolize.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/dvla/simple-symbolize' spec.license = 'MIT' - spec.required_ruby_version = Gem::Requirement.new('>= 3.0') + spec.required_ruby_version = Gem::Requirement.new('>= 3.2') spec.metadata['homepage_uri'] = spec.homepage spec.metadata['source_code_uri'] = spec.homepage diff --git a/spec/camelize_spec.rb b/spec/camelize_spec.rb index 1814af4..8346f3f 100644 --- a/spec/camelize_spec.rb +++ b/spec/camelize_spec.rb @@ -19,4 +19,11 @@ expect(SimpleSymbolize.camelize([])).to eq([]) expect(SimpleSymbolize.camelize('')).to eq('') end + + it 'handles camel case acronyms' do + expect(SimpleSymbolize.camelize('from gb')).to eq(:fromGb) + + SimpleSymbolize.translations.camel_case_acronyms = ['gb'] + expect(SimpleSymbolize.camelize('from gb')).to eq(:fromGB) + end end diff --git a/spec/string_spec.rb b/spec/core_ext/string_spec.rb similarity index 100% rename from spec/string_spec.rb rename to spec/core_ext/string_spec.rb diff --git a/spec/core_ext/symbol_spec.rb b/spec/core_ext/symbol_spec.rb new file mode 100644 index 0000000..63bc57c --- /dev/null +++ b/spec/core_ext/symbol_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +RSpec.describe Symbol do + context 'simple_symbolize method' do + it 'has a simple_symbolize method' do + Symbol.respond_to?(:simple_symbolize) + end + + it 'symbolizes the String' do + expect('This is quite a test'.simple_symbolize).to eq(:this_is_quite_a_test) + end + end + + context 'simple_snakeize method' do + it 'has a to_snake_case method' do + Symbol.respond_to?(:simple_snakeize) + end + + it 'returns a snake_case Symbol' do + expect('ThisIsQuiteATest'.simple_snakeize).to eq(:this_is_quite_a_test) + end + end + + context 'simple_elementize method' do + it 'has a simple_elementize method' do + Symbol.respond_to?(:simple_elementize) + end + + it 'elementizes the String' do + expect('This is quite a test'.simple_elementize).to eq('this_is_quite_a_test') + end + end + + context 'simple_camelize method' do + it 'has a to_snake_case method' do + Symbol.respond_to?(:simple_camelize) + end + + it 'returns a snake_case Symbol' do + expect('ThisIsQuiteATest'.simple_camelize).to eq(:thisIsQuiteATest) + end + end +end diff --git a/spec/simple_symbolize_spec.rb b/spec/simple_symbolize_spec.rb index 6cd1a28..8d90f21 100644 --- a/spec/simple_symbolize_spec.rb +++ b/spec/simple_symbolize_spec.rb @@ -21,10 +21,13 @@ expect(SimpleSymbolize.symbolize('This is a test')).to eq(:this_is_a_test) end - it 'will handle TrueClass, FalseClass, Integers and Classes/Modules' do - expect(SimpleSymbolize.symbolize(true)).to eq(:true) - expect(SimpleSymbolize.symbolize(false)).to eq(:false) - expect(SimpleSymbolize.symbolize(1)).to eq(:'1') + it 'will return objects not of type String or Symbol' do + expect(SimpleSymbolize.symbolize(true)).to eq(true) + expect(SimpleSymbolize.symbolize(false)).to eq(false) + expect(SimpleSymbolize.symbolize(1)).to eq(1) + expect(SimpleSymbolize.symbolize(SimpleSymbolize)).to eq(SimpleSymbolize) + expect(SimpleSymbolize.symbolize(String)).to eq(String) + expect(SimpleSymbolize.symbolize(SimpleSymbolize::Error)).to eq(SimpleSymbolize::Error) end it 'can cannot #symbolize without the namespace' do @@ -50,10 +53,10 @@ end it 'has consistent behaviour between methods' do - expect(SimpleSymbolize.symbolize(true)).to eq(:true) - expect(SimpleSymbolize.elementize(true)).to eq('true') - expect(SimpleSymbolize.camelize(true)).to eq(:true) - expect(SimpleSymbolize.snakeize(true)).to eq(:true) + expect(SimpleSymbolize.symbolize(true)).to eq(true) + expect(SimpleSymbolize.elementize(true)).to eq(true) + expect(SimpleSymbolize.camelize(true)).to eq(true) + expect(SimpleSymbolize.snakeize(true)).to eq(true) expect(SimpleSymbolize.symbolize(nil)).to eq(nil) expect(SimpleSymbolize.elementize(nil)).to eq(nil) @@ -76,12 +79,6 @@ expect(SimpleSymbolize.snakeize('')).to eq('') end - it 'handles Classes and Modules' do - expect(SimpleSymbolize.symbolize(SimpleSymbolize)).to eq(:simple_symbolize) - expect(SimpleSymbolize.symbolize(String)).to eq(:string) - expect(SimpleSymbolize.symbolize(SimpleSymbolize::Error)).to eq(:simple_symbolize_error) - end - it 'correctly handles : and ::' do expect(SimpleSymbolize.symbolize('Hello::World')).to eq(:hello_world) expect(SimpleSymbolize.symbolize('Hello:World')).to eq(:hello_world) @@ -90,7 +87,8 @@ context 'config' do it 'does not contain conflicting information by default' do SimpleSymbolize.translations.remove.any? do |remove_item| - SimpleSymbolize.translations.underscore.include?(remove_item) || SimpleSymbolize.translations.omit.include?(remove_item) + SimpleSymbolize.translations.underscore.include?(remove_item) || + SimpleSymbolize.translations.omit.include?(remove_item) end end diff --git a/spec/translations_spec.rb b/spec/translations_spec.rb new file mode 100644 index 0000000..05de1b1 --- /dev/null +++ b/spec/translations_spec.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +RSpec.describe SimpleSymbolize::Translations do + let(:default_underscore) { [' ', '::', '-'] } + let(:default_remove) { %w[' ( ) , . : " ! @ £ $ % ^ & * / { } [ ] < > ; = #] } + let(:default_omit) { [] } + let(:default_handle_camel_case) { true } + let(:default_acronyms) { [] } + + describe('#new') do + it 'has default strings to underscore' do + expect(subject.underscore).to eq(default_underscore) + end + + it 'has default strings to remove' do + expect(subject.remove).to eq(default_remove) + end + + it 'omits nothing by default' do + expect(subject.omit).to eq(default_omit) + end + + it 'sets handle_camel_case to true by default' do + expect(subject.handle_camel_case).to be(default_handle_camel_case) + end + + it 'has no acronyms to uppercase by default' do + expect(subject.camel_case_acronyms).to eq(default_acronyms) + end + end + + describe('#reset!') do + before do + subject.to_omit = ['abc'] + expect(subject.omit).to include('abc') + + subject.to_remove = ['def'] + expect(subject.remove).to include('def') + + subject.to_underscore = ['ghi'] + expect(subject.underscore).to include('ghi') + + subject.camel_case_acronyms = ['jkl'] + expect(subject.camel_case_acronyms).to include('jkl') + + subject.handle_camel_case = false + end + + it 'resets attributes back to their default values' do + subject.reset! + + expect(subject).to have_attributes(underscore: default_underscore, + omit: default_omit, + remove: default_remove, + camel_case_acronyms: default_acronyms, + handle_camel_case: default_handle_camel_case) + end + end + + describe('#to_underscore') do + context('arg as string') do + it('adds each char individually') do + subject.to_underscore = 'abc' + %w[a b c].each { |char| expect(subject.underscore).to include(char) } + end + end + + context('arg as array') do + it('adds each array object') do + to_underscore = %w[abc def] + subject.to_underscore = to_underscore + + to_underscore.each { |char| expect(subject.underscore).to include(char) } + end + end + end + + describe('#to_remove') do + context('arg as string') do + it('adds each char individually') do + subject.to_remove = 'abc' + %w[a b c].each { |char| expect(subject.remove).to include(char) } + end + end + + context('arg as array') do + it('adds each array object') do + to_remove = %w[abc def] + subject.to_remove = to_remove + + to_remove.each { |char| expect(subject.remove).to include(char) } + end + end + end + + describe('#to_omit') do + context('arg as string') do + it('adds each char individually') do + subject.to_omit = 'abc' + %w[a b c].each { |char| expect(subject.omit).to include(char) } + end + end + + context('arg as array') do + it('adds each array object') do + to_omit = %w[abc def] + subject.to_omit = to_omit + + to_omit.each { |char| expect(subject.omit).to include(char) } + end + end + end + + describe('#camel_case_acronyms') do + context('arg as string') do + it('adds each char individually') do + subject.camel_case_acronyms = 'abc' + %w[a b c].each { |char| expect(subject.camel_case_acronyms).to include(char) } + end + end + + context('arg as array') do + it('adds each array object') do + camel_case_acronyms = %w[abc def] + subject.camel_case_acronyms = camel_case_acronyms + + camel_case_acronyms.each { |char| expect(subject.camel_case_acronyms).to include(char) } + end + end + end + + context('contradiction') do + it('ensures no duplication between attributes') do + subject.to_underscore = 'a' + expect(subject.underscore).to include('a') + expect(subject.remove).not_to include('a') + expect(subject.omit).not_to include('a') + + subject.to_remove = 'a' + expect(subject.remove).to include('a') + expect(subject.underscore).not_to include('a') + expect(subject.omit).not_to include('a') + + subject.to_omit = 'a' + expect(subject.omit).to include('a') + expect(subject.underscore).not_to include('a') + expect(subject.remove).not_to include('a') + end + end +end From 6c6965ed886b80ee90025912ee6f519c43d8f57b Mon Sep 17 00:00:00 2001 From: alexo Date: Wed, 27 Aug 2025 13:52:41 +0100 Subject: [PATCH 2/2] [5.0.0] chore: abstracted logic for camelCase into private method --- README.md | 88 +++++++++++++++++++++++++++++++++++------ lib/simple_symbolize.rb | 61 ++++++++++++++++------------ 2 files changed, 112 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index cc28778..55c9bc2 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # SimpleSymbolize -SimpleSymbolize takes a string and transforms it into a symbol. Why? Because working with symbols in Ruby makes for a +SimpleSymbolize takes a string and transforms it into a symbol. Why? Because working with symbols in Ruby makes for a good time. Wait, doesn't String already have a `to_sym` method? -Correct! However, this gem takes it one step further by transforming special characters and whitespace to give you a +Correct! However, this gem takes it one step further by transforming special characters and whitespace to give you a simple easy to work with Symbol. It works by removing special characters in a String like `'!'` and underscoring any whitespace. @@ -38,9 +38,9 @@ Or install it yourself as: ## Usage -There are two ways to symbolize your String. +There are three ways to use this gem. -### Call the symbolize method and pass it your String +### SimpleSymbolize ```ruby require 'simple_symbolize' @@ -48,7 +48,16 @@ require 'simple_symbolize' SimpleSymbolize.symbolize('hello world!') # => :hello_world ``` -### Call the symbolize method on your String object +Available methods: + +| Method | What does it do? | +|------------|------------------------------------------------------------------------------------------------------------------------------------------| +| symbolize | Returns your object as a plain old symbol | +| elementize | Returns your object as a plain old String | +| camelize | Returns your object as a plain old camelCase symbol | +| snakeize | Returns your object as a plain old snake_case symbol (very similar to symbolize, only it does not respect the handle_camel_case setting) | | + +### Mixing into String ```ruby require 'simple_symbolize' @@ -58,7 +67,16 @@ String.include SimpleSymbolize::CoreExt::String 'hello world!'.simple_symbolize # => :hello_world ``` -### Call the symbolize method on your Symbol object +Available methods: + +| Method | What does it do? | +|------------|------------------------------------------------------------------------------------------------------------------------------------------| +| simple_symbolize | Returns your object as a plain old symbol | +| simple_elementize | Returns your object as a plain old String | +| simple_camelize | Returns your object as a plain old camelCase symbol | +| simple_snakeize | Returns your object as a plain old snake_case symbol (very similar to symbolize, only it does not respect the handle_camel_case setting) | | + +### Mixing into Symbol ```ruby require 'simple_symbolize' @@ -68,9 +86,18 @@ Symbol.include SimpleSymbolize::CoreExt::Symbol :hello_world!.simple_symbolize # => :hello_world ``` +Available methods: + +| Method | What does it do? | +|------------|------------------------------------------------------------------------------------------------------------------------------------------| +| simple_symbolize | Returns your object as a plain old symbol | +| simple_elementize | Returns your object as a plain old String | +| simple_camelize | Returns your object as a plain old camelCase symbol | +| simple_snakeize | Returns your object as a plain old snake_case symbol (very similar to symbolize, only it does not respect the handle_camel_case setting) | | + ## Configuration -Something not underscored or removed? Or even something underscored/removed that you didn't want transformed? +Something not underscored or removed? Or even something underscored/removed that you didn't want transformed? No sweat, you can configure this gem to underscore and remove to your hearts content! @@ -84,20 +111,51 @@ end ## Updates! +### V5 + +#### Dropped support for Ruby < 3.2 + +Ruby 3.1 reached EOL in 2024, as such this gem no longer supports versions older than 3.2. + +#### Only deals with Strings and Symbols + +In previous iterations, certain non String/Symbol objects would be handled `SimpleSymbolize.symbolze(true)` returned +`:true`. + +To be consistent, SimpleSymbolize now only accepts String/Symbols, everything else will be returned. + +#### Uppercase acronyms when camelizing + +Sometimes you want certain phrases to be in uppercase when camelizing, SimpleSymbolize now supports this. + +```ruby +SimpleSymbolize.translate { |t| t.camel_case_acronym = ['gb'] } + +SimpleSymbolize.camelize('from gb') # => :fromGB (without setting the camel_case_acronym this would return :fromGb) +``` + +--- + ### V4.1 -### Symbol methods can now be Mixed in -SimpleSymbolize now supports mixing in the methods on the Symbol class, allowing you to call `simple_symbolize` directly on a Symbol object. +#### Symbol methods can now be Mixed in + +SimpleSymbolize now supports mixing in the methods on the Symbol class, allowing you to call `simple_symbolize` directly +on a Symbol object. ```ruby Symbol.include SimpleSymbolize::CoreExt::Symbol :hello_world!.simple_symbolize # => :hello_world ``` +--- + ### V4 + #### String methods now need to be Mixed in -SimpleSymbolize is safe to use with other gems, particularly the popular ActiveSupport gem which SimpleSymbolize use to share +SimpleSymbolize is safe to use with other gems, particularly the popular ActiveSupport gem which SimpleSymbolize use to +share certain methods names with. You now need to deliberately mixin the methods on the String class: @@ -118,9 +176,13 @@ To make them easier to spot, the method names on the String class have been pref #### Introducing #snakeize The `#snakeize` method will return your object in snake_case. -This is the default behaviour of the `#symbolize` method however `#snakeize` will always return thr Symbol in snake_case. +This is the default behaviour of the `#symbolize` method however `#snakeize` will always return thr Symbol in +snake_case. + +--- ### V3 + #### String to_snake_case [DEPRECATED - replaced with `#simple_snakeize` in v4] `#to_snake_case` extends the String class to return you your String object in snake_case format. @@ -145,6 +207,8 @@ Arrays are now supported when configuring the gem SimpleSymbolize.translate { |trans| trans.to_underscore = %w[!&*] } ``` +--- + ### V2 SimpleSymbolize has got new friends! @@ -162,7 +226,7 @@ SimpleSymbolize.elementize('hello world!') # => "hello_world" #### Camelize -Great for working with APIs that require fields in a JSON format. Camelize clears away the clutter and returns you +Great for working with APIs that require fields in a JSON format. Camelize clears away the clutter and returns you a Symbolized object in camelCase. [comment]: <> (## Contributing) diff --git a/lib/simple_symbolize.rb b/lib/simple_symbolize.rb index e07453f..8f0cec0 100644 --- a/lib/simple_symbolize.rb +++ b/lib/simple_symbolize.rb @@ -69,19 +69,7 @@ def self.camelize(obj) first, *rest = elementize(obj).split('_') return obj if first.nil? - if rest.size.positive? - acronyms = SimpleSymbolize.translations.camel_case_acronyms - rest = if acronyms.empty? - rest.map(&:capitalize) - else - rest.map { |word| acronyms.include?(word) ? word.upcase : word.capitalize } - end - - word = first + rest.join - word.to_sym - else - symbolize(first) - end + assemble_came_case_string(first, rest) end # Turns a String || Symbol into a snake_case Symbol @@ -102,17 +90,40 @@ def self.snakeize(obj) .to_sym end - # Validates if the input object should be processed - # - # @param obj [Object] the object to validate - # @return [Boolean] true if the object should be processed, false otherwise - def self.valid_input?(obj) - return false unless [String, Symbol].include?(obj.class) - return false unless obj.respond_to?(:to_s) - return false if obj.to_s.empty? - - true - end + class << self + private + + # Validates if the input object should be processed + # + # @param obj [Object] the object to validate + # + # @return [Boolean] true if the object should be processed, false otherwise + def valid_input?(obj) + return false unless [String, Symbol].include?(obj.class) + return false unless obj.respond_to?(:to_s) + return false if obj.to_s.empty? - private_class_method :valid_input? + true + end + + # Abstracts the complicated building of the camelCase String + # + # @param first [String] the first part of the camelCase String + # @param rest [Array] the rest of the camelCase String + # + # @return [Symbol] camelCase representation of the input + def assemble_came_case_string(first, rest) + return symbolize(first) unless rest.size.positive? + + acronyms = SimpleSymbolize.translations.camel_case_acronyms + rest = if acronyms.empty? + rest.map(&:capitalize) + else + rest.map { |word| acronyms.include?(word) ? word.upcase : word.capitalize } + end + + word = first + rest.join + word.to_sym + end + end end