From 4b707b93102a7ccfc94d82648f07d1d9c1eb902e Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 30 Apr 2023 10:15:16 +0100 Subject: [PATCH] Extract locale file digest logic to a separate class and add tests --- app/helpers/application_helper.rb | 8 +---- config/application.rb | 6 ++-- lib/i18n_digests.rb | 25 +++++++++++++ spec/helpers/application_helper_spec.rb | 47 +++++++++++++++++++++++++ spec/lib/i18n_digests_spec.rb | 44 +++++++++++++++++++++++ 5 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 lib/i18n_digests.rb create mode 100644 spec/lib/i18n_digests_spec.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5d493c5a32..ea8c4beeab 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -76,12 +76,6 @@ module ApplicationHelper end def cache_key_with_locale(key, locale) - Array.wrap(key) + [locale.to_s, locale_digest(locale)] - end - - private - - def locale_digest(locale) - Rails.application.config.x.i18n_digests[locale] + Array.wrap(key) + [locale.to_s, I18nDigests.for_locale(locale)] end end diff --git a/config/application.rb b/config/application.rb index 943cc05474..13e94443fe 100644 --- a/config/application.rb +++ b/config/application.rb @@ -23,6 +23,7 @@ end require_relative "../lib/open_food_network/i18n_config" require_relative '../lib/spree/core/environment' require_relative '../lib/spree/core/mail_interceptor' +require_relative "../lib/i18n_digests" if defined?(Bundler) # If you precompile assets before deploying to production, use this line @@ -185,10 +186,7 @@ module Openfoodnetwork I18n.locale = config.i18n.locale = config.i18n.default_locale # Calculate digests for locale files so we can know when they change - config.i18n.available_locales.each do |locale| - (config.x.i18n_digests ||= {})[locale.to_sym] = - Digest::MD5.hexdigest(File.read(Rails.root.join("config/locales/#{locale}.yml"))) - end + I18nDigests.build_digests config.i18n.available_locales # Setting this to true causes a performance regression in Rails 3.2.17 # When we're on a version with the fix below, we can set it to true diff --git a/lib/i18n_digests.rb b/lib/i18n_digests.rb new file mode 100644 index 0000000000..23fe078a6a --- /dev/null +++ b/lib/i18n_digests.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class I18nDigests + class << self + def build_digests(available_locales) + available_locales.each do |locale| + i18n_digests[locale.to_sym] = locale_file_digest(locale) + end + end + + def for_locale(locale) + i18n_digests[locale.to_sym] + end + + private + + def i18n_digests + Rails.application.config.x.i18n_digests + end + + def locale_file_digest(locale) + Digest::MD5.hexdigest(Rails.root.join("config/locales/#{locale}.yml").read) + end + end +end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index a690869f93..80847b4f7f 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -42,4 +42,51 @@ describe ApplicationHelper, type: :helper do end end end + + describe "#cache_with_locale" do + let(:available_locales) { ["en", "es"] } + let(:current_locale) { "es" } + let(:locale_digest) { "8a7s5dfy28u0as9du" } + let(:options) { { expires_in: 10.seconds } } + + before do + allow(I18n).to receive(:available_locales) { available_locales } + allow(I18n).to receive(:locale) { current_locale } + allow(I18nDigests).to receive(:for_locale) { locale_digest } + end + + it "passes key, options, and block to #cache method with locale and locale digest appended" do + expect(helper).to receive(:cache_key_with_locale). + with("test-key", current_locale).and_return(["test-key", current_locale, locale_digest]) + + expect(helper).to receive(:cache). + with(["test-key", current_locale, locale_digest], options) do |&block| + expect(block.call).to eq("cached content") + end + + helper.cache_with_locale "test-key", options do + "cached content" + end + end + end + + describe "#cache_key_with_locale" do + let(:en_digest) { "asd689asy0239" } + let(:es_digest) { "9d8tu23oirhad" } + + before { allow(I18nDigests).to receive(:for_locale).with("en") { en_digest } } + before { allow(I18nDigests).to receive(:for_locale).with("es") { es_digest } } + + it "appends locale and digest to a single key" do + expect( + helper.cache_key_with_locale("single-key", "en") + ).to eq(["single-key", "en", en_digest]) + end + + it "appends locale and digest to multiple keys" do + expect( + helper.cache_key_with_locale(["array", "of", "keys"], "es") + ).to eq(["array", "of", "keys", "es", es_digest]) + end + end end diff --git a/spec/lib/i18n_digests_spec.rb b/spec/lib/i18n_digests_spec.rb new file mode 100644 index 0000000000..391cbb0050 --- /dev/null +++ b/spec/lib/i18n_digests_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe I18nDigests do + describe "#build_digests" do + let(:available_locales) { ["en", "es"] } + let(:md5_hex_regex) { /([a-f0-9]){10}/ } + + around do |example| + original = Rails.application.config.x.i18n_digests + example.run + Rails.application.config.x.i18n_digests = original + end + + it "computes and stores digests for each locale file" do + Rails.application.config.x.i18n_digests = {} + I18nDigests.build_digests(available_locales) + + expect(Rails.application.config.x.i18n_digests.keys).to eq [:en, :es] + expect(Rails.application.config.x.i18n_digests.values).to all match(md5_hex_regex) + + expect( + Rails.application.config.x.i18n_digests[:en] + ).to eq(Digest::MD5.hexdigest(Rails.root.join("config/locales/en.yml").read)) + + expect( + Rails.application.config.x.i18n_digests[:es] + ).to eq(Digest::MD5.hexdigest(Rails.root.join("config/locales/es.yml").read)) + end + end + + describe "#for_locale" do + let(:digests) { { en: "as8d7a9sdh", es: "iausyd9asdh" } } + + before do + allow(Rails).to receive_message_chain(:application, :config, :x, :i18n_digests) { digests } + end + + it "returns the digest for a given locale" do + expect(I18nDigests.for_locale("en")).to eq "as8d7a9sdh" + end + end +end