ffaker 2.23.0 → 2.24.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,12 +5,16 @@ module FFaker
5
5
  extend ModuleUtils
6
6
  extend self
7
7
 
8
+ ROUTING_NUMBER_PREFIXES = [*'00'..'12', *'21'..'32', *'61'..'72', '80'].freeze
9
+
8
10
  def account_number(min_digits: 9, max_digits: 17)
9
11
  FFaker.numerify('#' * rand(min_digits..max_digits))
10
12
  end
11
13
 
12
14
  def routing_number
13
- partial_routing_number = FFaker.numerify('########')
15
+ first_two_digits = fetch_sample(ROUTING_NUMBER_PREFIXES)
16
+
17
+ partial_routing_number = FFaker.numerify("#{first_two_digits}######")
14
18
  ninth_digit = generate_ninth_digit(partial_routing_number)
15
19
 
16
20
  "#{partial_routing_number}#{ninth_digit}"
data/lib/ffaker/guid.rb CHANGED
@@ -5,8 +5,14 @@ module FFaker
5
5
  extend ModuleUtils
6
6
  extend self
7
7
 
8
+ # Because this method uses arbitrary hexadecimal characters it is likely to
9
+ # generate invalid UUIDs--UUIDs must have a version (1-8) at bits 48-51,
10
+ # and bits 64-65 must be 0b10.
11
+ #
12
+ # @deprecated Often generates invalid UUIDs. Use {UUID} instead.
8
13
  def guid
9
- FFaker.hexify('########-####-####-####-############')
14
+ warn '[guid] is deprecated. Use the UUID.uuidv4 method instead.'
15
+ FFaker::UUID.uuidv4.upcase
10
16
  end
11
17
  end
12
18
  end
@@ -90,9 +90,9 @@ module FFaker
90
90
 
91
91
  def name_for_gender(name_type, gender) # :nodoc:
92
92
  raise(ArgumentError, "Gender must be one of: #{GENDERS}") unless GENDERS.include?(gender)
93
- return send("#{gender}_#{name_type}") unless gender == :random
93
+ return send(:"#{gender}_#{name_type}") unless gender == :random
94
94
 
95
- fetch_sample([send("female_#{name_type}"), send("male_#{name_type}")])
95
+ fetch_sample([send(:"female_#{name_type}"), send(:"male_#{name_type}")])
96
96
  end
97
97
  end
98
98
  end
@@ -14,7 +14,7 @@ module FFaker
14
14
 
15
15
  def const_missing(const_name)
16
16
  if const_name.match?(/[a-z]/) # Not a constant, probably a class/module name.
17
- super const_name
17
+ super(const_name)
18
18
  else
19
19
  mod_name = ancestors.first.to_s.split('::').last
20
20
  data_path = "#{FFaker::BASE_LIB_PATH}/ffaker/data/#{underscore(mod_name)}/#{underscore(const_name.to_s)}"
@@ -38,21 +38,12 @@ module FFaker
38
38
 
39
39
  # http://en.wikipedia.org/wiki/Luhn_algorithm
40
40
  def luhn_check(number)
41
- multiplications = []
42
-
43
- number.chars.each_with_index do |digit, i|
44
- multiplications << i.even? ? digit.to_i * 2 : digit.to_i
45
- end
46
-
47
- sum = 0
48
- multiplications.each do |num|
49
- num.to_s.each_byte do |character|
50
- sum += character.chr.to_i
51
- end
52
- end
53
-
54
- control_digit = (sum % 10).zero? ? 0 : (((sum / 10) + 1) * 10) - sum
55
- control_digit.to_s
41
+ sum = number.chars
42
+ .map(&:to_i)
43
+ .reverse
44
+ .each_with_index
45
+ .sum { |digit, index| index.even? ? (2 * digit).digits.sum : digit }
46
+ ((10 - (sum % 10)) % 10).to_s
56
47
  end
57
48
  end
58
49
  end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module FFaker
6
+ # UUIDs are a 128-bit value (16 bytes), often represented as a
7
+ # 32-character hexadecimal string in the format
8
+ # `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`.
9
+ #
10
+ # @note This generates lowercase strings, but UUIDs are case-insensitive.
11
+ #
12
+ # @see https://www.rfc-editor.org/rfc/rfc4122#section-4
13
+ # @see https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/
14
+ module UUID
15
+ extend ModuleUtils
16
+ extend self
17
+
18
+ # > UUID version 4 is meant for generating UUIDs from truly-random or
19
+ # > pseudo-random numbers.
20
+ def uuidv4
21
+ uuid = 0
22
+ # random_a
23
+ # > The first 48 bits of the layout that can be filled with random data
24
+ # > as specified in Section 6.9. Occupies bits 0 through 47 (octets 0-5).
25
+ uuid |= rand((2**48) - 1) << 80
26
+ # ver
27
+ # > The 4 bit version field as defined by Section 4.2, set to 0b0100 (4).
28
+ # > Occupies bits 48 through 51 of octet 6.
29
+ uuid |= 0b0100 << 76
30
+ # random_b
31
+ # > 12 more bits of the layout that can be filled random data as per
32
+ # > Section 6.9. Occupies bits 52 through 63 (octets 6-7).
33
+ uuid |= rand((2**12) - 1) << 64
34
+ # var
35
+ # > The 2 bit variant field as defined by Section 4.1, set to 0b10.
36
+ # > Occupies bits 64 and 65 of octet 8.
37
+ uuid |= 0b10 << 62
38
+ # random_c
39
+ # > The final 62 bits of the layout immediately following the var field
40
+ # > field to be filled with random data as per Section 6.9. Occupies bits
41
+ # > 66 through 127 (octets 8-15).
42
+ uuid |= rand((2**62) - 1)
43
+
44
+ as_string(uuid)
45
+ end
46
+
47
+ # > UUID version 6 is a field-compatible version of UUIDv1 Section 5.1,
48
+ # > reordered for improved DB locality. It is expected that UUIDv6 will
49
+ # > primarily be used in contexts where UUIDv1 is used. Systems that do not
50
+ # > involve legacy UUIDv1 SHOULD use UUIDv7 instead.
51
+ def uuidv6
52
+ timestamp = rand((2**60) - 1)
53
+
54
+ uuid = 0
55
+ # time_high
56
+ # > The most significant 32 bits of the 60 bit starting timestamp.
57
+ # > Occupies bits 0 through 31 (octets 0-3).
58
+ # @note Shifts 28 bits to remove `time_mid` and `time_low`.
59
+ uuid |= (timestamp >> 28) << 96
60
+ # time_mid
61
+ # > The middle 16 bits of the 60 bit starting timestamp. Occupies bits 32
62
+ # > through 47 (octets 4-5).
63
+ # @note Shifts 12 bits to remove `time_low`.
64
+ uuid |= ((timestamp >> 12) & ((2**16) - 1)) << 80
65
+ # ver
66
+ # > The 4 bit version field as defined by Section 4.2, set to 0b0110 (6).
67
+ # > Occupies bits 48 through 51 of octet 6.
68
+ uuid |= 0b0110 << 76
69
+ # time_low
70
+ # > 12 bits that will contain the least significant 12 bits from the 60
71
+ # > bit starting timestamp. Occupies bits 52 through 63 (octets 6-7).
72
+ uuid |= (timestamp & ((2**12) - 1)) << 64
73
+ # var
74
+ # > The 2 bit variant field as defined by Section 4.1, set to 0b10.
75
+ # > Occupies bits 64 and 65 of octet 8.
76
+ uuid |= 0b10 << 62
77
+ # clk_seq
78
+ # > The 14 bits containing the clock sequence. Occupies bits 66 through
79
+ # > 79 (octets 8-9).
80
+ #
81
+ # (earlier in the document)
82
+ # > The clock sequence and node bits SHOULD be reset to a pseudo-random
83
+ # > value for each new UUIDv6 generated; however, implementations MAY
84
+ # > choose to retain the old clock sequence and MAC address behavior from
85
+ # > Section 5.1.
86
+ uuid |= rand((2**14) - 1) << 48
87
+ # node
88
+ # > 48 bit spatially unique identifier. Occupies bits 80 through 127
89
+ # > (octets 10-15).
90
+ uuid |= rand((2**48) - 1)
91
+
92
+ as_string(uuid)
93
+ end
94
+
95
+ # > UUID version 7 features a time-ordered value field derived from the
96
+ # > widely implemented and well known Unix Epoch timestamp source, the
97
+ # > number of milliseconds since midnight 1 Jan 1970 UTC, leap seconds
98
+ # > excluded. UUIDv7 generally has improved entropy characteristics over
99
+ # > UUIDv1 Section 5.1 or UUIDv6 Section 5.6.
100
+ def uuidv7
101
+ timestamp = rand((2**48) - 1)
102
+
103
+ uuid = 0
104
+ # unix_ts_ms
105
+ # > 48 bit big-endian unsigned number of Unix epoch timestamp in
106
+ # > milliseconds as per Section 6.1. Occupies bits 0 through 47 (octets
107
+ # > 0-5).
108
+ uuid |= timestamp << 80
109
+ # ver
110
+ # > The 4 bit version field as defined by Section 4.2, set to 0b0111 (7).
111
+ # > Occupies bits 48 through 51 of octet 6.
112
+ uuid |= 0b0111 << 76
113
+ # rand_a
114
+ # > 12 bits pseudo-random data to provide uniqueness as per Section 6.9
115
+ # > and/or optional constructs to guarantee additional monotonicity as
116
+ # > per Section 6.2. Occupies bits 52 through 63 (octets 6-7).
117
+ uuid |= rand((2**12) - 1) << 64
118
+ # var
119
+ # > The 2 bit variant field as defined by Section 4.1, set to 0b10.
120
+ # > Occupies bits 64 and 65 of octet 8.
121
+ uuid |= 0b10 << 62
122
+ # rand_b
123
+ # > The final 62 bits of pseudo-random data to provide uniqueness as per
124
+ # > Section 6.9 and/or an optional counter to guarantee additional
125
+ # > monotonicity as per Section 6.2. Occupies bits 66 through 127 (octets
126
+ # > 8-15).
127
+ uuid |= rand((2**62) - 1)
128
+
129
+ as_string(uuid)
130
+ end
131
+
132
+ # > UUID version 8 provides an RFC-compatible format for experimental or
133
+ # > vendor-specific use cases. The only requirement is that the variant and
134
+ # > version bits MUST be set as defined in Section 4.1 and Section 4.2.
135
+ # > UUIDv8's uniqueness will be implementation-specific and MUST NOT be
136
+ # > assumed.
137
+ # >
138
+ # > [...] To be clear: UUIDv8 is not a replacement for UUIDv4 Section 5.4
139
+ # > where all 122 extra bits are filled with random data.
140
+ def uuidv8
141
+ uuid = 0
142
+ # custom_a
143
+ # > The first 48 bits of the layout that can be filled as an
144
+ # > implementation sees fit. Occupies bits 0 through 47 (octets 0-5).
145
+ uuid |= rand((2**48) - 1) << 80
146
+ # ver
147
+ # > The 4 bit version field as defined by Section 4.2, set to 0b1000 (8).
148
+ # > Occupies bits 48 through 51 of octet 6.
149
+ uuid |= 0b1000 << 76
150
+ # custom_b
151
+ # > 12 more bits of the layout that can be filled as an implementation
152
+ # > sees fit. Occupies bits 52 through 63 (octets 6-7).
153
+ uuid |= rand((2**12) - 1) << 64
154
+ # var
155
+ # > The 2 bit variant field as defined by Section 4.1, set to 0b10.
156
+ # > Occupies bits 64 and 65 of octet 8.
157
+ uuid |= 0b10 << 62
158
+ # custom_c
159
+ # > The final 62 bits of the layout immediately following the var field
160
+ # > to be filled as an implementation sees fit. Occupies bits 66 through
161
+ # > 127 (octets 8-15).
162
+ uuid |= rand((2**62) - 1)
163
+
164
+ as_string(uuid)
165
+ end
166
+
167
+ private
168
+
169
+ def as_string(uuid)
170
+ uuid.to_s(16)
171
+ .rjust(32, '0')
172
+ .gsub(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '\1-\2-\3-\4-\5')
173
+ end
174
+ end
175
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FFaker
4
- VERSION = '2.23.0'
4
+ VERSION = '2.24.0'
5
5
  end
data/lib/ffaker.rb CHANGED
@@ -76,6 +76,7 @@ module FFaker
76
76
  'ua' => 'UA',
77
77
  'uk' => 'UK',
78
78
  'us' => 'US',
79
+ 'uuid' => 'UUID',
79
80
  'vn' => 'VN'
80
81
  }
81
82
 
data/test/helper.rb CHANGED
@@ -35,7 +35,7 @@ module DeterministicHelper
35
35
  end
36
36
  operator_name += '_or_equal_to' if operator[1] == '='
37
37
 
38
- define_method "assert_#{operator_name}" do |got, expected|
38
+ define_method :"assert_#{operator_name}" do |got, expected|
39
39
  assert(
40
40
  got.public_send(operator, expected),
41
41
  "Expected #{operator} \"#{expected}\", but got #{got}"
@@ -56,8 +56,8 @@ module DeterministicHelper
56
56
  end
57
57
 
58
58
  %w[less_than_or_equal_to between].each do |method_name|
59
- define_method "assert_random_#{method_name}" do |*args, &block|
60
- assert_random(block) { send "assert_#{method_name}", block.call, *args }
59
+ define_method :"assert_random_#{method_name}" do |*args, &block|
60
+ assert_random(block) { send :"assert_#{method_name}", block.call, *args }
61
61
  end
62
62
  end
63
63
 
@@ -76,7 +76,7 @@ module DeterministicHelper
76
76
  # }
77
77
  def assert_methods_are_deterministic(klass, *methods)
78
78
  Array(methods).each do |meth|
79
- define_method "test_#{meth}_is_deterministic" do
79
+ define_method :"test_#{meth}_is_deterministic" do
80
80
  assert_deterministic(message: "Results from `#{klass}.#{meth}` are not repeatable") do
81
81
  klass.send(meth)
82
82
  end
data/test/test_bank_us.rb CHANGED
@@ -24,6 +24,8 @@ class TestBankUS < Test::Unit::TestCase
24
24
  routing_number = @tester.routing_number
25
25
  assert_match(/\A\d{9}\z/, routing_number)
26
26
 
27
+ assert_true(@tester::ROUTING_NUMBER_PREFIXES.include?(routing_number[0..1]))
28
+
27
29
  checksum = (
28
30
  (7 * (routing_number[0].to_i + routing_number[3].to_i + routing_number[6].to_i)) +
29
31
  (3 * (routing_number[1].to_i + routing_number[4].to_i + routing_number[7].to_i)) +
data/test/test_guid.rb CHANGED
@@ -8,7 +8,7 @@ class TestGuid < Test::Unit::TestCase
8
8
  assert_methods_are_deterministic(FFaker::Guid, :guid)
9
9
 
10
10
  def test_guid
11
- assert_match(/[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}/,
11
+ assert_match(/\A[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\z/,
12
12
  FFaker::Guid.guid)
13
13
  end
14
14
  end
@@ -44,4 +44,13 @@ class TestModuleUtils < Test::Unit::TestCase
44
44
  FFaker::UniqueUtils.clear
45
45
  generator.unique.test
46
46
  end
47
+
48
+ def test_luhn_check
49
+ obj = Object.new
50
+ obj.extend FFaker::ModuleUtils
51
+ assert obj.luhn_check('97248708') == '6'
52
+ assert obj.luhn_check('1789372997') == '4'
53
+ assert obj.luhn_check('8899982700037') == '1'
54
+ assert obj.luhn_check('1234567820001') == '0'
55
+ end
47
56
  end
data/test/test_uuid.rb ADDED
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class TestUUID < Test::Unit::TestCase
6
+ include DeterministicHelper
7
+
8
+ assert_methods_are_deterministic(
9
+ FFaker::UUID,
10
+ :uuidv4, :uuidv6, :uuidv7, :uuidv8
11
+ )
12
+
13
+ def setup
14
+ @tester = FFaker::UUID
15
+ end
16
+
17
+ # @see https://stackoverflow.com/a/38191104
18
+ def test_uuidv4
19
+ raw_uuid = @tester.uuidv4
20
+ assert_format(raw_uuid)
21
+
22
+ uuid = uuid_to_integer(raw_uuid)
23
+ assert_version(uuid, 0b0100)
24
+ assert_variant(uuid, 0b10)
25
+ end
26
+
27
+ def test_uuidv6
28
+ raw_uuid = @tester.uuidv6
29
+ assert_format(raw_uuid)
30
+
31
+ uuid = uuid_to_integer(raw_uuid)
32
+ assert_version(uuid, 0b0110)
33
+ assert_variant(uuid, 0b10)
34
+ end
35
+
36
+ def test_uuidv7
37
+ raw_uuid = @tester.uuidv7
38
+ assert_format(raw_uuid)
39
+
40
+ uuid = uuid_to_integer(raw_uuid)
41
+ assert_version(uuid, 0b0111)
42
+ assert_variant(uuid, 0b10)
43
+ end
44
+
45
+ def test_uuidv8
46
+ raw_uuid = @tester.uuidv8
47
+ assert_format(raw_uuid)
48
+
49
+ uuid = uuid_to_integer(raw_uuid)
50
+ assert_version(uuid, 0b1000)
51
+ assert_variant(uuid, 0b10)
52
+ end
53
+
54
+ private
55
+
56
+ # Matches structure of all UUID versions.
57
+ def assert_format(uuid)
58
+ assert_match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/,
59
+ uuid)
60
+ end
61
+
62
+ def assert_version(uuid, version)
63
+ assert_equal(version, (uuid >> 76) & 0b1111)
64
+ end
65
+
66
+ def assert_variant(uuid, variant)
67
+ assert_equal(variant, (uuid >> 62) & 0b11)
68
+ end
69
+
70
+ def uuid_to_integer(uuid)
71
+ uuid.delete('-').to_i(16)
72
+ end
73
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.23.0
4
+ version: 2.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/ffaker/ffaker/graphs/contributors
8
8
  - Emmanuel Oga
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-09-19 00:00:00.000000000 Z
12
+ date: 2025-02-02 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Ffaker generates dummy data.
15
15
  email: EmmanuelOga@gmail.com
@@ -587,6 +587,7 @@ files:
587
587
  - lib/ffaker/utils/module_utils.rb
588
588
  - lib/ffaker/utils/random_utils.rb
589
589
  - lib/ffaker/utils/unique_utils.rb
590
+ - lib/ffaker/uuid.rb
590
591
  - lib/ffaker/vehicle.rb
591
592
  - lib/ffaker/venue.rb
592
593
  - lib/ffaker/version.rb
@@ -788,6 +789,7 @@ files:
788
789
  - test/test_units.rb
789
790
  - test/test_units_english.rb
790
791
  - test/test_units_metric.rb
792
+ - test/test_uuid.rb
791
793
  - test/test_vehicle.rb
792
794
  - test/test_venue.rb
793
795
  - test/test_youtube.rb
@@ -798,7 +800,7 @@ metadata:
798
800
  changelog_uri: https://github.com/ffaker/ffaker/blob/main/Changelog.md
799
801
  documentation_uri: https://github.com/ffaker/ffaker/blob/main/REFERENCE.md
800
802
  rubygems_mfa_required: 'true'
801
- post_install_message:
803
+ post_install_message:
802
804
  rdoc_options:
803
805
  - "--charset=UTF-8"
804
806
  require_paths:
@@ -814,8 +816,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
814
816
  - !ruby/object:Gem::Version
815
817
  version: '0'
816
818
  requirements: []
817
- rubygems_version: 3.4.10
818
- signing_key:
819
+ rubygems_version: 3.4.19
820
+ signing_key:
819
821
  specification_version: 4
820
822
  summary: Ffaker generates dummy data.
821
823
  test_files: []