mrz 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 80f5720b27f8c119f51abaab7b7d9819b8615b6617bc5f3b3a6d3fba5fa9f575
4
+ data.tar.gz: ed30dc33fcd504994da3b68abc6af1defc8307966f777d5dee588d095f1bc64a
5
+ SHA512:
6
+ metadata.gz: 87aa4fb5b716201469e3da15bc13330bddf6c51a8baca6bd7c4ca62d57354c9e4e73b34c9889665d00d5ad5ad3dca29282ad730509b9e0b509c6aeb4c6f83d16
7
+ data.tar.gz: 833d145bf96df764b7ec4eaf8a16bbafe74c25a5b8152b5facd1a1bc1daaf57a38d4a79e83bca97f8a046499d3c5bfa0913f97588d16f441fdb50030e549907d
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.0
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in mrz.gemspec
6
+ gemspec
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mrz (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (10.0.1)
10
+ diff-lcs (1.3)
11
+ rake (10.5.0)
12
+ rspec (3.7.0)
13
+ rspec-core (~> 3.7.0)
14
+ rspec-expectations (~> 3.7.0)
15
+ rspec-mocks (~> 3.7.0)
16
+ rspec-core (3.7.1)
17
+ rspec-support (~> 3.7.0)
18
+ rspec-expectations (3.7.0)
19
+ diff-lcs (>= 1.2.0, < 2.0)
20
+ rspec-support (~> 3.7.0)
21
+ rspec-mocks (3.7.0)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.7.0)
24
+ rspec-support (3.7.1)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ bundler (~> 1.16)
31
+ byebug
32
+ mrz!
33
+ rake (~> 10.0)
34
+ rspec (~> 3.0)
35
+
36
+ BUNDLED WITH
37
+ 1.16.1
data/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2018 Streetspotr GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+
@@ -0,0 +1,60 @@
1
+ # MRZ
2
+
3
+ [![Build Status](https://travis-ci.org/streetspotr/mrz.svg?branch=master)](https://travis-ci.org/streetspotr/mrz)
4
+
5
+ MRZ is a small library which can parse MRZ codes on ID cards and passports. It was inspired by https://github.com/cheminfo-js/mrz.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'mrz'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install mrz
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ id_card = [
27
+ "IDD<<T220001293<<<<<<<<<<<<<<<",
28
+ "6408125<2010315D<<<<<<<<<<<<<4",
29
+ "MUSTERMANN<<ERIKA<PAULA<ANNA<<"
30
+ ]
31
+
32
+ result = MRZ.parse(id_card)
33
+
34
+ result.valid? # => true
35
+ result.birth_date # => Date.new(1964, 8, 12)
36
+ result.birth_date_check_digit # => "5"
37
+ result.composite_check_digit # => "4"
38
+ result.document_code # => "ID"
39
+ result.document_number # => "T22000129"
40
+ result.document_check_digit # => "3"
41
+ result.expiration_date # => Date.new(2020, 10, 15)
42
+ result.expiration_date_check_digit # => "5"
43
+ result.first_name # => "ERIKA PAULA ANNA"
44
+ result.issuing_state # => "D"
45
+ result.last_name # => "MUSTERMANN"
46
+ result.nationality # => "D"
47
+ result.optional1 # => ""
48
+ result.optional2 # => ""
49
+ result.sex # => "nonspecified" (otherwise "M" or "F")
50
+ ```
51
+
52
+ ## Development
53
+
54
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
55
+
56
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
57
+
58
+ ## Contributing
59
+
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/streetspotr/mrz.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mrz"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -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,35 @@
1
+ require "mrz/version"
2
+ require "mrz/invalid_format_error"
3
+ require "mrz/check_digit"
4
+ require "mrz/result"
5
+ require "mrz/base_parser"
6
+ require "mrz/td1_parser"
7
+ require "mrz/td2_parser"
8
+ require "mrz/td3_parser"
9
+
10
+ module MRZ
11
+ def self.parse(mrz_code)
12
+ case determine_type(mrz_code)
13
+ when :td1
14
+ TD1Parser.new(mrz_code).parse
15
+ when :td2
16
+ TD2Parser.new(mrz_code).parse
17
+ when :td3
18
+ TD3Parser.new(mrz_code).parse
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def self.determine_type(code)
25
+ if code.size == 3
26
+ :td1
27
+ elsif code.size == 2 && code.first.size == 36
28
+ :td2
29
+ elsif code.size == 2 && code.first.size == 44
30
+ :td3
31
+ else
32
+ raise MRZ::InvalidFormatError, "invalid or unsupported mrz code given"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ class BaseParser
2
+ SPECIAL_CHAR = "<"
3
+ WHITESPACE = " "
4
+ EMPTY_SPACE = ""
5
+
6
+ protected
7
+
8
+ def special_char_to_empty_space(str)
9
+ str.gsub(SPECIAL_CHAR, EMPTY_SPACE)
10
+ end
11
+
12
+ def special_char_to_white_space(str)
13
+ str.gsub(SPECIAL_CHAR, WHITESPACE)
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module MRZ
2
+ module CheckDigit
3
+ FACTORS = [7, 3, 1]
4
+
5
+ def self.calculate(sequence)
6
+ check_digit = sequence.split("").each_with_index.reduce(0) do |acc,(char, i)|
7
+ asciiCode = char.ord
8
+
9
+ normalized_code =
10
+ case asciiCode
11
+ when proc { |n| n == 60 }
12
+ 0
13
+ when proc { |n| n >= 65 }
14
+ asciiCode - 55
15
+ when proc { |n| n >= 48 }
16
+ asciiCode - 48
17
+ else
18
+ asciiCode
19
+ end
20
+
21
+ acc + normalized_code * FACTORS[i % 3]
22
+ end
23
+
24
+ check_digit % 10
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module MRZ
2
+ class InvalidFormatError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,86 @@
1
+ require "date"
2
+
3
+ module MRZ
4
+ class Result
5
+ attr_reader :birth_date_check_digit, :composite_check_digit,
6
+ :document_code, :document_number, :document_number_check_digit,
7
+ :expiration_date_check_digit, :first_name, :issuing_state,
8
+ :last_name, :nationality, :optional1, :optional2
9
+
10
+ def initialize(opts={})
11
+ @birth_date = opts.fetch(:birth_date)
12
+ @birth_date_check_digit = opts.fetch(:birth_date_check_digit)
13
+ @composite_check_digit = opts.fetch(:composite_check_digit)
14
+ @document_code = opts.fetch(:document_code)
15
+ @document_number = opts.fetch(:document_number)
16
+ @document_number_check_digit = opts.fetch(:document_number_check_digit)
17
+ @expiration_date = opts.fetch(:expiration_date)
18
+ @expiration_date_check_digit = opts.fetch(:expiration_date_check_digit)
19
+ @first_name = opts.fetch(:first_name)
20
+ @issuing_state = opts.fetch(:issuing_state)
21
+ @last_name = opts.fetch(:last_name)
22
+ @nationality = opts.fetch(:nationality)
23
+ @optional1 = opts.fetch(:optional1)
24
+ @optional2 = opts.fetch(:optional2)
25
+ @sex = opts.fetch(:sex)
26
+ @type = opts.fetch(:type)
27
+ end
28
+
29
+ def birth_date
30
+ @_birth_date ||= begin
31
+ year = @birth_date[0..1].to_i
32
+ month = @birth_date[2..3].to_i
33
+ day = @birth_date[4..5].to_i
34
+
35
+ Date.new(add_correct_century(year), month, day)
36
+ end
37
+ end
38
+
39
+ def expiration_date
40
+ @_expiration_date ||= Date.strptime(@expiration_date, "%y%m%d")
41
+ end
42
+
43
+ def sex
44
+ @_sex ||= @sex == "" ? "nonspecified" : @sex
45
+ end
46
+
47
+ def valid?
48
+ @_valid ||= begin
49
+ MRZ::CheckDigit.calculate(@birth_date).to_s == @birth_date_check_digit &&
50
+ MRZ::CheckDigit.calculate(@document_number).to_s == @document_number_check_digit &&
51
+ MRZ::CheckDigit.calculate(@expiration_date).to_s == @expiration_date_check_digit &&
52
+ composite_digit_valid?
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def add_correct_century(year)
59
+ if (Date.today.year - (1900 + year)) >= 100
60
+ 2000 + year
61
+ else
62
+ 1900 + year
63
+ end
64
+ end
65
+
66
+ def composite_digit_valid?
67
+ if @type == :td1
68
+ MRZ::CheckDigit.calculate(
69
+ @document_number + @document_number_check_digit +
70
+ @optional1 + @birth_date + @birth_date_check_digit +
71
+ @expiration_date + @expiration_date_check_digit +
72
+ @optional2
73
+ ).to_s == @composite_check_digit
74
+ elsif [:td2, :td3].include?(@type)
75
+ MRZ::CheckDigit.calculate(
76
+ @document_number + @document_number_check_digit +
77
+ @birth_date + @birth_date_check_digit +
78
+ @expiration_date + @expiration_date_check_digit +
79
+ @optional1 + @optional2
80
+ ).to_s == @composite_check_digit
81
+ else
82
+ raise InvalidFormatError, "Unknown format type"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,55 @@
1
+ module MRZ
2
+ class TD1Parser < BaseParser
3
+ FORMAT_ONE = /\A(.{2})(.{3})(.{9})(\d)(.{15})\z/
4
+ FORMAT_TWO = /\A(\d{6})(\d)(.)(\d{6})(\d)(.{3})(.{11})(\d)\z/
5
+ FORMAT_THREE = /\A([^<]+)<<(.+)\z/
6
+
7
+ def initialize(code_ary)
8
+ @code = code_ary
9
+ @one = code_ary[0]
10
+ @two = code_ary[1]
11
+ @three = code_ary[2]
12
+ end
13
+
14
+ def parse
15
+ if @code.size != 3
16
+ raise MRZ::InvalidFormatError, "td1 requires 3 mrz lines"
17
+ end
18
+
19
+ line_one_matches = FORMAT_ONE.match(@one)
20
+ line_two_matches = FORMAT_TWO.match(@two)
21
+ line_three_matches = FORMAT_THREE.match(@three)
22
+
23
+ if line_one_matches.nil?
24
+ raise MRZ::InvalidFormatError, "td1 first line does not match the required format"
25
+ end
26
+
27
+ if line_two_matches.nil?
28
+ raise MRZ::InvalidFormatError, "td1 second line does not match the required format"
29
+ end
30
+
31
+ if @three.size != 30 || line_three_matches.nil?
32
+ raise MRZ::InvalidFormatError, "td1 third line does not match the required format"
33
+ end
34
+
35
+ MRZ::Result.new(
36
+ birth_date: line_two_matches[1],
37
+ birth_date_check_digit: line_two_matches[2],
38
+ composite_check_digit: line_two_matches[8],
39
+ document_code: special_char_to_empty_space(line_one_matches[1]),
40
+ document_number: special_char_to_empty_space(line_one_matches[3]),
41
+ document_number_check_digit: line_one_matches[4],
42
+ expiration_date: line_two_matches[4],
43
+ expiration_date_check_digit: line_two_matches[5],
44
+ first_name: special_char_to_white_space(line_three_matches[2]).strip,
45
+ issuing_state: special_char_to_empty_space(line_one_matches[2]),
46
+ last_name: line_three_matches[1],
47
+ nationality: special_char_to_empty_space(line_two_matches[6]),
48
+ optional1: special_char_to_empty_space(line_one_matches[5]),
49
+ optional2: special_char_to_empty_space(line_two_matches[7]),
50
+ sex: special_char_to_empty_space(line_two_matches[3]),
51
+ type: :td1,
52
+ )
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,48 @@
1
+ module MRZ
2
+ class TD2Parser < BaseParser
3
+ FORMAT_ONE = /\A(.{2})(.{3})([^<]+)<<(.*)\z/
4
+ FORMAT_TWO = /\A(.{9})(\d)(.{3})(\d{6})(\d)(.)(\d{6})(.)(.{7})(.)\z/
5
+
6
+ def initialize(code_ary)
7
+ @code = code_ary
8
+ @one = code_ary[0]
9
+ @two = code_ary[1]
10
+ end
11
+
12
+ def parse
13
+ if @code.size != 2
14
+ raise MRZ::InvalidFormatError, "td2 requires two mrz lines"
15
+ end
16
+
17
+ line_one_matches = FORMAT_ONE.match(@one)
18
+ line_two_matches = FORMAT_TWO.match(@two)
19
+
20
+ if @one.size != 36 || line_one_matches.nil?
21
+ raise MRZ::InvalidFormatError, "td2 first line does not match the required format"
22
+ end
23
+
24
+ if line_two_matches.nil?
25
+ raise MRZ::InvalidFormatError, "td2 second line does not match the required format"
26
+ end
27
+
28
+ MRZ::Result.new(
29
+ birth_date: line_two_matches[4],
30
+ birth_date_check_digit: line_two_matches[5],
31
+ composite_check_digit: line_two_matches[10],
32
+ document_code: special_char_to_empty_space(line_one_matches[1]),
33
+ document_number: special_char_to_empty_space(line_two_matches[1]),
34
+ document_number_check_digit: line_two_matches[2],
35
+ expiration_date: line_two_matches[7],
36
+ expiration_date_check_digit: line_two_matches[8],
37
+ first_name: special_char_to_white_space(line_one_matches[4]).strip,
38
+ issuing_state: special_char_to_empty_space(line_one_matches[2]),
39
+ last_name: line_one_matches[3],
40
+ nationality: special_char_to_empty_space(line_two_matches[3]),
41
+ optional1: special_char_to_empty_space(line_two_matches[9]),
42
+ optional2: "",
43
+ sex: special_char_to_empty_space(line_two_matches[6]),
44
+ type: :td2,
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,48 @@
1
+ module MRZ
2
+ class TD3Parser < BaseParser
3
+ FORMAT_ONE = /\A(.{2})(.{3})([^<]+)<<(.*)\z/
4
+ FORMAT_TWO = /\A(.{9})(\d)(.{3})(\d{6})(\d)(.)(\d{6})(.)(.{14})(.)(\d)/
5
+
6
+ def initialize(code_ary)
7
+ @code = code_ary
8
+ @one = code_ary[0]
9
+ @two = code_ary[1]
10
+ end
11
+
12
+ def parse
13
+ if @code.size != 2
14
+ raise MRZ::InvalidFormatError, "td3 requires two mrz lines"
15
+ end
16
+
17
+ line_one_matches = FORMAT_ONE.match(@one)
18
+ line_two_matches = FORMAT_TWO.match(@two)
19
+
20
+ if @one.length != 44 || line_one_matches.nil?
21
+ raise MRZ::InvalidFormatError, "td3 line one does not match the required format"
22
+ end
23
+
24
+ if line_two_matches.nil?
25
+ raise MRZ::InvalidFormatError, "td3 line two does not match the required format"
26
+ end
27
+
28
+ MRZ::Result.new(
29
+ birth_date: line_two_matches[4],
30
+ birth_date_check_digit: line_two_matches[5],
31
+ composite_check_digit: line_two_matches[11],
32
+ document_code: special_char_to_empty_space(line_one_matches[1]),
33
+ document_number: special_char_to_empty_space(line_two_matches[1]),
34
+ document_number_check_digit: line_two_matches[2],
35
+ expiration_date: line_two_matches[7],
36
+ expiration_date_check_digit: line_two_matches[8],
37
+ first_name: special_char_to_white_space(line_one_matches[4]).strip,
38
+ issuing_state: special_char_to_empty_space(line_one_matches[2]),
39
+ last_name: line_one_matches[3],
40
+ nationality: special_char_to_empty_space(line_two_matches[3]),
41
+ optional1: special_char_to_empty_space(line_two_matches[9]),
42
+ optional2: special_char_to_empty_space(line_two_matches[10]),
43
+ sex: special_char_to_empty_space(line_two_matches[6]),
44
+ type: :td3,
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module MRZ
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,28 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "mrz/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mrz"
8
+ spec.version = MRZ::VERSION
9
+ spec.authors = ["Streetspotr GmbH"]
10
+ spec.email = ["devs@streetspotr.com"]
11
+
12
+ spec.summary = %q{Small library to read and parse MRZ codes on passports and ID cards}
13
+ spec.description = %q{Small library to read and parse MRZ codes on passports and ID cards}
14
+ spec.homepage = "https://github.com/streetspotr/mrz"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "byebug"
28
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mrz
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Streetspotr GmbH
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-22 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.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Small library to read and parse MRZ codes on passports and ID cards
70
+ email:
71
+ - devs@streetspotr.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - lib/mrz.rb
87
+ - lib/mrz/base_parser.rb
88
+ - lib/mrz/check_digit.rb
89
+ - lib/mrz/invalid_format_error.rb
90
+ - lib/mrz/result.rb
91
+ - lib/mrz/td1_parser.rb
92
+ - lib/mrz/td2_parser.rb
93
+ - lib/mrz/td3_parser.rb
94
+ - lib/mrz/version.rb
95
+ - mrz.gemspec
96
+ homepage: https://github.com/streetspotr/mrz
97
+ licenses: []
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.7.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Small library to read and parse MRZ codes on passports and ID cards
119
+ test_files: []