Skip to content

Commit

Permalink
Merge pull request #166 from Ross-Hunter/feature/conditional-normaliz…
Browse files Browse the repository at this point in the history
…ation

Conditional Normalization
  • Loading branch information
Joost Hietbrink authored Jun 20, 2017
2 parents 4e0a3df + 7422a3c commit aab3ab1
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 3 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class SomeModel < ActiveRecord::Base

# Creates method normalized_fax_number that returns the normalized version of fax_number
phony_normalized_method :fax_number

# Conditionally normalizes the attribute
phony_normalize :recipient, default_country_code: 'US', if: -> { contact_method == 'phone_number' }
end
```

Expand Down
35 changes: 33 additions & 2 deletions lib/phony_rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,17 @@ module ClassMethods
# you've geocoded before calling this method!
def phony_normalize(*attributes)
options = attributes.last.is_a?(Hash) ? attributes.pop : {}
options.assert_valid_keys :country_number, :default_country_number, :country_code, :default_country_code, :add_plus, :as, :enforce_record_country
options.assert_valid_keys :country_number, :default_country_number, :country_code, :default_country_code, :add_plus, :as, :enforce_record_country, :if, :unless
if options[:as].present?
raise ArgumentError, ':as option can not be used on phony_normalize with multiple attribute names! (PhonyRails)' if attributes.size > 1
end

options[:enforce_record_country] = true if options[:enforce_record_country].nil?

conditional = create_before_validation_conditional_hash(options)

# Add before validation that saves a normalized version of the phone number
before_validation do
before_validation conditional do
set_phony_normalized_numbers(attributes, options)
end
end
Expand All @@ -187,6 +189,35 @@ def phony_normalized_method(*attributes)
end
end
end

private

# Creates a hash representing a conditional for before_validation
# This allows conditional normalization
# Returns something like `{ unless: -> { attribute == 'something' } }`
# If no if/unless options passed in, returns `{ if: -> { true } }`
def create_before_validation_conditional_hash(options)
if options[:if].present?
type = :if
source = options[:if]
elsif options[:unless].present?
type = :unless
source = options[:unless]
else
type = :if
source = true
end

conditional = {}
conditional[type] = if source.respond_to?(:call)
source
elsif source.respond_to?(:to_sym)
-> { send(source.to_sym) }
else
-> { source }
end
conditional
end
end
end
end
Expand Down
50 changes: 50 additions & 0 deletions spec/lib/phony_rails_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,56 @@ class NormalHome < ActiveRecord::Base
expect(model).to be_valid
expect(model.symboled_phone).to eql('+33606060606')
end

context 'conditional normalization' do
context 'standalone methods' do
it 'should only normalize if the :if conditional is true' do
model_klass.phony_normalize :recipient, default_country_code: 'US', if: :use_phone?

sms_alarm = model_klass.new recipient: '222 333 4444', delivery_method: 'sms'
email_alarm = model_klass.new recipient: '[email protected]', delivery_method: 'email'
expect(sms_alarm).to be_valid
expect(email_alarm).to be_valid
expect(sms_alarm.recipient).to eq('+12223334444')
expect(email_alarm.recipient).to eq('[email protected]')
end

it 'should only normalize if the :unless conditional is false' do
model_klass.phony_normalize :recipient, default_country_code: 'US', unless: :use_email?

sms_alarm = model_klass.new recipient: '222 333 4444', delivery_method: 'sms'
email_alarm = model_klass.new recipient: '[email protected]', delivery_method: 'email'
expect(sms_alarm).to be_valid
expect(email_alarm).to be_valid
expect(sms_alarm.recipient).to eq('+12223334444')
expect(email_alarm.recipient).to eq('[email protected]')
end
end

context 'using lambdas' do
it 'should only normalize if the :if conditional is true' do
model_klass.phony_normalize :recipient, default_country_code: 'US', if: -> { delivery_method == 'sms' }

sms_alarm = model_klass.new recipient: '222 333 4444', delivery_method: 'sms'
email_alarm = model_klass.new recipient: '[email protected]', delivery_method: 'email'
expect(sms_alarm).to be_valid
expect(email_alarm).to be_valid
expect(sms_alarm.recipient).to eq('+12223334444')
expect(email_alarm.recipient).to eq('[email protected]')
end

it 'should only normalize if the :unless conditional is false' do
model_klass.phony_normalize :recipient, default_country_code: 'US', unless: -> { delivery_method == 'email' }

sms_alarm = model_klass.new recipient: '222 333 4444', delivery_method: 'sms'
email_alarm = model_klass.new recipient: '[email protected]', delivery_method: 'email'
expect(sms_alarm).to be_valid
expect(email_alarm).to be_valid
expect(sms_alarm.recipient).to eq('+12223334444')
expect(email_alarm.recipient).to eq('[email protected]')
end
end
end
end
end

Expand Down
10 changes: 9 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,22 @@
module SharedModelMethods
extend ActiveSupport::Concern
included do
attr_accessor :phone_method, :phone1_method, :symboled_phone_method, :country_code, :country_code_attribute
attr_accessor :phone_method, :phone1_method, :symboled_phone_method, :country_code, :country_code_attribute, :recipient, :delivery_method
phony_normalized_method :phone_attribute # adds normalized_phone_attribute method
phony_normalized_method :phone_method # adds normalized_phone_method method
phony_normalized_method :phone1_method, default_country_code: 'DE' # adds normalized_phone_method method
phony_normalized_method :symboled_phone_method, country_code: :country_code_attribute # adds phone_with_symboled_options method
phony_normalize :phone_number # normalized on validation
phony_normalize :fax_number, default_country_code: 'AU'
phony_normalize :symboled_phone, default_country_code: :country_code_attribute

def use_phone?
delivery_method == 'sms'
end

def use_email?
delivery_method == 'email'
end
end
end

Expand Down

0 comments on commit aab3ab1

Please sign in to comment.