From f431b611f837afaeb4f3fa6a7943d39b6b2dfae9 Mon Sep 17 00:00:00 2001 From: Connor Shea <2977353+connorshea@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:49:18 -0600 Subject: [PATCH] Avoid needless word-list copies in Lorem.words Only concatenate the supplemental list when requested, and only duplicate the word list when more words are asked for than the list contains. The list returned by translate is never mutated, since it may be the array cached by the I18n backend. Benchmark (Ruby 3.4.9, arm64-darwin25, benchmark-ips): require 'benchmark/ips' require 'faker' Benchmark.ips do |x| x.config(warmup: 2, time: 5) x.report('words(number: 4)') { Faker::Lorem.words(number: 4) } x.report('sentence') { Faker::Lorem.sentence } x.report('paragraph') { Faker::Lorem.paragraph } end Results: main: words(number: 4) 126.489k (+/- 2.2%) i/s sentence 40.797k (+/- 4.4%) i/s paragraph 12.455k (+/- 0.7%) i/s this commit: words(number: 4) 132.863k (+/- 1.0%) i/s (~1.05x) sentence 43.273k (+/- 0.4%) i/s (~1.06x) paragraph 12.733k (+/- 1.4%) i/s (~1.02x) --- lib/faker/default/lorem.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/faker/default/lorem.rb b/lib/faker/default/lorem.rb index 69e09f0584..3f107eb9c5 100644 --- a/lib/faker/default/lorem.rb +++ b/lib/faker/default/lorem.rb @@ -36,15 +36,16 @@ def word(exclude_words: nil) # @faker.version 2.1.3 def words(number: 3, supplemental: false, exclude_words: nil) resolved_num = resolve(number) - word_list = ( - translate('faker.lorem.words') + - (supplemental ? translate('faker.lorem.supplemental') : []) - ) + word_list = translate('faker.lorem.words') + word_list += translate('faker.lorem.supplemental') if supplemental if exclude_words exclude_words = exclude_words.split(', ') if exclude_words.instance_of?(::String) word_list -= exclude_words end - word_list *= ((resolved_num / word_list.length) + 1) + # Duplicate the word list only when more words are requested than the + # list contains. Never mutate word_list itself: it may be the array + # cached by the I18n backend. + word_list *= ((resolved_num / word_list.length) + 1) if resolved_num > word_list.length sample(word_list, resolved_num) end