# File lib/object_daddy.rb, line 94 def gather_exemplars return if exemplars_generated self.generators ||= {} if superclass.respond_to?(:gather_exemplars) superclass.gather_exemplars self.generators = (superclass.generators).merge(generators).dup end exemplar_path.each do |raw_path| path = File.join(raw_path, "#{underscore(name)}_exemplar.rb") load(path) if File.exists?(path) end self.exemplars_generated = true end
# File lib/object_daddy.rb, line 90 def generates_subclass(subclass_name) @concrete_subclass_name = subclass_name.to_s end
register a generator for an attribute of this class #generator_for :foo do |prev| … end #generator_for :foo do … end #generator_for :foo, value #generator_for :foo => value #generator_for :foo, :class => GeneratorClass #generator_for :foo, :method => :method_name
# File lib/object_daddy.rb, line 51 def generator_for(handle, args = {}, &block) if handle.is_a?(Hash) raise ArgumentError, "only specify one attr => value pair at a time" unless handle.keys.length == 1 gen_data = handle handle = gen_data.keys.first args = gen_data[handle] end raise ArgumentError, "an attribute name must be specified" unless handle = handle.to_sym unless args.is_a?(Hash) unless block retval = args block = lambda { retval } # lambda { args } results in returning the empty hash that args gets changed to end args = {} # args is assumed to be a hash for the rest of the method end if args[:start] block ||= lambda { |prev| prev.succ } end if args[:method] h = { :method => args[:method].to_sym } h[:start] = args[:start] if args[:start] record_generator_for(handle, h) elsif args[:class] raise ArgumentError, "generator class [#{args[:class].name}] does not have a :next method" unless args[:class].respond_to?(:next) record_generator_for(handle, :class => args[:class]) elsif block raise ArgumentError, "generator block must take an optional single argument" unless (-1..1).include?(block.arity) # NOTE: lambda {} has an arity of -1, while lambda {||} has an arity of 0 h = { :block => block } h[:start] = args[:start] if args[:start] record_generator_for(handle, h) else raise ArgumentError, "a block, :class generator, :method generator, or value must be specified to generator_for" end end
Creates a valid instance of this class, using any known generators. The generated instance is yielded to a block if provided.
# File lib/object_daddy.rb, line 28 def spawn(args = {}) gather_exemplars if @concrete_subclass_name return block_given? ? const_get(@concrete_subclass_name).spawn(args) {|instance| yield instance} : const_get(@concrete_subclass_name).spawn(args) end generate_values(args) instance = new args.each_pair do |attribute, value| instance.send("#{attribute}=", value) # support setting of mass-assignment protected attributes end yield instance if block_given? instance end
# File lib/object_daddy.rb, line 127 def record_generator_for(handle, generator) self.generators ||= {} raise ArgumentError, "a generator for attribute [:#{handle}] has already been specified" if (generators[handle] || {})[:source] == self generators[handle] = { :generator => generator, :source => self } end
we define an underscore helper ourselves since the ActiveSupport isn't available if we're not using Rails
# File lib/object_daddy.rb, line 123 def underscore(string) string.gsub(/([a-z])([A-Z])/, '\1_\2').downcase end
# File lib/object_daddy.rb, line 171 def generate_missing(args) if presence_validated_attributes and !presence_validated_attributes.empty? req = {} (presence_validated_attributes.keys - args.keys).each {|a| req[a.to_s] = true } # find attributes required by validates_presence_of not already set belongs_to_associations = reflect_on_all_associations(:belongs_to).to_a missing = belongs_to_associations.select { |a| req[a.name.to_s] or req[a.primary_key_name.to_s] } if create_scope = scope(:create) missing.reject! { |a| create_scope.include?(a.primary_key_name) } end missing.reject! { |a| [a.name, a.primary_key_name].any? { |n| args.stringify_keys.include?(n.to_s) } } missing.each {|a| args[a.name] = a.class_name.constantize.generate } end end
# File lib/object_daddy.rb, line 135 def generate_values(args) (generators || {}).each_pair do |handle, gen_data| next if args.include?(handle) or args.include?(handle.to_s) generator = gen_data[:generator] if generator[:block] process_generated_value(args, handle, generator, generator[:block]) elsif generator[:method] method = method(generator[:method]) if method.arity == 1 process_generated_value(args, handle, generator, method) else args[handle] = method.call end elsif generator[:class] args[handle] = generator[:class].next end end generate_missing(args) end
# File lib/object_daddy.rb, line 157 def process_generated_value(args, handle, generator, block) if generator[:start] value = generator[:start] generator.delete(:start) else if block.arity == 0 value = block.call else value = block.call(generator[:prev]) end end generator[:prev] = args[handle] = value end