iron_fixture_extractor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +142 -0
- data/Rakefile +16 -0
- data/iron_fixture_extractor.gemspec +21 -0
- data/lib/fe.rb +37 -0
- data/lib/fe/extractor.rb +132 -0
- data/lib/fe/version.rb +3 -0
- data/lib/iron_fixture_extractor.rb +7 -0
- data/test/basic_usage_test.rb +86 -0
- data/test/config/database.yml +11 -0
- data/test/fe_test_env.rb +84 -0
- data/test/migrations/20120604043601_create_posts.rb +12 -0
- data/test/migrations/20120604043602_create_authors.rb +9 -0
- data/test/migrations/20120604043639_create_comments.rb +13 -0
- data/test/migrations/20120604043808_create_group_members.rb +13 -0
- data/test/migrations/20120604043818_create_groups.rb +9 -0
- data/test/models/author.rb +5 -0
- data/test/models/comment.rb +5 -0
- data/test/models/group.rb +5 -0
- data/test/models/group_member.rb +5 -0
- data/test/models/post.rb +5 -0
- data/test/test_data_migrations/001_create_some_data.rb +14 -0
- data/test/test_helper.rb +10 -0
- metadata +136 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
# TEMP CRAP FOR DEV, COMMENT OUT OR DELETE
|
3
|
+
# USED w ruby 1.9.2
|
4
|
+
# http://dirk.net/2010/04/17/ruby-debug-with-ruby-19x-and-rails-3-on-rvm/
|
5
|
+
gem 'ruby-debug19', :require => 'ruby-debug'
|
6
|
+
gem 'rake'
|
7
|
+
# Specify your gem's dependencies in iron_fixture_extractor.gemspec
|
8
|
+
gemspec
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Joe Goggins
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
# About
|
2
|
+
|
3
|
+
When object factories don't work because your data is too complex and creating manual fixtures is cumbersome and brittle: Iron Fixture Extractor.
|
4
|
+
|
5
|
+
Iron fixture extractor makes extracting complex ActiveRecord dependency graphs from live databases sane. Feed it an array of ActiveRecord objects that have preloaded associations via the .include method or just an adhoc array of ActiveRecord instances you want to capture as fixtures and it will write a bunch of fixture files for usage in your test cases.
|
6
|
+
|
7
|
+
`###
|
8
|
+
,#
|
9
|
+
+#,
|
10
|
+
;+############++++++++++++++++++++++++++++
|
11
|
+
; + `:
|
12
|
+
## +# ++,
|
13
|
+
.++` ;#; :+
|
14
|
+
'' ;+` `;;'
|
15
|
+
;::' `;;. +;;+'
|
16
|
+
:;:;': +;;'' '+'+++:
|
17
|
+
`:';'++. '+''+`; .;;;;;''.
|
18
|
+
:,'''';; `````````
|
19
|
+
|
20
|
+
~|~ _ _ _ |~. _|_ _ _ (~ _|_ _ _ __|_ _ _
|
21
|
+
_|_| (_)| | |~|><||_|| (/_ (_><| | (_|(_ | (_)|
|
22
|
+
|
23
|
+
Iron Fixture Extractor
|
24
|
+
is
|
25
|
+
handy when
|
26
|
+
you require complex data extracted from
|
27
|
+
crusty legacy
|
28
|
+
or
|
29
|
+
big ERP
|
30
|
+
databases
|
31
|
+
for
|
32
|
+
test cases.
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
Add this line to your application's Gemfile:
|
36
|
+
|
37
|
+
gem 'iron_fixture_extractor'
|
38
|
+
|
39
|
+
And then execute:
|
40
|
+
|
41
|
+
$ bundle
|
42
|
+
|
43
|
+
Or install it yourself as:
|
44
|
+
|
45
|
+
$ gem install iron_fixture_extractor
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
The Iron Fixture Extractor gem exposes everything under the Fe
|
49
|
+
namespace, we'll refer to it as "Fe" from here on out.
|
50
|
+
|
51
|
+
Fe is designed to be used in an interactive Ruby shell or Rails console.
|
52
|
+
The idea is to poke around your data via your ActiveRecord models, then
|
53
|
+
once you have a good dataset, use Fe.extract to load it into fixture
|
54
|
+
files you can write tests against.
|
55
|
+
|
56
|
+
This gem is dirt simple--consider reading the source code
|
57
|
+
and test cases directly to clarify any behavioral details this readme
|
58
|
+
doesn't cover.
|
59
|
+
|
60
|
+
### Extract
|
61
|
+
|
62
|
+
Fe.extract 'Post.includes(:comments, :author).limit(1)', name => 'first_post_w_comments_and_authors'
|
63
|
+
|
64
|
+
### Load Fixtures (BE CAREFUL, THIS DELETES EVERYTHING IN THE TARGET TABLES)
|
65
|
+
|
66
|
+
Fe.load_db(:first_post_w_comments_and_authors)
|
67
|
+
|
68
|
+
### Rebuild Fixture Files
|
69
|
+
This uses the fe_manifest.yml's extract_code to re-extract fixtures
|
70
|
+
using the same code used to initially create them. Its handy when the live data changes and you want to refresh the fixture files to reflect it.
|
71
|
+
|
72
|
+
Fe.rebuild(:first_post_w_comments_and_authors)
|
73
|
+
|
74
|
+
## How it works
|
75
|
+
|
76
|
+
### Extract
|
77
|
+
The essense of the Fe.extract algorithm is:
|
78
|
+
|
79
|
+
for each record given to .extract
|
80
|
+
recursively resolve any association pre-loaded in the .association_cache [ActiveRecord] method
|
81
|
+
add it to a set of records keyed by model name
|
82
|
+
write each set of records as a <model_name>.yml fixture file to test/fe_fixtures/<the :name specified to .extract>/
|
83
|
+
|
84
|
+
The magic is all in the recursive usage of ActiveRecord::Base#association_cache. This means, that if you do something like:
|
85
|
+
|
86
|
+
p=Post.first
|
87
|
+
p.comments
|
88
|
+
Fe.extract(p)
|
89
|
+
|
90
|
+
you will get 2 fixture files: 1 post record fixture (not-surprising) and N comment fixtures because p.association_cache is populated for :comments on the post instance p.
|
91
|
+
|
92
|
+
### Load Fixtures
|
93
|
+
This uses the same mechanism as Rails' `rake db:fixtures:load`, aka ActiveRecord::Fixtures.create_fixtures method
|
94
|
+
|
95
|
+
### Rebuild Fixture Files
|
96
|
+
This is just like .extract, except the code used to do the query is
|
97
|
+
pulled from the fe_manifest.yml file.
|
98
|
+
|
99
|
+
## Missing Features
|
100
|
+
* rake fe:fixtures:extract, fe:fixtures:load_db, and fe:fixtures:rebuild
|
101
|
+
ought exist and be available in Rails context via a Railtie. They would simply wrap the capabilities of Fe's extract, load_db, and rebuild method.
|
102
|
+
* If you give a non-string arg to .extract, the manifest should resolve
|
103
|
+
the .extract_code to be a bunch of look-ups by primary key ala [Post.find(1),Comment.find(2)].
|
104
|
+
* The output of each of the main commands should be meaningful, aka,
|
105
|
+
make extractor implement a sensible .to_s and .inspect
|
106
|
+
* load_db should error if Rails.env or RAILS_ENV is defined and set to
|
107
|
+
production
|
108
|
+
|
109
|
+
## Contributing
|
110
|
+
To run test cases:
|
111
|
+
|
112
|
+
# clone or fork repo
|
113
|
+
cd iron_fixture_extractor
|
114
|
+
rake # runs test cases
|
115
|
+
|
116
|
+
Help on the missing features above would be much appreciated per the
|
117
|
+
usual github approach:
|
118
|
+
|
119
|
+
1. Fork it
|
120
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
121
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
122
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
123
|
+
5. Create new Pull Request
|
124
|
+
|
125
|
+
If you have other ideas for this tool, make a Github Issue.
|
126
|
+
|
127
|
+
## Footnotes
|
128
|
+
I used various ideas from the following blog posts, gists, and existing
|
129
|
+
ruby gems, thanks to the authors of these pages:
|
130
|
+
|
131
|
+
* http://nhw.pl/wp/2009/09/24/extracting-fixtures
|
132
|
+
* http://nhw.pl/download/extract_fixtures.rake
|
133
|
+
* https://rubygems.org/gems/fixture_builder
|
134
|
+
* https://rubygems.org/gems/fixture_dependencies
|
135
|
+
* http://topfunky.net/svn/plugins/ar_fixtures/
|
136
|
+
* https://gist.github.com/997746
|
137
|
+
* https://gist.github.com/2686783
|
138
|
+
* http://snippets.dzone.com/posts/show/4729
|
139
|
+
* http://rubygems.org/search?utf8=%E2%9C%93&query=fixture
|
140
|
+
* http://www.dan-manges.com/blog/38
|
141
|
+
* http://www.martinfowler.com/bliki/ObjectMother.html
|
142
|
+
* http://asciicasts.com/episodes/158-factories-not-fixtures
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.libs << 'lib'
|
7
|
+
t.libs << 'test'
|
8
|
+
t.pattern = 'test/**/*_test.rb'
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
task :default => 'test'
|
12
|
+
|
13
|
+
desc "Open an irb session preloaded with this library"
|
14
|
+
task :console do
|
15
|
+
sh "irb -rubygems -I lib -I test -r test_helper -r fe"
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/fe/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Joe Goggins"]
|
6
|
+
gem.email = ["goggins@umn.edu"]
|
7
|
+
gem.description = %q{When object factories don't work because your data is too complex and creating manual fixtures is cumbersome and brittle: Iron Fixture Extractor (for Rails/ActiveRecord) }
|
8
|
+
gem.summary = %q{Simplified dynamic fixture extraction for ActiveRecord}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "iron_fixture_extractor"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Fe::VERSION
|
17
|
+
gem.add_runtime_dependency "activerecord", "~> 3.2.1"
|
18
|
+
gem.add_runtime_dependency "activesupport", "~> 3.2.1"
|
19
|
+
gem.add_development_dependency "shoulda", "~> 3.0.1"
|
20
|
+
gem.add_development_dependency "sqlite3"
|
21
|
+
end
|
data/lib/fe.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# NOTE: require 'iron_fixture_extractor', NOT this file
|
2
|
+
module Fe
|
3
|
+
extend ActiveSupport::Autoload
|
4
|
+
autoload :Extractor
|
5
|
+
|
6
|
+
# global configuration
|
7
|
+
|
8
|
+
@@fixtures_root = 'test/fe_fixtures'
|
9
|
+
mattr_accessor :fixtures_root
|
10
|
+
|
11
|
+
# Top-level API methods
|
12
|
+
class << self
|
13
|
+
def extract(*args)
|
14
|
+
extractor = Fe::Extractor.new
|
15
|
+
extractor.load_from_args(*args)
|
16
|
+
extractor.extract
|
17
|
+
extractor
|
18
|
+
end
|
19
|
+
|
20
|
+
# NOTE: This is destructive, it will delete everything in the target table
|
21
|
+
#
|
22
|
+
def load_db(extract_name)
|
23
|
+
extractor = Fe::Extractor.new
|
24
|
+
extractor.name = extract_name
|
25
|
+
extractor.load_from_manifest
|
26
|
+
extractor.load_into_database
|
27
|
+
extractor
|
28
|
+
end
|
29
|
+
def rebuild(extract_name)
|
30
|
+
extractor = Fe::Extractor.new
|
31
|
+
extractor.name = extract_name
|
32
|
+
extractor.load_from_manifest
|
33
|
+
extractor.extract
|
34
|
+
extractor
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/fe/extractor.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
module Fe
|
2
|
+
class Extractor
|
3
|
+
attr_accessor :input_array, :extract_code, :name, :row_counts,:table_names
|
4
|
+
|
5
|
+
def extract
|
6
|
+
@row_counts = {}
|
7
|
+
@table_names = {}
|
8
|
+
self.output_hash.each_pair do |key,records|
|
9
|
+
@row_counts[key] = records.length
|
10
|
+
@table_names[key] = key.constantize.table_name
|
11
|
+
end
|
12
|
+
|
13
|
+
FileUtils.rmdir(self.target_path)
|
14
|
+
FileUtils.mkdir_p(self.target_path)
|
15
|
+
File.open(self.manifest_file_path,'w') do |file|
|
16
|
+
file.write( {:extract_code => self.extract_code,
|
17
|
+
:name => self.name,
|
18
|
+
:model_names => self.model_names,
|
19
|
+
:row_counts => self.row_counts,
|
20
|
+
:table_names => self.models.map {|m| m.table_name}
|
21
|
+
}.to_yaml)
|
22
|
+
end
|
23
|
+
self.write_model_fixtures
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_from_args(active_relation_or_array,*args)
|
27
|
+
options = args.extract_options!
|
28
|
+
@name = (options[:name] || Time.now.strftime("%Y_%m_%d_%H_%M_%S")).to_sym
|
29
|
+
if active_relation_or_array.kind_of? String
|
30
|
+
@extract_code = active_relation_or_array
|
31
|
+
@input_array = Array(eval(active_relation_or_array)).to_a
|
32
|
+
else
|
33
|
+
@extract_code = "CANNOT_REBUILD_THIS_FIXTURE_SET_USE_STRING_ARG_TO_DOT_EXTRACT_METHOD"
|
34
|
+
@input_array = Array(active_relation_or_array).to_a
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_from_manifest
|
39
|
+
raise "u gotta set .name to use this method" if self.name.blank?
|
40
|
+
h = YAML.load_file(self.manifest_file_path)
|
41
|
+
if h[:extract_code].match /CANNOT_REBUILD_THIS_FIXTURE_SET_USE_STRING_ARG_TO_DOT_EXTRACT_METHOD/
|
42
|
+
h[:extract_code] = [] # To make stuff not break cause it thinks its a string
|
43
|
+
end
|
44
|
+
self.load_from_args(h[:extract_code], :name => h[:name])
|
45
|
+
@models = h[:model_names].map {|x| x.constantize}
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_into_database
|
49
|
+
# necessary to make multiple invocations possible in a single test
|
50
|
+
# case possible
|
51
|
+
ActiveRecord::Fixtures.reset_cache
|
52
|
+
self.models.each do |model|
|
53
|
+
ActiveRecord::Fixtures.create_fixtures(self.target_path, model.table_name)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# Returns a hash with model class names for keys and Set's of AR
|
57
|
+
# instances for values
|
58
|
+
# aka like this
|
59
|
+
# {'Post' => [<#Post id:1>,<#Post id:2>],
|
60
|
+
# 'Comment' => [<#Comment id:1>,<#Comment id:2>]}
|
61
|
+
#
|
62
|
+
def output_hash
|
63
|
+
if @output_hash.blank?
|
64
|
+
@output_hash = {}
|
65
|
+
self.input_array.each do |t|
|
66
|
+
recurse(t)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
@output_hash
|
70
|
+
end
|
71
|
+
|
72
|
+
def model_names
|
73
|
+
self.output_hash.keys
|
74
|
+
end
|
75
|
+
|
76
|
+
# Note: this behavior is different if load_from_manifest vs
|
77
|
+
# load_from_args
|
78
|
+
def models
|
79
|
+
@models ||= self.model_names.map {|x| x.constantize}
|
80
|
+
end
|
81
|
+
|
82
|
+
def target_path
|
83
|
+
File.join(Fe.fixtures_root,self.name.to_s)
|
84
|
+
end
|
85
|
+
|
86
|
+
def manifest_file_path
|
87
|
+
File.join(self.target_path,'fe_manifest.yml')
|
88
|
+
end
|
89
|
+
|
90
|
+
def fixture_path_for_model(model_name)
|
91
|
+
File.join(self.target_path,"#{model_name.constantize.table_name}.yml")
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
# Recursively goes over all association_cache's from the record and builds the output_hash
|
97
|
+
# This is the meat-and-potatoes of this tool (plus the the recurse
|
98
|
+
# method) is where something interesting is happening
|
99
|
+
def recurse(record)
|
100
|
+
raise "This gem only knows how to extract stuff w ActiveRecord" unless record.kind_of? ActiveRecord::Base
|
101
|
+
@output_hash[record.class.to_s] ||= Set.new # Set ensures no duplicates
|
102
|
+
@output_hash[record.class.to_s].add record
|
103
|
+
record.association_cache.each do |assoc_cache|
|
104
|
+
assoc_name = assoc_cache.first
|
105
|
+
assoc_value = assoc_cache.last.target
|
106
|
+
unless assoc_value.kind_of? Array
|
107
|
+
assoc_value = Array(assoc_value)
|
108
|
+
end
|
109
|
+
assoc_value.each do |a|
|
110
|
+
self.recurse(a)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
def write_model_fixtures
|
115
|
+
FileUtils.mkdir_p(self.target_path)
|
116
|
+
self.output_hash.each_pair do |key,records|
|
117
|
+
# key is an ActiveRecord class
|
118
|
+
# records is an array of records to write
|
119
|
+
File.open(self.fixture_path_for_model(key),'w') do |file|
|
120
|
+
# props to Rails Receipts 3rd edition book for these 4 lines
|
121
|
+
# below
|
122
|
+
file.write records.inject({}) {|hash, record|
|
123
|
+
# Array() bit done to support composite primary keys
|
124
|
+
fixture_name = "r#{Array(record.id).join('_')}"
|
125
|
+
hash[fixture_name] = record.attributes
|
126
|
+
hash
|
127
|
+
}.to_yaml
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/fe/version.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class BasicUsage < ActiveSupport::TestCase
|
3
|
+
context "Main API" do
|
4
|
+
setup do
|
5
|
+
@extract_code = 'Post.includes(:comments, :author).limit(1)'
|
6
|
+
@extract_name = :first_post_w_comments_and_authors
|
7
|
+
end
|
8
|
+
context ".extract" do
|
9
|
+
setup do
|
10
|
+
FeTestEnv.setup
|
11
|
+
end
|
12
|
+
teardown do
|
13
|
+
FeTestEnv.teardown
|
14
|
+
end
|
15
|
+
should "provide the right output, and put the file in the right place" do
|
16
|
+
extractor = Fe.extract(@extract_code, :name => @extract_name)
|
17
|
+
assert_kind_of Fe::Extractor, extractor
|
18
|
+
assert (%w(Post Comment Author) - extractor.model_names).empty?, "only these keys should exist"
|
19
|
+
assert_equal @extract_name, extractor.name
|
20
|
+
assert_equal Post.table_name, extractor.table_names['Post']
|
21
|
+
assert File.exists?(File.join(Fe.fixtures_root,'first_post_w_comments_and_authors','fe_manifest.yml')), "The file that allows the fixtures to get rebuilt"
|
22
|
+
assert_equal 1, extractor.row_counts['Post']
|
23
|
+
assert File.exists?(File.join(Fe.fixtures_root,'first_post_w_comments_and_authors',"#{Post.table_name}.yml")), "The file is created"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
context ".load_db" do
|
27
|
+
setup do
|
28
|
+
FeTestEnv.setup # regular production db
|
29
|
+
extract_hash = Fe.extract(@extract_code, :name => @extract_name)
|
30
|
+
FeTestEnv.the_env = 'fake_test'
|
31
|
+
FeTestEnv.recreate_schema_without_data
|
32
|
+
end
|
33
|
+
teardown do
|
34
|
+
FeTestEnv.teardown
|
35
|
+
end
|
36
|
+
should "provide the ability to load fixtures" do
|
37
|
+
assert_equal 0, Post.count
|
38
|
+
assert_equal 0, Comment.count
|
39
|
+
assert_equal 0, Author.count
|
40
|
+
Fe.load_db(@extract_name)
|
41
|
+
assert_equal 1, Post.count
|
42
|
+
assert_equal 1, Comment.count
|
43
|
+
assert_equal 1, Author.count
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context ".rebuild" do
|
47
|
+
setup do
|
48
|
+
FeTestEnv.setup
|
49
|
+
@extractor = Fe.extract(@extract_code, :name => @extract_name)
|
50
|
+
end
|
51
|
+
teardown do
|
52
|
+
# FeTestEnv.teardown
|
53
|
+
end
|
54
|
+
should "be able to rebuild the fixture files from the manifest" do
|
55
|
+
# TODO: continue here, should delete a comment, then rebuild,
|
56
|
+
# and assert
|
57
|
+
# all files mtimes have changed
|
58
|
+
# there is no comment file
|
59
|
+
results = eval(@extract_code)
|
60
|
+
first_post = results.first
|
61
|
+
assert_match /First post/i, first_post.name
|
62
|
+
first_post.name = "UPDATED_FIRST_POST"
|
63
|
+
first_post.save!
|
64
|
+
rebuild_hash = Fe.rebuild(@extract_name)
|
65
|
+
assert_match /UPDATED_FIRST_POST/, File.read(@extractor.fixture_path_for_model('Post'))
|
66
|
+
#assert_equal 0, Post.count
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
# NOT SURE IF THESE MATTER, probably do..commented out for now
|
71
|
+
#context "2nd tier API" do
|
72
|
+
#should "provide an extractor class" do
|
73
|
+
#extract_code = Post.first
|
74
|
+
#e=Fe::Extractor.new
|
75
|
+
#e.input_array = [extract_code]
|
76
|
+
#assert_kind_of Hash, e.output_hash
|
77
|
+
#assert_equal Post, e.output_hash.keys.first
|
78
|
+
#assert_equal extract_code, e.output_hash[Post].first
|
79
|
+
#end
|
80
|
+
#should "work with recursive loading" do
|
81
|
+
#e=Fe::Extractor.new
|
82
|
+
#e.input_array = Post.includes(:comments, :author)
|
83
|
+
#assert (e.output_hash.keys - [Post,Comment,Author]).empty?, "There are only keys for the eager loaded models"
|
84
|
+
#end
|
85
|
+
#end
|
86
|
+
end
|
data/test/fe_test_env.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
class FeTestEnv
|
2
|
+
class << self
|
3
|
+
def models
|
4
|
+
[:post,:comment,:author,:group,:group_member]
|
5
|
+
end
|
6
|
+
def model_classes
|
7
|
+
self.models.map {|x| x.to_s.classify.constantize}
|
8
|
+
end
|
9
|
+
def fixtures_root
|
10
|
+
'test/tmp/fe_fixtures'
|
11
|
+
end
|
12
|
+
def migrate_schema
|
13
|
+
ActiveRecord::Migrator.migrate(File.join(File.dirname(__FILE__),'migrations'),nil)
|
14
|
+
end
|
15
|
+
def migrate_fake_production_data
|
16
|
+
ActiveRecord::Migrator.migrate(File.join(File.dirname(__FILE__),'test_data_migrations'),nil)
|
17
|
+
end
|
18
|
+
def destroy_tmp_test_stuff #sqlite dbs and fixture files
|
19
|
+
FileUtils.rm_rf Dir.glob("#{self.tmp_directory}/*")
|
20
|
+
end
|
21
|
+
def tmp_directory
|
22
|
+
File.join(File.dirname(__FILE__), "tmp")
|
23
|
+
end
|
24
|
+
def establish_connection
|
25
|
+
ActiveRecord::Base.establish_connection(self.connections[self.the_env])
|
26
|
+
ActiveRecord::Base.connection
|
27
|
+
end
|
28
|
+
def connections
|
29
|
+
YAML::load_file(File.join(File.dirname(__FILE__), 'config', 'database.yml'))
|
30
|
+
end
|
31
|
+
def load_models
|
32
|
+
self.models.each do |x|
|
33
|
+
require "models/#{x}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def unload_models
|
38
|
+
# DOESN"T WORK!!!!!!!!!
|
39
|
+
self.models.each do |x|
|
40
|
+
Object.send(:remove_const, "::#{x.to_s.capitalize}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def make_fixtures_dir_and_set_fixtures_root
|
44
|
+
FileUtils.mkdir_p FeTestEnv.fixtures_root
|
45
|
+
Fe.fixtures_root = FeTestEnv.fixtures_root
|
46
|
+
end
|
47
|
+
attr_accessor :the_env
|
48
|
+
|
49
|
+
def setup_methods
|
50
|
+
@the_env ||= 'fake_production'
|
51
|
+
[
|
52
|
+
:make_fixtures_dir_and_set_fixtures_root,
|
53
|
+
:load_models,
|
54
|
+
:establish_connection,
|
55
|
+
:migrate_schema,
|
56
|
+
:migrate_fake_production_data]
|
57
|
+
end
|
58
|
+
def setup
|
59
|
+
self.setup_methods.each {|m| send m}
|
60
|
+
end
|
61
|
+
def teardown_methods
|
62
|
+
[
|
63
|
+
:destroy_tmp_test_stuff
|
64
|
+
]
|
65
|
+
end
|
66
|
+
def teardown
|
67
|
+
self.teardown_methods.each {|m| send m}
|
68
|
+
end
|
69
|
+
def recreate_schema_without_data
|
70
|
+
f=File.join(self.tmp_directory,"#{self.the_env}.sqlite3")
|
71
|
+
begin
|
72
|
+
FileUtils.rm f
|
73
|
+
rescue
|
74
|
+
puts "#{f} does not exist"
|
75
|
+
end
|
76
|
+
[:load_models, :establish_connection,:migrate_schema].each {|m| send m}
|
77
|
+
end
|
78
|
+
def reload
|
79
|
+
teardown
|
80
|
+
setup
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateComments < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :comments do |t|
|
4
|
+
t.belongs_to :author
|
5
|
+
t.belongs_to :post
|
6
|
+
t.string :content
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :comments, :author_id
|
11
|
+
add_index :comments, :post_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateGroupMembers < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :group_members do |t|
|
4
|
+
t.belongs_to :author
|
5
|
+
t.belongs_to :group
|
6
|
+
t.string :role
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :group_members, :author_id
|
11
|
+
add_index :group_members, :group_id
|
12
|
+
end
|
13
|
+
end
|
data/test/models/post.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateSomeData < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
a=Author.create name: "Joe"
|
4
|
+
p1=a.posts.create name: "First post"
|
5
|
+
p1.comments.create content: "This is crap"
|
6
|
+
p2=a.posts.create name: "Second post"
|
7
|
+
p2.comments.create content: "This is great"
|
8
|
+
|
9
|
+
a2=Author.create name: "Bill"
|
10
|
+
g=Group.create name: "Group 1"
|
11
|
+
g.authors << a2
|
12
|
+
g.save
|
13
|
+
end
|
14
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iron_fixture_extractor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joe Goggins
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2012-06-16 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 3.2.1
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: activesupport
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 3.2.1
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: shoulda
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.1
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: sqlite3
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id004
|
59
|
+
description: "When object factories don't work because your data is too complex and creating manual fixtures is cumbersome and brittle: Iron Fixture Extractor (for Rails/ActiveRecord) "
|
60
|
+
email:
|
61
|
+
- goggins@umn.edu
|
62
|
+
executables: []
|
63
|
+
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files: []
|
67
|
+
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- iron_fixture_extractor.gemspec
|
75
|
+
- lib/fe.rb
|
76
|
+
- lib/fe/extractor.rb
|
77
|
+
- lib/fe/version.rb
|
78
|
+
- lib/iron_fixture_extractor.rb
|
79
|
+
- test/basic_usage_test.rb
|
80
|
+
- test/config/database.yml
|
81
|
+
- test/fe_test_env.rb
|
82
|
+
- test/migrations/20120604043601_create_posts.rb
|
83
|
+
- test/migrations/20120604043602_create_authors.rb
|
84
|
+
- test/migrations/20120604043639_create_comments.rb
|
85
|
+
- test/migrations/20120604043808_create_group_members.rb
|
86
|
+
- test/migrations/20120604043818_create_groups.rb
|
87
|
+
- test/models/author.rb
|
88
|
+
- test/models/comment.rb
|
89
|
+
- test/models/group.rb
|
90
|
+
- test/models/group_member.rb
|
91
|
+
- test/models/post.rb
|
92
|
+
- test/test_data_migrations/001_create_some_data.rb
|
93
|
+
- test/test_helper.rb
|
94
|
+
homepage: ""
|
95
|
+
licenses: []
|
96
|
+
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
requirements: []
|
115
|
+
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 1.8.24
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Simplified dynamic fixture extraction for ActiveRecord
|
121
|
+
test_files:
|
122
|
+
- test/basic_usage_test.rb
|
123
|
+
- test/config/database.yml
|
124
|
+
- test/fe_test_env.rb
|
125
|
+
- test/migrations/20120604043601_create_posts.rb
|
126
|
+
- test/migrations/20120604043602_create_authors.rb
|
127
|
+
- test/migrations/20120604043639_create_comments.rb
|
128
|
+
- test/migrations/20120604043808_create_group_members.rb
|
129
|
+
- test/migrations/20120604043818_create_groups.rb
|
130
|
+
- test/models/author.rb
|
131
|
+
- test/models/comment.rb
|
132
|
+
- test/models/group.rb
|
133
|
+
- test/models/group_member.rb
|
134
|
+
- test/models/post.rb
|
135
|
+
- test/test_data_migrations/001_create_some_data.rb
|
136
|
+
- test/test_helper.rb
|