ultra_settings 2.9.1 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/README.md +24 -0
  4. data/VERSION +1 -1
  5. data/app/_config_description.html.erb +10 -1
  6. data/app/_data_source.html.erb +2 -2
  7. data/app/application.css +119 -26
  8. data/app/application_vars.css.erb +40 -14
  9. data/app/configuration.html.erb +19 -1
  10. data/app/layout.css +41 -2
  11. data/app/layout.html.erb +46 -0
  12. data/app/layout_vars.css.erb +12 -8
  13. data/app/locales/ar.json +5 -2
  14. data/app/locales/cs.json +5 -2
  15. data/app/locales/da.json +5 -2
  16. data/app/locales/de.json +5 -2
  17. data/app/locales/el.json +5 -2
  18. data/app/locales/en.json +5 -2
  19. data/app/locales/es.json +5 -2
  20. data/app/locales/fa.json +5 -2
  21. data/app/locales/fr.json +5 -2
  22. data/app/locales/gd.json +5 -2
  23. data/app/locales/he.json +5 -2
  24. data/app/locales/hi.json +5 -2
  25. data/app/locales/it.json +5 -2
  26. data/app/locales/ja.json +5 -2
  27. data/app/locales/ko.json +5 -2
  28. data/app/locales/lt.json +5 -2
  29. data/app/locales/nb.json +5 -2
  30. data/app/locales/nl.json +5 -2
  31. data/app/locales/pl.json +5 -2
  32. data/app/locales/pt-br.json +5 -2
  33. data/app/locales/pt.json +5 -2
  34. data/app/locales/ru.json +5 -2
  35. data/app/locales/sv.json +5 -2
  36. data/app/locales/ta.json +5 -2
  37. data/app/locales/tr.json +5 -2
  38. data/app/locales/uk.json +5 -2
  39. data/app/locales/ur.json +5 -2
  40. data/app/locales/vi.json +5 -2
  41. data/app/locales/zh-cn.json +5 -2
  42. data/app/locales/zh-tw.json +5 -2
  43. data/lib/ultra_settings/application_view.rb +17 -7
  44. data/lib/ultra_settings/audit_data_sources.rb +1 -1
  45. data/lib/ultra_settings/coerce.rb +1 -1
  46. data/lib/ultra_settings/configuration.rb +36 -10
  47. data/lib/ultra_settings/configuration_view.rb +166 -9
  48. data/lib/ultra_settings/mini_i18n.rb +14 -10
  49. data/lib/ultra_settings/rack_app.rb +4 -4
  50. data/lib/ultra_settings/view_helper.rb +27 -5
  51. data/lib/ultra_settings/web_view.rb +26 -16
  52. data/lib/ultra_settings/yaml_config.rb +10 -2
  53. data/lib/ultra_settings.rb +66 -2
  54. data/ultra_settings.gemspec +1 -1
  55. metadata +2 -2
data/app/locales/pl.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Kliknij, aby rozwinąć",
19
19
  "field.not_set": "nie ustawiono",
20
+ "field.copy": "Kopiuj wartość",
21
+ "field.copy_disabled": "Nie można kopiować tajnych wartości",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "USTAWIENIE",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "DOMYŚLNE",
24
- "source.active": "● Aktywne",
26
+ "source.active": "Aktywne",
25
27
  "source.overridden": "Nadpisane",
26
28
  "detail.field_detail": "Szczegóły pola",
27
29
  "detail.close_panel": "Zamknij panel",
28
30
  "detail.type_label": "Typ:",
29
31
  "detail.secret_badge": "TAJNE",
30
32
  "detail.secret_value": "•••••••• (tajne)",
31
- "config.file_not_found": "(nie znaleziono)",
33
+ "config.file_not_found": "plik nie istnieje",
34
+ "config.show_yaml_keys": "pokaż klucze",
32
35
  "config.edit_tooltip": "Edytuj ${name}",
33
36
  "edit.title": "Edytuj ustawienie środowiska uruchomieniowego",
34
37
  "edit.open_dashboard": "Otwórz w panelu ustawień ↗",
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Clique para expandir",
19
19
  "field.not_set": "não definido",
20
+ "field.copy": "Copiar valor",
21
+ "field.copy_disabled": "Valores secretos não podem ser copiados",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "CONFIGURAÇÃO",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "PADRÃO",
24
- "source.active": "● Ativo",
26
+ "source.active": "Ativo",
25
27
  "source.overridden": "Substituído",
26
28
  "detail.field_detail": "Detalhes do campo",
27
29
  "detail.close_panel": "Fechar painel",
28
30
  "detail.type_label": "Tipo:",
29
31
  "detail.secret_badge": "SECRETO",
30
32
  "detail.secret_value": "•••••••• (secreto)",
31
- "config.file_not_found": "(não encontrado)",
33
+ "config.file_not_found": "o arquivo não existe",
34
+ "config.show_yaml_keys": "mostrar chaves",
32
35
  "config.edit_tooltip": "Editar ${name}",
33
36
  "edit.title": "Editar configuração de runtime",
34
37
  "edit.open_dashboard": "Abrir no painel de configurações ↗",
data/app/locales/pt.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Clique para expandir",
19
19
  "field.not_set": "não definido",
20
+ "field.copy": "Copiar valor",
21
+ "field.copy_disabled": "Os valores secretos não podem ser copiados",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "CONFIGURAÇÃO",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "PREDEFINIDO",
24
- "source.active": "● Ativo",
26
+ "source.active": "Ativo",
25
27
  "source.overridden": "Substituído",
26
28
  "detail.field_detail": "Detalhes do campo",
27
29
  "detail.close_panel": "Fechar painel",
28
30
  "detail.type_label": "Tipo:",
29
31
  "detail.secret_badge": "SECRETO",
30
32
  "detail.secret_value": "•••••••• (secreto)",
31
- "config.file_not_found": "(não encontrado)",
33
+ "config.file_not_found": "o ficheiro não existe",
34
+ "config.show_yaml_keys": "mostrar chaves",
32
35
  "config.edit_tooltip": "Editar ${name}",
33
36
  "edit.title": "Editar configuração de runtime",
34
37
  "edit.open_dashboard": "Abrir no painel de configurações ↗",
data/app/locales/ru.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Нажмите, чтобы развернуть",
19
19
  "field.not_set": "не задано",
20
+ "field.copy": "Копировать значение",
21
+ "field.copy_disabled": "Секретные значения нельзя копировать",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "НАСТРОЙКА",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "ПО УМОЛЧАНИЮ",
24
- "source.active": "● Активно",
26
+ "source.active": "Активно",
25
27
  "source.overridden": "Переопределено",
26
28
  "detail.field_detail": "Сведения о поле",
27
29
  "detail.close_panel": "Закрыть панель",
28
30
  "detail.type_label": "Тип:",
29
31
  "detail.secret_badge": "СЕКРЕТНО",
30
32
  "detail.secret_value": "•••••••• (секретно)",
31
- "config.file_not_found": "(не найдено)",
33
+ "config.file_not_found": "файл не существует",
34
+ "config.show_yaml_keys": "показать ключи",
32
35
  "config.edit_tooltip": "Изменить ${name}",
33
36
  "edit.title": "Изменить настройку времени выполнения",
34
37
  "edit.open_dashboard": "Открыть на панели настроек ↗",
data/app/locales/sv.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Klicka för att expandera",
19
19
  "field.not_set": "inte angivet",
20
+ "field.copy": "Kopiera värde",
21
+ "field.copy_disabled": "Hemliga värden kan inte kopieras",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "INSTÄLLNING",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "STANDARD",
24
- "source.active": "● Aktiv",
26
+ "source.active": "Aktiv",
25
27
  "source.overridden": "Åsidosatt",
26
28
  "detail.field_detail": "Fältdetaljer",
27
29
  "detail.close_panel": "Stäng panel",
28
30
  "detail.type_label": "Typ:",
29
31
  "detail.secret_badge": "HEMLIG",
30
32
  "detail.secret_value": "•••••••• (hemlig)",
31
- "config.file_not_found": "(hittades inte)",
33
+ "config.file_not_found": "filen finns inte",
34
+ "config.show_yaml_keys": "visa nycklar",
32
35
  "config.edit_tooltip": "Redigera ${name}",
33
36
  "edit.title": "Redigera runtime-inställning",
34
37
  "edit.open_dashboard": "Öppna i inställningspanelen ↗",
data/app/locales/ta.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "விரிவாக்க கிளிக் செய்யவும்",
19
19
  "field.not_set": "அமைக்கப்படவில்லை",
20
+ "field.copy": "மதிப்பை நகலெடு",
21
+ "field.copy_disabled": "ரகசிய மதிப்புகளை நகலெடுக்க முடியாது",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "அமைப்பு",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "இயல்புநிலை",
24
- "source.active": "● செயலில்",
26
+ "source.active": "செயலில்",
25
27
  "source.overridden": "மேலெழுதப்பட்டது",
26
28
  "detail.field_detail": "புல விவரம்",
27
29
  "detail.close_panel": "பலகையை மூடு",
28
30
  "detail.type_label": "வகை:",
29
31
  "detail.secret_badge": "ரகசியம்",
30
32
  "detail.secret_value": "•••••••• (ரகசியம்)",
31
- "config.file_not_found": "(கண்டுபிடிக்கவில்லை)",
33
+ "config.file_not_found": "கோப்பு இல்லை",
34
+ "config.show_yaml_keys": "விசைகளைக் காட்டு",
32
35
  "config.edit_tooltip": "${name} ஐத் திருத்து",
33
36
  "edit.title": "இயக்கநேர அமைப்பைத் திருத்து",
34
37
  "edit.open_dashboard": "அமைப்புகள் டாஷ்போர்டில் திற ↗",
data/app/locales/tr.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Genişletmek için tıklayın",
19
19
  "field.not_set": "ayarlanmamış",
20
+ "field.copy": "Değeri kopyala",
21
+ "field.copy_disabled": "Gizli değerler kopyalanamaz",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "AYAR",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "VARSAYILAN",
24
- "source.active": "● Etkin",
26
+ "source.active": "Etkin",
25
27
  "source.overridden": "Geçersiz kılındı",
26
28
  "detail.field_detail": "Alan ayrıntısı",
27
29
  "detail.close_panel": "Paneli kapat",
28
30
  "detail.type_label": "Tür:",
29
31
  "detail.secret_badge": "GİZLİ",
30
32
  "detail.secret_value": "•••••••• (gizli)",
31
- "config.file_not_found": "(bulunamadı)",
33
+ "config.file_not_found": "dosya mevcut değil",
34
+ "config.show_yaml_keys": "anahtarları göster",
32
35
  "config.edit_tooltip": "${name} öğesini düzenle",
33
36
  "edit.title": "Çalışma zamanı ayarını düzenle",
34
37
  "edit.open_dashboard": "Ayarlar panosunda aç ↗",
data/app/locales/uk.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Натисніть, щоб розгорнути",
19
19
  "field.not_set": "не задано",
20
+ "field.copy": "Копіювати значення",
21
+ "field.copy_disabled": "Секретні значення не можна копіювати",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "НАЛАШТУВАННЯ",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "ЗА ЗАМОВЧУВАННЯМ",
24
- "source.active": "● Активно",
26
+ "source.active": "Активно",
25
27
  "source.overridden": "Перевизначено",
26
28
  "detail.field_detail": "Деталі поля",
27
29
  "detail.close_panel": "Закрити панель",
28
30
  "detail.type_label": "Тип:",
29
31
  "detail.secret_badge": "СЕКРЕТНО",
30
32
  "detail.secret_value": "•••••••• (секретно)",
31
- "config.file_not_found": "(не знайдено)",
33
+ "config.file_not_found": "файл не існує",
34
+ "config.show_yaml_keys": "показати ключі",
32
35
  "config.edit_tooltip": "Редагувати ${name}",
33
36
  "edit.title": "Редагувати налаштування часу виконання",
34
37
  "edit.open_dashboard": "Відкрити на панелі налаштувань ↗",
data/app/locales/ur.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "پھیلانے کے لیے کلک کریں",
19
19
  "field.not_set": "سیٹ نہیں",
20
+ "field.copy": "قدر کاپی کریں",
21
+ "field.copy_disabled": "خفیہ اقدار کاپی نہیں کی جا سکتیں",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "ترتیب",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "طے شدہ",
24
- "source.active": "● فعال",
26
+ "source.active": "فعال",
25
27
  "source.overridden": "اووررائیڈ شدہ",
26
28
  "detail.field_detail": "فیلڈ کی تفصیل",
27
29
  "detail.close_panel": "پینل بند کریں",
28
30
  "detail.type_label": "قسم:",
29
31
  "detail.secret_badge": "خفیہ",
30
32
  "detail.secret_value": "•••••••• (خفیہ)",
31
- "config.file_not_found": "(نہیں ملا)",
33
+ "config.file_not_found": "فائل موجود نہیں ہے",
34
+ "config.show_yaml_keys": "کیز دکھائیں",
32
35
  "config.edit_tooltip": "${name} میں ترمیم کریں",
33
36
  "edit.title": "رن ٹائم ترتیب میں ترمیم کریں",
34
37
  "edit.open_dashboard": "ترتیبات ڈیش بورڈ میں کھولیں ↗",
data/app/locales/vi.json CHANGED
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "Bấm để mở rộng",
19
19
  "field.not_set": "chưa đặt",
20
+ "field.copy": "Sao chép giá trị",
21
+ "field.copy_disabled": "Không thể sao chép giá trị bí mật",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "CÀI ĐẶT",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "MẶC ĐỊNH",
24
- "source.active": "● Hoạt động",
26
+ "source.active": "Hoạt động",
25
27
  "source.overridden": "Bị ghi đè",
26
28
  "detail.field_detail": "Chi tiết trường",
27
29
  "detail.close_panel": "Đóng bảng",
28
30
  "detail.type_label": "Loại:",
29
31
  "detail.secret_badge": "BÍ MẬT",
30
32
  "detail.secret_value": "•••••••• (bí mật)",
31
- "config.file_not_found": "(không tìm thấy)",
33
+ "config.file_not_found": "tệp không tồn tại",
34
+ "config.show_yaml_keys": "hiện khóa",
32
35
  "config.edit_tooltip": "Chỉnh sửa ${name}",
33
36
  "edit.title": "Chỉnh sửa cài đặt runtime",
34
37
  "edit.open_dashboard": "Mở trong bảng điều khiển cài đặt ↗",
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "点击展开",
19
19
  "field.not_set": "未设置",
20
+ "field.copy": "复制值",
21
+ "field.copy_disabled": "无法复制机密值",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "设置",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "默认",
24
- "source.active": "● 当前生效",
26
+ "source.active": "当前生效",
25
27
  "source.overridden": "已覆盖",
26
28
  "detail.field_detail": "字段详情",
27
29
  "detail.close_panel": "关闭面板",
28
30
  "detail.type_label": "类型:",
29
31
  "detail.secret_badge": "机密",
30
32
  "detail.secret_value": "•••••••• (机密)",
31
- "config.file_not_found": "(未找到)",
33
+ "config.file_not_found": "文件不存在",
34
+ "config.show_yaml_keys": "显示键",
32
35
  "config.edit_tooltip": "编辑 ${name}",
33
36
  "edit.title": "编辑运行时设置",
34
37
  "edit.open_dashboard": "在设置仪表板中打开 ↗",
@@ -17,18 +17,21 @@
17
17
  "field.nil": "nil",
18
18
  "field.click_to_expand": "點擊以展開",
19
19
  "field.not_set": "未設定",
20
+ "field.copy": "複製值",
21
+ "field.copy_disabled": "無法複製機密值",
20
22
  "source.env": "ENV",
21
23
  "source.setting": "設定",
22
24
  "source.yaml": "YAML",
23
25
  "source.default": "預設",
24
- "source.active": "● 目前生效",
26
+ "source.active": "目前生效",
25
27
  "source.overridden": "已覆寫",
26
28
  "detail.field_detail": "欄位詳細資料",
27
29
  "detail.close_panel": "關閉面板",
28
30
  "detail.type_label": "類型:",
29
31
  "detail.secret_badge": "機密",
30
32
  "detail.secret_value": "•••••••• (機密)",
31
- "config.file_not_found": "(找不到)",
33
+ "config.file_not_found": "檔案不存在",
34
+ "config.show_yaml_keys": "顯示鍵",
32
35
  "config.edit_tooltip": "編輯 ${name}",
33
36
  "edit.title": "編輯執行階段設定",
34
37
  "edit.open_dashboard": "在設定儀表板中開啟 ↗",
@@ -18,23 +18,33 @@ module UltraSettings
18
18
  # Initialize the application view with a color scheme.
19
19
  #
20
20
  # @param color_scheme [Symbol] The color scheme to use (:light, :dark, or :system).
21
+ # @param dark_mode_selector [String, nil] The CSS selector for dark mode.
21
22
  # @param locale [String] The locale code for translations.
22
- def initialize(color_scheme: :light, locale: UltraSettings::MiniI18n::DEFAULT_LOCALE)
23
- @css = application_css(color_scheme)
23
+ def initialize(color_scheme: :light, dark_mode_selector: nil, locale: UltraSettings::MiniI18n::DEFAULT_LOCALE)
24
+ @css = application_css(color_scheme, dark_mode_selector)
24
25
  @css = @css.html_safe if @css.respond_to?(:html_safe)
25
26
  @locale = locale
26
27
  end
27
28
 
28
29
  # Render the HTML for the configuration settings UI.
29
30
  #
31
+ # The runtime settings cache is reloaded before rendering so that values changed
32
+ # from the UI are displayed immediately rather than after the runtime settings
33
+ # engine next refreshes itself.
34
+ #
30
35
  # @param select_class [String] @deprecated; no longer used.
31
36
  # @param table_class [String] @deprecated; no longer used.
32
37
  # @return [String] The rendered HTML.
33
38
  def render(select_class: nil, table_class: nil)
34
- locale = @locale # used by ERB template via binding
35
- html = ViewHelper.erb_template("index.html.erb").result(binding)
36
- html = html.html_safe if html.respond_to?(:html_safe)
37
- html
39
+ UltraSettings.with_runtime_settings_reloaded do
40
+ # Expose locale as a local for the ERB template without a direct
41
+ # assignment, which would emit an unused variable warning under ruby -w.
42
+ template_binding = binding
43
+ template_binding.local_variable_set(:locale, @locale)
44
+ html = ViewHelper.erb_template("index.html.erb").result(template_binding)
45
+ html = html.html_safe if html.respond_to?(:html_safe)
46
+ html
47
+ end
38
48
  end
39
49
 
40
50
  # Generate an HTML style tag with the CSS for the view.
@@ -74,7 +84,7 @@ module UltraSettings
74
84
  ViewHelper.read_app_file("application.js")
75
85
  end
76
86
 
77
- def application_css(color_scheme)
87
+ def application_css(color_scheme, dark_mode_selector)
78
88
  vars = ViewHelper.erb_template("application_vars.css.erb").result(binding).strip
79
89
  css = ViewHelper.read_app_file("application.css").strip
80
90
  "#{vars}\n#{css}"
@@ -91,7 +91,7 @@ module UltraSettings
91
91
  def default_config_value(config, field)
92
92
  yaml_value = config.__value_from_source__(field.name, :yaml)
93
93
  default_value = config.__value_from_source__(field.name, :default)
94
- yaml_value || default_value
94
+ yaml_value.nil? ? default_value : yaml_value
95
95
  end
96
96
  end
97
97
  end
@@ -60,8 +60,8 @@ module UltraSettings
60
60
  # @param value [Object]
61
61
  # @return [Boolean]
62
62
  def boolean(value)
63
- return nil if blank?(value)
64
63
  return false if value == false
64
+ return nil if blank?(value)
65
65
 
66
66
  !FALSE_VALUES.include?(value.to_s.downcase)
67
67
  end
@@ -7,6 +7,9 @@ module UltraSettings
7
7
  ALLOWED_NAME_PATTERN = /\A[a-z_][a-zA-Z0-9_]*\z/
8
8
  ALLOWED_TYPES = [:string, :symbol, :integer, :float, :boolean, :datetime, :array].freeze
9
9
 
10
+ DESCENDANTS_MUTEX = Mutex.new
11
+ private_constant :DESCENDANTS_MUTEX
12
+
10
13
  @env_var_prefix = nil
11
14
  @runtime_setting_prefix = nil
12
15
  @description = nil
@@ -373,10 +376,15 @@ module UltraSettings
373
376
 
374
377
  # Get all descendant configuration classes (subclasses and their subclasses, recursively).
375
378
  #
379
+ # Note that in Rails development mode this list can include stale classes from
380
+ # previous code reloads; callers that display the results should filter out
381
+ # classes that no longer resolve to a defined constant (see
382
+ # UltraSettings.__configurations__).
383
+ #
376
384
  # @return [Array<Class>] All classes that inherit from this class.
377
385
  def descendant_configurations
378
- @descendants ||= []
379
- @descendants.flat_map { |subclass| [subclass] + subclass.descendant_configurations }
386
+ descendants = DESCENDANTS_MUTEX.synchronize { (@descendants || []).dup }
387
+ descendants.flat_map { |subclass| [subclass] + subclass.descendant_configurations }
380
388
  end
381
389
 
382
390
  private
@@ -387,8 +395,10 @@ module UltraSettings
387
395
  # @return [void]
388
396
  def inherited(subclass)
389
397
  super
390
- @descendants ||= []
391
- @descendants << subclass
398
+ DESCENDANTS_MUTEX.synchronize do
399
+ @descendants ||= []
400
+ @descendants << subclass
401
+ end
392
402
  end
393
403
 
394
404
  def defined_fields
@@ -496,7 +506,8 @@ module UltraSettings
496
506
  end
497
507
 
498
508
  def override!(values, &block)
499
- save_val = @ultra_settings_override_values[Thread.current.object_id]
509
+ thread_id = Thread.current.object_id
510
+ save_val = @ultra_settings_mutex.synchronize { @ultra_settings_override_values[thread_id] }
500
511
 
501
512
  temp_values = (save_val || {}).dup
502
513
  values.each do |key, value|
@@ -505,12 +516,18 @@ module UltraSettings
505
516
 
506
517
  begin
507
518
  @ultra_settings_mutex.synchronize do
508
- @ultra_settings_override_values[Thread.current.object_id] = temp_values
519
+ @ultra_settings_override_values[thread_id] = temp_values
509
520
  end
510
521
  yield
511
522
  ensure
512
523
  @ultra_settings_mutex.synchronize do
513
- @ultra_settings_override_values[Thread.current.object_id] = save_val
524
+ if save_val.nil?
525
+ # Remove the key entirely so the hash doesn't accumulate an entry
526
+ # for every thread that has ever used override!.
527
+ @ultra_settings_override_values.delete(thread_id)
528
+ else
529
+ @ultra_settings_override_values[thread_id] = save_val
530
+ end
514
531
  end
515
532
  end
516
533
  end
@@ -592,11 +609,20 @@ module UltraSettings
592
609
  field = self.class.send(:defined_fields)[name]
593
610
  return nil unless field
594
611
 
595
- override_values = @ultra_settings_mutex.synchronize { @ultra_settings_override_values[Thread.current.object_id] }
612
+ override_values = nil
613
+ memoized = false
614
+ memoized_value = nil
615
+ @ultra_settings_mutex.synchronize do
616
+ override_values = @ultra_settings_override_values[Thread.current.object_id]
617
+ if field.static? && @ultra_settings_memoized_values.include?(name)
618
+ memoized = true
619
+ memoized_value = @ultra_settings_memoized_values[name]
620
+ end
621
+ end
596
622
  use_override = override_values&.include?(name)
597
623
 
598
- if field.static? && !use_override && @ultra_settings_memoized_values.include?(name)
599
- return @ultra_settings_memoized_values[name]
624
+ if memoized && !use_override
625
+ return memoized_value
600
626
  end
601
627
 
602
628
  value = nil