Permalink
Browse files

version 0.0.1

  • Loading branch information...
1 parent 04e86c9 commit 5c16f52e2544db99b782c9644129d740ffd94d36 @garysweaver committed Nov 1, 2012
Showing with 155 additions and 96 deletions.
  1. +8 −35 README.md
  2. +3 −0 bin/stepford
  3. +2 −0 lib/stepford.rb
  4. +18 −0 lib/stepford/cli.rb
  5. +28 −0 lib/stepford/common.rb
  6. +90 −32 lib/stepford/factory_girl.rb
  7. +0 −26 lib/stepford/options.rb
  8. 0 lib/stepford/railtie.rb
  9. +6 −3 stepford.gemspec
View
@@ -17,50 +17,23 @@ Then run:
#### Factory Girl
-To automatically create factories for [Factory Girl][factory_girl] from models, somewhere in tests, use:
+To automatically generate factories for [Factory Girl][factory_girl] from models, type this at command-line:
- # create default factories for all models
- Stepford::FactoryGirl.define_factories
+ bundle exec stepford factories
-or:
+That will create a `test/factories` directory and put a `some_model.rb` for each model into it with a starter FactoryGirl factory definition that may or may not work for you.
- Stepford::FactoryGirl.define_factories(:my_model_name_1, :my_model_name_2, :my_model_name_3)
+Or, to generate a single file with all factories in `spec/factories.rb`, you'd use:
-TODO: need to somehow hook in so that we aren't overwriting other factories.
+ bundle exec stepford factories --single --path spec
-#### Machinist
+Or it will figure it out yourself that you want a single file if the path ends in `.rb`:
-Feel free to fork and add support.
-
-### Configuration
-
- Stepford.configure do
- @debug = true
- @model_attr_match_test_data = {
- /|*.\_at,*.\_on,|/ => Time.now
- }
- @model_datatype_test_data = {
- string: lambda{|c|generate(:random_string)},
- integer: lambda{|c|Random.rand(9999)},
- decimal: lambda{|c|Random.rand(9999.9)},
- datetime: Time.now,
- timestamp: Time.now,
- time: Time.now,
- date: Time.now,
- binary: Random.bytes(8),
- boolean: true,
- xml: lambda{|c|"<test>#{generate(:random_string)}</test>"},
- ts_vector: nil
- }
- end
-
-* debug is for debugging.
-* attr_match_test_data is hash of regexp to match model column names.
-* model_datatype_test_data is hash of regexp to match model column types.
+ bundle exec stepford factories --path spec/support/factories.rb
### License
Copyright (c) 2012 Gary S. Weaver, released under the [MIT license][lic].
[factory_girl]: https://github.com/thoughtbot/factory_girl/
-[lic]: http://github.com/garysweaver/restful_json/blob/master/LICENSE
+[lic]: http://github.com/garysweaver/stepford/blob/master/LICENSE
View
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+require 'stepford'
+require 'stepford/cli'
View
@@ -1 +1,3 @@
require 'stepford/version'
+require 'stepford/common'
+
View
@@ -0,0 +1,18 @@
+require 'thor'
+
+module Stepford
+ class CLI < Thor
+ desc "factories", "create FactoryGirl factories"
+ method_option :single, :desc => "Put all factories into a single file"
+ method_option :path, :desc => "Pathname of file to contain factories or path of directory to contain factory/factories"
+ def factories()
+ # load Rails environment
+ require './config/environment'
+ # load FactoryGirl and generate factories
+ require 'stepford/factory_girl'
+ exit Stepford::FactoryGirl.generate_factories(options) ? 0 : 1
+ end
+ end
+end
+
+Stepford::CLI.start
@@ -0,0 +1,28 @@
+module Stepford
+ class Common
+ def self.value_for(column_name, type)
+ case type
+ when :string
+ "'Test #{column_name.titleize}'"
+ when :integer
+ '123'
+ when :decimal
+ '1.23'
+ when :datetime
+ '{ 2.weeks.ago }'
+ when :timestamp
+ '{ 2.weeks.ago }'
+ when :binary
+ '0b010101'
+ when :boolean
+ 'true'
+ when :xml
+ '<test>Test #{column_name.titleize}</test>'
+ when :ts_vector
+ 'nil'
+ else
+ 'nil'
+ end
+ end
+ end
+end
@@ -1,48 +1,106 @@
require 'factory_girl'
+require 'stepford/common'
module Stepford
class FactoryGirl
- def self.define_factories(model_names)
- model_names = Array.wrap(model_names)
- if model_names.size > 0
- # Assume the people want them all so...
- # Load all the models and let's crap out if fails to load any models, as that is probably not a good thing
- Dir.glob(File.join(Rails.root, 'app', 'models', '*.rb').each { |file| require file }
- models = ActiveRecord::Base.descendants.collect { |type| type.name }.sort
+ def self.generate_factories(options={})
+ factories = {}
+
+ expected = {}
+ Dir[File.join('app','models','*.rb').to_s].each do |filename|
+ model_name = File.basename(filename).sub(/.rb$/, '')
+ load File.join('app','models',"#{model_name}.rb")
+ model_class = model_name.camelize.constantize
+ next unless model_class.ancestors.include?(ActiveRecord::Base)
+ factory = (factories[model_name.to_sym] ||= [])
+ foreign_keys = []
+ model_class.reflections.collect {|a,b| (expected[b.class_name.underscore.to_sym] ||= []) << model_name; foreign_keys << b.foreign_key.to_sym; "association #{b.name.to_sym.inspect}, factory: #{b.class_name.underscore.to_sym.inspect}"}.sort.each {|l|factory << l}
+ model_class.columns.collect {|c| "#{c.name.to_sym} #{Stepford::Common.value_for(c.name, c.type)}" unless foreign_keys.include?(c.name.to_sym)}.compact.sort.each {|l|factory << l}
end
- puts "#{self} models: #{model_names.collect{|model_name|model_name.to_sym.inspect}.join(', ')}" if Stepford.debug
- model_names.each do |model_name|
- model_class = model_name.constantize
- FactoryGirl.define do
- factory model_name.to_sym do
- # auto-create associations to other factories
- model_class.reflect_on_all_associations.each do |a|
- association a.name.to_sym, factory: a.model_class.underscore.to_sym
- end
-
- # set all attributes with sample data
- model_class.columns.each do |c|
- send(c.name.to_sym, sample_data(c))
- end
+ failed = false
+ model_to_fixes_required = {}
+ expected.keys.sort.each do |factory_name|
+ unless factories[factory_name.to_sym]
+ puts "#{File.join('app','models',"#{factory_name}.rb")} missing. Model(s) with associations to it: #{expected[factory_name].sort.join(', ')}"
+ expected[factory_name].each do |model_name|
+ (model_to_fixes_required[model_name.to_sym] ||= []) << factory_name.to_sym
end
+ failed = true
end
end
- end
+ model_to_fixes_required.keys.each do |model_to_fix|
+ puts ""
+ puts "In #{model_to_fix}:"
+ model_to_fixes_required[model_to_fix].each do |fix|
+ puts "- comment/remove/fix broken association to #{fix}"
+ end
+ end
+ return false if failed
- private
+ path = File.join('test','factories.rb')
+ if options[:path]
+ if options[:path].end_with?('.rb')
+ path = options[:path]
+ else
+ if options[:single]
+ path = File.join(options[:path],'factories.rb')
+ else
+ path = options[:path]
+ end
+ end
+ end
+
+ if path.end_with?('.rb')
+ dirpath = File.dirname(path)
+ unless File.directory?(dirpath)
+ puts "Please create this directory first: #{dirpath}"
+ return false
+ end
- def sample_data(column)
- Stepford.model_attr_match_test_data.keys.each do |rexp|
- puts "#{self} checking regexp #{rexp.to_s} to attempt match against column.name #{column.name}" if Stepford.debug
- if rexp ~= column.name
- puts "#{self} regexp #{rexp.to_s} matched column.name #{column.name}" if Stepford.debug
- return Stepford.attr_match_test_data[rexp]
+ File.open(path, "w") do |f|
+ f.puts 'require \'factory_girl_rails\''
+ f.puts ''
+ f.puts 'FactoryGirl.define do'
+ f.puts ' '
+ factories.keys.sort.each do |factory_name|
+ factory = factories[factory_name]
+ write_factory(factory_name, factory, f)
+ f.puts ' '
+ end
+ f.puts "end"
+ end
+ else
+ unless File.directory?(path)
+ puts "Please create this directory first: #{path}"
+ return false
+ end
+
+ factories.keys.sort.each do |factory_name|
+ factory = factories[factory_name]
+ File.open(File.join(path,"#{factory_name}.rb"), "w") do |f|
+ f.puts 'require \'factory_girl_rails\''
+ f.puts ''
+ f.puts 'FactoryGirl.define do'
+ f.puts ' '
+ write_factory(factory_name, factory, f)
+ f.puts ' '
+ f.puts "end"
+ end
end
end
- result = Stepford.model_datatype_test_data[c.type.to_sym]
- puts "#{self} using Stepford.datatype_test_data for type #{column.type.to_sym.inspect}: #{result}" if Stepford.debug
- result
+ return true
+ end
+
+ private
+
+ def self.write_factory(factory_name, factory, f)
+ f.puts " factory #{factory_name.inspect} do"
+ factory.each do |line|
+ f.puts " #{line}"
+ end
+ f.puts " end"
+ end
end
end
@@ -1,26 +0,0 @@
-module Stepford
- class << self
- attr_accessor :debug, :attr_match_test_data, :datatype_test_data
- def configure(&blk); class_eval(&blk); end
- end
-end
-
-Stepford.configure do
- @debug = true
- @attr_match_test_data = {
- /|*.\_at,*.\_on,|/ => Time.now
- }
- @datatype_test_data = {
- string: lambda{|c|generate(:random_string)},
- integer: lambda{|c|Random.rand(9999)},
- decimal: lambda{|c|Random.rand(9999.9)},
- datetime: Time.now,
- timestamp: Time.now,
- time: Time.now,
- date: Time.now,
- binary: Random.bytes(8),
- boolean: true,
- xml: lambda{|c|"<test>#{generate(:random_string)}</test>"},
- ts_vector: nil
- }
-end
No changes.
View
@@ -8,10 +8,13 @@ Gem::Specification.new do |s|
s.authors = ['Gary S. Weaver']
s.email = ['garysweaver@gmail.com']
s.homepage = 'https://github.com/garysweaver/stepford'
- s.summary = %q{The land of Stepford comes to your Ruby testing.}
- s.description = %q{See the README. It's more up-to-date.}
+ s.summary = %q{A utility to assist with Ruby tests.}
+ s.description = %q{Stepford helps you with your tests. See README.}
s.files = Dir['lib/**/*'] + ['Rakefile', 'README.md']
s.license = 'MIT'
- s.add_runtime_dependency 'activerecord'
+ s.add_dependency 'thor'
+ s.add_runtime_dependency 'rails'
s.add_runtime_dependency 'factory_girl'
+ s.executables = %w(stepford)
+ s.require_paths = ["lib"]
end

0 comments on commit 5c16f52

Please sign in to comment.