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 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
- ├── cities.yml
26
- └── countries.yml
25
+ └── default
26
+ ├── cities.yml
27
+ └── countries.yml
27
28
 
28
- Fixie use 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 database and then include the Fixie module in your test class to use it. Your test helper might look like this:
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.db = Sequel.sqlite
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 Test::Unit::TestCase
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 all the fixtures will be loaded into the test database, and you can access them from within a test like this:
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", countries(: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.countries(:us)
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(FastGettext::Translation)
107
+ Fixie.extend FastGettext::Translation
88
108
  ```
89
109
 
90
110
  ``` yaml
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "fixie"
5
- gem.version = "0.1.0"
5
+ gem.version = "0.2.0"
6
6
  gem.authors = ["Paul Barry"]
7
7
  gem.email = ["mail@paulbarry.com"]
8
8
  gem.description = %q{A standalone library for managing test fixture data}
@@ -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 :db, :dir, :fixtures
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.included(cls)
32
- fixtures # load the fixtures
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
- # First pass, load all the fixtures
44
- Dir[File.join(Fixie.dir, "**/*.yml")].each do |file|
45
- fixture_name = File.basename(file, '.yml')
46
- fixture_class = fixture_name.singularize.classify.constantize
42
+ all_fixtures = {}
43
+
44
+ now = Time.now.utc
47
45
 
48
- fixtures = YAML.load(ERB.new(IO.read(file)).result(binding)).symbolize_keys
46
+ dbs.each do |db_name, db|
47
+ all_fixtures[db_name] = {}
49
48
 
50
- fixtures.each do |name, data|
51
- data["id"] ||= identify(name)
52
- end
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
- unless respond_to?(fixture_name)
55
- define_method(fixture_name) do |fixture|
56
- fixture_class.new(fixtures[fixture])
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
- all_fixtures[fixture_name.to_sym] = fixtures
61
- end
59
+ all_fixtures[db_name][table_name.to_sym] = fixtures
60
+ end
62
61
 
63
- # Do a second pass to resolve associations
64
- all_fixtures.each do |fixture_name, fixtures|
65
- fixture_class = fixture_name.to_s.singularize.classify.constantize
66
- fixtures.each do |name, data|
67
- data.keys.each do |attr|
68
- associated_fixtures = all_fixtures[attr.to_s.pluralize.to_sym]
69
- if associated_fixtures && fixture_class.method_defined?("#{attr}_id=")
70
- associated_fixture = associated_fixtures[data[attr].to_sym]
71
- if associated_fixture
72
- data["#{attr}_id"] = associated_fixture['id']
73
- data.delete(attr)
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
@@ -1,3 +1,3 @@
1
1
  module Fixie
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -26,15 +26,15 @@ class City < Model
26
26
  attr_accessor :name, :country, :country_id, :created_at
27
27
  end
28
28
 
29
- Fixie.db = Sequel.sqlite(logger: Logger.new("log/test.log"))
29
+ db = Sequel.sqlite(logger: Logger.new("log/test.log"))
30
30
 
31
- Fixie.db.create_table :countries do
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
- Fixie.db.create_table :cities do
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(FakeGetText)
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", countries(:us).name
58
- assert_equal 1, countries(:us).id
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", countries(:canada).name
63
- assert_equal 842554592, countries(:canada).id
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 countries(:us).id, cities(:baltimore).country_id
70
+ assert_equal Country.fixture(:us).id, City.fixture(:baltimore).country_id
68
71
  # TODO: make this work
69
- # assert_equal countries(:us), cities(:baltimore).country
72
+ # assert_equal countries(:us), City.fixture(:baltimore).country
70
73
  end
71
74
 
72
75
  def test_get
73
- assert_equal "US", Fixie.countries(:us).code
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.db[:countries].all.map{|c| c[:code] }.sort
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, cities(:baltimore).created_at.class
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", cities(:baltimore).name
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
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.1.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-04-12 00:00:00.000000000 Z
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: