trucker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,236 @@
1
+ Background
2
+ ==========
3
+
4
+ Trucker is based on a migration technique using LegacyModels first pioneered by Dave Thomas.
5
+
6
+ Sharing External ActiveRecord Connections
7
+ http://pragdave.blogs.pragprog.com/pragdave/2006/01/sharing_externa.html
8
+
9
+ Using this, I've developed a set of helpers for migrating code.
10
+
11
+ - /app/models/legacy/
12
+ - /app/models/legacy/legacy_base.rb
13
+ - /app/models/legacy/legacy_model.rb
14
+ - /config/database.yml
15
+ - /config/environment.rb
16
+ - /lib/migration_helper.rb
17
+ - /lib/tasks/migrate.rake
18
+
19
+
20
+
21
+ /app/models/legacy/
22
+ ===================
23
+
24
+ This folder will contain the base Legacy model, and all subclasses.
25
+
26
+
27
+ /app/models/legacy/legacy_base.rb
28
+ =================================
29
+
30
+ This is the base Legacy model which connects to the legacy database and handles the migration.
31
+
32
+ class LegacyBase < ActiveRecord::Base
33
+ self.abstract_class = true
34
+ establish_connection "legacy"
35
+
36
+ def migrate
37
+ new_record = self.class.to_s.gsub(/Legacy/,'::').constantize.new(map)
38
+ new_record[:id] = self.id
39
+ new_record.save
40
+ end
41
+
42
+ end
43
+
44
+
45
+ /app/models/legacy/legacy_model.rb
46
+ =================================
47
+
48
+ This is a sample Legacy subclass, which specifies the legacy model name and defines a map of old field names to new field names. All Legacy models are stored in /app/models/legacy to keep your main app model namespace unaffected.
49
+
50
+ class LegacyModel < LegacyBase
51
+ set_table_name "model"
52
+
53
+ def map
54
+ {
55
+ :make => self.car_company.squish,
56
+ :model => self.car_name.squish
57
+ }
58
+ end
59
+
60
+ end
61
+
62
+
63
+
64
+ /config/environment.rb
65
+ ======================
66
+
67
+ We need to update the app environment so we can load the legacy models correctly.
68
+
69
+ Rails::Initializer.run do |config|
70
+ config.load_paths += %W( #{RAILS_ROOT}/app/models/legacy )
71
+ end
72
+
73
+
74
+
75
+ /config/database.yml
76
+ ====================
77
+
78
+ We need to add a custom database adapter so that we can connect to our legacy database.
79
+
80
+ By convention, I've used APPNAME_legacy for my legacy databases, but you can easily customize this.
81
+
82
+ legacy:
83
+ adapter: mysql
84
+ database: APPNAME_legacy
85
+ username: root
86
+ password:
87
+
88
+
89
+
90
+ /app/models/legacy/legacy_base.rb
91
+ =================================
92
+
93
+ This model connects to our legacy database, and provides a migration method.
94
+
95
+ class LegacyBase < ActiveRecord::Base
96
+ self.abstract_class = true
97
+ establish_connection "legacy"
98
+
99
+ def migrate
100
+ new_record = self.class.to_s.gsub(/Legacy/,'::').constantize.new(map)
101
+ new_record[:id] = self.id
102
+ new_record.save
103
+ end
104
+
105
+ end
106
+
107
+
108
+
109
+ /lib/migration_helper.rb
110
+ ========================
111
+
112
+ This helper is used by the rake task to manage the actual migration process.
113
+
114
+ def migrate(name, options={})
115
+ # Grab custom entity label if present
116
+ label = options.delete(:label) if options[:label]
117
+
118
+ unless options[:helper]
119
+
120
+ # Grab model to migrate
121
+ model = name.to_s.singularize.capitalize
122
+
123
+ # Wipe out existing records
124
+ model.constantize.delete_all
125
+
126
+ # Status message
127
+ status = "Migrating "
128
+ status += "#{number_of_records || "all"} #{label || name}"
129
+ status += " after #{offset_for_records}" if offset_for_records
130
+
131
+ # Set import counter
132
+ counter = 0
133
+ counter += offset_for_records if offset_for_records
134
+ total_records = "Legacy#{model}".constantize.find(:all).size
135
+
136
+ # Start import
137
+ "Legacy#{model}".constantize.find(:all, with(options)).each do |record|
138
+ counter += 1
139
+ puts status + " (#{counter}/#{total_records})"
140
+ record.migrate
141
+ end
142
+ else
143
+ eval options[:helper].to_s
144
+ end
145
+ end
146
+
147
+ def with(options={})
148
+ {:limit => number_of_records, :offset => offset_for_records}.merge(options)
149
+ end
150
+
151
+ def number_of_records
152
+ nil || ENV['limit'].to_i if ENV['limit'].to_i > 0
153
+ end
154
+
155
+ def offset_for_records
156
+ nil || ENV['offset'].to_i if ENV['offset'].to_i > 0
157
+ end
158
+
159
+ Available options include offset and limit:
160
+
161
+ rake db:migrate:architects limit=1000
162
+ rake db:migrate:architects limit=1000 offset=2000
163
+
164
+
165
+
166
+ /lib/tasks/migrate.rake
167
+ ========================
168
+
169
+ This is the basic rake task for migrating legacy data. With a sample model, just add a new migration task with the pluralized name of your existing model. For more complicated migrations, the migrate method supports a helper method which will override the default migration behavior and allow you to do a highly customized migration.
170
+
171
+ require 'migration_helper'
172
+
173
+ namespace :db do
174
+ namespace :migrate do
175
+
176
+ desc 'Migrates architects'
177
+ task :architects => :environment do
178
+ migrate :architects
179
+ end
180
+
181
+ desc 'Migrates theaters'
182
+ task :architects => :environment do
183
+ migrate :theaters, :helper => :migrate_theaters
184
+ end
185
+
186
+ end
187
+ end
188
+
189
+ def migrate_theaters
190
+
191
+ # Delete all theaters if delete_all=true
192
+ Theater.delete_all if ENV['delete_all']
193
+
194
+ # Set default conditions
195
+ conditions = ["status_publish = 'Yes' AND location_address1 != '' AND location_address1 IS NOT NULL"]
196
+
197
+ # Set counters to monitor migration
198
+ success, failure, skipped = 0, 0, 0
199
+
200
+ # Count number of theaters
201
+ start = Theater.count
202
+
203
+ # Migrate theaters
204
+ puts "\nMigrating #{number_of_records || "all"} theaters #{"after #{offset_for_records}\n\n" if offset_for_records}"
205
+ LegacyTheater.find(:all, with(:conditions => conditions)).each_with_index do |record, i|
206
+
207
+ # Migrate theater
208
+ new_record = record.migrate
209
+ message = "#{new_record.name} (#{record.id})"
210
+
211
+ if Theater.exists?(record.id)
212
+ puts "#{i+1} SKIP #{message}\n\n"
213
+ skipped += 1
214
+ elsif new_record.save
215
+ puts "#{i+1} PASS #{message}\n\n"
216
+ success += 1
217
+ else
218
+ puts "#{i+1} FAIL #{message}\n#{new_record.inspect}\n\n"
219
+ failure += 1
220
+ end
221
+
222
+ # Archive old theater data
223
+ archive_old_theater_data(record)
224
+
225
+ end
226
+
227
+ # Count number of theaters
228
+ finish = Theater.count
229
+
230
+ # Batch stats
231
+ percentage = (failure.to_f / (skipped + success + failure).to_f).to_f * 100
232
+ puts "BATCH: #{number_of_records || "all"} theaters => #{success} passed, #{failure} failed (#{percentage.truncate}%), #{skipped} skipped (already imported)"
233
+
234
+ end
235
+
236
+
data/INSTALL.markdown ADDED
@@ -0,0 +1,30 @@
1
+
2
+ Here are some imaginary install instructions.
3
+
4
+ 1. Install the trucker gem and add to your gem config block.
5
+
6
+ 2. Generate the basic trucker files
7
+
8
+ script/generate truck
9
+
10
+ - Add legacy adapter to database.yml
11
+ - Add legacy base class
12
+ - (Optionally) Add legacy sub classes for all existing models
13
+ - Add app/models/legacy to load path in Rails Initializer config block
14
+ - Generate sample migration task (using pluralized model names)
15
+
16
+ 3. Update database.yml with legacy database info
17
+
18
+ 4. Run rake db:create:all to create the legacy database
19
+
20
+ 5. Import your legacy database.
21
+ (Make sure the legacy adapter is using the correct name.)
22
+
23
+ 6. Update legacy model table names as needed
24
+
25
+ 7. Update legacy model field mappings as needed
26
+
27
+ 8. Start migrating!
28
+ rake db:migrate:models
29
+
30
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Patrick Crowley and Rob Kaufman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = Trucker
2
+
3
+ Trucker is a gem for migrating legacy data into a Rails app.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Patrick Crowley and Rob Kaufman. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "trucker"
8
+ gem.summary = %Q{Bring your legacy along}
9
+ gem.description = %Q{Trucker is a gem for migrating legacy data into a Rails app}
10
+ gem.email = "patrick@mokolabs.com"
11
+ gem.homepage = "http://github.com/mokolabs/trucker"
12
+ gem.authors = ["Patrick Crowley and Rob Kaufman"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_development_dependency "yard", ">= 0"
15
+ gem.files = FileList["[A-Z]*", "{generators,lib,rails}/**/*"]
16
+
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'spec/rake/spectask'
25
+ Spec::Rake::SpecTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.spec_files = FileList['spec/**/*_spec.rb']
28
+ end
29
+
30
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
31
+ spec.libs << 'lib' << 'spec'
32
+ spec.pattern = 'spec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :spec => :check_dependencies
37
+
38
+ task :default => :spec
39
+
40
+ begin
41
+ require 'yard'
42
+ YARD::Rake::YardocTask.new
43
+ rescue LoadError
44
+ task :yardoc do
45
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
46
+ end
47
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :build:
4
+ :minor: 1
5
+ :patch: 0
@@ -0,0 +1 @@
1
+ script/generate truck
@@ -0,0 +1,76 @@
1
+ # Mostly pinched from http://github.com/ryanb/nifty-generators/tree/master
2
+
3
+ Rails::Generator::Commands::Base.class_eval do
4
+ def file_contains?(relative_destination, line)
5
+ File.read(destination_path(relative_destination)).include?(line)
6
+ end
7
+ end
8
+
9
+ Rails::Generator::Commands::Create.class_eval do
10
+ def insert_before(file, line, stop='^(class|module) .+$')
11
+ logger.insert "#{line} into #{file}"
12
+ unless options[:pretend] || file_contains?(file, line)
13
+ gsub_file file, /^#{stop}/ do |match|
14
+ "#{line}\n#{match}"
15
+ end
16
+ end
17
+ end
18
+
19
+ def insert_after(file, line, stop='^(class|module) .+$')
20
+ logger.insert "#{line} into #{file}"
21
+ @run = false
22
+ unless options[:pretend] || file_contains?(file, line)
23
+ gsub_file file, /#{stop}/ do |match|
24
+ @run = true
25
+ "#{match}\n #{line}"
26
+ end
27
+ raise "Append Key Not Found, was looking for #{stop}" unless @run
28
+ end
29
+ end
30
+
31
+ def append(file, line)
32
+ logger.insert "added legacy adapter to end of database.yml"
33
+ unless options[:pretend] || file_contains?(file, line)
34
+ File.open(file, "a") do |file|
35
+ file.write("\n" + line)
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ Rails::Generator::Commands::Destroy.class_eval do
43
+ def insert_before(file, line, stop='')
44
+ logger.remove "#{line} from #{file}"
45
+ unless options[:pretend]
46
+ gsub_file file, "\n #{line}", ''
47
+ end
48
+ end
49
+
50
+ def insert_after(file, line, stop='')
51
+ logger.remove "#{line} from #{file}"
52
+ unless options[:pretend]
53
+ gsub_file file, "\n #{line}", ''
54
+ end
55
+ end
56
+
57
+ def append(file, line)
58
+ logger.insert "added legacy adapter to end of database.yml"
59
+ end
60
+
61
+ end
62
+
63
+ Rails::Generator::Commands::List.class_eval do
64
+ def insert_before(file, line, stop='')
65
+ logger.insert "#{line} into #{file}"
66
+ end
67
+
68
+ def insert_after(file, line, stop='')
69
+ logger.insert "#{line} into #{file}"
70
+ end
71
+
72
+ def append(file, line)
73
+ logger.insert "added legacy adapter to end of database.yml"
74
+ end
75
+
76
+ end
@@ -0,0 +1,11 @@
1
+ class LegacyBase < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ establish_connection "legacy"
4
+
5
+ def migrate
6
+ new_record = self.class.to_s.gsub(/Legacy/,'::').constantize.new(map)
7
+ new_record[:id] = self.id
8
+ new_record.save
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class Legacy<%= model_name.classify %> < LegacyBase
2
+ set_table_name "<%= model_name.pluralize %>"
3
+
4
+ def map
5
+ {
6
+ :field_one => self.old_field_one.squish,
7
+ :field_two => self.old_field_two.squish
8
+ }
9
+ end
10
+
11
+ end
@@ -0,0 +1,23 @@
1
+ require 'trucker'
2
+ include Trucker
3
+
4
+ namespace :db do
5
+ namespace :migrate do
6
+
7
+ <%- unless legacy_models.size > 0 -%>
8
+ # desc 'Migrates products'
9
+ # task :products => :environment do
10
+ # migrate :products
11
+ # end
12
+ <%- end -%>
13
+
14
+ <%- legacy_models.each do |model_name| -%>
15
+ desc 'Migrates <%= model_name.pluralize.downcase %>'
16
+ task :<%= model_name.pluralize.downcase %> => :environment do
17
+ Trucker.migrate :<%= model_name.pluralize.downcase %>
18
+ end
19
+
20
+ <%- end -%>
21
+
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/lib/insert_commands.rb")
2
+
3
+ class TruckGenerator < Rails::Generator::Base
4
+
5
+ def manifest
6
+ record do |m|
7
+ @legacy_models = Dir.glob(RAILS_ROOT + '/app/models/*.rb').collect { |model_path| File.basename(model_path).gsub('.rb', '') }
8
+
9
+ m.directory 'app/models/legacy'
10
+ m.file 'legacy_base.rb', 'app/models/legacy/legacy_base.rb'
11
+
12
+ @legacy_models.each do |model_name|
13
+ m.template 'legacy_model.erb', "app/models/legacy/legacy_#{model_name.downcase}.rb", :assigns => { :model_name => model_name }
14
+ end
15
+
16
+ m.directory 'lib/tasks'
17
+ m.template 'legacy_task.erb', 'lib/tasks/legacy.rake', :assigns => { :legacy_models => @legacy_models }
18
+
19
+ snippet = <<EOS
20
+ legacy:
21
+ adapter: mysql
22
+ database: #{RAILS_ROOT.split('/').last}_legacy
23
+ encoding: utf8
24
+ username:
25
+ password:
26
+ EOS
27
+
28
+ m.append "config/database.yml", snippet
29
+
30
+ snippet = 'config.load_paths += %W( #{RAILS_ROOT}/app/models/legacy )'
31
+ m.insert_after "config/environment.rb", snippet, '^Rails::Initializer\.run do.+$'
32
+
33
+ end
34
+ end
35
+
36
+ end
data/lib/trucker.rb ADDED
@@ -0,0 +1,50 @@
1
+ module Trucker
2
+
3
+ def self.migrate(name, options={})
4
+ # Grab custom entity label if present
5
+ label = options.delete(:label) if options[:label]
6
+
7
+ unless options[:helper]
8
+
9
+ # Grab model to migrate
10
+ model = name.to_s.singularize.capitalize
11
+
12
+ # Wipe out existing records
13
+ model.constantize.delete_all
14
+
15
+ # Status message
16
+ status = "Migrating "
17
+ status += "#{number_of_records || "all"} #{label || name}"
18
+ status += " after #{offset_for_records}" if offset_for_records
19
+
20
+ # Set import counter
21
+ counter = 0
22
+ counter += offset_for_records if offset_for_records
23
+ total_records = "Legacy#{model}".constantize.find(:all).size
24
+
25
+ # Start import
26
+ "Legacy#{model}".constantize.find(:all, with(options)).each do |record|
27
+ counter += 1
28
+ puts status + " (#{counter}/#{total_records})"
29
+ record.migrate
30
+ end
31
+ else
32
+ eval options[:helper].to_s
33
+ end
34
+ end
35
+
36
+ protected
37
+
38
+ def self.with(options={})
39
+ {:limit => number_of_records, :offset => offset_for_records}.merge(options)
40
+ end
41
+
42
+ def self.number_of_records
43
+ nil || ENV['limit'].to_i if ENV['limit'].to_i > 0
44
+ end
45
+
46
+ def self.offset_for_records
47
+ nil || ENV['offset'].to_i if ENV['offset'].to_i > 0
48
+ end
49
+
50
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'trucker'
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'trucker'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Trucker" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trucker
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Patrick Crowley and Rob Kaufman
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-15 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 2
33
+ - 9
34
+ version: 1.2.9
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: yard
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ description: Trucker is a gem for migrating legacy data into a Rails app
52
+ email: patrick@mokolabs.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files:
58
+ - LICENSE
59
+ - README.rdoc
60
+ files:
61
+ - BACKGROUND.markdown
62
+ - INSTALL.markdown
63
+ - LICENSE
64
+ - README.rdoc
65
+ - Rakefile
66
+ - VERSION.yml
67
+ - generators/truck/USAGE
68
+ - generators/truck/lib/insert_commands.rb
69
+ - generators/truck/templates/legacy_base.rb
70
+ - generators/truck/templates/legacy_model.erb
71
+ - generators/truck/templates/legacy_task.erb
72
+ - generators/truck/truck_generator.rb
73
+ - lib/trucker.rb
74
+ - rails/init.rb
75
+ - spec/spec_helper.rb
76
+ - spec/trucker_spec.rb
77
+ has_rdoc: true
78
+ homepage: http://github.com/mokolabs/trucker
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ requirements: []
105
+
106
+ rubyforge_project:
107
+ rubygems_version: 1.3.7
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: Bring your legacy along
111
+ test_files:
112
+ - spec/spec_helper.rb
113
+ - spec/trucker_spec.rb