Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor validators similar ActiveModel::Validations format #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/bookland.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'bookland/identifier'
require 'bookland/ean'
require 'bookland/invalid_isbn'
require 'bookland/isbn'
require 'bookland/asin'
require 'bookland/isbn10'
require 'bookland/validators' if defined?(ActiveModel)
2 changes: 1 addition & 1 deletion lib/bookland/identifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def self.calculate_checksum_digit(data_digits)
attr :digits

def initialize(raw)
@digits = raw.split('')
@digits = raw.gsub('-','').split('')
end

def data_digits
Expand Down
4 changes: 4 additions & 0 deletions lib/bookland/invalid_isbn.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Bookland
class InvalidISBN < StandardError
end
end
37 changes: 37 additions & 0 deletions lib/bookland/isbn10.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module Bookland
# The now-obsolete 10-digit ISBN.
class ISBN10 < Identifier
# Calculates the checksum for the 9-digit data_digits of an ISBN-10.
def self.calculate_checksum_digit(data_digits)
data_digits.map! &:to_i
weights = 10.downto(2).to_a
sum = data_digits.zip(weights).inject(0) { |a , (i, j)| a + i * j }
checksum = 11 - sum % 11

case checksum
when 0..9 then checksum.to_s
when 10 then 'X'
when 11 then '0'
end
end

# Converts the given ISBN-10 to an ISBN.
def self.to_isbn(raw)
new(raw).to_isbn
end

# Converts the ISBN-10 to an ISBN.
def to_isbn
raise InvalidISBN unless valid?

new_data_digits = [9, 7, 8] + data_digits
new_checksum = ISBN.calculate_checksum_digit new_data_digits

(new_data_digits << new_checksum).join
end

def valid?
digits.size == 10 && super
end
end
end
57 changes: 48 additions & 9 deletions lib/bookland/validators.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,55 @@
%w(ASIN EAN ISBN).each do |klass|
%w(ASIN EAN).each do |klass|
Object.class_eval <<-EOF
class #{klass.capitalize}Validator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless Bookland::#{klass}.valid?(value)
message = "is not an #{klass}"
if options[:strict]
raise ActiveModel::StrictValidationFailed, "\#{value} \#{message}"
else
record.errors[attribute] << message
module ValidationExtensions
class #{klass.capitalize}Validator < ActiveModel::EachValidator
def initialize(options)
options[:message] ||= "is not a valid #{klass} code"
options[:allow_nil] ||= false
options[:allow_blank] ||= false
super(options)
end

def validate_each(record, attribute, value)
unless Bookland::#{klass}.valid?(value) || (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
record.errors.add(attribute, options[:message])
end
end
end

module HelperMethods
def validates_#{klass.downcase}(*attr_names)
validates_with #{klass.capitalize}Validator, _merge_attributes(attr_names)
end
end
end
EOF
end

module ValidationExtensions
class IsbnValidator < ActiveModel::EachValidator
def initialize(options)
options[:message] ||= "is not a valid ISBN code"
options[:allow_nil] ||= false
options[:allow_blank] ||= false
options[:compatible] ||= true
super(options)
end

def validate_each(record, attribute, value)
return if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
unless Bookland::ISBN.valid?(value) || (options[:compatible] && Bookland::ISBN10.valid?(value))
record.errors.add(attribute, options[:message])
end
end
end

module HelperMethods
def validates_isbn(*attr_names)
validates_with IsbnValidator, _merge_attributes(attr_names)
end
end
end

ActiveModel::Validations.send(:include, ValidationExtensions)
ActiveModel::Validations::HelperMethods.send(:include, ValidationExtensions::HelperMethods)