fixie 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +31 -11
- data/fixie.gemspec +1 -1
- data/lib/fixie.rb +126 -36
- data/lib/fixie/version.rb +1 -1
- data/test/fixie_test.rb +22 -15
- data/test/fixtures/{cities.yml → default/cities.yml} +0 -0
- data/test/fixtures/{countries.yml → default/countries.yml} +0 -0
- metadata +6 -6
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Fixie
|
2
2
|
|
3
|
-
A standalone library for managing test fixture data
|
3
|
+
A standalone library for managing test fixture data with good support for multiple databases.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -22,31 +22,51 @@ To use Fixie, you first create some fixture files in a directory called `fixture
|
|
22
22
|
|
23
23
|
test/
|
24
24
|
└── fixtures
|
25
|
-
|
26
|
-
|
25
|
+
└── default
|
26
|
+
├── cities.yml
|
27
|
+
└── countries.yml
|
27
28
|
|
28
|
-
|
29
|
+
You must put all your fixtures into a subdirectory of the `fixtures` directory. The name of the directory should be a good logical name for the database that the fixtures. If you have only one database, `default` is a reasonable name, but if you have an app with customers in one database and orders in another, you would name them `customers` and `orders`.
|
30
|
+
|
31
|
+
Fixie uses Sequel to load the data into the database. Fixie will work even if you aren't using Sequel in your application. You must configure the Fixie databases and then call `load_fixtures` to get the fixtures to actually be loaded. Your test helper might look like this:
|
29
32
|
|
30
33
|
``` ruby
|
31
|
-
Fixie.
|
34
|
+
Fixie.dbs[:default] = Sequel.sqlite
|
35
|
+
|
36
|
+
Fixie.load_fixtures
|
37
|
+
```
|
38
|
+
|
39
|
+
Now all the fixtures will be loaded into the test database. In order to access them from a test, you need to mix the `Fixie::Model` module into the base class of your models. For example, say you have models defined like this:
|
40
|
+
|
41
|
+
``` ruby
|
42
|
+
class Model
|
43
|
+
end
|
32
44
|
|
33
|
-
class
|
34
|
-
include Fixie
|
45
|
+
class Country < Model
|
35
46
|
end
|
47
|
+
|
48
|
+
class City < Model
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
In your test helper, you mix in `Fixie::Model` like this:
|
53
|
+
|
54
|
+
``` ruby
|
55
|
+
Model.extend Fixie::Model
|
36
56
|
```
|
37
57
|
|
38
|
-
Now
|
58
|
+
Now in your tests, you can refer to fixtures like this:
|
39
59
|
|
40
60
|
``` ruby
|
41
61
|
def test_something
|
42
|
-
assert_equal "US",
|
62
|
+
assert_equal "US", Country.fixture(:us)
|
43
63
|
end
|
44
64
|
```
|
45
65
|
|
46
66
|
You can also access the fixtures in any context once they have been loaded like this:
|
47
67
|
|
48
68
|
``` ruby
|
49
|
-
Fixie.
|
69
|
+
Fixie.fixture(:default, :countries, :us)
|
50
70
|
```
|
51
71
|
|
52
72
|
Fixtures are defined in YAML files like this:
|
@@ -84,7 +104,7 @@ baltimore:
|
|
84
104
|
The ERB is evaluated in the context of the Fixie module, so if there is anything else you want to make available in that context, just mix the module into Fixie:
|
85
105
|
|
86
106
|
``` ruby
|
87
|
-
Fixie.extend
|
107
|
+
Fixie.extend FastGettext::Translation
|
88
108
|
```
|
89
109
|
|
90
110
|
``` yaml
|
data/fixie.gemspec
CHANGED
data/lib/fixie.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fixie/version'
|
2
2
|
require 'active_support/core_ext'
|
3
3
|
require 'erb'
|
4
|
+
require 'sequel'
|
4
5
|
require 'yaml'
|
5
6
|
require 'zlib'
|
6
7
|
|
@@ -16,7 +17,11 @@ module Fixie
|
|
16
17
|
end
|
17
18
|
|
18
19
|
class << self
|
19
|
-
attr_accessor :
|
20
|
+
attr_accessor :dbs, :dir, :fixtures
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.dbs
|
24
|
+
@dbs ||= {}
|
20
25
|
end
|
21
26
|
|
22
27
|
def self.dir
|
@@ -28,60 +33,145 @@ module Fixie
|
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
def self.
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.fixtures
|
36
|
-
@fixtures ||= begin
|
37
|
-
all_fixtures = {}
|
38
|
-
|
36
|
+
def self.all_fixtures
|
37
|
+
@all_fixtures ||= begin
|
39
38
|
unless Dir.exists?(Fixie.dir)
|
40
39
|
raise "There is no directory in the $LOAD_PATH with a 'fixtures' directory in it"
|
41
40
|
end
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
fixture_class = fixture_name.singularize.classify.constantize
|
42
|
+
all_fixtures = {}
|
43
|
+
|
44
|
+
now = Time.now.utc
|
47
45
|
|
48
|
-
|
46
|
+
dbs.each do |db_name, db|
|
47
|
+
all_fixtures[db_name] = {}
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
# First pass, load all the fixtures
|
50
|
+
Dir[File.join(Fixie.dir, "#{db_name}/*.yml")].each do |file|
|
51
|
+
table_name = File.basename(file, '.yml')
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
fixtures = YAML.load(ERB.new(IO.read(file)).result(binding)).symbolize_keys
|
54
|
+
|
55
|
+
fixtures.each do |name, data|
|
56
|
+
data["id"] ||= identify(name)
|
57
57
|
end
|
58
|
-
end
|
59
58
|
|
60
|
-
|
61
|
-
|
59
|
+
all_fixtures[db_name][table_name.to_sym] = fixtures
|
60
|
+
end
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
62
|
+
# Do a second pass to resolve associations and load data in DB
|
63
|
+
all_fixtures[db_name].each do |table_name, fixtures|
|
64
|
+
table = db[table_name]
|
65
|
+
table_has_created_at = table.columns.include?(:created_at)
|
66
|
+
table_has_updated_at = table.columns.include?(:updated_at)
|
67
|
+
|
68
|
+
fixtures.each do |name, data|
|
69
|
+
|
70
|
+
# Change attributes like city: baltimore to city_id: baltimore.id
|
71
|
+
data.keys.each do |attr|
|
72
|
+
associated_fixtures = all_fixtures[db_name][attr.to_s.pluralize.to_sym]
|
73
|
+
if associated_fixtures && table.columns.include?("#{attr}_id".to_sym)
|
74
|
+
associated_fixture = associated_fixtures[data[attr].to_sym]
|
75
|
+
if associated_fixture
|
76
|
+
data["#{attr}_id"] = associated_fixture['id']
|
77
|
+
data.delete(attr)
|
78
|
+
end
|
74
79
|
end
|
80
|
+
|
81
|
+
data["created_at"] = now if table_has_created_at && !data.key?("created_at")
|
82
|
+
data["updated_at"] = now if table_has_updated_at && !data.key?("updated_at")
|
75
83
|
end
|
84
|
+
|
85
|
+
# Set created_at/updated_at if they exist
|
86
|
+
|
87
|
+
# Finally, put the data in the DB
|
88
|
+
table.insert(data)
|
76
89
|
end
|
77
|
-
db[fixture_name].insert(data)
|
78
90
|
end
|
79
|
-
|
80
91
|
end
|
81
92
|
|
82
93
|
all_fixtures
|
83
94
|
end
|
84
95
|
end
|
85
96
|
|
97
|
+
def self.fixture(db_name, table_name, fixture_name)
|
98
|
+
db = all_fixtures[db_name]
|
99
|
+
if db
|
100
|
+
fixtures = db[table_name]
|
101
|
+
if fixtures
|
102
|
+
fixture = fixtures[fixture_name]
|
103
|
+
if fixture
|
104
|
+
fixture
|
105
|
+
else
|
106
|
+
raise "No fixture #{fixture_name.inspect} in #{db_name}.#{table_name}"
|
107
|
+
end
|
108
|
+
else
|
109
|
+
raise "No fixtures for #{table_name.inspect} in #{db_name.inspect}"
|
110
|
+
end
|
111
|
+
else
|
112
|
+
raise "Unknown fixture database #{db_name.inspect}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.load_fixtures
|
117
|
+
Fixie.all_fixtures
|
118
|
+
end
|
119
|
+
|
120
|
+
module Model
|
121
|
+
# This will return an instance of this class loaded from
|
122
|
+
# the fixtures matching the name
|
123
|
+
#
|
124
|
+
# @param fixture_name [Symbol] The name of the fixture
|
125
|
+
# @return [Object] An instance of this class
|
126
|
+
def fixture(fixture_name)
|
127
|
+
@fixtures ||= {}
|
128
|
+
fixture = @fixtures[fixture_name]
|
129
|
+
if fixture
|
130
|
+
fixture
|
131
|
+
else
|
132
|
+
@fixtures[fixture_name] = instantiate_from_fixture(Fixie.fixture(fixture_db_name, fixture_table_name, fixture_name))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# This method is used to get an instance of the model from a fixture hash.
|
137
|
+
# The default implementation is to just pass the hash to the model's constructor.
|
138
|
+
#
|
139
|
+
# @param fixture [Hash<String, Object>] The fixture
|
140
|
+
# @return [Object] An instance of this class
|
141
|
+
def instantiate_from_fixture(fixture)
|
142
|
+
new(fixture)
|
143
|
+
end
|
144
|
+
|
145
|
+
# This method determine which database is used to load the fixture.
|
146
|
+
# The default implementation is to check the class to see if it has a
|
147
|
+
# namespace, like 'Foo::Bar', and if it does, return :foo.
|
148
|
+
# If it does not have a namespace, it will return :default.
|
149
|
+
#
|
150
|
+
# You should override this method if you have multiple databases in your app
|
151
|
+
# and you have a different way of determining the DB name based on the class.
|
152
|
+
#
|
153
|
+
# @return [Symbol] The db name for this class
|
154
|
+
def fixture_db_name
|
155
|
+
if match_data = name.match(/([^:]+)::/)
|
156
|
+
match_data[1].to_sym
|
157
|
+
else
|
158
|
+
:default
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# This method returns the name of the table that the fixtures for this model
|
163
|
+
# should be loaded into/from. The default is to just underscore and pluralize
|
164
|
+
# the table name, e.g. City => cities.
|
165
|
+
#
|
166
|
+
# @return [Symbol] The table name for this class
|
167
|
+
def fixture_table_name
|
168
|
+
@fixture_table_name ||= if respond_to?(:table_name)
|
169
|
+
table_name.to_sym
|
170
|
+
else
|
171
|
+
name.demodulize.tableize.to_sym
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
86
176
|
extend self
|
87
177
|
end
|
data/lib/fixie/version.rb
CHANGED
data/test/fixie_test.rb
CHANGED
@@ -26,15 +26,15 @@ class City < Model
|
|
26
26
|
attr_accessor :name, :country, :country_id, :created_at
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
db = Sequel.sqlite(logger: Logger.new("log/test.log"))
|
30
30
|
|
31
|
-
|
31
|
+
db.create_table :countries do
|
32
32
|
primary_key :id
|
33
33
|
String :name
|
34
34
|
String :code
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
db.create_table :cities do
|
38
38
|
primary_key :id
|
39
39
|
Integer :country_id
|
40
40
|
String :name
|
@@ -42,46 +42,53 @@ Fixie.db.create_table :cities do
|
|
42
42
|
Time :created_at
|
43
43
|
end
|
44
44
|
|
45
|
+
Fixie.dbs[:default] = db
|
46
|
+
|
45
47
|
module FakeGetText
|
46
48
|
def _(key)
|
47
49
|
key.to_s.titleize
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
51
|
-
Fixie.extend
|
53
|
+
Fixie.extend FakeGetText
|
54
|
+
Fixie.load_fixtures
|
55
|
+
Model.extend Fixie::Model
|
52
56
|
|
53
57
|
class FixieTest < MiniTest::Unit::TestCase
|
54
|
-
include Fixie
|
55
58
|
|
56
59
|
def test_explicit_id
|
57
|
-
assert_equal "United States",
|
58
|
-
assert_equal 1,
|
60
|
+
assert_equal "United States", Country.fixture(:us).name
|
61
|
+
assert_equal 1, Country.fixture(:us).id
|
59
62
|
end
|
60
63
|
|
61
64
|
def test_implicity_id
|
62
|
-
assert_equal "Canada",
|
63
|
-
assert_equal 842554592,
|
65
|
+
assert_equal "Canada", Country.fixture(:canada).name
|
66
|
+
assert_equal 842554592, Country.fixture(:canada).id
|
64
67
|
end
|
65
68
|
|
66
69
|
def test_association
|
67
|
-
assert_equal
|
70
|
+
assert_equal Country.fixture(:us).id, City.fixture(:baltimore).country_id
|
68
71
|
# TODO: make this work
|
69
|
-
# assert_equal countries(:us),
|
72
|
+
# assert_equal countries(:us), City.fixture(:baltimore).country
|
70
73
|
end
|
71
74
|
|
72
75
|
def test_get
|
73
|
-
assert_equal "US", Fixie.
|
76
|
+
assert_equal "US", Fixie.fixture(:default, :countries, :us)["code"]
|
74
77
|
end
|
75
78
|
|
76
79
|
def test_loaded_in_db
|
77
|
-
assert_equal ["CA","US"], Fixie.
|
80
|
+
assert_equal ["CA","US"], Fixie.dbs[:default][:countries].all.map{|c| c[:code] }.sort
|
78
81
|
end
|
79
82
|
|
80
83
|
def test_erb
|
81
|
-
assert_equal Time,
|
84
|
+
assert_equal Time, City.fixture(:baltimore).created_at.class
|
82
85
|
end
|
83
86
|
|
84
87
|
def test_erb_is_evaled_in_context_of_fixie
|
85
|
-
assert_equal "Baltimore",
|
88
|
+
assert_equal "Baltimore", City.fixture(:baltimore).name
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_timestamps
|
92
|
+
assert City.fixture(:baltimore).created_at.present?
|
86
93
|
end
|
87
94
|
end
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fixie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -75,8 +75,8 @@ files:
|
|
75
75
|
- lib/fixie.rb
|
76
76
|
- lib/fixie/version.rb
|
77
77
|
- test/fixie_test.rb
|
78
|
-
- test/fixtures/cities.yml
|
79
|
-
- test/fixtures/countries.yml
|
78
|
+
- test/fixtures/default/cities.yml
|
79
|
+
- test/fixtures/default/countries.yml
|
80
80
|
homepage: http://github.com/pjb3/fixie
|
81
81
|
licenses: []
|
82
82
|
post_install_message:
|
@@ -103,6 +103,6 @@ specification_version: 3
|
|
103
103
|
summary: A standalone library for managing test fixture data
|
104
104
|
test_files:
|
105
105
|
- test/fixie_test.rb
|
106
|
-
- test/fixtures/cities.yml
|
107
|
-
- test/fixtures/countries.yml
|
106
|
+
- test/fixtures/default/cities.yml
|
107
|
+
- test/fixtures/default/countries.yml
|
108
108
|
has_rdoc:
|