Skip to content

Commit

Permalink
allow proc for brands option
Browse files Browse the repository at this point in the history
  • Loading branch information
Fivell committed Jan 14, 2015
1 parent 482c3f1 commit 0237739
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 14 deletions.
54 changes: 42 additions & 12 deletions lib/active_model/credit_card_number_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,35 @@
# attr_accessor :number
# include ActiveModel::Validations
# validates :number, credit_card_number: {except: [:maestro]}
# end
# end
#
# Proc can be used as well
#
# class CreditCard
# attr_accessor :number, :card_type
# include ActiveModel::Validations
# validates :number, credit_card_number: {brands: ->{|record| Array(record.accepted_brands) } }
#
# def accepted_brands
# if card_type == 'Maestro'
# :maestro
# elsif card_type == 'American Express'
# :amex
# else
# :visa
# end
# end
#
# end
#
#

module ActiveModel
module Validations
class CreditCardNumberValidator < EachValidator

def validate_each(record, attribute, value)
record.errors.add(attribute) unless credit_card_valid?(value, extract_brands(options))
record.errors.add(attribute) unless credit_card_valid?(value, extract_brands(record, options))
end

def credit_card_valid?(number, brands = [])
Expand All @@ -32,17 +52,27 @@ def credit_card_valid?(number, brands = [])

protected

def extract_brands(options)
if options.has_key?(:brands)
options[:brands] == :any ? [] : Array(options[:brands])
elsif options.has_key?(:only)
Array(options[:only])
elsif options.has_key?(:except)
Array(CreditCardValidations::Detector.brands.keys) - Array(options[:except])
else
[]
end
def extract_brands(record, options)
if options.has_key?(:brands)
with_brands(record, options[:brands])
elsif options.has_key?(:only)
Array(options[:only])
elsif options.has_key?(:except)
Array(CreditCardValidations::Detector.brands.keys) - Array(options[:except])
else
[]
end

end

def with_brands(record, brands)
if brands.is_a?(Proc)
brands.call(record)
elsif options[:brands] == :any
[]
else
Array(options[:brands])
end
end

end
Expand Down
18 changes: 17 additions & 1 deletion spec/active_model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,30 @@

let(:model) { CreditCard.new }

describe "Proc support" do
it "should be valid if brands from proc valid" do
card = model.dup
card.card_type = "Master Card"
card.number6 = CreditCardValidations::Factory.random(:visa)
card.valid?.must_equal false
card.number6 = CreditCardValidations::Factory.random(:mastercard)
card.valid?.must_equal true

end

end

describe "Any Brand" do
it "should be alid for all prepared valid numbers" do
it "should be valid for all prepared valid numbers" do
VALID_NUMBERS.each do |_, numbers|

numbers.each do |number|
card = model
card.number4 = number
card.number5 = number
unless card.valid?
p card.errors
end
card.valid?.must_equal true

end
Expand Down
12 changes: 11 additions & 1 deletion spec/models/credit_card.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
class CreditCard
attr_accessor :number, :number2, :number3, :number4, :number5
attr_accessor :number, :number2, :number3, :number4, :number5, :number6, :card_type
include ActiveModel::Validations
validates :number, credit_card_number: {brands: [:amex, :maestro]} , allow_blank: true
validates :number2, credit_card_number: {only: [:amex, :maestro]}, allow_blank: true
validates :number3, credit_card_number: {except: [:amex, :maestro]} , allow_blank: true
validates :number4, credit_card_number: {brands: :any} , allow_blank: true
validates :number5, credit_card_number: true , allow_blank: true
validates :number6, credit_card_number: { brands: ->(record){ record.supported_brand } } , allow_blank: true


def supported_brand
{
"Master Card" => :mastercard,
"Visa" => :visa
}[self.card_type]
end

end

0 comments on commit 0237739

Please sign in to comment.