Permalink
Browse files

moving stuff around

  • Loading branch information...
1 parent ef8b2d9 commit 98ade353666ac82fd71418eed635f70848441936 @codeprimate committed Aug 30, 2009
Showing with 261 additions and 14 deletions.
  1. +1 −11 Manifest.txt
  2. +1 −1 README.rdoc
  3. +2 −2 Rakefile
  4. +36 −0 genericgenerator.gemspec
  5. +221 −0 lib/genericgenerator.rb
View
@@ -1,11 +1 @@
-History.txt
-Manifest.txt
-PostInstall.txt
-README.rdoc
-Rakefile
-lib/codeprimate-generator.rb
-script/console
-script/destroy
-script/generate
-test/test_codeprimate-generator.rb
-test/test_helper.rb
+["Rakefile" , "PostInstall.txt" , "README.rdoc" , "genericgenerator.gemspec" , "History.txt" , "manifest.txt" , "lib" , "lib/genericgenerator.rb" , "test" , "script" , "script/destroy" , "script/generate" , "script/console" ]
View
@@ -1,6 +1,6 @@
= codeprimate-generator
-http://github.com/codeprimate/codeprimate-generator
+http://github.com/codeprimate/genericgenerator
== DESCRIPTION:
View
@@ -2,15 +2,15 @@ require 'rubygems'
gem 'hoe', '>= 2.1.0'
require 'hoe'
require 'fileutils'
-require './lib/codeprimate-generator'
+require './lib/generic-generator'
Hoe.plugin :newgem
# Hoe.plugin :website
# Hoe.plugin :cucumberfeatures
# Generate all the Rake tasks
# Run 'rake -T' to see list of generated tasks (from gem root directory)
-$hoe = Hoe.spec 'codeprimate-generator' do
+$hoe = Hoe.spec 'generic-generator' do
self.developer 'Patrick Morgan', 'patrick.morgan@masterwebdesign.net'
#self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
self.rubyforge_name = self.name # TODO this is default value
View
@@ -0,0 +1,36 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{genericgenerator}
+ s.version = "0.1.0"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Patrick Morgan"]
+ s.date = %q{2009-08-30}
+ s.description = %q{GenericGenerator is an inheritable class that aids in quick generaration of data}
+ s.email = %q{patrick.morgan@masterwebdesign.net}
+ #s.extra_rdoc_files = ["README.md", "LICENSE"]
+ s.files = ["README.rdoc" , "History.txt" , "lib/genericgenerator.rb" ]
+ s.has_rdoc = true
+ s.homepage = %q{http://github.com/codeprimate/generator}
+ s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ a.rubyforge_project = %q{genericgenerator}
+ s.rubygems_version = %q{1.3.0}
+ s.summary = %q{GenericGenerator is an inheritable class that aids in quick generaration of data.}
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 2
+
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<faker>, [])
+ s.add_runtime_dependency(%q<ar-extensions>, [])
+ else
+ s.add_runtime_dependency(%q<faker>, [])
+ s.add_runtime_dependency(%q<ar-extensions>, [])
+ else
+ s.add_runtime_dependency(%q<faker>, [])
+ s.add_runtime_dependency(%q<ar-extensions>, [])
+ end
+end
View
@@ -0,0 +1,221 @@
+module Codeprimate
+ VERSION = "0.1.0"
+ class GenericGenerator
+ require 'faker'
+
+ @fields = []
+ @model_klass = nil
+ @generator = lambda{nil}
+ @associated = {}
+ @validated = false
+ @generated = false
+ @before_block = Proc.new{}
+ @after_block = Proc.new{}
+
+ # Set the generator model, accepts a Class
+ def self.set_model(model)
+ @model_klass = model
+ end
+
+ # Specify a list of field names used by the generator. Accepts an arbitrary
+ # number of Symbol's as arguments
+ def self.has_fields(*field_names)
+ @fields = field_names
+ end
+
+ # Specify a dependent Model, and generate data for it.
+ #
+ # Possible options:
+ #
+ # :generator => GenericGenerator (Required. Specify the generator)
+ # :count => Integer (Required. Specify the number of records to create)
+ # :as => Symbol (Optional. Specify a polymorphic type)
+ # :fixture => String (Optional. Override with filename)
+ #
+ def self.has_many(assoc_model, options={})
+ raise "Specify generator for 'has_many'" if options[:generator].to_s.empty?
+ raise "Invalid generator" unless options[:generator].is_a?(Class)
+ raise "Invalid generator" unless options[:generator].respond_to?("generate!")
+ @associated ||= {}
+ @associated[assoc_model] = options
+ end
+
+ # private
+ def self.fields
+ @fields
+ end
+
+ # private
+ def self.model
+ @model_klass
+ end
+
+ # private
+ def self.before_block
+ @before_block
+ end
+
+ # private
+ def self.after_block
+ @after_block
+ end
+
+ # Generate Random Data
+ #
+ # Example:
+ #
+ # FoobarGenerator.generate!(100) => Generate 100 Foobars
+ # FoobarGenerator.generate!(50, {:user_id => 10}) =>
+ # Generate 50 Foobars, with default data
+ def self.generate!(count=1, default_values={})
+ validate_generator
+ puts " * Generating #{count} #{model.to_s.pluralize}..."
+ run_before
+ data = self.generate_data(count, default_values)
+ model.import(fields, data, {:validate => false})
+ @generated = true
+ generate_associations!
+ run_after
+ return true
+ end
+
+ # private
+ def self.generate_associations!
+ raise "Cannot create associations until generate! is called" unless @generated
+ puts " - Generating associations for #{model.to_s}..."
+ assoc_data = []
+ @associated ||= {}
+ @associated.each_pair do |assoc, options|
+ opts = {:foreign_key => model.to_s.foreign_key, :count => 1, :as => false}.merge(options)
+ default_values = {}
+ puts " - Generating #{assoc.to_s} associations (#{opts[:count]} per #{model.to_s})..."
+
+ # Load fixture if specified
+ if opts[:fixture]
+ options[:generator].class_eval "fixture '#{opts[:fixture]}'"
+ end
+
+ options[:generator].run_before
+
+ model.find(:all, :select => :id).each do |m|
+ id = m.id
+ if opts[:as]
+ # Add polymorphic association keys
+ polymorphic_base = opts[:as].to_s
+ polymorphic_id = (polymorphic_base + '_id').to_sym
+ polymorphic_type = (polymorphic_base + '_type').to_sym
+ default_values[polymorphic_id] = id
+ default_values[polymorphic_type] = m.class.to_s
+ else
+ # Or just set the foreign key
+ default_values[opts[:foreign_key]] = id
+ end
+ default_values = default_values.symbolize_keys.merge((options[:defaults] || {}))
+ assoc_data += options[:generator].generate_data(opts[:count].to_i, default_values)
+ end
+
+ options[:generator].model.import(options[:generator].fields, assoc_data, {:validate => false})
+ options[:generator].run_after
+ end
+ end
+
+ # private
+ def self.generate_data(count=1, default_values={})
+ return Array.new(count){new_record(default_values)}
+ end
+
+ # private
+ def self.new_record(default_values={})
+ validate_generator
+ data = run_generator(default_values)
+ return fields.inject(out=[]){|out, f| out << data[f]}
+ end
+
+ # private
+ def self.run_generator(default_values={})
+ return @generator.call(default_values).merge(default_values)
+ end
+
+ # private
+ def self.validate_generator
+ unless @validated
+ raise "Model not specified, use 'set_model Modelname' declaration" if model.nil?
+ raise "No fields specified, use 'has_fields :field1, :field2' declaration" if fields.empty?
+ raise "Is the 'ar-extensions' module loaded?" unless @model_klass.respond_to?("import")
+ @validated = true
+ end
+ end
+
+ # Cache data for key using value returned from block
+ def self.cache_data(key, &block)
+ @cache_block ||= {}
+ @cache_block[key] = block || Proc.new{}
+ end
+
+ # private
+ def self.cache_for(key)
+ @cache ||= {}
+ @cache[key] ||= @cache_block[key].call
+ end
+
+ # private
+ def self.cache_size(key)
+ @cache_size ||= {}
+ @cache_size[key] ||= cache_for(key).size
+ end
+
+ # Clear cache for key. Use ":all" as argument to clear entire cache
+ def self.clear_cache(key = :all)
+ if key == :all
+ @cache = {}
+ @cache_size = {}
+ @cache_block = {}
+ else
+ @cache ||= {}
+ @cache_size ||= {}
+ @cache_block ||= {}
+ @cache[key] = nil
+ @cache_size[key] = nil
+ @cache_block[key] = nil
+ end
+ end
+
+ # Get random data from cache identified by key
+ def self.get_random(key)
+ cache_for(key)[rand(cache_size(key) - 1)]
+ end
+
+ # Specify random data generator block
+ def self.generator(&block)
+ @generator = block
+ end
+
+ # Load YAML into cache for key ":fixture"
+ def self.fixture(filename)
+ clear_cache(:fixture)
+ cache_data(:fixture) do
+ YAML.load(File.read(filename))
+ end
+ end
+
+ # Specify block to be executed before generation
+ def self.before(&block)
+ @before_block = block
+ end
+
+ # Specify block to be executed after generation
+ def self.after(&block)
+ @after_block = block
+ end
+
+ # private
+ def self.run_before
+ before_block.call if before_block
+ end
+
+ # private
+ def self.run_after
+ after_block.call if after_block
+ end
+ end
+end

0 comments on commit 98ade35

Please sign in to comment.