isbn_validation 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008, 2009 Nick Plante
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,27 @@
1
+ IsbnValidation
2
+ ==============
3
+
4
+ Custom ActiveRecord Validation for International Standard Book Number (ISBN) fields.
5
+ Supports both ISBN-10 and ISBN-13. Will guarantee that validated fields contain valid
6
+ ISBNs.
7
+
8
+ Default behavior is to allow either ISBN-10 or ISBN-13, but this can be altered by
9
+ specifying the :with option as shown in the example below.
10
+
11
+ For more information on ISBN, see http://en.wikipedia.org/wiki/Isbn
12
+
13
+ Installation
14
+ ============
15
+
16
+ ruby script/plugin install git://github.com/zapnap/isbn_validation
17
+
18
+ Example
19
+ =======
20
+
21
+ class Book < ActiveRecord::Base
22
+ validates_isbn :isbn
23
+ validates_isbn :isbn10, :with => :isbn10
24
+ validates_isbn :isbn13, :with => :isbn13
25
+ end
26
+
27
+ Copyright (c) 2008 Nick Plante, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the isbn_validation plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the isbn_validation plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'IsbnValidation'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ spec = Gem::Specification.new do |s|
25
+ s.name = %q{isbn_validation}
26
+ s.name = %q{isbn_validation}
27
+ s.version = "0.1.2"
28
+ s.summary = %q{isbn_validation adds an isbn validation routine to active record models.}
29
+ s.description = %q{isbn_validation adds an isbn validation routine to active record models.}
30
+
31
+ s.files = FileList['[A-Z]*', '{lib,test}/**/*.rb']
32
+ s.require_path = 'lib'
33
+ s.test_files = Dir[*['test/**/*_test.rb']]
34
+
35
+ s.has_rdoc = true
36
+ s.extra_rdoc_files = ["README"]
37
+ s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README"]
38
+
39
+ s.authors = ["Nick Plante"]
40
+ s.email = %q{nap@zerosum.org}
41
+
42
+ s.platform = Gem::Platform::RUBY
43
+ s.add_dependency(%q<activerecord>, [">= 2.1.2"])
44
+ end
45
+
46
+ desc "Generate a gemspec file"
47
+ task :gemspec do
48
+ File.open("#{spec.name}.gemspec", 'w') do |f|
49
+ f.write spec.to_ruby
50
+ end
51
+ end
@@ -0,0 +1,87 @@
1
+ module Zerosum
2
+ module ValidationExtensions
3
+ module IsbnValidation
4
+ ISBN10_REGEX = /^(?:\d[\ |-]?){9}[\d|X]$/
5
+ ISBN13_REGEX = /^(?:\d[\ |-]?){13}$/
6
+
7
+ # Validates whether the value of the specified attribute is a proper ISBN number.
8
+ # Defaults to verifying that the value is either a valid ISBN-10 or ISBN-13 number
9
+ # but this behavior can be modified using configuration options (as shown below).
10
+ #
11
+ # class Book < ActiveRecord::Base
12
+ # validates_isbn :isbn
13
+ # #validates_isbn :isbn10, :with => :isbn10
14
+ # #validates_isbn :isbn13, :with => :isbn13
15
+ # end
16
+ #
17
+ # Configuration options:
18
+ # * <tt>:message</tt> - A custom error message (default is: "is not a valid ISBN")
19
+ # * <tt>:with</tt> - A symbol referencing the type of ISBN to validate (:isbn10 or :isbn13)
20
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
21
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
22
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
23
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
24
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
25
+ # method, proc or string should return or evaluate to a true or false value.
26
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
27
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
28
+ # method, proc or string should return or evaluate to a true or false value.
29
+ def validates_isbn(*attr_names)
30
+ configuration = {
31
+ :message => "is not a valid ISBN code"
32
+ }
33
+
34
+ configuration.update(attr_names.extract_options!)
35
+ validates_each(attr_names, configuration) do |record, attr_name, value|
36
+ valid = case configuration[:with]
37
+ when :isbn10
38
+ validate_with_isbn10(value)
39
+ when :isbn13
40
+ validate_with_isbn13(value)
41
+ else
42
+ validate_with_isbn10(value) || validate_with_isbn13(value)
43
+ end
44
+ record.errors.add(attr_name, configuration[:message]) unless valid
45
+ end
46
+ end
47
+
48
+ def validate_with_isbn10(isbn) #:nodoc:
49
+ if (isbn || '').match(ISBN10_REGEX)
50
+ isbn_values = isbn.upcase.gsub(/\ |-/, '').split('')
51
+ check_digit = isbn_values.pop # last digit is check digit
52
+ check_digit = (check_digit == 'X') ? 10 : check_digit.to_i
53
+
54
+ sum = 0
55
+ isbn_values.each_with_index do |value, index|
56
+ sum += (index + 1) * value.to_i
57
+ end
58
+
59
+ (sum % 11) == check_digit
60
+ else
61
+ false
62
+ end
63
+ end
64
+
65
+ def validate_with_isbn13(isbn) #:nodoc:
66
+ if (isbn || '').match(ISBN13_REGEX)
67
+ isbn_values = isbn.upcase.gsub(/\ |-/, '').split('')
68
+ check_digit = isbn_values.pop.to_i # last digit is check digit
69
+
70
+ sum = 0
71
+ isbn_values.each_with_index do |value, index|
72
+ multiplier = (index % 2 == 0) ? 1 : 3
73
+ sum += multiplier * value.to_i
74
+ end
75
+
76
+ result = (10 - (sum % 10))
77
+ result = 0 if result == 10
78
+
79
+ result == check_digit
80
+ else
81
+ false
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require File.dirname(__FILE__) + '/models'
3
+
4
+ class IsbnValidationTest < Test::Unit::TestCase
5
+ def setup
6
+ @book = Book.new
7
+ end
8
+
9
+ def test_isbn10_should_match_regex
10
+ isbn = '1590599934'
11
+ assert isbn.match(Zerosum::ValidationExtensions::IsbnValidation::ISBN10_REGEX)
12
+ end
13
+
14
+ def test_isbn10_should_not_match_regex
15
+ isbn = 'abc123ab3344'
16
+ assert !isbn.match(Zerosum::ValidationExtensions::IsbnValidation::ISBN10_REGEX)
17
+ end
18
+
19
+ def test_isbn10_with_dashes_and_spaces_should_match_regex
20
+ isbn = '159-059 9934'
21
+ assert isbn.match(Zerosum::ValidationExtensions::IsbnValidation::ISBN10_REGEX)
22
+ end
23
+
24
+ def test_isbn13_should_match_regex
25
+ isbn = '9781590599938'
26
+ assert isbn.match(Zerosum::ValidationExtensions::IsbnValidation::ISBN13_REGEX)
27
+ end
28
+
29
+ def test_isbn13_should_not_match_regex
30
+ isbn = '9991a9010599938'
31
+ assert !isbn.match(Zerosum::ValidationExtensions::IsbnValidation::ISBN13_REGEX)
32
+ end
33
+
34
+ def test_isbn13_with_dashes_and_spaces_should_match_regex
35
+ isbn = '978-159059 9938'
36
+ assert isbn.match(Zerosum::ValidationExtensions::IsbnValidation::ISBN13_REGEX)
37
+ end
38
+
39
+ def test_isbn10_should_pass_check_digit_verification
40
+ @book.isbn = '159059993-4'
41
+ assert @book.valid?
42
+ end
43
+
44
+ def test_isbn10_should_fail_check_digit_verification
45
+ @book.isbn = '159059993-0'
46
+ assert !@book.valid?
47
+ end
48
+
49
+ def test_isbn10_should_handle_x_character_checksum
50
+ @book.isbn = '0-9722051-1-X'
51
+ assert @book.valid?
52
+ end
53
+
54
+ def test_isbn13_should_pass_check_digit_verification
55
+ @book.isbn = '978-1590599938'
56
+ assert @book.valid?
57
+ end
58
+
59
+ def test_isbn13_should_fail_check_digit_verification
60
+ @book.isbn = '978-1590599934'
61
+ assert !@book.valid?
62
+ end
63
+
64
+ def test_isbn_should_be_valid_if_either_isbn10_or_isbn13
65
+ @book.isbn = '978-1590599938'
66
+ assert @book.valid?
67
+ @book.isbn = '1590599934'
68
+ assert @book.valid?
69
+ end
70
+
71
+ def test_isbn_should_validate_only_isbn10
72
+ @book = Book10.new
73
+ @book.isbn = '978-1590599938'
74
+ assert !@book.valid?
75
+ @book.isbn = '1590599934'
76
+ assert @book.valid?
77
+ end
78
+
79
+ def test_isbn_should_validate_only_isbn13
80
+ @book = Book13.new
81
+ @book.isbn = '1590599934'
82
+ assert !@book.valid?
83
+ @book.isbn = '978-1590599938'
84
+ assert @book.valid?
85
+ end
86
+
87
+ def test_should_have_custom_error_message
88
+ @book.isbn = '978-159059AAAAAA'
89
+ @book.valid?
90
+ assert_equal 'is too fantastical!', @book.errors.on(:isbn)
91
+ end
92
+
93
+ def test_isbn13_with_zero_check_digit_should_validate
94
+ @book.isbn = '978-1-60746-006-0'
95
+ assert @book.valid?
96
+ end
97
+ end
data/test/models.rb ADDED
@@ -0,0 +1,13 @@
1
+ class Book < ActiveRecord::Base
2
+ validates_isbn :isbn, :message => 'is too fantastical!'
3
+ end
4
+
5
+ class Book10 < ActiveRecord::Base
6
+ set_table_name 'books'
7
+ validates_isbn :isbn, :with => :isbn10
8
+ end
9
+
10
+ class Book13 < ActiveRecord::Base
11
+ set_table_name 'books'
12
+ validates_isbn :isbn, :with => :isbn13
13
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+ create_table :books, :force => true do |t|
3
+ t.string :isbn
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ RAILS_ROOT = File.dirname(__FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'active_record'
7
+ require "#{File.dirname(__FILE__)}/../init"
8
+
9
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
10
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
11
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
12
+
13
+ load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: isbn_validation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Nick Plante
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-10 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.1.2
24
+ version:
25
+ description: isbn_validation adds an isbn validation routine to active record models.
26
+ email: nap@zerosum.org
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ files:
34
+ - MIT-LICENSE
35
+ - Rakefile
36
+ - README
37
+ - lib/isbn_validation.rb
38
+ - test/isbn_validation_test.rb
39
+ - test/models.rb
40
+ - test/schema.rb
41
+ - test/test_helper.rb
42
+ has_rdoc: true
43
+ homepage:
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --line-numbers
49
+ - --inline-source
50
+ - --main
51
+ - README
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.5
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: isbn_validation adds an isbn validation routine to active record models.
73
+ test_files:
74
+ - test/isbn_validation_test.rb