datashift 0.7.0 → 0.8.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.
- data/README.markdown +14 -98
- data/VERSION +1 -1
- data/datashift.gemspec +6 -4
- data/lib/applications/jruby/jexcel_file.rb +69 -52
- data/lib/datashift/method_detail.rb +3 -2
- data/lib/datashift/method_dictionary.rb +7 -2
- data/lib/datashift/method_mapper.rb +12 -3
- data/lib/datashift/model_mapper.rb +4 -4
- data/lib/generators/excel_generator.rb +17 -6
- data/lib/loaders/excel_loader.rb +3 -2
- data/lib/loaders/loader_base.rb +62 -27
- data/lib/loaders/paperclip/image_loader.rb +75 -0
- data/lib/loaders/spree/image_loader.rb +11 -42
- data/lib/loaders/spree/product_loader.rb +94 -52
- data/lib/thor/generate_excel.thor +5 -2
- data/lib/thor/spree/bootstrap_cleanup.thor +22 -16
- data/lib/thor/spree/products_images.thor +58 -45
- data/lib/thor/spree/reports.thor +66 -0
- data/spec/db/migrate/20110803201325_create_test_bed.rb +12 -1
- data/spec/excel_generator_spec.rb +39 -1
- data/spec/excel_loader_spec.rb +1 -0
- data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
- data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
- data/spec/fixtures/spree/SpreeMultiVariant.csv +4 -0
- data/spec/fixtures/spree/SpreeProductsSimple.csv +1 -1
- data/spec/fixtures/spree/SpreeProductsSimple.xls +0 -0
- data/spec/fixtures/test_model_defs.rb +4 -0
- data/spec/spree_images_loader_spec.rb +11 -29
- data/spec/spree_loader_spec.rb +60 -15
- data/tasks/db_tasks.rake +45 -0
- metadata +6 -4
- data/datashift-0.6.0.gem +0 -0
- data/datashift-0.6.1.gem +0 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2012
|
2
|
+
# Author :: Tom Statter
|
3
|
+
# Date :: March 2012
|
4
|
+
# License:: MIT. Free, Open Source.
|
5
|
+
#
|
6
|
+
# Usage::
|
7
|
+
# bundle exec thor help datashift:spreeboot
|
8
|
+
# bundle exec thor datashift:spreeboot:cleanup
|
9
|
+
#
|
10
|
+
# Note, not DataShift, case sensitive, create namespace for command line : datashift
|
11
|
+
|
12
|
+
require 'excel_exporter'
|
13
|
+
|
14
|
+
module Datashift
|
15
|
+
|
16
|
+
class Reports < Thor
|
17
|
+
|
18
|
+
include DataShift::Logging
|
19
|
+
|
20
|
+
desc "missing_images", "Spree Products without an image"
|
21
|
+
|
22
|
+
def missing_images(report = nil)
|
23
|
+
|
24
|
+
require 'spree_helper'
|
25
|
+
require 'image_loader'
|
26
|
+
|
27
|
+
require File.expand_path('config/environment.rb')
|
28
|
+
|
29
|
+
klass = DataShift::SpreeHelper::get_spree_class('Product')
|
30
|
+
|
31
|
+
missing = klass.all.find_all {|p| p.images.size == 0 }
|
32
|
+
|
33
|
+
puts "There are #{missing.size} Products without an associated Image"
|
34
|
+
|
35
|
+
if(DataShift::Guards::jruby?)
|
36
|
+
fname = report ? report : "missing_images.xls"
|
37
|
+
DataShift::ExcelExporter.new( fname ).export( missing )
|
38
|
+
else
|
39
|
+
puts missing.collect(&:name).inspect
|
40
|
+
end
|
41
|
+
|
42
|
+
@drop_box = "/home/stattert/Dropbox/DaveWebsiteInfo/"
|
43
|
+
|
44
|
+
@image_list = %w{
|
45
|
+
010InafixTheArmourGodAllFolders
|
46
|
+
01Figuresurbanlandscapepaintings
|
47
|
+
01FinishedArtPrints
|
48
|
+
02Seascapespainting
|
49
|
+
03Landscapes
|
50
|
+
04Spain
|
51
|
+
|
52
|
+
07SignsJohnAllFolders
|
53
|
+
07_Mar
|
54
|
+
09Powerpointsermonaids
|
55
|
+
}
|
56
|
+
|
57
|
+
options = { :recursive => true }
|
58
|
+
|
59
|
+
images = @image_list.collect do |p|
|
60
|
+
DataShift::ImageLoading::get_files(File.join(@drop_box,p), options)
|
61
|
+
end
|
62
|
+
|
63
|
+
puts images.inspect
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -9,7 +9,14 @@ class CreateTestBed < ActiveRecord::Migration
|
|
9
9
|
|
10
10
|
def self.up
|
11
11
|
|
12
|
+
create_table :users do |t|
|
13
|
+
t.string :title
|
14
|
+
t.string :first_name
|
15
|
+
end
|
16
|
+
|
17
|
+
# belongs_to :user
|
12
18
|
# has many :milestones
|
19
|
+
#
|
13
20
|
create_table :projects do |t|
|
14
21
|
t.string :title
|
15
22
|
t.string :value_as_string
|
@@ -18,10 +25,13 @@ class CreateTestBed < ActiveRecord::Migration
|
|
18
25
|
t.datetime :value_as_datetime, :default => nil
|
19
26
|
t.integer :value_as_integer, :default => 0
|
20
27
|
t.decimal :value_as_double, :precision => 8, :scale => 2, :default => 0.0
|
28
|
+
t.references :user
|
21
29
|
t.timestamps
|
22
30
|
end
|
23
31
|
|
24
|
-
# belongs_to :project
|
32
|
+
# belongs_to :project
|
33
|
+
# @project => has_many :milestones
|
34
|
+
|
25
35
|
create_table :milestones do |t|
|
26
36
|
t.string :name
|
27
37
|
t.datetime :datetime, :default => nil
|
@@ -73,6 +83,7 @@ class CreateTestBed < ActiveRecord::Migration
|
|
73
83
|
end
|
74
84
|
|
75
85
|
def self.down
|
86
|
+
drop_table :users
|
76
87
|
drop_table :projects
|
77
88
|
drop_table :categories
|
78
89
|
drop_table :loader_releases
|
@@ -56,7 +56,7 @@ if(Guards::jruby?)
|
|
56
56
|
puts "Can manually check file @ #{expect}"
|
57
57
|
end
|
58
58
|
|
59
|
-
it "should
|
59
|
+
it "should include all associations in template .xls file from model" do
|
60
60
|
|
61
61
|
expect= result_file('project_plus_assoc_template_spec.xls')
|
62
62
|
|
@@ -67,7 +67,45 @@ if(Guards::jruby?)
|
|
67
67
|
File.exists?(expect).should be_true
|
68
68
|
|
69
69
|
end
|
70
|
+
|
71
|
+
|
72
|
+
it "should enable us to exclude cetain associations in template .xls file from model" do
|
73
|
+
|
74
|
+
expect= result_file('project_plus_some_assoc_template_spec.xls')
|
75
|
+
|
76
|
+
gen = ExcelGenerator.new(expect)
|
77
|
+
|
78
|
+
options = {:exclude => :milestones }
|
79
|
+
|
80
|
+
gen.generate_with_associations(Project, options)
|
81
|
+
|
82
|
+
File.exists?(expect).should be_true
|
83
|
+
|
84
|
+
excel = JExcelFile.new(expect)
|
85
|
+
|
86
|
+
excel.each_row {|r| puts r.inspect }
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
it "should enable us to autosize columns in the .xls file" do
|
92
|
+
|
93
|
+
expect= result_file('project_autosized_template_spec.xls')
|
94
|
+
|
95
|
+
gen = ExcelGenerator.new(expect)
|
96
|
+
|
97
|
+
options = {:autosize => true, :exclude => :milestones }
|
98
|
+
|
99
|
+
gen.generate_with_associations(Project, options)
|
70
100
|
|
101
|
+
File.exists?(expect).should be_true
|
102
|
+
|
103
|
+
excel = JExcelFile.new(expect)
|
104
|
+
|
105
|
+
excel.each_row {|r| puts r.inspect }
|
106
|
+
|
107
|
+
end
|
108
|
+
|
71
109
|
end
|
72
110
|
else
|
73
111
|
puts "WARNING: skipped excel_generator_spec : Requires JRUBY - JExcelFile requires JAVA"
|
data/spec/excel_loader_spec.rb
CHANGED
@@ -114,6 +114,7 @@ if(Guards::jruby?)
|
|
114
114
|
loader.perform_load( $DataShiftFixturePath + '/ProjectsMultiCategoriesHeaderLookup.xls')
|
115
115
|
|
116
116
|
loader.loaded_count.should == (Project.count - count)
|
117
|
+
loader.loaded_count.should > 3
|
117
118
|
|
118
119
|
{'004' => 4, '005' => 1, '006' => 0, '007' => 1 }.each do|title, expected|
|
119
120
|
project = Project.find_by_title(title)
|
Binary file
|
Binary file
|
@@ -0,0 +1,4 @@
|
|
1
|
+
"SKU","Name","Description","Available On"," Price","CostPrice","Option Types","Option Types","Variants","count_on_hand"
|
2
|
+
"MV_001","Demo Product for AR Loader","blah blah","2011-02-14",399.99,320.00,"mime_type:jpeg, PDF;print_type:colour",,"mime_type:PNG","12|6|7"
|
3
|
+
"MV_002","Demo Excel Load via Jruby","less blah","2011-05-14",100.00,30.00,"mime_type:jpeg;print_type:black_white",,"mime_type:PNG;print_type:black_white","5|4"
|
4
|
+
"MV_003","Demo third row in future","more blah blah","2012-07-01",50.34,23.34,"mime_type:jpeg;print_type:colour, sepia;size:large|mime_type:PNG","mime_type:PDF|print_type:black_white",,"12|4|7|12"
|
@@ -1,4 +1,4 @@
|
|
1
1
|
"SKU","Name","Description","Available On"," Price","CostPrice","count_on_hand","Option Types"
|
2
2
|
"SIMPLE_001","Simple Product for AR Loader","blah blah","2011-02-14",345.78,320.00,12,"mime_type"
|
3
3
|
"SIMPLE_002","Simple Excel Load via Jruby","less blah","2011-05-14",100.00,30.00,5,"mime_type"
|
4
|
-
"SIMPLE_003","Simple third row avail in future","more blah blah","
|
4
|
+
"SIMPLE_003","Simple third row avail in future","more blah blah","2112-07-01",50.34,23.34,23,"mime_type|print_type"
|
Binary file
|
@@ -35,7 +35,10 @@ describe 'SpreeImageLoading' do
|
|
35
35
|
@Product_klass.count.should == 0
|
36
36
|
|
37
37
|
MethodDictionary.clear
|
38
|
-
|
38
|
+
|
39
|
+
# For Spree important to get instance methods too as Product delegates
|
40
|
+
# many important attributes to Variant (master)
|
41
|
+
MethodDictionary.find_operators( @Product_klass, :instance_methods => true )
|
39
42
|
|
40
43
|
@product_loader = DataShift::SpreeHelper::ProductLoader.new
|
41
44
|
rescue => e
|
@@ -45,17 +48,13 @@ describe 'SpreeImageLoading' do
|
|
45
48
|
end
|
46
49
|
|
47
50
|
|
48
|
-
it "should
|
49
|
-
|
50
|
-
# In >= 1.1.0 Image moved to master Variant from Product
|
51
|
-
|
51
|
+
it "should create Image from path in Product loading column from CSV", :fail => true do
|
52
|
+
|
52
53
|
options = {:mandatory => ['sku', 'name', 'price']}
|
53
54
|
|
54
|
-
options[:force_inclusion] = ['sku', 'images'] if(SpreeHelper::version.to_f > 1 )
|
55
|
-
|
56
55
|
@product_loader.perform_load( SpecHelper::spree_fixture('SpreeProductsWithImages.csv'), options )
|
57
56
|
|
58
|
-
@Image_klass.all.each_with_index {|i, x| puts "
|
57
|
+
@Image_klass.all.each_with_index {|i, x| puts "SPEC CHECK IMAGE #{x}", i.inspect }
|
59
58
|
|
60
59
|
p = @Product_klass.find_by_name("Demo Product for AR Loader")
|
61
60
|
|
@@ -70,15 +69,11 @@ describe 'SpreeImageLoading' do
|
|
70
69
|
end
|
71
70
|
|
72
71
|
|
73
|
-
it "should
|
72
|
+
it "should create Image from path in Product loading column from Excel", :fail => true do
|
74
73
|
|
75
74
|
options = {:mandatory => ['sku', 'name', 'price']}
|
76
75
|
|
77
|
-
options[:force_inclusion] = ['sku', 'images'] if(SpreeHelper::version.to_f > 1 )
|
78
|
-
|
79
76
|
@product_loader.perform_load( SpecHelper::spree_fixture('SpreeProductsWithImages.xls'), options )
|
80
|
-
|
81
|
-
@Image_klass.all.each_with_index {|i, x| puts "RESULT IMAGE #{x}", i.inspect }
|
82
77
|
|
83
78
|
p = @klass.find_by_name("Demo Product for AR Loader")
|
84
79
|
|
@@ -91,7 +86,9 @@ describe 'SpreeImageLoading' do
|
|
91
86
|
|
92
87
|
end
|
93
88
|
|
94
|
-
it "should be able to assign Images to preloaded Products"
|
89
|
+
it "should be able to assign Images to preloaded Products" do
|
90
|
+
|
91
|
+
pending "Currently functionality supplied by a thor task images()"
|
95
92
|
|
96
93
|
MethodDictionary.find_operators( @Image_klass )
|
97
94
|
|
@@ -101,24 +98,9 @@ describe 'SpreeImageLoading' do
|
|
101
98
|
|
102
99
|
@Image_klass.all.size.should == 0
|
103
100
|
|
104
|
-
# force inclusion means add to operator list even if not present
|
105
|
-
options = { :verbose => true, :force_inclusion => ['sku', 'attachment'] } if(SpreeHelper::version.to_f > 1 )
|
106
|
-
|
107
101
|
loader = DataShift::SpreeHelper::ImageLoader.new(nil, options)
|
108
102
|
|
109
103
|
loader.perform_load( SpecHelper::spree_fixture('SpreeImages.xls'), options )
|
110
|
-
|
111
|
-
@Image_klass.all.each_with_index {|i, x| puts "RESULT IMAGE #{x}", i.inspect }
|
112
|
-
|
113
|
-
@Image_klass.count.should == 3
|
114
|
-
|
115
|
-
p = @klass.find_by_name("Demo Product for AR Loader")
|
116
|
-
|
117
|
-
p.name.should == "Demo Product for AR Loader"
|
118
|
-
|
119
|
-
p.images.should have_exactly(1).items
|
120
|
-
|
121
|
-
@Product_klass.all.each {|p| p.images.should have_exactly(1).items }
|
122
104
|
|
123
105
|
end
|
124
106
|
|
data/spec/spree_loader_spec.rb
CHANGED
@@ -30,8 +30,7 @@ describe 'SpreeLoader' do
|
|
30
30
|
before(:each) do
|
31
31
|
|
32
32
|
begin
|
33
|
-
|
34
|
-
|
33
|
+
|
35
34
|
before_each_spree
|
36
35
|
|
37
36
|
@Product_klass.count.should == 0
|
@@ -39,7 +38,10 @@ describe 'SpreeLoader' do
|
|
39
38
|
@Variant_klass.count.should == 0
|
40
39
|
|
41
40
|
MethodDictionary.clear
|
42
|
-
|
41
|
+
|
42
|
+
# For Spree important to get instance methods too as Product delegates
|
43
|
+
# many important attributes to Variant (master)
|
44
|
+
MethodDictionary.find_operators( @Product_klass, :instance_methods => true )
|
43
45
|
|
44
46
|
# want to test both lookup and dynamic creation - this Taxonomy should be found, rest created
|
45
47
|
root = @Taxonomy_klass.create( :name => 'Paintings' )
|
@@ -80,25 +82,24 @@ describe 'SpreeLoader' do
|
|
80
82
|
loader.loaded_count.should == @Zone_klass.count
|
81
83
|
end
|
82
84
|
|
85
|
+
it "should raise an error for missing file" do
|
86
|
+
lambda { test_basic_product('SpreeProductsSimple.txt') }.should raise_error BadFile
|
87
|
+
end
|
83
88
|
|
89
|
+
it "should raise an error for unsupported file types" do
|
90
|
+
lambda { test_basic_product('SpreeProductsDefaults.yml') }.should raise_error UnsupportedFileType
|
91
|
+
end
|
92
|
+
|
84
93
|
# Loader should perform identically regardless of source, whether csv, .xls etc
|
85
94
|
|
86
|
-
it "should load basic Products .xls via Spree loader", :
|
95
|
+
it "should load basic Products .xls via Spree loader", :opts => true do
|
87
96
|
test_basic_product('SpreeProductsSimple.xls')
|
88
97
|
end
|
89
98
|
|
90
|
-
it "should load basic Products from .csv via Spree loader", :csv => true
|
99
|
+
it "should load basic Products from .csv via Spree loader", :csv => true do
|
91
100
|
test_basic_product('SpreeProductsSimple.csv')
|
92
101
|
end
|
93
102
|
|
94
|
-
it "should raise an error for missing file" do
|
95
|
-
lambda { test_basic_product('SpreeProductsSimple.txt') }.should raise_error BadFile
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should raise an error for unsupported file types" do
|
99
|
-
lambda { test_basic_product('SpreeProductsDefaults.yml') }.should raise_error UnsupportedFileType
|
100
|
-
end
|
101
|
-
|
102
103
|
def test_basic_product( source )
|
103
104
|
|
104
105
|
@product_loader.perform_load( SpecHelper::spree_fixture(source), :mandatory => ['sku', 'name', 'price'] )
|
@@ -224,13 +225,13 @@ describe 'SpreeLoader' do
|
|
224
225
|
p.option_types[0].name.should == "mime_type"
|
225
226
|
p.option_types[0].presentation.should == "Mime type"
|
226
227
|
|
227
|
-
@Variant_klass.all[1].sku.should == "
|
228
|
+
@Variant_klass.all[1].sku.should == "DEMO_001_1"
|
228
229
|
@Variant_klass.all[1].price.should == 399.99
|
229
230
|
|
230
231
|
# V1
|
231
232
|
v1 = p.variants[0]
|
232
233
|
|
233
|
-
v1.sku.should == "
|
234
|
+
v1.sku.should == "DEMO_001_1"
|
234
235
|
v1.price.should == 399.99
|
235
236
|
v1.count_on_hand.should == 12
|
236
237
|
|
@@ -258,7 +259,50 @@ describe 'SpreeLoader' do
|
|
258
259
|
|
259
260
|
@product_loader.failed_objects.size.should == 0
|
260
261
|
end
|
262
|
+
|
263
|
+
# Composite Variant Syntax is option_type_A_name:value;option_type_B_name:value
|
264
|
+
# which creates a SINGLE Variant with 2 option types
|
261
265
|
|
266
|
+
it "should create Variants with MULTIPLE option types from single column", :new => true do
|
267
|
+
@product_loader.perform_load( SpecHelper::spree_fixture('SpreeMultiVariant.csv'), :mandatory => ['sku', 'name', 'price'] )
|
268
|
+
|
269
|
+
# Product 1)
|
270
|
+
# 1 + 2) mime_type:jpeg,PDF;print_type:colour equivalent to (mime_type:jpeg;print_type:colour|mime_type:PDF;print_type:colour)
|
271
|
+
# 3) mime_type:PNG
|
272
|
+
#
|
273
|
+
# Product 2
|
274
|
+
# 4) mime_type:jpeg;print_type:black_white
|
275
|
+
# 5) mime_type:PNG;print_type:black_white
|
276
|
+
#
|
277
|
+
# Product 3
|
278
|
+
# 6 +7) mime_type:jpeg;print_type:colour,sepia;size:large
|
279
|
+
# 8) mime_type:jpeg;print_type:colour
|
280
|
+
# 9) mime_type:PNG
|
281
|
+
# 9 + 10) mime_type:PDF|print_type:black_white
|
282
|
+
|
283
|
+
prod_count = 3
|
284
|
+
var_count = 10
|
285
|
+
|
286
|
+
# plus 3 MASTER VARIANTS
|
287
|
+
@Product_klass.count.should == prod_count
|
288
|
+
@Variant_klass.count.should == prod_count + var_count
|
289
|
+
|
290
|
+
p = @Product_klass.first
|
291
|
+
|
292
|
+
p.variants_including_master.should have_exactly(4).items
|
293
|
+
p.variants.should have_exactly(3).items
|
294
|
+
|
295
|
+
p.variants.each { |v| v.option_values.each {|o| puts o.inspect } }
|
296
|
+
|
297
|
+
p.option_types.each { |ot| puts ot.inspect }
|
298
|
+
p.option_types.should have_exactly(2).items # mime_type, print_type
|
299
|
+
|
300
|
+
v1 = p.variants[0]
|
301
|
+
v1.option_values.should have_exactly(2).items
|
302
|
+
v1.option_values.collect(&:name).sort.should == ['colour','jpeg']
|
303
|
+
|
304
|
+
end
|
305
|
+
|
262
306
|
##################
|
263
307
|
### PROPERTIES ###
|
264
308
|
##################
|
@@ -429,5 +473,6 @@ describe 'SpreeLoader' do
|
|
429
473
|
it "should raise exception when single mandatory column missing from .csv", :ex => true do
|
430
474
|
expect {@product_loader.perform_load($SpreeNegativeFixturePath + '/SpreeProdMiss1Mandatory.csv', :mandatory => 'sku' )}.to raise_error(DataShift::MissingMandatoryError)
|
431
475
|
end
|
476
|
+
|
432
477
|
|
433
478
|
end
|
data/tasks/db_tasks.rake
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
namespace :datashift do
|
2
|
+
|
3
|
+
namespace :db do
|
4
|
+
|
5
|
+
SYSTEM_TABLE_EXCLUSION_LIST = ['schema_migrations']
|
6
|
+
|
7
|
+
desc "Purge the current database"
|
8
|
+
task :purge, [:exclude_system_tables] => [:environment] do |t, args|
|
9
|
+
require 'highline/import'
|
10
|
+
|
11
|
+
if(Rails.env.production?)
|
12
|
+
agree("WARNING: In Production database, REALLY PURGE ? [y]:")
|
13
|
+
end
|
14
|
+
|
15
|
+
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
16
|
+
case config['adapter']
|
17
|
+
when "mysql", "mysql2", "jdbcmysql"
|
18
|
+
ActiveRecord::Base.establish_connection(config)
|
19
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
20
|
+
next if(args[:exclude_system_tables] && SYSTEM_TABLE_EXCLUSION_LIST.include?(table) )
|
21
|
+
puts "purging table: #{table}"
|
22
|
+
ActiveRecord::Base.connection.execute("TRUNCATE #{table}")
|
23
|
+
end
|
24
|
+
when "sqlite","sqlite3"
|
25
|
+
dbfile = config["database"] || config["dbfile"]
|
26
|
+
File.delete(dbfile) if File.exist?(dbfile)
|
27
|
+
when "sqlserver"
|
28
|
+
dropfkscript = "#{config["host"]}.#{config["database"]}.DP1".gsub(/\\/,'-')
|
29
|
+
`osql -E -S #{config["host"]} -d #{config["database"]} -i db\\#{dropfkscript}`
|
30
|
+
`osql -E -S #{config["host"]} -d #{config["database"]} -i db\\#{Rails.env}_structure.sql`
|
31
|
+
when "oci", "oracle"
|
32
|
+
ActiveRecord::Base.establish_connection(config)
|
33
|
+
ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
|
34
|
+
ActiveRecord::Base.connection.execute(ddl)
|
35
|
+
end
|
36
|
+
when "firebird"
|
37
|
+
ActiveRecord::Base.establish_connection(config)
|
38
|
+
ActiveRecord::Base.connection.recreate_database!
|
39
|
+
else
|
40
|
+
raise "Task not supported by '#{config["adapter"]}'"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|