Skip to content

Commit 72122bf

Browse files
committed
Merge branch 'ISBN'
2 parents b3820da + 9770acf commit 72122bf

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

data/isbn.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package data
2+
3+
// Prefixes for ISBN standards
4+
const (
5+
ISBN13Prefix = "978"
6+
ISBN10Prefix = "979"
7+
)
8+
9+
// ISBNRule defines a registrant rule range and its length
10+
type ISBNRule struct {
11+
Min string
12+
Max string
13+
Length int
14+
}
15+
16+
// ISBNRules maps prefix -> registration group -> registrant rules
17+
var ISBNRules = map[string]map[string][]ISBNRule{
18+
ISBN13Prefix: {
19+
"0": {
20+
{Min: "0000000", Max: "1999999", Length: 2},
21+
{Min: "2000000", Max: "2279999", Length: 3},
22+
{Min: "2280000", Max: "2289999", Length: 4},
23+
{Min: "2290000", Max: "6479999", Length: 3},
24+
{Min: "6480000", Max: "6489999", Length: 7},
25+
{Min: "6490000", Max: "6999999", Length: 3},
26+
{Min: "7000000", Max: "8499999", Length: 4},
27+
{Min: "8500000", Max: "8999999", Length: 5},
28+
{Min: "9000000", Max: "9499999", Length: 6},
29+
{Min: "9500000", Max: "9999999", Length: 7},
30+
},
31+
"1": {
32+
{Min: "0000000", Max: "0999999", Length: 2},
33+
{Min: "1000000", Max: "3999999", Length: 3},
34+
{Min: "4000000", Max: "5499999", Length: 4},
35+
{Min: "5500000", Max: "7319999", Length: 5},
36+
{Min: "7320000", Max: "7399999", Length: 7},
37+
{Min: "7400000", Max: "8697999", Length: 5},
38+
{Min: "8698000", Max: "9729999", Length: 6},
39+
{Min: "9730000", Max: "9877999", Length: 4},
40+
{Min: "9878000", Max: "9989999", Length: 6},
41+
{Min: "9990000", Max: "9999999", Length: 7},
42+
},
43+
},
44+
ISBN10Prefix: {
45+
"8": {
46+
{Min: "0000000", Max: "1999999", Length: 2},
47+
{Min: "2000000", Max: "2279999", Length: 3},
48+
{Min: "2280000", Max: "2289999", Length: 4},
49+
{Min: "2290000", Max: "6479999", Length: 3},
50+
{Min: "6480000", Max: "6489999", Length: 7},
51+
{Min: "6490000", Max: "6999999", Length: 3},
52+
{Min: "7000000", Max: "8499999", Length: 4},
53+
{Min: "8500000", Max: "8999999", Length: 5},
54+
{Min: "9000000", Max: "9499999", Length: 6},
55+
{Min: "9500000", Max: "9999999", Length: 7},
56+
},
57+
},
58+
}

product.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package gofakeit
22

33
import (
44
"fmt"
5+
"strconv"
56
"strings"
7+
8+
"github.com/brianvoe/gofakeit/v7/data"
69
)
710

811
type ProductInfo struct {
@@ -233,6 +236,87 @@ func productSuffix(f *Faker) string {
233236
return getRandValue(f, []string{"product", "suffix"})
234237
}
235238

239+
// ProductISBN13 will generate a random ISBN-13 string for the product
240+
func ProductISBN(opts *ISBNOptions) string { return productISBN(GlobalFaker, opts) }
241+
242+
// ProductISBN13 will generate a random ISBN-13 string for the product
243+
func (f *Faker) ProductISBN(opts *ISBNOptions) string { return productISBN(f, opts) }
244+
245+
type ISBNOptions struct {
246+
Version string // "10" or "13"
247+
Separator string // e.g. "-", "" (default: "-")
248+
}
249+
250+
func productISBN(f *Faker, opts *ISBNOptions) string {
251+
if opts == nil {
252+
opts = &ISBNOptions{Version: "13", Separator: "-"}
253+
}
254+
255+
sep := opts.Separator
256+
if sep == "" {
257+
sep = "-"
258+
}
259+
260+
// string of n random digits
261+
randomDigits := func(f *Faker, n int) string {
262+
digits := make([]byte, n)
263+
for i := 0; i < n; i++ {
264+
digits[i] = byte('0' + number(f, 0, 9))
265+
}
266+
return string(digits)
267+
}
268+
269+
switch opts.Version {
270+
case "10":
271+
// ISBN-10 format: group(1)-registrant(4)-publication(3)-check(1)
272+
group := randomDigits(f, 1)
273+
registrant := randomDigits(f, 4)
274+
publication := randomDigits(f, 3)
275+
base := group + registrant + publication
276+
277+
// checksum
278+
sum := 0
279+
for i, c := range base {
280+
digit := int(c - '0')
281+
sum += digit * (10 - i)
282+
}
283+
remainder := (11 - (sum % 11)) % 11
284+
check := "X"
285+
if remainder < 10 {
286+
check = strconv.Itoa(remainder)
287+
}
288+
289+
return strings.Join([]string{group, registrant, publication, check}, sep)
290+
291+
case "13":
292+
// ISBN-13 format: prefix(3)-group(1)-registrant(4)-publication(4)-check(1)
293+
prefix := data.ISBN13Prefix
294+
group := randomDigits(f, 1)
295+
registrant := randomDigits(f, 4)
296+
publication := randomDigits(f, 4)
297+
base := prefix + group + registrant + publication
298+
299+
// checksum
300+
sum := 0
301+
for i, c := range base {
302+
digit := int(c - '0')
303+
if i%2 == 0 {
304+
sum += digit
305+
} else {
306+
sum += digit * 3
307+
}
308+
}
309+
remainder := (10 - (sum % 10)) % 10
310+
check := strconv.Itoa(remainder)
311+
312+
return strings.Join([]string{prefix, group, registrant, publication, check}, sep)
313+
314+
default:
315+
// fallback to ISBN-13 if invalid version provided
316+
return productISBN(f, &ISBNOptions{Version: "13", Separator: sep})
317+
}
318+
}
319+
236320
func addProductLookup() {
237321
AddFuncLookup("product", Info{
238322
Display: "Product",
@@ -387,4 +471,15 @@ func addProductLookup() {
387471
return productSuffix(f), nil
388472
},
389473
})
474+
475+
AddFuncLookup("productisbn", Info{
476+
Display: "Product ISBN",
477+
Category: "product",
478+
Description: "ISBN-10 or ISBN-13 identifier for books",
479+
Example: "978-1-4028-9462-6",
480+
Output: "string",
481+
Generate: func(f *Faker, m *MapParams, info *Info) (any, error) {
482+
return productISBN(f, nil), nil
483+
},
484+
})
390485
}

product_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,37 @@ func BenchmarkProductSuffix(b *testing.B) {
362362
ProductSuffix()
363363
}
364364
}
365+
366+
func ExampleProductISBN() {
367+
Seed(11)
368+
fmt.Println(ProductISBN(&ISBNOptions{Version: "13", Separator: "-"}))
369+
370+
// Output: 978-8-8125-2759-5
371+
}
372+
373+
func ExampleFaker_ProductISBN() {
374+
f := New(11)
375+
fmt.Println(f.ProductISBN(&ISBNOptions{Version: "13", Separator: "-"}))
376+
377+
// Output: 978-8-8125-2759-5
378+
}
379+
380+
func BenchmarkProductISBN(b *testing.B) {
381+
for i := 0; i < b.N; i++ {
382+
ProductISBN(&ISBNOptions{Version: "13", Separator: "-"})
383+
}
384+
}
385+
386+
func ExampleProductISBN_isbn10() {
387+
Seed(11)
388+
fmt.Println(ProductISBN(&ISBNOptions{Version: "10", Separator: "-"}))
389+
390+
// Output: 8-8125-275-7
391+
}
392+
393+
func ExampleFaker_ProductISBN_isbn10() {
394+
f := New(11)
395+
fmt.Println(f.ProductISBN(&ISBNOptions{Version: "10", Separator: "-"}))
396+
397+
// Output: 8-8125-275-7
398+
}

0 commit comments

Comments
 (0)