Skip to content

Instantly share code, notes, and snippets.

@datenimperator
Created December 3, 2013 11:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save datenimperator/7767986 to your computer and use it in GitHub Desktop.
Save datenimperator/7767986 to your computer and use it in GitHub Desktop.
An International Securities Identification Number (ISIN) uniquely identifies a security. Its structure is defined in ISO 6166. This Ruby code implements a validity check for a given ISIN string.
class Isin
COUNTRY_CODES = %w{AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM VA HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NL NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF PM VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS SS ES LK SD SR SJ SZ SE CH SY TW TJ TZ TH TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VE VN VG VI WF EH YE ZM ZW}
def initialize(v)
@content = v.upcase
end
def to_s
@content
end
def valid?
return false if @content.blank?
if m = @content.match(/^(\w{2})(\w{9})(\d)$/)
country, identifier, checksum = m.captures
return false unless COUNTRY_CODES.include?(country)
if c = self.class.calculate_checksum(country + identifier)
return true if checksum.to_i == c
end
end
false
end
def self.calculate_checksum(txt)
return nil unless txt.ascii_only?
digits = txt.chars.map do |c|
case c
when 'A'..'Z' then (c.ord - 55).to_s.chars #we're ascii-only, A has code 65
when '0'..'9' then c
end
end.flatten.map(&:to_i)
pos = 1
sum = digits.reverse.map{|a| pos += 1; (a*(2-pos%2)).to_s}.join.chars.map(&:to_i).sum
(10 - (sum%10)) % 10
end
end
require 'spec_helper'
describe Isin do
it "can be instantiated" do
i = Isin.new 'DE000BAY0017'
i.to_s.should == 'DE000BAY0017'
end
context "validity" do
it "validates proper ISIN" do
%w{DE000BAY0017 AU0000XVGZA3 US0378331005 US30231G1022}.each do |isin|
Isin.new(isin).valid?.should be_true
end
end
it "detects invalid formats" do
%w{ZZ1234567890 DE00BAY0017 DE000BAY00178}.each do |isin|
Isin.new(isin).valid?.should be_false
end
end
it "detects invalid checksum" do
Isin.new('DE000BAY0018').valid?.should be_false
Isin.new('DE000BAZ0017').valid?.should be_false
Isin.new('AU0000XVGZA5').valid?.should be_false
end
it "accepts lowercase" do
Isin.new('de000bay0017').valid?.should be_true
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment