sec_id 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0f9406f82fc8d468dff0ada3da32d7c9a3cf69d3f18e57eee32c146bf4d7057e
4
+ data.tar.gz: 8b85da6d43ebd5c46daff708c0070693e16dd8f66e11a0682e4c54c0d46aeead
5
+ SHA512:
6
+ metadata.gz: 867400988954ad03423b476920077c8d498ed2744cb1b863c4ab2959478609b6ce3cd8b424f4189d5d6220a9794fb3df9e3abe3c2b948273c41754e34a69f9de
7
+ data.tar.gz: 0a357e424416fc0969a25fc492c05215a54dd5c8518978fb55830dbac47e656fa5b50e482e34e09b7d0cb21057bf906dda963350a826e934f77e107a727d28ca
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,24 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.3
6
+ DisplayCopNames: true
7
+ DisplayStyleGuide: true
8
+ ExtraDetails: true
9
+
10
+ Metrics/LineLength:
11
+ Max: 120
12
+
13
+ Style/Documentation:
14
+ Enabled: false
15
+
16
+ Metrics/BlockLength:
17
+ Exclude:
18
+ - 'spec/**/*'
19
+
20
+ RSpec/MultipleExpectations:
21
+ Max: 5
22
+
23
+ RSpec/ExampleLength:
24
+ Max: 10
data/.travis.yml ADDED
@@ -0,0 +1,35 @@
1
+ ---
2
+ sudo: false
3
+ cache: bundler
4
+ language: ruby
5
+
6
+ env:
7
+ global:
8
+ - CC_TEST_REPORTER_ID=9995f7b2aa6866b0427aef31d946ff1feded8f6e109eaf6ccb58e91c73d0bfeb
9
+
10
+ rvm:
11
+ - 2.3
12
+ - 2.4
13
+ - 2.5
14
+ - 2.6
15
+ - ruby-head
16
+
17
+ matrix:
18
+ allow_failures:
19
+ - rvm: ruby-head
20
+ fast_finish: true
21
+
22
+ before_script:
23
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
24
+ - chmod +x ./cc-test-reporter
25
+ - ./cc-test-reporter before-build
26
+
27
+ script:
28
+ - bundle exec rake
29
+
30
+ after_script:
31
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
32
+
33
+ notifications:
34
+ recipients: leonid@svyatov.ru
35
+ on_failure: change
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in sec_id.gemspec
8
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Leonid Svyatov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # SecId
2
+ [![Gem Version](https://badge.fury.io/rb/sec_id.svg)](https://badge.fury.io/rb/sec_id)
3
+ [![Build Status](https://travis-ci.org/svyatov/sec_id.svg?branch=master)](https://travis-ci.org/svyatov/sec_id)
4
+
5
+ Validate security identification numbers with ease!
6
+
7
+ Check-digit calculation is also available.
8
+
9
+ Currently supported standards:
10
+ [ISIN](https://en.wikipedia.org/wiki/International_Securities_Identification_Number)
11
+
12
+ WIP: [CUSIP](https://en.wikipedia.org/wiki/CUSIP),
13
+ [SEDOL](https://en.wikipedia.org/wiki/SEDOL),
14
+ [IBAN](https://en.wikipedia.org/wiki/International_Bank_Account_Number).
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'sec_id', '~> 1.0'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install sec_id
31
+
32
+ ## Usage
33
+
34
+ ### Base API
35
+
36
+ Base API has 4 main methods which can be used both on class level and on instance level:
37
+
38
+ * `valid?` - never raises any errors, always returns `true` or `false`,
39
+ numbers without the check-digit will return `false`
40
+
41
+ ```ruby
42
+ # class level
43
+ SecId::ISIN.valid?('US5949181045') # => true
44
+ SecId::ISIN.valid?('US594918104') # => false
45
+
46
+ # instance level
47
+ isin = SecId::ISIN.new('US5949181045')
48
+ isin.valid? # => true
49
+ ```
50
+
51
+ * `valid_format?` - never raises any errors, always returns `true` or `false`,
52
+ numbers without the check-digit but in valid format will return `true`
53
+
54
+ ```ruby
55
+ # class level
56
+ SecId::ISIN.valid_format?('US5949181045') # => true
57
+ SecId::ISIN.valid_format?('US594918104') # => true
58
+
59
+ # instance level
60
+ isin = SecId::ISIN.new('US594918104')
61
+ isin.valid_format? # => true
62
+ ```
63
+
64
+ * `restore!` - restores check-digit and returns the full number,
65
+ raises an error if number's format is invalid and thus check-digit is impossible to calculate
66
+
67
+ ```ruby
68
+ # class level
69
+ SecId::ISIN.restore!('US594918104') # => 'US5949181045'
70
+
71
+ # instance level
72
+ isin = SecId::ISIN.new('US5949181045')
73
+ isin.restore! # => 'US5949181045'
74
+ ```
75
+
76
+ * `check_digit` and `calculate_check_digit` - these are the same,
77
+ but the former is used at class level for bravity,
78
+ and the latter is used at instance level for clarity;
79
+ it calculates and returns the check-digit if the number is valid
80
+ and raises an error otherwise.
81
+
82
+ ```ruby
83
+ # class level
84
+ SecId::ISIN.check_digit('US594918104') # => 5
85
+
86
+ # instance level
87
+ isin = SecId::ISIN.new('US594918104')
88
+ isin.calculate_check_digit # => 5
89
+ isin.check_digit # => nil
90
+ ```
91
+
92
+ :exclamation: Please note that `isin.check_digit` returns `nil` because `#check_digit`
93
+ at instance level represents original check-digit of the number passed to `new`,
94
+ which in this example is missing and thus it's `nil`.
95
+
96
+ ### SecId::ISIN full example
97
+
98
+ ```ruby
99
+ # class level
100
+ SecId::ISIN.valid?('US5949181045') # => true
101
+ SecId::ISIN.valid_format?('US594918104') # => true
102
+ SecId::ISIN.restore!('US594918104') # => 'US5949181045'
103
+ SecId::ISIN.check_digit('US594918104') # => 5
104
+
105
+ # instance level
106
+ isin = SecId::ISIN.new('US5949181045')
107
+ isin.isin # => 'US5949181045'
108
+ isin.country_code # => 'US'
109
+ isin.nsin # => '594918104'
110
+ isin.check_digit # => 5
111
+ isin.valid? # => true
112
+ isin.valid_format? # => true
113
+ isin.restore! # => 'US5949181045'
114
+ isin.calculate_check_digit # => 5
115
+ ```
116
+
117
+ ## Development
118
+
119
+ After checking out the repo, run `bin/setup` to install dependencies.
120
+ Then, run `rake spec` to run the tests. You can also run `bin/console`
121
+ for an interactive prompt that will allow you to experiment.
122
+
123
+ To install this gem onto your local machine, run `bundle exec rake install`.
124
+
125
+ ## Contributing
126
+
127
+ Bug reports and pull requests are welcome on
128
+ GitHub at https://github.com/svyatov/sec_id.
129
+
130
+ ## License
131
+
132
+ The gem is available as open source under the terms of
133
+ the [MIT License](LICENSE.txt).
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ RuboCop::RakeTask.new do |task|
10
+ task.requires << 'rubocop-rspec'
11
+ end
12
+
13
+ task default: %i[rubocop spec]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'sec_id'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SecId
4
+ class Base
5
+ LETTERS = Set.new('A'..'Z').freeze
6
+
7
+ attr_reader :identifier, :check_digit
8
+
9
+ def self.valid?(id)
10
+ new(id).valid?
11
+ end
12
+
13
+ def self.valid_format?(id)
14
+ new(id).valid_format?
15
+ end
16
+
17
+ def self.restore!(id_without_check_digit)
18
+ new(id_without_check_digit).restore!
19
+ end
20
+
21
+ def self.check_digit(id)
22
+ new(id).calculate_check_digit
23
+ end
24
+
25
+ def initialize(_sec_id_number)
26
+ raise NotImplementedError
27
+ end
28
+
29
+ def valid?
30
+ raise NotImplementedError
31
+ end
32
+
33
+ def valid_format?
34
+ raise NotImplementedError
35
+ end
36
+
37
+ def restore!
38
+ raise NotImplementedError
39
+ end
40
+
41
+ def calculate_check_digit
42
+ raise NotImplementedError
43
+ end
44
+
45
+ def to_s
46
+ "#{identifier}#{check_digit}"
47
+ end
48
+ alias to_str to_s
49
+
50
+ private
51
+
52
+ def digitized_identifier
53
+ @digitized_identifier ||= identifier.each_char.flat_map { |char| char_to_digits char }
54
+ end
55
+
56
+ def char_to_digits(char)
57
+ return char.to_i unless LETTERS.include? char
58
+
59
+ number = char.to_i(36)
60
+ [number / 10, number % 10]
61
+ end
62
+
63
+ def mod_10(sum)
64
+ (10 - (sum % 10)) % 10
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SecId
4
+ # https://en.wikipedia.org/wiki/International_Securities_Identification_Number
5
+ class ISIN < Base
6
+ ID_REGEX = /\A
7
+ (?<identifier>
8
+ (?<country_code>[A-Z]{2})
9
+ (?<nsin>[A-Z0-9]{9}))
10
+ (?<check_digit>\d)?
11
+ \z/x.freeze
12
+
13
+ attr_reader :isin, :country_code, :nsin
14
+
15
+ def initialize(isin)
16
+ @isin = isin.to_s.strip.upcase
17
+ isin_parts = @isin.match(ID_REGEX) || {}
18
+
19
+ @identifier = isin_parts[:identifier]
20
+ @country_code = isin_parts[:country_code]
21
+ @nsin = isin_parts[:nsin]
22
+ @check_digit = isin_parts[:check_digit].to_i if isin_parts[:check_digit]
23
+ end
24
+
25
+ def valid?
26
+ return false unless valid_format?
27
+
28
+ check_digit == calculate_check_digit
29
+ end
30
+
31
+ def valid_format?
32
+ identifier ? true : false
33
+ end
34
+
35
+ def restore!
36
+ @check_digit = calculate_check_digit
37
+ @isin = to_s
38
+ end
39
+
40
+ def calculate_check_digit
41
+ raise InvalidFormatError, "ISIN '#{isin}' is invalid and check-digit cannot be calculated!" unless valid_format?
42
+
43
+ mod_10 luhn_sum
44
+ end
45
+
46
+ private
47
+
48
+ # https://en.wikipedia.org/wiki/Luhn_algorithm
49
+ def luhn_sum
50
+ sum = 0
51
+
52
+ digitized_identifier.reverse.each_slice(2) do |even, odd|
53
+ double_even = (even || 0) * 2
54
+ double_even -= 9 if double_even > 9
55
+ sum += double_even + (odd || 0)
56
+ end
57
+
58
+ sum
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SecId
4
+ VERSION = '1.0.0'
5
+ end
data/lib/sec_id.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'sec_id/version'
5
+ require 'sec_id/base'
6
+ require 'sec_id/isin'
7
+
8
+ module SecId
9
+ Error = Class.new(StandardError)
10
+ InvalidFormatError = Class.new(Error)
11
+ end
data/sec_id.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'sec_id/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'sec_id'
9
+ spec.version = SecId::VERSION
10
+ spec.authors = ['Leonid Svyatov']
11
+ spec.email = ['leonid@svyatov.ru']
12
+
13
+ spec.summary = 'Validate security identification numbers with ease!'
14
+ spec.description = %(#{spec.summary} Currently supported standards: ISIN, CUSIP, SEDOL, IBAN.)
15
+ spec.homepage = 'https://github.com/svyatov/sec_id'
16
+ spec.license = 'MIT'
17
+
18
+ spec.required_ruby_version = '>= 2.3.0'
19
+
20
+ spec.require_paths = ['lib']
21
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
22
+ f.match(%r{^(test|spec|features)/})
23
+ end
24
+
25
+ spec.add_development_dependency 'bundler', '>= 1.16'
26
+ spec.add_development_dependency 'rake', '>= 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.8'
28
+ spec.add_development_dependency 'rubocop', '~> 0.63.1'
29
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.32'
30
+ spec.add_development_dependency 'simplecov', '~> 0.16.1'
31
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sec_id
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Leonid Svyatov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.63.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.63.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.32'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.32'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.16.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.16.1
97
+ description: 'Validate security identification numbers with ease! Currently supported
98
+ standards: ISIN, CUSIP, SEDOL, IBAN.'
99
+ email:
100
+ - leonid@svyatov.ru
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".rubocop.yml"
108
+ - ".travis.yml"
109
+ - Gemfile
110
+ - LICENSE.txt
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - lib/sec_id.rb
116
+ - lib/sec_id/base.rb
117
+ - lib/sec_id/isin.rb
118
+ - lib/sec_id/version.rb
119
+ - sec_id.gemspec
120
+ homepage: https://github.com/svyatov/sec_id
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 2.3.0
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.0.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Validate security identification numbers with ease!
143
+ test_files: []