Module: Lich::Common::Vars
- Defined in:
- documented/common/vars.rb,
documented/vars.rb
Overview
Provides persistent variable storage per game/character combination. Variables are automatically loaded from SQLite database on first access and periodically saved every 5 minutes via background thread.
All keys are normalized to strings for consistent access regardless of whether they’re accessed via bracket notation or method syntax.
Constant Summary collapse
- @@vars =
Hash.new
- @@md5 =
nil- @@load_state =
LoadState::UNLOADED
- @@load =
Proc that loads variables from database on first access
proc { Lich.db_mutex.synchronize { if @@load_state == LoadState::UNLOADED @@load_state = LoadState::LOADING begin h = Lich.db.get_first_value( 'SELECT hash FROM uservars WHERE scope=?;', ["#{XMLData.game}:#{XMLData.name}".encode('UTF-8')] ) rescue SQLite3::BusyException sleep 0.1 retry end if h begin hash = Marshal.load(h) # Normalize all keys to strings during load hash.each { |k, v| @@vars[normalize_key(k)] = v } @@md5 = Digest::MD5.hexdigest(hash.to_s) rescue StandardError => e respond "--- Lich: error: #{e}" respond e.backtrace[0..2] end end @@load_state = LoadState::LOADED end } nil }
- @@save =
Proc that saves variables to database if modified
proc { Lich.db_mutex.synchronize { if @@load_state == LoadState::LOADED current_md5 = Digest::MD5.hexdigest(@@vars.to_s) if current_md5 != @@md5 @@md5 = current_md5 blob = SQLite3::Blob.new(Marshal.dump(@@vars)) begin Lich.db.execute( 'INSERT OR REPLACE INTO uservars(scope,hash) VALUES(?,?);', ["#{XMLData.game}:#{XMLData.name}".encode('UTF-8'), blob] ) rescue SQLite3::BusyException sleep 0.1 retry end end end } nil }
Class Method Summary collapse
-
.[](name) ⇒ Object?
Retrieves a variable value by name.
-
.[]=(name, val) ⇒ Object?
Sets a variable value by name.
-
.list ⇒ Hash
Returns a duplicate of all variables as a Hash.
-
.method_missing(method_name, *args) ⇒ Object?
Handles dynamic method calls for variable access.
-
.normalize_key(key) ⇒ String
private
Normalizes a key to a string for consistent storage and retrieval.
-
.respond_to_missing?(method_name, _include_private = false) ⇒ Boolean
Declares that method_missing can respond to valid Ruby method names.
-
.save ⇒ nil
Immediately saves all variables to the database.
Class Method Details
.[](name) ⇒ Object?
Retrieves a variable value by name
Keys are normalized to strings, so symbols and strings are equivalent.
92 93 94 95 |
# File 'documented/vars.rb', line 92 def Vars.[](name) @@load.call unless @@load_state == LoadState::LOADED @@vars[normalize_key(name)] end |
.[]=(name, val) ⇒ Object?
Sets a variable value by name
Keys are normalized to strings, so symbols and strings are equivalent.
103 104 105 106 107 108 109 110 111 |
# File 'documented/vars.rb', line 103 def Vars.[]=(name, val) @@load.call unless @@load_state == LoadState::LOADED key = normalize_key(name) if val.nil? @@vars.delete(key) else @@vars[key] = val end end |
.list ⇒ Hash
Returns a duplicate of all variables as a Hash
117 118 119 120 |
# File 'documented/vars.rb', line 117 def Vars.list @@load.call unless @@load_state == LoadState::LOADED @@vars.dup end |
.method_missing(method_name, *args) ⇒ Object?
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'documented/common/vars.rb', line 185 def Vars.method_missing(method_name, *args) @@load.call unless @@load_state == LoadState::LOADED # Handle []= called through method_missing if method_name == :[]= && args.length == 2 key = normalize_key(args[0]) if args[1].nil? @@vars.delete(key) else @@vars[key] = args[1] end # Handle [] called through method_missing elsif method_name == :[] && args.length == 1 @@vars[normalize_key(args[0])] # Handle setter methods (e.g., foo=) elsif method_name.to_s.end_with?('=') key = normalize_key(method_name.to_s.chop) if args[0].nil? @@vars.delete(key) else @@vars[key] = args[0] end # Handle getter methods else @@vars[normalize_key(method_name.to_s)] end end |
.normalize_key(key) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Normalizes a key to a string for consistent storage and retrieval
39 40 41 |
# File 'documented/common/vars.rb', line 39 def self.normalize_key(key) key.to_s end |
.respond_to_missing?(method_name, _include_private = false) ⇒ Boolean
Declares that method_missing can respond to valid Ruby method names
Only returns true for method names that could be valid Ruby identifiers or the bracket operators. This helps catch obvious typos while still allowing dynamic variable access.
164 165 166 167 168 169 170 171 172 173 174 |
# File 'documented/vars.rb', line 164 def Vars.respond_to_missing?(method_name, _include_private = false) method_str = method_name.to_s # Allow bracket operators return true if method_name == :[] || method_name == :[]= # Allow valid Ruby method names (with or without trailing =) # Valid: starts with letter or underscore, contains letters/digits/underscores # and optionally ends with = for setters method_str.match?(/\A[a-zA-Z_][a-zA-Z0-9_]*=?\z/) end |
.save ⇒ nil
Immediately saves all variables to the database
126 127 128 |
# File 'documented/vars.rb', line 126 def Vars.save @@save.call end |