diff --git a/README.md b/README.md index 683a277d71..83fbaca022 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ gem 'faker', :git => 'https://github.com/faker-ruby/faker.git', :branch => 'mast - [Faker::Artist](doc/default/artist.md) - [Faker::Avatar](doc/default/avatar.md) - [Faker::Bank](doc/default/bank.md) + - [Faker::Barcode](doc/default/barcode.md) - [Faker::Beer](doc/default/beer.md) - [Faker::Blood](doc/default/blood.md) - [Faker::Boolean](doc/default/boolean.md) diff --git a/doc/default/barcode.md b/doc/default/barcode.md new file mode 100644 index 0000000000..d9ea26ada8 --- /dev/null +++ b/doc/default/barcode.md @@ -0,0 +1,36 @@ +# Faker::Barcode + +Generates EAN, UPC, ISBN, ISMN, ISSN format barcode with check digit attached at last + +```ruby +# EAN barcodes +Faker::Barcode.ean => "85657526" +Faker::Barcode.ean(8) => "30152700" +Faker::Barcode.ean(13) => "2115190480285" + +# EAN barcodes with composite string attached in code +Faker::Barcode.ean_with_composite_symbology => "41007624|JHOC6649" +Faker::Barcode.ean_with_composite_symbology(8) => "38357961|XUYJ3266" +Faker::Barcode.ean_with_composite_symbology(13) => "9530722443911|CKHWQHID" + +# UPC_A barcodes +Faker::Barcode.upc_a => "766807541831" + +# UPC_A barcode with composite symbology attached +Faker::Barcode.upc_a_with_composite_symbology => "790670155765|JOVG6208" + +# UPC_E barcode numbers +Faker::Barcode.upc_e => "03746820" + +# UPC_E barcode with composite symbology attached +Faker::Barcode.upc_e_with_composite_symbology => "05149247|BKZX9722" + +# ISBN barcode numbers +Faker::Barcode.isbn => "9798363807732" + +# ISMN barcode numbers +Faker::Barcode.ismn => "9790527672897" + +# ISSN barcode numbers +Faker::Barcode.issn => "9775541703338" +``` diff --git a/lib/faker/default/barcode.rb b/lib/faker/default/barcode.rb new file mode 100644 index 0000000000..fff3503a4a --- /dev/null +++ b/lib/faker/default/barcode.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true + +module Faker + class Barcode < Base + class << self + ## Returns a EAN 8 or 13 digit format barcode number with check digit + # @returns [String] + # + # @example + # Faker::Barcode.ean => "85657526" + # Faker::Barcode.ean(8) => "30152700" + # Faker::Barcode.ean(13) => "2115190480285" + # + # @faker.version next + def ean(length = 8) + generate_barcode("barcode.ean_#{Integer(length)}") + end + + ## Returns a EAN 8 or 13 digit format barcode number with composite string attached with check digit + # @returns [String] + # + # @example + # Faker::Barcode.ean_with_composite_sumbology => "41007624|JHOC6649" + # Faker::Barcode.ean_with_composite_sumbology(8) => "38357961|XUYJ3266" + # Faker::Barcode.ean_with_composite_sumbology(13) => "9530722443911|CKHWQHID" + # + # @faker.version next + def ean_with_composite_symbology(length = 8) + "#{ean(length)}|#{bothify(parse('barcode.composite_symbol'))}" + end + + ## Returns a UPC_A format barcode number with check digit + # @returns [String] + # + # @example + # Faker::Barcode.upc_a => "766807541831" + # + # @faker.version next + def upc_a + generate_barcode('barcode.upc_a') + end + + ## Returns a UPC_E format barcode number with check digit + # @returns [String] + # + # @example + # Faker::Barcode.upc_e => "03746820" + # + # @faker.version next + def upc_e + generate_barcode('barcode.upc_e') + end + + ## Returns a UPC_A format barcode number with composite string attached with check digit + # @returns [String] + # + # @example + # Faker::Barcode.upc_a_with_composite_symbology => "790670155765|JOVG6208" + # + # @faker.version next + def upc_a_with_composite_symbology + "#{upc_a}|#{bothify(parse('barcode.composite_symbol'))}" + end + + ## Returns a UPC_E format barcode number with composite string attached with check digit + # @returns [String] + # + # @example + # Faker::Barcode.upc_e_with_composite_symbology => "05149247|BKZX9722" + # + # @faker.version next + def upc_e_with_composite_symbology + "#{upc_e}|#{bothify(parse('barcode.composite_symbol'))}" + end + + ## Returns a ISBN format barcode number with check digit + # @returns [String] + # + # @example + # Faker::Barcode.isbn => "9798363807732" + # + # @faker.version next + def isbn + generate_barcode('barcode.isbn') + end + + ## Returns a ISMN format barcode number with check digit + # @returns [String] + # + # @example + # Faker::Barcode.ismn => "9790527672897" + # + # @faker.version next + def ismn + generate_barcode('barcode.ismn') + end + + ## Returns a ISSN format barcode number with check digit + # @returns [String] + # + # @example + # Faker::Barcode.issn => "9775541703338" + # + # @faker.version next + def issn + generate_barcode('barcode.issn') + end + + private + + def generate_barcode(key) + barcode = parse(key) + check_digit = generate_check_digit(*sum_even_odd(barcode)) + "#{barcode}#{check_digit}" + end + + ## Returns the sum of even and odd numbers from value passed + # + # @returns [Array] + # + # @example + # Faker::Barcode.send(:sum_even_odd, 12345) => [9, 5] + # Faker::Barcode.send(:sum_even_odd, 87465) => [17, 13] + # + # @faker.version next + def sum_even_odd(fake_num) + number = fake_num.to_i + sum_even, sum_odd = 0, 0, index = 1 + + while number != 0 + index.even? ? sum_even += number % 10 : sum_odd += number % 10 + + number /= 10 + index += 1 + end + + [sum_odd, sum_even] + end + + ## Generates the check digits from sum passed + # + # @returns [Integer] + # + # @example + # Faker::Barcode.send(:generate_check_digit, 12, 4) => 0 + # Faker::Barcode.send(:generate_check_digit, 23, 5) => 6 + # + # @faker.version next + def generate_check_digit(odd_sum, even_sum) + (10 - (odd_sum * 3 + even_sum) % 10) % 10 + end + end + end +end diff --git a/lib/locales/en/barcode.yml b/lib/locales/en/barcode.yml new file mode 100644 index 0000000000..39d1dde697 --- /dev/null +++ b/lib/locales/en/barcode.yml @@ -0,0 +1,24 @@ +en: + faker: + barcode: + ean_8: '#######' + ean_13: '############' + upc_a: '###########' + upc_e: + - '0######' + - '1######' + composite_symbol: + - '########' + - '????????' + - '####????' + - '????####' + - '##??##??' + - '??##??##' + isbn: + - '978#########' + - '9798########' + - '97910#######' + - '97911#######' + - '97912#######' + ismn: '9790########' + issn: '977#########' diff --git a/test/faker/default/test_barcodes.rb b/test/faker/default/test_barcodes.rb new file mode 100644 index 0000000000..6a58dfb676 --- /dev/null +++ b/test/faker/default/test_barcodes.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require_relative '../../test_helper' + +class TestFakerBarcodes < Test::Unit::TestCase + def setup + @tester = Faker::Barcode + end + + def test_ean + assert @tester.ean.match(/[0-9]{8}/) + assert_equal @tester.ean.length, 8 + + assert @tester.ean(8).match(/[0-9]{8}/) + assert_equal @tester.ean(8).length, 8 + + assert @tester.ean(13).match(/[0-9]{13}/) + assert_equal @tester.ean(13).length, 13 + end + + def test_ean_with_composite_symbology + assert @tester.ean_with_composite_symbology.match(/[0-9]{8}|[A-Za-z0-9]{8}/) + assert_equal @tester.ean_with_composite_symbology.length, 17 + + assert @tester.ean_with_composite_symbology(8).match(/[0-9]{8}|[A-Za-z0-9]{8}/) + assert_equal @tester.ean_with_composite_symbology(8).length, 17 + + assert @tester.ean_with_composite_symbology(13).match(/[0-9]{13}|[A-Za-z0-9]{8}/) + assert_equal @tester.ean_with_composite_symbology(13).length, 22 + end + + def test_upc_a + assert @tester.upc_a.match(/[0-9]{12}/) + assert_equal @tester.upc_a.length, 12 + end + + def test_upc_a_with_composite_symbol + assert @tester.upc_a_with_composite_symbology.match(/[0-9]{12}|[A-Za-z0-9]{8}/) + assert_equal @tester.upc_a_with_composite_symbology.length, 21 + end + + def test_upc_e + assert @tester.upc_e.match(/[0-9]{8}/) + assert_equal @tester.upc_e.length, 8 + end + + def test_upc_e_with_composite_symbol + assert @tester.upc_e_with_composite_symbology.match(/[0-9]{8}|[A-Za-z0-9]{8}/) + assert_equal @tester.upc_e_with_composite_symbology.length, 17 + end + + def test_isbn + assert @tester.isbn.match(/^(978|9798|97910|97911|97912)[0-9]{8,10}/) + assert_equal @tester.isbn.length, 13 + end + + def test_ismn + assert @tester.ismn.match(/9790[0-9]{9}/) + assert_equal @tester.ismn.length, 13 + end + + def test_issn + assert @tester.issn.match(/977[0-9]{10}/) + assert_equal @tester.issn.length, 13 + end + + def test_sum_even_odd + assert_equal @tester.send(:sum_even_odd, 123_456), [12, 9] + assert_equal @tester.send(:sum_even_odd, 857_363), [11, 21] + end + + def test_generate_check_digit + assert_equal @tester.send(:generate_check_digit, 18, 24), 2 + assert_equal @tester.send(:generate_check_digit, 21, 13), 4 + end +end