-
Notifications
You must be signed in to change notification settings - Fork 3
/
accessor.rb
160 lines (138 loc) · 4.16 KB
/
accessor.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#
# Helper class to make accessing record specific settings easier
#
class SettingAccessors::Accessor
def initialize(record)
@record = record
@temp_settings = {}
end
#
# Gets a setting's value
#
def [](key)
has_key?(key) ? @temp_settings[key.to_sym] : SettingAccessors.setting_class.get(key, @record)
end
#
# Tries to fetch a setting value using the provided key and #[].
# It will only return the +default+ value if there is
# - no temporary setting with the given key AND
# - no already persisted setting (see #[])
#
def fetch(key, default = nil)
result = self[key]
return default if result.nil? && !has_key?(key)
result
end
def has_key?(key)
@temp_settings.has_key?(key.to_sym)
end
#
# Writes a setting's value
#
def []=(key, val)
set_value_before_type_cast(key, val)
@temp_settings[key.to_sym] = SettingAccessors::Internal.converter(value_type(key)).convert(val)
end
#
# Tries to find a setting for this record.
# If none is found, will return the default setting value
# specified in the setting config file.
#
def get_or_default(key)
fetch key, SettingAccessors.setting_class.get_or_default(key, @record)
end
#
# Tries to find a setting for this record first.
# If none is found, tries to find a global setting with the same name
#
def get_or_global(key)
fetch key, SettingAccessors.setting_class.get(key)
end
#
# Tries to find a setting for this record first,
# if none is found, it will return the given value instead.
#
def get_or_value(key, value)
fetch key, value
end
def get_with_fallback(key, fallback = nil)
return self[key] if fallback.nil?
case fallback.to_s
when 'default' then get_or_default(key)
when 'global' then get_or_global(key)
else get_or_value(key, fallback)
end
end
#
# @return [String] the setting's value type in the +@record+'s context
#
def value_type(key)
SettingAccessors::Internal.setting_value_type(key, @record)
end
#----------------------------------------------------------------
# ActiveRecord Helper Methods Emulation
#----------------------------------------------------------------
def value_was(key, fallback = nil)
return SettingAccessors.setting_class.get(key, @record) if fallback.nil?
case fallback.to_s
when 'default' then SettingAccessors.setting_class.get_or_default(key, @record)
when 'global' then SettingAccessors.setting_class.get(key)
else fallback
end
end
def value_changed?(key)
self[key] != value_was(key)
end
def value_before_type_cast(key)
SettingAccessors::Internal.lookup_nested_hash(@values_before_type_casts, key.to_s) || self[key]
end
protected
#
# Keeps a record of the originally set value for a setting before it was
# automatically converted.
#
def set_value_before_type_cast(key, value)
@values_before_type_casts ||= {}
@values_before_type_casts[key.to_s] = value
end
#
# Validates the new setting values.
# If there is an accessor for the setting, the errors will be
# directly forwarded to it, otherwise to :base
#
# Please do not call this method directly, use the IntegrationValidator
# class instead, e.g.
#
# validates_with SettingAccessors::IntegrationValidator
#
def validate!
@temp_settings.each do |key, value|
validation_errors = SettingAccessors.setting_class.validation_errors(key, value, @record)
validation_errors.each do |message|
if @record.respond_to?("#{key}=")
@record.errors.add(key, message)
else
@record.errors.add :base, :invalid_setting, :name => key, :message => message
end
end
end
end
#
# Saves the new setting values into the database
# Please note that there is no check if the values changed their
# in the meantime.
#
# Also, this method expects that the settings were validated
# before using #validate! and will therefore not perform
# validations itself.
#
def persist!
@temp_settings.each do |key, value|
Setting.create_or_update(key, value, @record)
end
flush!
end
def flush!
@temp_settings = {}
end
end