我想要类似下面的东西,但希望它可以重复使用不同的类。
如何重构这段代码,所以只需要很少的努力就可以将它包含在一个类中,并且只要调用new,该类就会自动收集实例?
我尝试了各种各样的事情,例如重写新的或初始化但却无法让魔法发生。
class Person
@@people_instances = []
def initialize
@@people_instances << self
end
def self.instances
@@people_instances
end
end
People.new
People.new
Poople.instances
=> [#<Person:0x000001071a7e28>, #<Person:0x000001071a3828>]
在下面的一些反馈之后,我认为答案不是将实例放在一个类变量中,因为它将永远留在内存中。 Rails缓存也不太合适,因为我不需要实例持久化。
以下代码使用类实例变量而不是类变量。
http://www.dzone.com/snippets/class-variables-vs-class
class Employee
class << self; attr_accessor :instances; end
def store
self.class.instances ||= []
self.class.instances << self
end
def initialize name
@name = name
end
end
class Overhead < Employee; end
class Programmer < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size # => 2
puts Programmer.instances.size # => 1
这些实例变量是否对每个rails请求都是唯一的,还是会持续存在?
答案 0 :(得分:4)
更新的答案
如果您希望仅在请求期间保持可用,则之前答案的无可以执行此操作。仅在请求 - 响应周期期间保持其可用的解决方案是使用在控制器方法中分配的线程本地,例如:
class YourController < ApplicationController
around_filter :cache_objects
protected
def cache_objects
Thread.current[:my_objects] = ['my-object', 'my-other-object']
yield
ensure
Thread.current[:my_objects]
end
end
然后,在需要它的代码中,你只需执行Thread.current[:my_objects]
并做任何你想做的事情。您需要使用 around_filter ,因为您的Web框架或服务器结构可能会尝试重用线程,唯一真正的解决方案是在请求完成后清理它们以避免内存泄漏。
OLD ANSWER
不确定您要做什么,但您可以使用ObjectSpace
轻松选择每个班级的实例:
ObjectSpace.each_object(String) { |s| puts(s) }
如果你需要的是数据库缓存,只需使用Rails缓存,加载这些对象一次,然后将它们保存在缓存中。使用Rails缓存时,您只需将对象发送到缓存:
Rails.cache.write( "my_cached_objects", [ 'first-object', 'second-object' ] )
然后把它们带到其他地方:
Rails.cache.fetch("my_cached_objects") do
# generate your objects here if there was a cache miss
[ 'first-object', 'second-object' ]
end
正如您所看到的,您甚至不必调用cache.write
,您只需使用fetch,每当有缓存未命中时,将调用给定的块并创建对象。
您可以阅读有关铁路缓存here的更多信息,您可以看到ActiveSupport::Cache::Store here支持的所有方法。
另一种不使用ObjectSpace
但仍使用丑陋解决方案的方法,现在使用alias_method
:
module Counter
def self.included( base )
base.extend(ClassMethods)
base.class_eval do
alias_method :initialize_without_counter, :initialize
alias_method :initialize, :initialize_with_counter
end
end
def count_class_variable_name
:"@@#{self.class.name.downcase}_instances"
end
def initialize_with_counter( *args )
unless self.class.class_variable_defined?(count_class_variable_name)
self.class.class_variable_set(count_class_variable_name, [])
end
self.class.class_variable_get(count_class_variable_name) << self
initialize_without_counter(*args)
end
module ClassMethods
def all_instances
class_variable_get(:"@@#{name.downcase}_instances")
end
end
end
class Person
def initialize
puts 'new person'
end
include Counter
end
p1 = Person.new
p2 = Person.new
p3 = Person.new
puts Person.all_instances.size
答案 1 :(得分:2)
LIB / keeper.rb
def initialize
instance_eval "@@#{self.class.to_s.downcase}_instances ||= []"
instance_eval "@@#{self.class.to_s.downcase}_instances << self"
end
def self.instances
return class_eval "@@#{self.to_s.downcase}_instances"
end
person.rb
class Person
eval File.open('./lib/keeper.rb','rb').read
end
然后这个有效:
Person.new
Person.new
Person.instances