A => CHANGELOG +11 -0
@@ 1,11 @@
+0.2 (8th March 2008)
+--------------------
+
+ * Update to remove require_gem.
+ * Changed format of CHANGELOG.
+ * First public release.
+
+0.1 (30th June 2007)
+--------------------
+
+ * Initial version.<
\ No newline at end of file
A => README +28 -0
@@ 1,28 @@
+ValidatesAsIsbn
+===============
+
+This Ruby on Rails plugin implements an ActiveRecord validation helper
+called validates_as_isbn. The helper validates that the string provided
+is a valid ISBN. It works on both the original 10-character ISBN, or
+the newer 13-character version.
+
+Installation
+------------
+
+ruby script/plugin install http://svn.deeden.co.uk/validates_as_isbn
+
+Full documentation on script/plugin can be obtained by invoking the plugin
+script with no arguments:
+
+ruby script/plugin
+
+You may need to restart your webserver in order to load the plugin files.
+
+Usage
+-----
+
+In your model file do something like:
+
+class MyClass < ActiveRecord::Base
+ validates_as_isbn :isbn
+end<
\ No newline at end of file
A => Rakefile +22 -0
@@ 1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the validates_as_isbn plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the validates_as_isbn plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'ValidatesAsIsbn'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
A => data/invalid.txt +23 -0
@@ 1,23 @@
+0300088745
+352805747
+3932588745
+3827317184
+3898641148
+393258853X
+3446215910
+3333336363
+3446194345
+3446216347
+34462
+344621
+3446216
+00071039
+000710559
+0007111291
+0007612630
+0020199853
+0020209855
+0020345546
+0020389657
+abcdefghij
+xxxxxxxxxx<
\ No newline at end of file
A => data/valid_isbn_10.txt +997 -0
@@ 1,997 @@
+0000000000
+0000000027
+0000000035
+0000000043
+0000000051
+000000006X
+0000000078
+0000000086
+0000000094
+0000000132
+0000000329
+0100000010
+0101021429
+0101049927
+0101339224
+010138890X
+0101390408
+0101453426
+0101474105
+0101644922
+0102645981
+0103000003
+0200000004
+0200000039
+0200000063
+0200000071
+0200000616
+020000106X
+0200001310
+0200001337
+0200001515
+0200714252
+0200714848
+0300000014
+0300000022
+0300000049
+0300000138
+0300000170
+0300000197
+0300000316
+0300000375
+0300000383
+0300000391
+030010006X
+0400377012
+0400649861
+0401101746
+0401254968
+0401819337
+0402122119
+0402123115
+040212491X
+0402140184
+0402141210
+0403001293
+050001034X
+0500010587
+0500010625
+0500010633
+0500010676
+0500010684
+0500010862
+0500010870
+0500010919
+0500010951
+0500011648
+0600000079
+0600000370
+0600000427
+0600000532
+0600000761
+060000077X
+0600000788
+0600000796
+0600000834
+0600000893
+0600000915
+0700001530
+0700001557
+0700001859
+070000193X
+0700012915
+0700113622
+0700222413
+0700222634
+0700222898
+0700222901
+0700223096
+0800000080
+0800100891
+0800100964
+0800101529
+080010255X
+0800103106
+0800103688
+0800106105
+0800106903
+0800109872
+0800141687
+0900000015
+0900000066
+0900000139
+090000021X
+0900000457
+0900000821
+0900000848
+0900000902
+0900001224
+0900001283
+0900009020
+1000001563
+1001000145
+1011561239
+1015010830
+1029289506
+1030722382
+1050550277
+106277101X
+1064602061
+111100000X
+1111028001
+1111046204
+1111050988
+1111096112
+1111099553
+1111261350
+1111411727
+1111549745
+1111734186
+1112330089
+1210354489
+1224565304
+1225019710
+1225703603
+1231018992
+1245002341
+1298611067
+1299004768
+1299231845
+129926218X
+1308005830
+1314567845
+1326584944
+1334132658
+1338668072
+1340021021
+1345020147
+1345022816
+1345023413
+1375430939
+139915110X
+1400000289
+1400000300
+1400000327
+1400000696
+1400000785
+1400000823
+1400000831
+1400000904
+1400000912
+1400001188
+140000229X
+150001060X
+1500506575
+1503524450
+1505838738
+1506007724
+1518789552
+1520003307
+1538101173
+1550010506
+1550010689
+1550010921
+1600010415
+1600010423
+160001044X
+1600010458
+1600010474
+1600019927
+1600021131
+1600050042
+1600060226
+1600060250
+1600090079
+1700000829
+1701130092
+171450042X
+1718108001
+1718112440
+1723158518
+1739425057
+1740092384
+1740092643
+1740092686
+1740092805
+1800788312
+1805210076
+1805290223
+1807281965
+1816043710
+1830280058
+1840000031
+184000004X
+1840000279
+1840000414
+1840000627
+1900007029
+1900007223
+1900027011
+1900029030
+1900032082
+1900032104
+1900032147
+1900032155
+1900032368
+1900032856
+190012100X
+2000021891
+2000021905
+2000021913
+2000022669
+200002422X
+2000025196
+2000026877
+2008052060
+2010003454
+2010005392
+2010021398
+2100000918
+210000302X
+2100012851
+2100014315
+2100016520
+2100016814
+2100017276
+2100020277
+2100026003
+2100026259
+2100049682
+2200012861
+2200013728
+2200014155
+2200014317
+2200016026
+2200016522
+2200016794
+2200017049
+2200019343
+2200019890
+220021622X
+2300131196
+2310011452
+2350040178
+2350050009
+2350120163
+2350120635
+2350121054
+2350180050
+2350210197
+2350781291
+235078133X
+2402559721
+2441659790
+2493435117
+2495000258
+2495000266
+2495005209
+2495010725
+249501075X
+2495010954
+2501000307
+2501000560
+2501000595
+2501001311
+2501001516
+2501002059
+2501002644
+2501002822
+250100342X
+2501005473
+2501006488
+2600001832
+2600002057
+2600005145
+2600006893
+2600007520
+2600009221
+2600010998
+2601002654
+260103131X
+2603007246
+2603010859
+2700001117
+2700001974
+2700002369
+2700002733
+2700003160
+2700010566
+2700011015
+2700011058
+2700011422
+270001197X
+2700019121
+2800100060
+2800100087
+2800100095
+2800100133
+2800100141
+280010015X
+2800100168
+2800100176
+2800100184
+2800100249
+2800100362
+2900130808
+2900200067
+2900269016
+2900269075
+290029715X
+2900297192
+2900297214
+2900319331
+2900339049
+2901076343
+2901422330
+3000004270
+3000005447
+3000005765
+300001375X
+3000024492
+3000024816
+3000026231
+3000026304
+3000058338
+3000060073
+3000087079
+3100001362
+3100002377
+3100003373
+3100004205
+3100005139
+3100006208
+3100011066
+310001524X
+3100015401
+3100044134
+3100108310
+3200002867
+3200003898
+3200006021
+3201000426
+3201009385
+3201009512
+3201010774
+3201010960
+3201015393
+3203750139
+320375875X
+3303152438
+3305000740
+3305001216
+3305002557
+3309001695
+3310001954
+3310002349
+3310002942
+331000306X
+3310003221
+3310007103
+3401002031
+3401002112
+3401002236
+3401002325
+340100252X
+3401002597
+3401002600
+3401002619
+3401011944
+3401012428
+3401012703
+3500245404
+3501001002
+3501003099
+3501004001
+3501011288
+3501011547
+3501012055
+3501013736
+3501013973
+3501014260
+350101452X
+3600301004
+3600301063
+3601004836
+3602145549
+360214691X
+3607000018
+3608206000
+3608206205
+3608860037
+3608896201
+3608911332
+3700102569
+370010331X
+3700103417
+3700103743
+3700104642
+3700107854
+3700119976
+3700121210
+3700122241
+3700126735
+3700129238
+3800012103
+3800014327
+3800014904
+3800015501
+3800016036
+3800016125
+3800016362
+3800016559
+3800020238
+3800020440
+380002053X
+3900036349
+3900051127
+390010042X
+3900134014
+3900134251
+3900134286
+3900134340
+3900134448
+3900134472
+3900134715
+3900252173
+4000002538
+4000013815
+4000020153
+4000029010
+4000033344
+4000041576
+4000072749
+4000224417
+400023403X
+4000801112
+4001110121
+4101001014
+4101001022
+4101001235
+4101001340
+4101001359
+4101001413
+4101001421
+410100143X
+4101005036
+4101005087
+4101010048
+4245008350
+4250085104
+4250270157
+4250980138
+4253010695
+4253059759
+4253071112
+4253071163
+4253071171
+425307118X
+4253071236
+4306043479
+4306043886
+4306044211
+4306044297
+430604436X
+4306044734
+4306050173
+4306051625
+4306093778
+4309015050
+4309408362
+4400002780
+4400013006
+4400107825
+4400481212
+440086250X
+4401013468
+4401015584
+4401611527
+4401618009
+4402052491
+4403500293
+4501321601
+4501540109
+4502335215
+450369992X
+4517234150
+4524211756
+4524214232
+4527002074
+4529027813
+4529032108
+4529039927
+4620305774
+4620792330
+4621038656
+4621039733
+4621045199
+4621052055
+4621074687
+4622039702
+4635062171
+463506302X
+4636174828
+472746621X
+4750311235
+4750316202
+4750319600
+4750587028
+4753413071
+4756102107
+4756118089
+4756132243
+4756702716
+4756704034
+4803020000
+4803404089
+4804033173
+4804611061
+4804611347
+4804612262
+4804750215
+4805301066
+480530152X
+4805303174
+4805303948
+4900090891
+4900105295
+4900211230
+4900211508
+4900211516
+4900211524
+4900211532
+4900422029
+4900480053
+490050212X
+4900737097
+5010004488
+5010004550
+5010004984
+5010005131
+501001114X
+5010011557
+5010019752
+5010019833
+5010029529
+5010032996
+5010042665
+5100000317
+510360745X
+5103683954
+5105453956
+5110014000
+5120001378
+5120004725
+5130218841
+5150002623
+5170044399
+5170045972
+5200000181
+5200000386
+5200000467
+5200000483
+520000067X
+5200001420
+5200002044
+5200002249
+5200003318
+5200003512
+5200007135
+5300001333
+5300005568
+5300005851
+5300013587
+5300016276
+5300020494
+5300022209
+530101224X
+5303000702
+5306002900
+5352000125
+5410001591
+5415004637
+5415004734
+541500677X
+5415012990
+5415014268
+5415014306
+5415014322
+5415014543
+5415015795
+5420015439
+5504400651
+5504401267
+5504401313
+550440178X
+5504402964
+5511003115
+5511006610
+5530835112
+5550007738
+5550031906
+5550033089
+5605000039
+5610004276
+5615008490
+5628020583
+5640014105
+5648007388
+5670705157
+5670705661
+5691003054
+5699005862
+569902784X
+5700000059
+5700001292
+5700001314
+5700002078
+5700002825
+570000299X
+5702702840
+5702704916
+5702709497
+5704209173
+5710756121
+580150169X
+5801571183
+5802600209
+5804400878
+5804600605
+5806700534
+5812201137
+5815300012
+5815900400
+5815900591
+5815900966
+5900033422
+590003612X
+5900118053
+5900134016
+5900161064
+5900310019
+5900370127
+5900939235
+5900959201
+5901229010
+5901250028
+6000006756
+6000020724
+6000020740
+6000058152
+6000067291
+6000091133
+6000109199
+6000111177
+6000120915
+6000137338
+600014329X
+6101644340
+6105372906
+610621350X
+6125010392
+6125030474
+6125038831
+6161834669
+6300157563
+6300174921
+6300181286
+6300181367
+6300182320
+630018403X
+6300185095
+6300214052
+6300214699
+6300215814
+6300217388
+6441660040
+6451152749
+6694701292
+6706705535
+6710000990
+6712040418
+6712118972
+671221078X
+6714003501
+6714003994
+6714005997
+6714006993
+6718204439
+6841256840
+684130750X
+6848010863
+6848181838
+7010003718
+7010085722
+7018980917
+7018981069
+7018981514
+702001271X
+7020012876
+7020025943
+7020031331
+7020043275
+7020044360
+7100000335
+7100000432
+7100000440
+7100000904
+7100000939
+7100000947
+7100003113
+7100007038
+710001056X
+7100026016
+7101012191
+7200002194
+7200010308
+7200015830
+7200032271
+7200046566
+7204009932
+7205048907
+7207034393
+7213007599
+721400528X
+7215964965
+7300066763
+7300066909
+7301002351
+7301015054
+7301018940
+7301026188
+7301027737
+7301028156
+7301035195
+730202832X
+7356150042
+7410959444
+7418310013
+7472016772
+7500101430
+7500101449
+7500101473
+7500101481
+7500105568
+7500302312
+7500404204
+7500407726
+750061070X
+7500612575
+7501555087
+7629437404
+7632401466
+7671336459
+7673263262
+7673499967
+7674356663
+7770020557
+777710473X
+7777777238
+7777777289
+7778006995
+7780038181
+7800029921
+7800030180
+7800050076
+7800050807
+7800050963
+7800051102
+7800051145
+7800051188
+780005134X
+7800053229
+7800055574
+7900363416
+7900730001
+790128000X
+7901280077
+7910904444
+8000000830
+8000002817
+800000450X
+8000005875
+8000006413
+8000007584
+8000008742
+8000014106
+8004191649
+8004239978
+8020004181
+8101867163
+8109005640
+8109010725
+8110724779
+8114675357
+8120202538
+8120300114
+8120301722
+812030585X
+8120306686
+8120310071
+8200013146
+8200013677
+8200013871
+8200014924
+8200016420
+8200017273
+8200019608
+8200028585
+8200029182
+8200032159
+824211272X
+8300006575
+8300008659
+8300022627
+8301001623
+8301032391
+8301037326
+8301057750
+830109530X
+8301110694
+8301114878
+8301135042
+840001801X
+8400036387
+8400051505
+8400056906
+8400058704
+8400065638
+8400071212
+8400076591
+8400078683
+8401012090
+8401012449
+8500000686
+8500000708
+8500001240
+8500001267
+8500001712
+850000178X
+8500001844
+8500001895
+8500003901
+8500006889
+8500007923
+8601011349
+8601012086
+8601015115
+8601016413
+8603001308
+8603003602
+8603990360
+8603990581
+8607003097
+8607013564
+861115584X
+8700000612
+8700001945
+8700002216
+8700007129
+8700014044
+8700019127
+8700029270
+8700032913
+8700042358
+8700146021
+8800454771
+8800811418
+8800852637
+8800852750
+8800853579
+8800860613
+8800861024
+8801020422
+880102729X
+8802050775
+8804083956
+8900005456
+8900049011
+8900070134
+8900820745
+890105180X
+8901056372
+8901057069
+8901732173
+8908167358
+8930081150
+8931003897
+9000001420
+9000009189
+9000013968
+9000014336
+9000019451
+9000020867
+900002210X
+9000026083
+9000031745
+9001093922
+9001121004
+9100100196
+9100100315
+9100100390
+9100100447
+9100100471
+9100100528
+9100100692
+9100100773
+9100100919
+9100101044
+910114605X
+9200115969
+9200129382
+9200943055
+9210001346
+9210020251
+9210120507
+9210120604
+9211002990
+9211007933
+9211008638
+922101598X
+9309192380
+9310100648
+9312073516
+9316881404
+9329700292
+9343200129
+934641684X
+9350515067
+9394583815
+9408180003
+941895429X
+9423340180
+9488144076
+9500080176
+9500120275
+9500170000
+9500201259
+9500258994
+9500262967
+9500263432
+9500263661
+950026370X
+9500274493
+9500285118
+9600105480
+9600300577
+9600310599
+9600329915
+9600339058
+9600400423
+9600400512
+9600404801
+960040481X
+9600404836
+9600404844
+9700300331
+9700302555
+9700313662
+970040174X
+9700500969
+9700502023
+9700502384
+9700502740
+9700503046
+9700503577
+9700513378
+9800100814
+9800101063
+9800101799
+9800103708
+980010397X
+9800105891
+9800110852
+9800737170
+9802040126
+9802081515
+9802222267
+9900003292
+9900052110
+9900730879
+9900730925
+9900733207
+990073369X
+9901000033
+9901981476
+9907659754
+9914537308
+9949101131
A => data/valid_isbn_13.txt +27 -0
@@ 1,27 @@
+9780571232796
+9781845293079
+9780451460899
+9780370329215
+9780553384079
+9780007219155
+9780575079144
+9780575079120
+9780434014088
+9780739439708
+9780575079410
+9780007148929
+9780007232178
+9781594146015
+9780575077836
+9780007252237
+9780571236596
+9780375838583
+9780958685696
+9780575076952
+9781741146585
+9781741146608
+9781741146592
+9781741140811
+9780330422451
+9781862916326
+9780979534904<
\ No newline at end of file
A => init.rb +1 -0
@@ 1,1 @@
+require 'validates_as_isbn'<
\ No newline at end of file
A => lib/validates_as_isbn.rb +53 -0
@@ 1,53 @@
+module ISBN
+ class Validations
+ def self.clean(isbn)
+ isbn.upcase.gsub(/[^0-9X]/, '')
+ end
+
+ def self.looks_valid?(isbn)
+ return /^(?:\d{9}[0-9X]|97[89]\d{10})$/.match(isbn)
+ end
+
+ def self.is_valid?(isbn)
+ isbn = clean(isbn)
+ return false unless looks_valid?(isbn)
+
+ bits = isbn.split(//)
+ sum = 0
+ if isbn.length == 10
+ 10.downto(2) do |pos|
+ sum += pos * bits.shift.to_i
+ end
+ checksum = bits[0] == 'X' ? 10 : bits[0].to_i
+ return ((sum + checksum) % 11) == 0
+ else
+ 0.step(10, 2) do |pos|
+ sum += bits[pos].to_i
+ end
+ 1.step(11, 2) do |pos|
+ sum += bits[pos].to_i * 3
+ end
+ return ((sum + bits[12].to_i) % 10) == 0
+ end
+ end
+ end
+end
+
+module ActiveRecord
+ module Validations
+ module ClassMethods
+ def validates_as_isbn(*attr_names)
+ configuration = {
+ :message => 'is not a valid ISBN'
+ }
+ configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
+
+ validates_each(attr_names, configuration) do |record, attr_name, value|
+ unless ISBN::Validations.is_valid?(value)
+ record.errors.add(attr_name, configuration[:message])
+ end
+ end
+ end
+ end
+ end
+end<
\ No newline at end of file
A => test/validates_as_isbn_test.rb +59 -0
@@ 1,59 @@
+require 'test/unit'
+
+begin
+ require File.dirname(__FILE__) + '/../../../../config/boot'
+ require 'active_record'
+ require 'validates_as_isbn'
+rescue LoadError
+ require 'rubygems'
+ gem 'activerecord'
+ require 'active_record'
+ require File.dirname(__FILE__) + '/../lib/validates_as_isbn'
+end
+
+class TestRecord < ActiveRecord::Base
+ def self.columns; []; end
+ attr_accessor :isbn
+ validates_as_isbn :isbn
+end
+
+class ValidatesAsIsbnTest < Test::Unit::TestCase
+ # Check that valid 10-digit isbns are validated as such.
+ def test_should_validate_10_digit_isbn
+ isbns = IO.readlines(File.dirname(__FILE__) + '/../data/valid_isbn_10.txt')
+
+ isbns.each do |isbn|
+ isbn.chomp!
+ assert TestRecord.new(:isbn => isbn).valid?, "#{isbn} should be valid."
+ assert TestRecord.new(:isbn => isbn.downcase).valid?, "#{isbn.downcase} should be valid."
+ assert TestRecord.new(:isbn => isbn.gsub('[^0-9X]', '')).valid?, "#{isbn.gsub('[^0-9X]', '')} should be valid."
+ assert TestRecord.new(:isbn => isbn.downcase.gsub('[^0-9X]', '')).valid?, "#{isbn.downcase.gsub('[^0-9X]', '')} should be valid."
+ end
+ end
+
+ # Check that valid 13-digit isbns are validated as such.
+ def test_should_validate_13_digit_isbn
+ isbns = IO.readlines(File.dirname(__FILE__) + '/../data/valid_isbn_13.txt')
+
+ isbns.each do |isbn|
+ isbn.chomp!
+ assert TestRecord.new(:isbn => isbn).valid?, "#{isbn} should be valid."
+ assert TestRecord.new(:isbn => isbn.downcase).valid?, "#{isbn.downcase} should be valid."
+ assert TestRecord.new(:isbn => isbn.gsub('[^0-9X]', '')).valid?, "#{isbn.gsub('[^0-9X]', '')} should be valid."
+ assert TestRecord.new(:isbn => isbn.downcase.gsub('[^0-9X]', '')).valid?, "#{isbn.downcase.gsub('[^0-9X]', '')} should be valid."
+ end
+ end
+
+ # Check that invalid isbns are validated as such.
+ def test_should_not_validate
+ isbns = IO.readlines(File.dirname(__FILE__) + '/../data/invalid.txt')
+
+ isbns.each do |isbn|
+ isbn.chomp!
+ assert !TestRecord.new(:isbn => isbn).valid?, "#{isbn} should be invalid."
+ assert !TestRecord.new(:isbn => isbn.downcase).valid?, "#{isbn.downcase} should not be invalid."
+ assert !TestRecord.new(:isbn => isbn.gsub('[^0-9X]', '')).valid?, "#{isbn.gsub('[^0-9X]', '')} should be invalid."
+ assert !TestRecord.new(:isbn => isbn.downcase.gsub('[^0-9X]', '')).valid?, "#{isbn.downcase.gsub('[^0-9X]', '')} should be invalid."
+ end
+ end
+end