lib/redis/objects.rb in redis-objects-1.7.0 vs lib/redis/objects.rb in redis-objects-2.0.0.alpha
- old
+ new
@@ -99,17 +99,94 @@
attr_writer :redis_objects
def redis_objects
@redis_objects ||= {}
end
- # Set the Redis redis_prefix to use. Defaults to model_name
- def redis_prefix=(redis_prefix) @redis_prefix = redis_prefix end
+ # Toggles whether to use the legacy redis key naming scheme, which causes
+ # naming conflicts in certain cases.
+ attr_accessor :redis_legacy_naming
+ attr_accessor :redis_silence_warnings
+
+ # Set the Redis redis_prefix to use. Defaults to class_name.
+ def redis_prefix=(redis_prefix)
+ @silence_warnings_as_redis_prefix_was_set_manually = true
+ @redis_prefix = redis_prefix
+ end
+
def redis_prefix(klass = self) #:nodoc:
- @redis_prefix ||= klass.name.to_s.
- sub(%r{(.*::)}, '').
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ @redis_prefix ||=
+ if redis_legacy_naming
+ redis_legacy_prefix(klass)
+ else
+ redis_legacy_naming_warning_message(klass)
+ redis_modern_prefix(klass)
+ end
+
+ @redis_prefix
+ end
+
+ def redis_modern_prefix(klass = self) #:nodoc:
+ klass.name.to_s.
+ gsub(/::/, '__'). # Nested::Class => Nested__Class
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). # ClassName => Class_Name
+ gsub(/([a-z\d])([A-Z])/,'\1_\2'). # className => class_Name
downcase
+ end
+
+ def redis_legacy_prefix(klass = self) #:nodoc:
+ klass.name.to_s.
+ sub(%r{(.*::)}, ''). # Nested::Class => Class (problematic)
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). # ClassName => Class_Name
+ gsub(/([a-z\d])([A-Z])/,'\1_\2'). # className => class_Name
+ downcase
+ end
+
+ # Temporary warning to help with migrating key names
+ def redis_legacy_naming_warning_message(klass)
+ # warn @silence_warnings_as_redis_prefix_was_set_manually.inspect
+ unless redis_legacy_naming || redis_silence_warnings || @silence_warnings_as_redis_prefix_was_set_manually
+ modern = redis_modern_prefix(klass)
+ legacy = redis_legacy_prefix(klass)
+ if modern != legacy
+ warn <<EOW
+WARNING: In redis-objects 2.0.0, key naming will change to fix longstanding bugs.
+Your class #{klass.name.to_s} will be affected by this change!
+Current key prefix: #{legacy.inspect}
+Future key prefix: #{modern.inspect}
+Read more at https://github.com/nateware/redis-objects/issues/231
+EOW
+ end
+ end
+ end
+
+ def migrate_redis_legacy_keys
+ cursor = 0
+ legacy = redis_legacy_prefix
+ total_keys = 0
+ if legacy == redis_prefix
+ raise "Failed to migrate keys for #{self.name.to_s} as legacy and new redis_prefix are the same (#{redis_prefix})"
+ end
+ warn "Migrating keys from #{legacy} prefix to #{redis_prefix}"
+
+ loop do
+ cursor, keys = redis.scan(cursor, :match => "#{legacy}:*")
+ total_keys += keys.length
+ keys.each do |key|
+ # Split key name apart on ':'
+ base_class, id, name = key.split(':')
+
+ # Figure out the new name
+ new_key = redis_field_key(name, id=id, context=self)
+
+ # Rename the key
+ warn "Rename '#{key}', '#{new_key}'"
+ ok = redis.rename(key, new_key)
+ warn "Warning: Rename '#{key}', '#{new_key}' failed: #{ok}" if ok != 'OK'
+ end
+ break if cursor == "0"
+ end
+
+ warn "Migrated #{total_keys} total number of redis keys"
end
def redis_options(name)
klass = first_ancestor_with(name)
return klass.redis_objects[name.to_sym] || {}