require 'metaid'class Object def solidify self endendclass Range def solidify to_a.sort_by {|x| rand}.fetch(0) endendmodule Prototyping def new instance = self.class.allocate instance.class.instance_variable_get(:@prototype_copy).each do |var| instance.instance_variable_set :"@#{var}", instance_variable_get(:"@#{var}") end instance.class.instance_variable_get(:@prototype_solidify).each do |var| instance.instance_variable_set :"@#{var}", instance_variable_get(:"@#{var}").solidify end instance end module Meta def copy *names @prototype_copy ||= [] names.each do |name| @prototype_copy << name end end def solidify *names @prototype_solidify ||= [] names.each do |name| @prototype_solidify << name end end end def self.append_features klass super klass.meta_eval {include Meta} endendclass Person include Prototyping attr_reader :name, :age, :strength copy :name, :age solidify :strength def initialize name, age, strength @name, @age, @strength = name, age, strength endend# Create a new instance of Person to be used as a prototypescott_prototype = Person.new("Scott", 17, 1 .. 2)puts scott_prototype.inspect # #<Person:0x27f05b0 @strength=1..2, @age=17, @name=\"Scott\"># Create a new instance of Person from the prototype# Copies or "solidify"s instance variables depending on the class definition# In this case, solidifies the range @strengthscott_instance = scott_prototype.newputs scott_instance.inspect# Either:# #<Person:0x27f0430 @strength=1, @age=17, @name=\"Scott\"># or# #<Person:0x27f0430 @strength=2, @age=17, @name=\"Scott\">