class Lit::Cache

Public Class Methods

new() click to toggle source
# File lib/lit/cache.rb, line 24
def initialize
  @hits_counter = Lit.get_key_value_engine
  @request_info_store = Lit.get_key_value_engine
  @hits_counter_working = Lit.hits_counter_enabled
  @keys = nil

  # current instance cache
  @localization_object_cache = {}
  @localization_key_object_cache = {}
  clear_localization_cache
end

Private Class Methods

flatten_hash(hash_to_flatten, parent = []) click to toggle source
# File lib/lit/cache.rb, line 398
def self.flatten_hash(hash_to_flatten, parent = [])
  hash_to_flatten.flat_map do |key, value|
    case value
    when Hash then flatten_hash(value, parent + [key])
    else [(parent + [key]).join('.'), value]
    end
  end
end
split_key(key) click to toggle source
# File lib/lit/cache.rb, line 394
def self.split_key(key)
  key.split('.', 2)
end

Public Instance Methods

[](key) click to toggle source
# File lib/lit/cache.rb, line 36
def [](key)
  value = nil
  check_and_clean_if_required
  unless localization_cache.key?(key)
    value = localizations[key]
    localization_cache[key] = value
  else
    value = localization_cache[key]
  end
  update_hits_count(key) if @hits_counter_working

  if Lit.store_request_info ||
     Lit.store_request_keys
    key_without_locale = split_key(key).last
    store_request_info(key_without_locale)
    update_request_keys(key_without_locale, value)
  end
  value
end
[]=(key, value) click to toggle source
# File lib/lit/cache.rb, line 56
def []=(key, value)
  update_locale(key, value)
end
check_and_clean_if_required() click to toggle source
# File lib/lit/cache.rb, line 193
def check_and_clean_if_required
  # we want this method to run only once during a request or background job
  return if Thread.current[:localization_cache_valid]

  # get most recently updated translation and compare with what we store in class var
  last_up = Lit::Localization.order(updated_at: :desc).limit(1).pluck(:updated_at).first.to_i
  if last_up != @@last_update
    clear_localization_cache
    @@last_update = last_up
  end
  Thread.current[:localization_cache_valid] = true
end
clear()
Alias for: reset
clear_localization_cache() click to toggle source
# File lib/lit/cache.rb, line 188
def clear_localization_cache
  # Thread.current[:lit_thread_cache] = {}
  @@localization_cache = {}
end
delete_key(key) click to toggle source
# File lib/lit/cache.rb, line 131
def delete_key(key)
  key = key.to_s
  localizations.delete(key)
  key_without_locale = split_key(key).last
  localization_keys.delete(key_without_locale)
  @localization_object_cache.delete(key)
  @localization_key_object_cache.delete(key_without_locale)
  I18n.backend.reload!
end
delete_locale(key) click to toggle source
# File lib/lit/cache.rb, line 99
def delete_locale(key)
  key = key.to_s
  keys.delete(key)
  locale_key, key_without_locale = split_key(key)
  locale = find_locale(locale_key)
  delete_localization(locale, key_without_locale)
  @localization_key_object_cache = {}
  @localization_object_cache = {}
  clear_localization_cache
end
find_locale(locale_key) click to toggle source
# File lib/lit/cache.rb, line 157
def find_locale(locale_key)
  locale_key = locale_key.to_s
  @locale_cache ||= {}
  unless @locale_cache.key?(locale_key) && @locale_cache[locale_key].id
    locale = Lit::Locale.where(locale: locale_key).first_or_create!
    @locale_cache[locale_key] = locale
  end
  @locale_cache[locale_key]
end
get_global_hits_counter(key) click to toggle source
# File lib/lit/cache.rb, line 167
def get_global_hits_counter(key)
  @hits_counter['global_hits_counter.' + key]
end
get_hits_counter(key) click to toggle source
# File lib/lit/cache.rb, line 171
def get_hits_counter(key)
  @hits_counter['hits_counter.' + key]
end
get_request_info(key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 389
def get_request_info(key_without_locale)
  @request_info_store['request_info.' + key_without_locale].to_s
end
has_key?(key) click to toggle source
# File lib/lit/cache.rb, line 64
def has_key?(key)
  # check for instance cache first
  localization_cache.has_key?(key) || localizations.has_key?(key)
end
init_key_with_value(key, value) click to toggle source
# File lib/lit/cache.rb, line 60
def init_key_with_value(key, value)
  update_locale(key, value, true)
end
keys() click to toggle source
# File lib/lit/cache.rb, line 73
def keys
  return @keys if @keys.present?
  @keys = localizations.keys
  return @keys if localizations.prefix.nil?
  @keys = @keys.map do |k|
    k.gsub(/^#{localizations.prefix}/, '')
  end
end
load_all_translations() click to toggle source
# File lib/lit/cache.rb, line 110
def load_all_translations
  first = Localization.active.order(id: :asc).first
  last = Localization.active.order(id: :desc).first
  if !first || (!localizations.has_key?(first.full_key) ||
    !localizations.has_key?(last.full_key))
    Localization.includes(%i[locale localization_key]).active.find_each do |l|
      localizations[l.full_key] = l.translation
    end
  end
end
localization_cache() click to toggle source
# File lib/lit/cache.rb, line 183
def localization_cache
  # Thread.current[:lit_thread_cache] ||= {}
  @@localization_cache ||= {}
end
refresh_key(key) click to toggle source
# File lib/lit/cache.rb, line 121
def refresh_key(key)
  key = key.to_s
  locale_key, key_without_locale = split_key(key)
  locale = find_locale(locale_key)
  @localization_object_cache.delete(key)
  localization = find_localization(locale, key_without_locale, default_fallback: true)
  localizations[key] = localization.translation if localization
  clear_localization_cache
end
request_keys() click to toggle source
# File lib/lit/cache.rb, line 384
def request_keys
  Thread.current[:lit_request_keys] || {}
end
reset() click to toggle source
# File lib/lit/cache.rb, line 149
def reset
  reset_local_cache
  localizations.clear
  localization_keys.clear
  load_all_translations
end
Also aliased as: clear
reset_local_cache() click to toggle source
# File lib/lit/cache.rb, line 141
def reset_local_cache
  @locale_cache = {}
  @localization_key_object_cache = {}
  @localization_object_cache = {}
  @localization_cache = {}
  clear_localization_cache
end
restore_hits_counter() click to toggle source
# File lib/lit/cache.rb, line 179
def restore_hits_counter
  @hits_counter_working = true
end
stop_hits_counter() click to toggle source
# File lib/lit/cache.rb, line 175
def stop_hits_counter
  @hits_counter_working = false
end
sync() click to toggle source
# File lib/lit/cache.rb, line 69
def sync
  localizations.clear
end
update_cache(key, value) click to toggle source
# File lib/lit/cache.rb, line 93
def update_cache(key, value)
  key = key.to_s
  localizations[key] = value
  localization_cache[key] = value
end
update_locale(key, value, force_array = false, startup_process = false) click to toggle source
# File lib/lit/cache.rb, line 82
def update_locale(key, value, force_array = false, startup_process = false)
  key = key.to_s
  locale_key, key_without_locale = split_key(key)
  locale = find_locale(locale_key)
  localization = find_localization(locale, key_without_locale, value: value, force_array: force_array, update_value: true)
  return localization.translation if startup_process && localization.is_changed?

  localizations[key] = localization.translation if localization
  localization_cache[key] = localizations[key]
end

Private Instance Methods

delete_localization(locale, key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 280
def delete_localization(locale, key_without_locale)
  localization = find_localization_for_delete(locale, key_without_locale)
  return unless localization
  localizations.delete("#{locale.locale}.#{key_without_locale}")
  localization_keys.delete(key_without_locale)
  localization.destroy # or localization.default_value = nil; localization.save!
end
fallback_localization(locale, key_without_locale) click to toggle source

fallback to translation in different locale

# File lib/lit/cache.rb, line 252
def fallback_localization(locale, key_without_locale)
  value = nil
  return nil unless fallbacks = ::Rails.application.config.i18n.fallbacks
  keys = fallbacks == true ? @locale_cache.keys : fallbacks
  keys.map(&:to_s).each do |lc|
    if lc != locale.locale && value.nil?
      nk = "#{lc}.#{key_without_locale}"
      v = localizations[nk]
      value = v if v.present? && value.nil?
    end
  end
  value
end
fallback_to_default(localization_key, localization) click to toggle source

tries to get `default_value` from localization_key - checks other localizations

# File lib/lit/cache.rb, line 268
def fallback_to_default(localization_key, localization)
  localization_key.localizations.where.not(default_value: nil). \
    where.not(id: localization.id).first&.default_value
end
find_localization(locale, key_without_locale, value: nil, force_array: false, update_value: false, default_fallback: false) click to toggle source
# File lib/lit/cache.rb, line 216
def find_localization(locale, key_without_locale, value: nil, force_array: false, update_value: false, default_fallback: false)
  return nil if value.is_a?(Hash)
  full_key = "#{locale}.#{key_without_locale}"
  ActiveRecord::Base.transaction do
    localization_key = find_localization_key(key_without_locale)
    localization = @localization_object_cache[full_key]
    localization ||=
      Lit::Localization.where(locale_id: locale.id)
                       .where(localization_key_id: localization_key.id)
                       .first_or_initialize
    if update_value || localization.new_record?
      if value.is_a?(Array)
        value = parse_array_value(value, locale) unless force_array
      elsif !value.nil?
        value = parse_value(value, locale)
      else
        if ::Rails.application.config.i18n.fallbacks
          value = fallback_localization(locale, key_without_locale)
        elsif default_fallback
          value = fallback_to_default(localization_key, localization)
        end
      end
      # Prevent overwriting existing default value with nil.
      # However, if the localization record is #new_record?, we still need
      # to insert it with an empty default value.
      localization.locale = locale
      localization.localization_key = localization_key
      localization.full_key_str = full_key
      localization.update_default_value(value) if localization.new_record? || value
      @localization_object_cache[full_key] = localization
    end
    localization
  end
end
find_localization_for_delete(locale, key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 273
def find_localization_for_delete(locale, key_without_locale)
  localization_key = find_localization_key_for_delete(key_without_locale)
  return nil unless localization_key
  Lit::Localization.active.find_by(locale_id: locale.id,
                                   localization_key_id: localization_key.id)
end
find_localization_key(key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 326
def find_localization_key(key_without_locale)
  return @localization_key_object_cache[key_without_locale] if @localization_key_object_cache.key?(key_without_locale)
  @localization_key_object_cache[key_without_locale] = if localization_keys.key?(key_without_locale)
                                                         Lit::LocalizationKey.find_by(
                                                           id: localization_keys[key_without_locale]
                                                         ) || find_or_create_localization_key(key_without_locale)
                                                       else
                                                         find_or_create_localization_key(key_without_locale)
                                                       end
  @localization_key_object_cache[key_without_locale]
end
find_localization_key_for_delete(key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 338
def find_localization_key_for_delete(key_without_locale)
  return @localization_key_object_cache[key_without_locale] if @localization_key_object_cache.key?(key_without_locale)
  lk = Lit::LocalizationKey.find_by(id: localization_keys[key_without_locale]) if localization_keys.has_key?(key_without_locale)
  lk || Lit::LocalizationKey.where(localization_key: key_without_locale).first
end
find_or_create_localization_key(key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 348
def find_or_create_localization_key(key_without_locale)
  localization_key = Lit::LocalizationKey.find_or_initialize_by(
    localization_key: key_without_locale
  )
  localization_key.is_visited_again = true if localization_key.is_deleted?
  localization_key.save! if localization_key.changed?
  localization_keys[key_without_locale] = localization_key.id
  localization_key
end
localization_keys() click to toggle source
# File lib/lit/cache.rb, line 212
def localization_keys
  @localization_keys ||= Lit.get_key_value_engine
end
localizations() click to toggle source
# File lib/lit/cache.rb, line 208
def localizations
  @localizations ||= Lit.get_key_value_engine
end
parse_array_value(value, locale) click to toggle source
# File lib/lit/cache.rb, line 316
def parse_array_value(value, locale)
  new_value = nil
  value_clone = value.dup
  while (v = value_clone.shift) && v.present?
    pv = parse_value(v, locale)
    new_value = pv unless pv.nil?
  end
  new_value
end
parse_value(v, locale) click to toggle source

checks parameter type and returns value basing on it symbols are beeing looked up in db string are returned directly procs are beeing called (once) hashes are converted do string (for now)

# File lib/lit/cache.rb, line 293
def parse_value(v, locale)
  new_value = nil
  case v
    when Symbol then
      lk = @localization_key_object_cache[v.to_s] || \
        Lit::LocalizationKey.where(localization_key: v.to_s).first
      if lk
        loca = Lit::Localization.active.where(locale_id: locale.id).
                    where(localization_key_id: lk.id).first
        new_value = loca.translation if loca && loca.translation.present?
      end
    when String then
      new_value = v
    when Hash then
      new_value = nil
    when Proc then
      new_value = nil # was v.call - requires more love
    else
      new_value = v.to_s
  end
  new_value
end
split_key(key) click to toggle source
# File lib/lit/cache.rb, line 344
def split_key(key)
  Lit::Cache.split_key(key)
end
store_request_info(key_without_locale) click to toggle source
# File lib/lit/cache.rb, line 366
def store_request_info(key_without_locale)
  return unless Lit.store_request_info
  return unless Thread.current[:lit_current_request_path].present?

  info = get_request_info(key_without_locale)
  parts = info.split(' ').push(Thread.current[:lit_current_request_path]).uniq
  parts.shift if parts.count > 10
  @request_info_store['request_info.' + key_without_locale] = parts.join ' '
end
update_hits_count(key) click to toggle source
# File lib/lit/cache.rb, line 358
def update_hits_count(key)
  return unless @hits_counter_working

  key_without_locale = split_key(key).last
  @hits_counter.incr('hits_counter.' + key)
  @hits_counter.incr('global_hits_counter.' + key_without_locale)
end
update_request_keys(key_without_locale, localization) click to toggle source
# File lib/lit/cache.rb, line 376
def update_request_keys(key_without_locale, localization)
  return unless Lit.store_request_keys
  return if Thread.current[:lit_request_keys].nil?

  Thread.current[:lit_request_keys] ||= {}
  Thread.current[:lit_request_keys][key_without_locale] = localization
end