importu 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,13 @@
1
+ FactoryGirl.define do
2
+ factory :importer_record, :class => Importu::Record do
3
+ initialize_with do
4
+ Importu::Record.new(importer, data, raw_data)
5
+ end
6
+
7
+ ignore do
8
+ importer { build(:importer) }
9
+ data { Hash.new }
10
+ raw_data { Hash.new }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ FactoryGirl.define do
2
+ factory :json_importer, :class => Importu::Importer::Json do
3
+ initialize_with do
4
+ infile = StringIO.new(data) if data
5
+ Importu::Importer::Json.new(infile, options)
6
+ end
7
+
8
+ ignore do
9
+ data nil # string version of input file
10
+ infile { StringIO.new("[]") }
11
+ options { Hash.new }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :xml_importer, :class => Importu::Importer::Xml do
3
+ initialize_with do
4
+ Importu::Importer::Xml.new(infile, options)
5
+ end
6
+
7
+ ignore do
8
+ infile { StringIO.new("<r/>") }
9
+ options { Hash.new }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,276 @@
1
+ require 'spec_helper'
2
+
3
+ require 'active_support/core_ext/time/calculations'
4
+
5
+ describe Importu::Importer do
6
+ subject(:record) { build(:importer_record) }
7
+
8
+ describe ":raw converter" do
9
+ it "uses definition's label as key when looking up data" do
10
+ record.stub(:definitions => { :field1 => { :label => "field1", :required => true } })
11
+ record.stub(:data => { "field1" => " value1 ", "field2" => "value2" })
12
+ record.convert(:field1, :raw).should eq " value1 "
13
+ end
14
+
15
+ it "raises an exception if field definition is not defined" do
16
+ expect { record.convert(:field1, :raw) }.to raise_error
17
+ end
18
+
19
+ it "raises MissingField if field data not defined" do
20
+ record.stub(:definitions => { :field1 => { :required => true } })
21
+ expect { record.convert(:field1, :raw) }.to raise_error(Importu::MissingField)
22
+ end
23
+ end
24
+
25
+ describe ":clean converter" do
26
+ it "returns nil if raw data is nil" do
27
+ record.converters[:raw] = proc { nil }
28
+ record.convert(:field1, :clean).should be nil
29
+ end
30
+
31
+ it "returns nil if a blank string" do
32
+ record.converters[:raw] = proc { "" }
33
+ record.convert(:field1, :clean).should be nil
34
+ end
35
+
36
+ it "returns stripped value if a string" do
37
+ record.converters[:raw] = proc { " abc 123 " }
38
+ record.convert(:field1, :clean).should eq "abc 123"
39
+ end
40
+
41
+ it "returns original value if not a string" do
42
+ raw_val = Time.now
43
+ record.converters[:raw] = proc { raw_val }
44
+ record.convert(:field1, :clean).should eq raw_val
45
+ end
46
+ end
47
+
48
+ describe ":string converter" do
49
+ it "returns nil if clean value is nil" do
50
+ record.converters[:clean] = proc { nil }
51
+ record.convert(:field1, :string).should be nil
52
+ end
53
+
54
+ it "returns string if clean value is a string" do
55
+ record.converters[:clean] = proc { "six pence" }
56
+ record.convert(:field1, :string).should eq "six pence"
57
+ end
58
+
59
+ it "converts clean value to string if not a string" do
60
+ clean_val = Time.now
61
+ record.converters[:clean] = proc { clean_val }
62
+ record.convert(:field1, :string).should eq clean_val.to_s
63
+ end
64
+ end
65
+
66
+ describe ":integer converter" do
67
+ it "returns nil if clean value is nil" do
68
+ record.converters[:clean] = proc { nil }
69
+ record.convert(:field1, :integer).should be nil
70
+ end
71
+
72
+ it "returns integer if clean value returns an integer" do
73
+ record.converters[:clean] = proc { 92 }
74
+ record.convert(:field1, :integer).should eq 92
75
+ end
76
+
77
+ it "converts clean value to integer if not an integer type" do
78
+ record.converters[:clean] = proc { "29" }
79
+ record.convert(:field1, :integer).should eq 29
80
+ end
81
+
82
+ it "raises an exception if clean value is not a valid integer" do
83
+ record.converters[:clean] = proc { "4.25" }
84
+ expect { record.convert(:field1, :integer) }.to raise_error(Importu::FieldParseError)
85
+ end
86
+ end
87
+
88
+ describe ":float converter" do
89
+ it "returns nil if clean value is nil" do
90
+ record.converters[:clean] = proc { nil }
91
+ record.convert(:field1, :float).should be nil
92
+ end
93
+
94
+ it "returns float if clean value returns an float" do
95
+ record.converters[:clean] = proc { 92.25 }
96
+ record.convert(:field1, :float).should eq 92.25
97
+ end
98
+
99
+ it "converts clean value to float if not an float type" do
100
+ record.converters[:clean] = proc { "29.4" }
101
+ record.convert(:field1, :float).should eq 29.4
102
+ end
103
+
104
+ it "converts whole values to float" do
105
+ record.converters[:clean] = proc { "77" }
106
+ record.convert(:field1, :float).should eq 77.0
107
+ end
108
+
109
+ it "raises an exception if clean value is not a valid float" do
110
+ record.converters[:clean] = proc { "4d6point3" }
111
+ expect { record.convert(:field1, :float) }.to raise_error(Importu::FieldParseError)
112
+ end
113
+ end
114
+
115
+ describe ":decimal converter" do
116
+ it "returns nil if clean value is nil" do
117
+ record.converters[:clean] = proc { nil }
118
+ record.convert(:field1, :decimal).should be nil
119
+ end
120
+
121
+ it "returns decimal if clean value returns an decimal" do
122
+ clean_val = BigDecimal("92.25")
123
+ record.converters[:clean] = proc { clean_val }
124
+ record.convert(:field1, :decimal).should eq clean_val
125
+ end
126
+
127
+ it "converts clean value to decimal if not an decimal type" do
128
+ record.converters[:clean] = proc { "29.4" }
129
+ record.convert(:field1, :decimal).should eq BigDecimal("29.4")
130
+ end
131
+
132
+ it "converts whole values to decimal" do
133
+ record.converters[:clean] = proc { "77" }
134
+ record.convert(:field1, :decimal).should eq BigDecimal("77.0")
135
+ end
136
+
137
+ it "raises an exception if clean value is not a valid decimal" do
138
+ record.converters[:clean] = proc { "4d6point3" }
139
+ expect { record.convert(:field1, :decimal) }.to raise_error(Importu::FieldParseError)
140
+ end
141
+ end
142
+
143
+ describe ":boolean converter" do
144
+ it "returns nil if clean value is nil" do
145
+ record.converters[:clean] = proc { nil }
146
+ record.convert(:field1, :boolean).should be nil
147
+ end
148
+
149
+ it "returns true if clean value is true" do
150
+ record.converters[:clean] = proc { true }
151
+ record.convert(:field1, :boolean).should eq true
152
+ end
153
+
154
+ it "returns true if clean value is 'true'" do
155
+ record.converters[:clean] = proc { "true" }
156
+ record.convert(:field1, :boolean).should eq true
157
+ end
158
+
159
+ it "returns true if clean value is 'yes'" do
160
+ record.converters[:clean] = proc { "yes" }
161
+ record.convert(:field1, :boolean).should eq true
162
+ end
163
+
164
+ it "returns true if clean value is '1'" do
165
+ record.converters[:clean] = proc { "1" }
166
+ record.convert(:field1, :boolean).should eq true
167
+ end
168
+
169
+ it "returns true if clean value is 1" do
170
+ record.converters[:clean] = proc { 1 }
171
+ record.convert(:field1, :boolean).should eq true
172
+ end
173
+
174
+ it "returns false if clean value is false" do
175
+ record.converters[:clean] = proc { false }
176
+ record.convert(:field1, :boolean).should eq false
177
+ end
178
+
179
+ it "returns false if clean value is 'false'" do
180
+ record.converters[:clean] = proc { "false" }
181
+ record.convert(:field1, :boolean).should eq false
182
+ end
183
+
184
+ it "returns false if clean value is 'no'" do
185
+ record.converters[:clean] = proc { "no" }
186
+ record.convert(:field1, :boolean).should eq false
187
+ end
188
+
189
+ it "returns false if clean value is '0'" do
190
+ record.converters[:clean] = proc { "0" }
191
+ record.convert(:field1, :boolean).should eq false
192
+ end
193
+
194
+ it "returns false if clean value is 0" do
195
+ record.converters[:clean] = proc { 0 }
196
+ record.convert(:field1, :boolean).should eq false
197
+ end
198
+ end
199
+
200
+ describe ":date converter" do
201
+ it "returns nil if clean value is nil" do
202
+ record.converters[:clean] = proc { nil }
203
+ record.convert(:field1, :date).should be nil
204
+ end
205
+
206
+ context "when a format is not specified" do
207
+ it "tries to guess the date format (DD/MM/YYYY is default?)" do
208
+ expected = Date.new(2012, 10, 3)
209
+ record.converters[:clean] = proc { "03/10/2012" }
210
+ record.convert(:field1, :date).should eq expected
211
+ end
212
+
213
+ it "raises an exception if the date is invaild" do
214
+ record.converters[:clean] = proc { "2012-04-32" }
215
+ expect { record.convert(:field1, :date) }.to raise_error(Importu::FieldParseError)
216
+ end
217
+ end
218
+
219
+ context "when a format is specified" do
220
+ it "parses dates that match the format" do
221
+ expected = Date.new(2012, 4, 18)
222
+ record.converters[:clean] = proc { "04/18/2012" }
223
+ record.convert(:field1, :date, :format => "%m/%d/%Y").should eq expected
224
+ end
225
+
226
+ it "raises exception if date doesn't match the format" do
227
+ record.converters[:clean] = proc { "04-18-2012" }
228
+ expect { record.convert(:field1, :date) }.to raise_error(Importu::FieldParseError)
229
+ end
230
+
231
+ it "raises an exception if the date is invalid" do
232
+ record.converters[:clean] = proc { "04/32/2012" }
233
+ expect { record.convert(:field1, :date) }.to raise_error(Importu::FieldParseError)
234
+ end
235
+ end
236
+ end
237
+
238
+ describe ":datetime converter" do
239
+ it "returns nil if clean value is nil" do
240
+ record.converters[:clean] = proc { nil }
241
+ record.convert(:field1, :datetime).should be nil
242
+ end
243
+
244
+ context "when a format is not specified" do
245
+ it "tries to guess the date format (DD/MM/YYYY is default?)" do
246
+ expected = DateTime.parse("2012-10-03 04:37:29")
247
+ record.converters[:clean] = proc { "03/10/2012 04:37:29" }
248
+ record.convert(:field1, :datetime).should eq expected
249
+ end
250
+
251
+ it "raises an exception if the datetime is invaild" do
252
+ record.converters[:clean] = proc { "2012-04-32 15:41:22" }
253
+ expect { record.convert(:field1, :datetime) }.to raise_error(Importu::FieldParseError)
254
+ end
255
+ end
256
+
257
+ context "when a format is specified" do
258
+ it "parses datetimes that match the format" do
259
+ expected = DateTime.parse("2012-04-18 16:37:00")
260
+ record.converters[:clean] = proc { "04/18/2012 16:37" }
261
+ record.convert(:field1, :datetime, :format => "%m/%d/%Y %H:%M").should eq expected
262
+ end
263
+
264
+ it "raises exception if datetime doesn't match the format" do
265
+ record.converters[:clean] = proc { "04-18-2012 15:22:19" }
266
+ expect { record.convert(:field1, :datetime) }.to raise_error(Importu::FieldParseError)
267
+ end
268
+
269
+ it "raises an exception if the datetime is invalid" do
270
+ record.converters[:clean] = proc { "04/32/2012 00:00:00" }
271
+ expect { record.convert(:field1, :datetime) }.to raise_error(Importu::FieldParseError)
272
+ end
273
+ end
274
+ end
275
+
276
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importu::Importer do
4
+ describe "::record_class" do
5
+ it "returns Importu::Record by default" do
6
+ Importu::Importer.record_class.should eq Importu::Record
7
+ end
8
+
9
+ it "can be overridden globally" do
10
+ custom_record_class = Class.new(Importu::Record)
11
+ orig = Importu::Importer.record_class
12
+ Importu::Importer.record_class custom_record_class
13
+ Importu::Importer.record_class.should eq custom_record_class
14
+ Importu::Importer.record_class orig
15
+ end
16
+
17
+ it "can be overridden in a subclass" do
18
+ custom_record_class = Class.new(Importu::Record)
19
+ klass = Class.new(Importu::Importer) do
20
+ record_class custom_record_class
21
+ end
22
+
23
+ klass.record_class.should eq custom_record_class
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importu::ImportuException do
4
+ subject(:exception) { Importu::ImportuException.new }
5
+
6
+ it "#name should return 'ImportuException" do
7
+ exception.name.should eq "ImportuException"
8
+ end
9
+
10
+ describe Importu::InvalidInput do
11
+ subject(:exception) { Importu::InvalidInput.new }
12
+
13
+ it "should be a subclass of Importu::ImportuException" do
14
+ exception.class.ancestors.include?(Importu::ImportuException)
15
+ end
16
+
17
+ it "#name should return 'InvalidInput'" do
18
+ exception.name.should eq "InvalidInput"
19
+ end
20
+ end
21
+
22
+ describe Importu::InvalidRecord do
23
+ subject(:exception) { Importu::InvalidRecord.new }
24
+
25
+ it "should be a subclass of Importu::ImportuException" do
26
+ exception.class.ancestors.include?(Importu::ImportuException)
27
+ end
28
+
29
+ it "#name should return 'InvalidRecord'" do
30
+ exception.name.should eq "InvalidRecord"
31
+ end
32
+ end
33
+
34
+ describe Importu::FieldParseError do
35
+ subject(:exception) { Importu::FieldParseError.new }
36
+
37
+ it "should be a subclass of Importu::InvalidRecord" do
38
+ exception.class.ancestors.include?(Importu::InvalidRecord)
39
+ end
40
+
41
+ it "#name should return 'FieldParseError'" do
42
+ exception.name.should eq "FieldParseError"
43
+ end
44
+ end
45
+
46
+ describe Importu::MissingField do
47
+ let(:definition) { { :name => "foo_field_1", :label => "Field 1" } }
48
+ subject(:exception) { Importu::MissingField.new(definition) }
49
+
50
+ it "should be a subclass of Importu::InvalidRecord" do
51
+ exception.class.ancestors.include?(Importu::InvalidRecord)
52
+ end
53
+
54
+ it "#name should return 'MissingField'" do
55
+ exception.name.should eq "MissingField"
56
+ end
57
+
58
+ it "#definition should return the definition passed during construction" do
59
+ exception.definition.should eq definition
60
+ end
61
+
62
+ describe "#message" do
63
+ it "should mention a missing field" do
64
+ exception.message.should match(/missing field/i)
65
+ end
66
+
67
+ context "field definition has a label" do
68
+ let(:definition) { { :label => "Field 2" } }
69
+ it "mentions missing field's label" do
70
+ exception.message.should match(/Field 2/)
71
+ end
72
+ end
73
+
74
+ context "field definition is missing a label" do
75
+ let(:definition) { { :name => "foo_field_2" } }
76
+
77
+ it "mentions missing field's name" do
78
+ exception.message.should match(/foo_field_2/)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ describe Importu::DuplicateRecord do
85
+ subject(:exception) { Importu::DuplicateRecord.new }
86
+
87
+ it "should be a subclass of Importu::InvalidRecord" do
88
+ exception.class.ancestors.include?(Importu::InvalidRecord)
89
+ end
90
+
91
+ it "#name should return 'DuplicateRecord'" do
92
+ exception.name.should eq "DuplicateRecord"
93
+ end
94
+ end
95
+
96
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Importu::Importer::Json do
4
+ subject(:importer) { build(:json_importer, :data => data) }
5
+
6
+ context "input file is blank" do
7
+ let(:data) { "" }
8
+
9
+ it "raises an InvalidInput exception" do
10
+ expect { importer }.to raise_error Importu::InvalidInput
11
+ end
12
+ end
13
+
14
+ context "non-array root elements" do
15
+ %w({}, "foo", 3, 3.7, false, nil).each do |data|
16
+ it "raises InvalidInput exception if root is #{data}" do
17
+ expect { build(:json_importer, :data => "") }.to raise_error Importu::InvalidInput
18
+ end
19
+ end
20
+ end
21
+
22
+ context "input file is []" do
23
+ let(:data) { "[]" }
24
+
25
+ it "treats file as having 0 records" do
26
+ importer.records.should have(0).items
27
+ end
28
+ end
29
+
30
+ context "input file is [{},{}]" do
31
+ let(:data) { "[{},{}]" }
32
+
33
+ it "treats file as having 2 records" do
34
+ importer.records.should have(2).items
35
+ end
36
+ end
37
+ end