Class: Tina4::FakeData

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/seeder.rb

Overview

Zero-dependency fake data generator with deterministic seeding. Uses Ruby’s built-in Random for reproducible data generation.

Examples:

fake = Tina4::FakeData.new(seed: 42)
fake.name        # => "Sarah Johnson"
fake.email       # => "sarah.johnson123@example.com"
fake.integer(1, 100)

Constant Summary collapse

FIRST_NAMES =
%w[
  James Mary Robert Patricia John Jennifer Michael Linda David Elizabeth
  William Barbara Richard Susan Joseph Jessica Thomas Sarah Charles Karen
  Christopher Lisa Daniel Nancy Matthew Betty Anthony Margaret Mark Sandra
  Donald Ashley Steven Dorothy Paul Kimberly Andrew Emily Joshua Donna
  Kenneth Michelle Kevin Carol Brian Amanda George Melissa Timothy Deborah
  Ronald Stephanie Edward Rebecca Jason Sharon Jeffrey Laura Ryan Cynthia
  Jacob Kathleen Gary Amy Nicholas Angela Eric Shirley Jonathan Anna
  Stephen Brenda Larry Pamela Justin Emma Scott Nicole Brandon Helen
  Benjamin Samantha Samuel Katherine Raymond Christine Gregory Debra
  Frank Rachel Alexander Carolyn Patrick Janet Jack Catherine Andre Aisha
  Wei Yuki Carlos Fatima Raj Priya Mohammed Sophia Liam Olivia Noah Ava
  Ethan Mia Lucas Isabella Mason Charlotte Logan Amelia Aiden Harper
].freeze
LAST_NAMES =
%w[
  Smith Johnson Williams Brown Jones Garcia Miller Davis Rodriguez Martinez
  Hernandez Lopez Gonzalez Wilson Anderson Thomas Taylor Moore Jackson Martin
  Lee Perez Thompson White Harris Sanchez Clark Ramirez Lewis Robinson Walker
  Young Allen King Wright Scott Torres Nguyen Hill Flores Green Adams Nelson
  Baker Hall Rivera Campbell Mitchell Carter Roberts Gomez Phillips Evans
  Turner Diaz Parker Cruz Edwards Collins Reyes Stewart Morris Morales
  Murphy Cook Rogers Gutierrez Ortiz Morgan Cooper Peterson Bailey Reed
  Kelly Howard Ramos Kim Cox Ward Richardson Watson Brooks Chavez Wood
  James Bennett Gray Mendoza Ruiz Hughes Price Alvarez Castillo Sanders
  Patel Müller Nakamura Singh Chen Silva Ali Okafor
].freeze
WORDS =
%w[
  the be to of and a in that have it for not on with he as you do at
  this but his by from they we say her she or an will my one all would
  there their what so up out if about who get which go me when make can
  like time no just him know take people into year your good some could
  them see other than then now look only come its over think also back
  after use two how our work first well way even new want because any
  these give day most us great small large every found still between name
  should home big end along each much both help line turn move thing right
  same old better point long real system data report order product service
  customer account payment record total status market world company project
  team value process business group result information development management
  quality performance technology support research design program network
].freeze
CITIES =
[
  "New York", "London", "Tokyo", "Paris", "Berlin", "Sydney", "Toronto",
  "Mumbai", "São Paulo", "Cairo", "Lagos", "Dubai", "Singapore",
  "Hong Kong", "Seoul", "Mexico City", "Bangkok", "Istanbul", "Moscow",
  "Rome", "Barcelona", "Amsterdam", "Nairobi", "Cape Town", "Johannesburg",
  "Buenos Aires", "Lima", "Santiago", "Jakarta", "Manila", "Kuala Lumpur",
  "Auckland", "Vancouver", "Chicago", "San Francisco", "Los Angeles",
  "Miami", "Boston", "Seattle", "Denver"
].freeze
COUNTRIES =
[
  "United States", "United Kingdom", "Canada", "Australia", "Germany",
  "France", "Japan", "Brazil", "India", "South Africa", "Nigeria",
  "Egypt", "Kenya", "Mexico", "Argentina", "Chile", "Colombia", "Spain",
  "Italy", "Netherlands", "Sweden", "Norway", "Denmark", "Finland",
  "Switzerland", "Belgium", "Austria", "New Zealand", "Singapore",
  "South Korea", "Thailand", "Indonesia", "Philippines", "Vietnam",
  "Malaysia", "United Arab Emirates", "Saudi Arabia", "Turkey", "Poland"
].freeze
DOMAINS =
%w[
  example.com test.org sample.net demo.io mail.com
  inbox.org webmail.net company.com corp.io biz.net
].freeze
STREETS =
%w[Main Oak Pine Maple Cedar Elm Park Lake Hill River Church Market King Queen High].freeze
STREET_TYPES =
%w[Street Avenue Road Drive Lane Boulevard Way Place].freeze
COMPANY_WORDS =
%w[Tech Global Apex Nova Core Prime Next Blue Bright Smart Swift Peak Fusion Pulse Vertex].freeze
COMPANY_SUFFIXES =
%w[Inc Corp Ltd LLC Group Solutions Systems Labs].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(seed: nil) ⇒ FakeData

Returns a new instance of FakeData.



89
90
91
# File 'lib/tina4/seeder.rb', line 89

def initialize(seed: nil)
  @rng = seed ? Random.new(seed) : Random.new
end

Class Method Details

.seed(seed) ⇒ Object

Static factory — create a seeded FakeData instance.

fake = FakeData.seed(42)
fake.name  # deterministic


96
97
98
# File 'lib/tina4/seeder.rb', line 96

def self.seed(seed)
  new(seed: seed)
end

Instance Method Details

#addressObject



209
210
211
# File 'lib/tina4/seeder.rb', line 209

def address
  "#{@rng.rand(1..9999)} #{STREETS[@rng.rand(STREETS.length)]} #{STREET_TYPES[@rng.rand(STREET_TYPES.length)]}"
end

#blob(size: 64) ⇒ Object



184
185
186
# File 'lib/tina4/seeder.rb', line 184

def blob(size: 64)
  SecureRandom.random_bytes(size)
end

#booleanObject



165
166
167
# File 'lib/tina4/seeder.rb', line 165

def boolean
  @rng.rand(2)
end

#choice(items) ⇒ Object



197
198
199
# File 'lib/tina4/seeder.rb', line 197

def choice(items)
  items[@rng.rand(items.length)]
end

#cityObject



201
202
203
# File 'lib/tina4/seeder.rb', line 201

def city
  CITIES[@rng.rand(CITIES.length)]
end

#color_hexObject



224
225
226
# File 'lib/tina4/seeder.rb', line 224

def color_hex
  "#%06x" % @rng.rand(0..0xFFFFFF)
end

#companyObject



217
218
219
220
221
222
# File 'lib/tina4/seeder.rb', line 217

def company
  w1 = COMPANY_WORDS[@rng.rand(COMPANY_WORDS.length)]
  w2 = COMPANY_WORDS[@rng.rand(COMPANY_WORDS.length)]
  suffix = COMPANY_SUFFIXES[@rng.rand(COMPANY_SUFFIXES.length)]
  "#{w1}#{w2} #{suffix}"
end

#countryObject



205
206
207
# File 'lib/tina4/seeder.rb', line 205

def country
  COUNTRIES[@rng.rand(COUNTRIES.length)]
end

#date(start_year: 2020, end_year: 2026) ⇒ Object



176
177
178
# File 'lib/tina4/seeder.rb', line 176

def date(start_year: 2020, end_year: 2026)
  datetime(start_year: start_year, end_year: end_year).strftime("%Y-%m-%d")
end

#datetime(start_year: 2020, end_year: 2026) ⇒ Object



169
170
171
172
173
174
# File 'lib/tina4/seeder.rb', line 169

def datetime(start_year: 2020, end_year: 2026)
  start_time = Time.new(start_year, 1, 1)
  end_time = Time.new(end_year, 12, 31, 23, 59, 59)
  delta = (end_time - start_time).to_i
  Time.at(start_time.to_i + @rng.rand(0..delta))
end

#email(from_name: nil) ⇒ Object



112
113
114
115
116
117
118
119
120
# File 'lib/tina4/seeder.rb', line 112

def email(from_name: nil)
  if from_name
    local = from_name.downcase.split.join(".")
  else
    local = "#{first_name.downcase}.#{last_name.downcase}"
  end
  local += @rng.rand(1..999).to_s
  "#{local}@#{DOMAINS[@rng.rand(DOMAINS.length)]}"
end

#first_nameObject



100
101
102
# File 'lib/tina4/seeder.rb', line 100

def first_name
  FIRST_NAMES[@rng.rand(FIRST_NAMES.length)]
end

#for_field(field_def, column_name = nil) ⇒ Object

Generate appropriate data based on field definition and column name.



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/tina4/seeder.rb', line 239

def for_field(field_def, column_name = nil)
  col = (column_name || "").to_s.downcase
  type = field_def[:type]

  # Skip auto-increment primary keys
  return nil if field_def[:primary_key] && field_def[:auto_increment]

  case type
  when :integer
    return integer(min: 18, max: 85) if col.include?("age")
    return integer(min: 1950, max: 2026) if col.include?("year")
    return integer(min: 1, max: 100) if col =~ /quantity|qty|count/
    return boolean if col =~ /active|enabled|visible|^is_/
    return integer(min: 1, max: 10) if col =~ /rating|score/
    integer(min: 1, max: 10_000)

  when :float, :decimal
    decimals = field_def[:scale] || 2
    return numeric(min: 0.01, max: 9999.99, decimals: decimals) if col =~ /price|cost|amount|total|fee/
    return numeric(min: 0.0, max: 100.0, decimals: decimals) if col =~ /rate|percent|ratio/
    return numeric(min: -90.0, max: 90.0, decimals: 6) if col.include?("lat")
    return numeric(min: -180.0, max: 180.0, decimals: 6) if col =~ /lon|lng/
    numeric(min: 0.0, max: 10_000.0, decimals: decimals)

  when :date
    date

  when :datetime, :timestamp
    timestamp

  when :boolean
    boolean

  when :blob
    blob

  when :json
    json_data

  when :string, :text
    max_len = field_def[:length] || 255
    val = generate_string_for(col, max_len)
    val.length > max_len ? val[0...max_len] : val

  else
    word
  end
end

#integer(min: 0, max: 10_000) ⇒ Object



156
157
158
# File 'lib/tina4/seeder.rb', line 156

def integer(min: 0, max: 10_000)
  @rng.rand(min..max)
end

#json_data(keys: nil) ⇒ Object



188
189
190
191
192
193
194
195
# File 'lib/tina4/seeder.rb', line 188

def json_data(keys: nil)
  if keys
    keys.each_with_object({}) { |k, h| h[k] = word }
  else
    n = @rng.rand(2..5)
    n.times.each_with_object({}) { |_, h| h[word] = word }
  end
end

#last_nameObject



104
105
106
# File 'lib/tina4/seeder.rb', line 104

def last_name
  LAST_NAMES[@rng.rand(LAST_NAMES.length)]
end

#nameObject



108
109
110
# File 'lib/tina4/seeder.rb', line 108

def name
  "#{first_name} #{last_name}"
end

#numeric(min: 0.0, max: 1000.0, decimals: 2) ⇒ Object



160
161
162
163
# File 'lib/tina4/seeder.rb', line 160

def numeric(min: 0.0, max: 1000.0, decimals: 2)
  val = min + @rng.rand * (max - min)
  val.round(decimals)
end

#paragraph(sentences: 3) ⇒ Object



135
136
137
# File 'lib/tina4/seeder.rb', line 135

def paragraph(sentences: 3)
  Array.new(sentences) { sentence(words: @rng.rand(5..12)) }.join(" ")
end

#password(length: 16) ⇒ Object



233
234
235
236
# File 'lib/tina4/seeder.rb', line 233

def password(length: 16)
  chars = [*"a".."z", *"A".."Z", *"0".."9"]
  Array.new(length) { chars[@rng.rand(chars.length)] }.join
end

#phoneObject



122
123
124
125
126
127
# File 'lib/tina4/seeder.rb', line 122

def phone
  area = @rng.rand(200..999)
  mid = @rng.rand(100..999)
  tail = @rng.rand(1000..9999)
  "+1 (#{area}) #{mid}-#{tail}"
end

#sentence(words: 6) ⇒ Object



129
130
131
132
133
# File 'lib/tina4/seeder.rb', line 129

def sentence(words: 6)
  w = Array.new(words) { WORDS[@rng.rand(WORDS.length)] }
  w[0] = w[0].capitalize
  "#{w.join(' ')}."
end

#slug(words: 3) ⇒ Object



148
149
150
# File 'lib/tina4/seeder.rb', line 148

def slug(words: 3)
  Array.new(words) { WORDS[@rng.rand(WORDS.length)] }.join("-")
end

#text(max_length: 200) ⇒ Object



139
140
141
142
# File 'lib/tina4/seeder.rb', line 139

def text(max_length: 200)
  t = paragraph(sentences: 2)
  t.length > max_length ? t[0...max_length] : t
end

#timestamp(start_year: 2020, end_year: 2026) ⇒ Object



180
181
182
# File 'lib/tina4/seeder.rb', line 180

def timestamp(start_year: 2020, end_year: 2026)
  datetime(start_year: start_year, end_year: end_year).strftime("%Y-%m-%d %H:%M:%S")
end

#urlObject



152
153
154
# File 'lib/tina4/seeder.rb', line 152

def url
  "https://#{DOMAINS[@rng.rand(DOMAINS.length)]}/#{slug}"
end

#uuidObject



228
229
230
231
# File 'lib/tina4/seeder.rb', line 228

def uuid
  h = Array.new(32) { "0123456789abcdef"[@rng.rand(16)] }.join
  "#{h[0..7]}-#{h[8..11]}-#{h[12..15]}-#{h[16..19]}-#{h[20..31]}"
end

#wordObject



144
145
146
# File 'lib/tina4/seeder.rb', line 144

def word
  WORDS[@rng.rand(WORDS.length)]
end

#zip_codeObject



213
214
215
# File 'lib/tina4/seeder.rb', line 213

def zip_code
  @rng.rand(10_000..99_999).to_s
end