datashift 0.2.1 → 0.2.2

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.
Files changed (84) hide show
  1. data/.document +5 -5
  2. data/LICENSE.txt +26 -26
  3. data/README.markdown +326 -305
  4. data/README.rdoc +19 -19
  5. data/Rakefile +86 -93
  6. data/VERSION +1 -1
  7. data/datashift.gemspec +163 -152
  8. data/lib/applications/jruby/jexcel_file.rb +410 -408
  9. data/lib/applications/jruby/word.rb +79 -79
  10. data/lib/datashift.rb +183 -152
  11. data/lib/datashift/exceptions.rb +11 -11
  12. data/lib/datashift/file_definitions.rb +353 -353
  13. data/lib/datashift/mapping_file_definitions.rb +87 -87
  14. data/lib/datashift/method_detail.rb +293 -275
  15. data/lib/datashift/method_dictionary.rb +208 -209
  16. data/lib/datashift/method_mapper.rb +90 -90
  17. data/lib/datashift/model_mapper.rb +27 -0
  18. data/lib/exporters/csv_exporter.rb +36 -0
  19. data/lib/exporters/excel_exporter.rb +116 -0
  20. data/lib/exporters/exporter_base.rb +15 -0
  21. data/lib/generators/csv_generator.rb +36 -36
  22. data/lib/generators/excel_generator.rb +106 -122
  23. data/lib/generators/generator_base.rb +13 -13
  24. data/lib/helpers/core_ext/to_b.rb +24 -24
  25. data/lib/helpers/rake_utils.rb +42 -0
  26. data/lib/helpers/spree_helper.rb +194 -153
  27. data/lib/java/poi-3.7/LICENSE +507 -507
  28. data/lib/java/poi-3.7/NOTICE +21 -21
  29. data/lib/java/poi-3.7/RELEASE_NOTES.txt +115 -115
  30. data/lib/loaders/csv_loader.rb +98 -98
  31. data/lib/loaders/excel_loader.rb +155 -155
  32. data/lib/loaders/loader_base.rb +420 -420
  33. data/lib/loaders/spreadsheet_loader.rb +136 -136
  34. data/lib/loaders/spree/image_loader.rb +67 -63
  35. data/lib/loaders/spree/product_loader.rb +289 -248
  36. data/lib/thor/generate_excel.thor +54 -0
  37. data/sandbox/app/controllers/application_controller.rb +3 -0
  38. data/sandbox/config/application.rb +43 -0
  39. data/sandbox/config/database.yml +34 -0
  40. data/sandbox/config/environment.rb +7 -0
  41. data/sandbox/config/environments/development.rb +30 -0
  42. data/spec/csv_loader_spec.rb +30 -30
  43. data/spec/datashift_spec.rb +26 -26
  44. data/spec/db/migrate/20110803201325_create_test_bed.rb +85 -85
  45. data/spec/excel_exporter_spec.rb +78 -78
  46. data/spec/excel_generator_spec.rb +78 -78
  47. data/spec/excel_loader_spec.rb +223 -223
  48. data/spec/file_definitions.rb +141 -141
  49. data/spec/fixtures/ProjectsDefaults.yml +29 -29
  50. data/spec/fixtures/config/database.yml +27 -27
  51. data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
  52. data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
  53. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +4 -4
  54. data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +4 -4
  55. data/spec/fixtures/spree/SpreeProducts.csv +4 -4
  56. data/spec/fixtures/spree/SpreeProducts.xls +0 -0
  57. data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +4 -4
  58. data/spec/fixtures/spree/SpreeProductsMultiColumn.xls +0 -0
  59. data/spec/fixtures/spree/SpreeProductsSimple.csv +4 -4
  60. data/spec/fixtures/spree/SpreeProductsWithImages.csv +4 -4
  61. data/spec/fixtures/spree/SpreeZoneExample.csv +5 -5
  62. data/spec/fixtures/test_model_defs.rb +57 -57
  63. data/spec/loader_spec.rb +120 -120
  64. data/spec/method_dictionary_spec.rb +242 -242
  65. data/spec/method_mapper_spec.rb +41 -41
  66. data/spec/spec_helper.rb +154 -116
  67. data/spec/spree_exporter_spec.rb +67 -0
  68. data/spec/spree_generator_spec.rb +77 -64
  69. data/spec/spree_loader_spec.rb +363 -324
  70. data/spec/spree_method_mapping_spec.rb +218 -214
  71. data/tasks/config/seed_fu_product_template.erb +15 -15
  72. data/tasks/config/tidy_config.txt +12 -12
  73. data/tasks/{excel_generator.rake → export/excel_generator.rake} +101 -78
  74. data/tasks/file_tasks.rake +36 -36
  75. data/tasks/import/csv.rake +50 -49
  76. data/tasks/import/excel.rake +74 -71
  77. data/tasks/spree/image_load.rake +108 -108
  78. data/tasks/spree/product_loader.rake +43 -43
  79. data/tasks/word_to_seedfu.rake +166 -166
  80. data/test/helper.rb +18 -18
  81. data/test/test_interact.rb +7 -7
  82. metadata +16 -8
  83. data/datashift-0.1.0.gem +0 -0
  84. data/tasks/db_tasks.rake +0 -66
@@ -1,215 +1,219 @@
1
- # Copyright:: (c) Autotelik Media Ltd 2011
2
- # Author :: Tom Statter
3
- # Date :: Summer 2011
4
- #
5
- # License:: MIT - Free, OpenSource
6
- #
7
- # Details:: Specification for Spree aspect of datashift gem.
8
- #
9
- # Tests the method mapping aspect, such as that we correctly identify
10
- # Spree Product attributes and associations
11
- #
12
- require File.dirname(__FILE__) + '/spec_helper'
13
-
14
- require 'spree_helper'
15
- require 'product_loader'
16
-
17
- include DataShift
18
-
19
- describe 'SpreeLoader' do
20
-
21
- before(:all) do
22
-
23
- # we are not a Spree project, nor is it practical to externally generate
24
- # a complete Spree application for testing so we implement a mini migrate/boot of our own
25
- Spree.load() # require Spree gems
26
-
27
- # key to YAML db e.g test_memory, test_mysql
28
- db_connect( 'test_spree_standalone' )
29
-
30
- Spree.boot # create a sort-of Spree app
31
-
32
- Spree.migrate_up # create an sqlite Spree database on the fly
33
-
34
- @klazz = Product
35
-
36
- # Reset main tables - TODO should really purge properly, or roll back a transaction
37
- [OptionType, OptionValue, Product, Property, Variant, Taxonomy, Taxon, Zone].each { |x| x.delete_all }
38
- end
39
-
40
- before(:each) do
41
- MethodMapper.clear
42
- MethodDictionary.find_operators( @klazz )
43
- end
44
-
45
-
46
- it "should populate operators for a Spree Product" do
47
-
48
- MethodMapper.has_many.should_not be_empty
49
- MethodMapper.belongs_to.should_not be_empty
50
- MethodMapper.assignments.should_not be_empty
51
-
52
- assign = MethodMapper.assignments_for(@klazz)
53
-
54
- assign.should include('available_on') # Example of a simple column
55
-
56
- MethodMapper.assignments[@klazz].should include('available_on')
57
-
58
- has_many_ops = MethodMapper.has_many_for(@klazz)
59
-
60
- has_many_ops.should include('properties') # Product can have many properties
61
-
62
- MethodMapper.has_many[@klazz].should include('properties')
63
-
64
- btf = MethodMapper.belongs_to_for(@klazz)
65
-
66
- btf.should include('tax_category') # Example of a belongs_to assignment
67
-
68
- MethodMapper.belongs_to[@klazz].should include('tax_category')
69
-
70
- MethodMapper.column_types[@klazz].size.should == @klazz.columns.size
71
- end
72
-
73
-
74
- it "should find method details correctly for different forms of a column name" do
75
-
76
- ["available On", 'available_on', "Available On", "AVAILABLE_ON"].each do |format|
77
-
78
- method_details = MethodMapper.find_method_detail( @klazz, format )
79
-
80
- method_details.operator.should == 'available_on'
81
- method_details.operator_for(:assignment).should == 'available_on'
82
-
83
- method_details.operator_for(:belongs_to).should be_nil
84
- method_details.operator_for(:has_many).should be_nil
85
-
86
- method_details.col_type.should_not be_nil
87
- method_details.col_type.name.should == 'available_on'
88
- method_details.col_type.default.should == nil
89
- method_details.col_type.sql_type.should include 'datetime' # works on mysql and sqlite
90
- method_details.col_type.type.should == :datetime
91
- end
92
- end
93
-
94
- it "should populate method details correctly for has_many forms of association name" do
95
-
96
- MethodMapper.has_many[@klazz].should include('product_option_types')
97
-
98
- ["product_option_types", "product option types", 'product Option_types', "ProductOptionTypes", "Product_Option_Types"].each do |format|
99
- method_detail = MethodMapper.find_method_detail( @klazz, format )
100
-
101
- method_detail.should_not be_nil
102
-
103
- method_detail.operator_for(:has_many).should eq('product_option_types')
104
- method_detail.operator_for(:belongs_to).should be_nil
105
- method_detail.operator_for(:assignment).should be_nil
106
- end
107
- end
108
-
109
-
110
- it "should populate method details correctly for assignment operators (none columns on #{@klazz})" do
111
-
112
- MethodDictionary.find_operators( @klazz, :reload => true, :instance_methods => true )
113
-
114
- # Example of delegates i.e. cost_price column on Variant, delegated to Variant by Product
115
-
116
- MethodMapper.assignments[@klazz].should include('cost_price')
117
- MethodMapper.assignments[@klazz].should include('sku')
118
-
119
-
120
- count_on_hand = MethodMapper.find_method_detail( @klazz, 'count on hand' )
121
- count_on_hand.should_not be_nil
122
- count_on_hand.operator.should == 'count_on_hand'
123
-
124
- method = MethodMapper.find_method_detail( @klazz, 'sku' )
125
- method.should_not be_nil
126
- method.operator.should == 'sku'
127
- end
128
-
129
- it "should enable assignment via operators for none columns on #{@klazz}" do
130
-
131
- MethodDictionary.find_operators( @klazz, :reload => true, :instance_methods => true )
132
-
133
- klazz_object = @klazz.new
134
-
135
- klazz_object.should be_new_record
136
-
137
- # we can use method details to populate a new AR object, essentailly same as
138
- # klazz_object.send( count_on_hand.operator, 2)
139
- count_on_hand = MethodMapper.find_method_detail( @klazz, 'count on hand' )
140
-
141
- count_on_hand.assign( klazz_object, 2 )
142
- klazz_object.count_on_hand.should == 2
143
-
144
- count_on_hand.assign( klazz_object, 5 )
145
- klazz_object.count_on_hand.should == 5
146
-
147
- method = MethodMapper.find_method_detail( @klazz, 'sku' )
148
- method.should_not be_nil
149
-
150
- method.operator.should == 'sku'
151
-
152
- method.assign( klazz_object, 'TEST_SK 001')
153
- klazz_object.sku.should == 'TEST_SK 001'
154
-
155
- end
156
-
157
- it "should enable assignment to has_many association on new object" do
158
-
159
- method_detail = MethodMapper.find_method_detail( @klazz, 'taxons' )
160
-
161
- method_detail.operator.should == 'taxons'
162
-
163
- klazz_object = @klazz.new
164
-
165
- klazz_object.taxons.size.should == 0
166
-
167
- # NEW ASSOCIATION ASSIGNMENT
168
-
169
- # assign via the send operator directly on load object
170
- klazz_object.send( method_detail.operator ) << Taxon.new
171
-
172
- klazz_object.taxons.size.should == 1
173
-
174
- klazz_object.send( method_detail.operator ) << [Taxon.new, Taxon.new]
175
- klazz_object.taxons.size.should == 3
176
-
177
- # Use generic assignment on method detail - expect has_many to use << not =
178
- method_detail.assign( klazz_object, Taxon.new )
179
- klazz_object.taxons.size.should == 4
180
-
181
- method_detail.assign( klazz_object, [Taxon.new, Taxon.new])
182
- klazz_object.taxons.size.should == 6
183
- end
184
-
185
- it "should enable assignment to has_many association using existing objects" do
186
-
187
- MethodDictionary.find_operators( @klazz )
188
-
189
- method_detail = MethodMapper.find_method_detail( @klazz, 'product_properties' )
190
-
191
- method_detail.operator.should == 'product_properties'
192
-
193
- klazz_object = @klazz.new
194
-
195
- ProductProperty.new(:property => @prop1)
196
-
197
- # NEW ASSOCIATION ASSIGNMENT
198
- klazz_object.send( method_detail.operator ) << ProductProperty.new
199
-
200
- klazz_object.product_properties.size.should == 1
201
-
202
- klazz_object.send( method_detail.operator ) << [ProductProperty.new, ProductProperty.new]
203
- klazz_object.product_properties.size.should == 3
204
-
205
- # Use generic assignment on method detail - expect has_many to use << not =
206
- method_detail.assign( klazz_object, ProductProperty.new(:property => @prop1) )
207
- klazz_object.product_properties.size.should == 4
208
-
209
- method_detail.assign( klazz_object, [ProductProperty.new(:property => @prop2), ProductProperty.new(:property => @prop3)])
210
- klazz_object.product_properties.size.should == 6
211
-
212
- end
213
-
214
-
1
+ # Copyright:: (c) Autotelik Media Ltd 2011
2
+ # Author :: Tom Statter
3
+ # Date :: Summer 2011
4
+ #
5
+ # License:: MIT - Free, OpenSource
6
+ #
7
+ # Details:: Specification for Spree aspect of datashift gem.
8
+ #
9
+ # Tests the method mapping aspect, such as that we correctly identify
10
+ # Spree Product attributes and associations
11
+ #
12
+ require File.dirname(__FILE__) + '/spec_helper'
13
+
14
+ require 'spree_helper'
15
+ require 'product_loader'
16
+
17
+ include DataShift
18
+
19
+ describe 'SpreeLoader' do
20
+
21
+ before(:all) do
22
+ SpecHelper::before_all_spree
23
+ end
24
+
25
+ before(:each) do
26
+
27
+ include SpecHelper
28
+ extend SpecHelper
29
+
30
+ before_each_spree
31
+
32
+ MethodDictionary.clear
33
+ MethodDictionary.find_operators( @Product_klass )
34
+ #MethodDictionary.build_method_details( @Product_klass )
35
+ end
36
+
37
+
38
+ it "should populate operators for a Spree Product" do
39
+
40
+ MethodDictionary.has_many.should_not be_empty
41
+ MethodDictionary.belongs_to.should_not be_empty
42
+ MethodDictionary.assignments.should_not be_empty
43
+
44
+ assign = MethodDictionary.assignments_for(@Product_klass)
45
+
46
+ assign.should include('available_on') # Example of a simple column
47
+
48
+ MethodDictionary.assignments[@Product_klass].should include('available_on')
49
+
50
+ has_many_ops = MethodDictionary.has_many_for(@Product_klass)
51
+
52
+ has_many_ops.should include('properties') # Product can have many properties
53
+
54
+ MethodDictionary.has_many[@Product_klass].should include('properties')
55
+
56
+ btf = MethodDictionary.belongs_to_for(@Product_klass)
57
+
58
+ btf.should include('tax_category') # Example of a belongs_to assignment
59
+
60
+ MethodDictionary.belongs_to[@Product_klass].should include('tax_category')
61
+
62
+ MethodDictionary.column_types[@Product_klass].size.should == @Product_klass.columns.size
63
+ end
64
+
65
+
66
+ it "should find method details correctly for different forms of a column name" do
67
+
68
+ MethodDictionary.build_method_details( @Product_klass )
69
+
70
+ ["available On", 'available_on', "Available On", "AVAILABLE_ON"].each do |format|
71
+
72
+ method_details = MethodDictionary.find_method_detail( @Product_klass, format )
73
+
74
+ method_details.operator.should == 'available_on'
75
+ method_details.operator_for(:assignment).should == 'available_on'
76
+
77
+ method_details.operator_for(:belongs_to).should be_nil
78
+ method_details.operator_for(:has_many).should be_nil
79
+
80
+ method_details.col_type.should_not be_nil
81
+ method_details.col_type.name.should == 'available_on'
82
+ method_details.col_type.default.should == nil
83
+ method_details.col_type.sql_type.should include 'datetime' # works on mysql and sqlite
84
+ method_details.col_type.type.should == :datetime
85
+ end
86
+ end
87
+
88
+ it "should populate method details correctly for has_many forms of association name" do
89
+
90
+ MethodDictionary.has_many[@Product_klass].should include('product_option_types')
91
+
92
+ MethodDictionary.build_method_details( @Product_klass )
93
+
94
+ ["product_option_types", "product option types", 'product Option_types', "ProductOptionTypes", "Product_Option_Types"].each do |format|
95
+ method_detail = MethodDictionary.find_method_detail( @Product_klass, format )
96
+
97
+ method_detail.should_not be_nil
98
+
99
+ method_detail.operator_for(:has_many).should eq('product_option_types')
100
+ method_detail.operator_for(:belongs_to).should be_nil
101
+ method_detail.operator_for(:assignment).should be_nil
102
+ end
103
+ end
104
+
105
+
106
+ it "should populate method details correctly for assignment operators (none columns on #{@Product_klass})" do
107
+
108
+ MethodDictionary.find_operators( @Product_klass, :reload => true, :instance_methods => true )
109
+
110
+ MethodDictionary.build_method_details( @Product_klass )
111
+
112
+ # Example of delegates i.e. cost_price column on Variant, delegated to Variant by Product
113
+
114
+ MethodDictionary.assignments[@Product_klass].should include('cost_price')
115
+ MethodDictionary.assignments[@Product_klass].should include('sku')
116
+
117
+
118
+ count_on_hand = MethodDictionary.find_method_detail( @Product_klass, 'count on hand' )
119
+ count_on_hand.should_not be_nil
120
+ count_on_hand.operator.should == 'count_on_hand'
121
+
122
+ method = MethodDictionary.find_method_detail( @Product_klass, 'sku' )
123
+ method.should_not be_nil
124
+ method.operator.should == 'sku'
125
+ end
126
+
127
+ it "should enable assignment via operators for none columns on #{@Product_klass}" do
128
+
129
+ MethodDictionary.find_operators( @Product_klass, :reload => true, :instance_methods => true )
130
+
131
+ MethodDictionary.build_method_details( @Product_klass )
132
+
133
+ klazz_object = @Product_klass.new
134
+
135
+ klazz_object.should be_new_record
136
+
137
+ # we can use method details to populate a new AR object, essentailly same as
138
+ # klazz_object.send( count_on_hand.operator, 2)
139
+ count_on_hand = MethodDictionary.find_method_detail( @Product_klass, 'count on hand' )
140
+
141
+ count_on_hand.assign( klazz_object, 2 )
142
+ klazz_object.count_on_hand.should == 2
143
+
144
+ count_on_hand.assign( klazz_object, 5 )
145
+ klazz_object.count_on_hand.should == 5
146
+
147
+ method = MethodDictionary.find_method_detail( @Product_klass, 'sku' )
148
+ method.should_not be_nil
149
+
150
+ method.operator.should == 'sku'
151
+
152
+ method.assign( klazz_object, 'TEST_SK 001')
153
+ klazz_object.sku.should == 'TEST_SK 001'
154
+
155
+ end
156
+
157
+ it "should enable assignment to has_many association on new object" do
158
+
159
+ MethodDictionary.build_method_details( @Product_klass )
160
+
161
+ method_detail = MethodDictionary.find_method_detail( @Product_klass, 'taxons' )
162
+
163
+ method_detail.operator.should == 'taxons'
164
+
165
+ upload_object = @Product_klass.new
166
+
167
+ upload_object.taxons.size.should == 0
168
+
169
+ # NEW ASSOCIATION ASSIGNMENT
170
+
171
+ # assign via the send operator directly on load object
172
+ upload_object.send( method_detail.operator ) << @Taxon_klass.new
173
+
174
+ upload_object.taxons.size.should == 1
175
+
176
+ upload_object.send( method_detail.operator ) << [@Taxon_klass.new, @Taxon_klass.new]
177
+ upload_object.taxons.size.should == 3
178
+
179
+ # Use generic assignment on method detail - expect has_many to use << not =
180
+ method_detail.assign( upload_object, @Taxon_klass.new )
181
+ upload_object.taxons.size.should == 4
182
+
183
+ method_detail.assign( upload_object, [@Taxon_klass.new, @Taxon_klass.new])
184
+ upload_object.taxons.size.should == 6
185
+ end
186
+
187
+ it "should enable assignment to has_many association using existing objects" do
188
+
189
+ MethodDictionary.find_operators( @Product_klass )
190
+
191
+ MethodDictionary.build_method_details( @Product_klass )
192
+
193
+ method_detail = MethodDictionary.find_method_detail( @Product_klass, 'product_properties' )
194
+
195
+ method_detail.operator.should == 'product_properties'
196
+
197
+ klazz_object = @Product_klass.new
198
+
199
+ @ProductProperty_klass.new(:property => @prop1)
200
+
201
+ # NEW ASSOCIATION ASSIGNMENT
202
+ klazz_object.send( method_detail.operator ) << @ProductProperty_klass.new
203
+
204
+ klazz_object.product_properties.size.should == 1
205
+
206
+ klazz_object.send( method_detail.operator ) << [@ProductProperty_klass.new, @ProductProperty_klass.new]
207
+ klazz_object.product_properties.size.should == 3
208
+
209
+ # Use generic assignment on method detail - expect has_many to use << not =
210
+ method_detail.assign( klazz_object, @ProductProperty_klass.new(:property => @prop1) )
211
+ klazz_object.product_properties.size.should == 4
212
+
213
+ method_detail.assign( klazz_object, [@ProductProperty_klass.new(:property => @prop2), @ProductProperty_klass.new(:property => @prop3)])
214
+ klazz_object.product_properties.size.should == 6
215
+
216
+ end
217
+
218
+
215
219
  end
@@ -1,15 +1,15 @@
1
- p = Product.seed( :name ) do |s|
2
- s.name = <%= @name %>
3
- s.available_on = '2009-09-01 09:00:00.0'
4
- s.meta_keywords = ['training', 'training']
5
- s.meta_description = ""
6
- s.description = '<%= @description %>'
7
- s.price = 0.00
8
- s.sku = '<%= @sku %>'
9
-
10
- s.is_physical = false
11
- s.is_private = false
12
-
13
- s.append_association :taxons, Taxon.find_by_name( 'Training' )
14
-
15
- end
1
+ p = Product.seed( :name ) do |s|
2
+ s.name = <%= @name %>
3
+ s.available_on = '2009-09-01 09:00:00.0'
4
+ s.meta_keywords = ['training', 'training']
5
+ s.meta_description = ""
6
+ s.description = '<%= @description %>'
7
+ s.price = 0.00
8
+ s.sku = '<%= @sku %>'
9
+
10
+ s.is_physical = false
11
+ s.is_private = false
12
+
13
+ s.append_association :taxons, Taxon.find_by_name( 'Training' )
14
+
15
+ end