remi 0.2.42 → 0.3.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.
- checksums.yaml +4 -4
- data/.yardopts +7 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -26
- data/README.md +1 -1
- data/features/step_definitions/remi_step.rb +33 -13
- data/features/sub_job_example.feature +24 -0
- data/features/sub_transform_example.feature +35 -0
- data/features/sub_transform_many_to_many.feature +49 -0
- data/features/support/env_app.rb +1 -1
- data/jobs/all_jobs_shared.rb +19 -16
- data/jobs/copy_source_job.rb +11 -9
- data/jobs/csv_file_target_job.rb +10 -9
- data/jobs/json_job.rb +18 -14
- data/jobs/metadata_job.rb +33 -28
- data/jobs/parameters_job.rb +14 -11
- data/jobs/sample_job.rb +106 -77
- data/jobs/sftp_file_target_job.rb +14 -13
- data/jobs/sub_job_example_job.rb +86 -0
- data/jobs/sub_transform_example_job.rb +43 -0
- data/jobs/sub_transform_many_to_many_job.rb +46 -0
- data/jobs/transforms/concatenate_job.rb +16 -12
- data/jobs/transforms/data_frame_sieve_job.rb +24 -19
- data/jobs/transforms/date_diff_job.rb +15 -11
- data/jobs/transforms/nvl_job.rb +16 -12
- data/jobs/transforms/parse_date_job.rb +17 -14
- data/jobs/transforms/partitioner_job.rb +27 -19
- data/jobs/transforms/prefix_job.rb +13 -10
- data/jobs/transforms/truncate_job.rb +14 -10
- data/jobs/transforms/truthy_job.rb +11 -8
- data/lib/remi.rb +25 -11
- data/lib/remi/data_frame.rb +4 -4
- data/lib/remi/data_frame/daru.rb +1 -37
- data/lib/remi/data_subject.rb +234 -48
- data/lib/remi/data_subjects/csv_file.rb +171 -0
- data/lib/remi/data_subjects/data_frame.rb +106 -0
- data/lib/remi/data_subjects/file_system.rb +115 -0
- data/lib/remi/data_subjects/local_file.rb +109 -0
- data/lib/remi/data_subjects/none.rb +31 -0
- data/lib/remi/data_subjects/postgres.rb +186 -0
- data/lib/remi/data_subjects/s3_file.rb +84 -0
- data/lib/remi/data_subjects/salesforce.rb +211 -0
- data/lib/remi/data_subjects/sftp_file.rb +196 -0
- data/lib/remi/data_subjects/sub_job.rb +50 -0
- data/lib/remi/dsl.rb +74 -0
- data/lib/remi/encoder.rb +45 -0
- data/lib/remi/extractor.rb +21 -0
- data/lib/remi/field_symbolizers.rb +1 -0
- data/lib/remi/job.rb +279 -113
- data/lib/remi/job/parameters.rb +90 -0
- data/lib/remi/job/sub_job.rb +35 -0
- data/lib/remi/job/transform.rb +165 -0
- data/lib/remi/loader.rb +22 -0
- data/lib/remi/monkeys/daru.rb +4 -0
- data/lib/remi/parser.rb +44 -0
- data/lib/remi/testing/business_rules.rb +17 -23
- data/lib/remi/testing/data_stub.rb +2 -2
- data/lib/remi/version.rb +1 -1
- data/remi.gemspec +3 -0
- data/spec/data_subject_spec.rb +475 -11
- data/spec/data_subjects/csv_file_spec.rb +69 -0
- data/spec/data_subjects/data_frame_spec.rb +52 -0
- data/spec/{extractor → data_subjects}/file_system_spec.rb +0 -0
- data/spec/{extractor → data_subjects}/local_file_spec.rb +0 -0
- data/spec/data_subjects/none_spec.rb +41 -0
- data/spec/data_subjects/postgres_spec.rb +80 -0
- data/spec/{extractor → data_subjects}/s3_file_spec.rb +0 -0
- data/spec/data_subjects/salesforce_spec.rb +117 -0
- data/spec/{extractor → data_subjects}/sftp_file_spec.rb +16 -0
- data/spec/data_subjects/sub_job_spec.rb +33 -0
- data/spec/encoder_spec.rb +38 -0
- data/spec/extractor_spec.rb +11 -0
- data/spec/fixtures/sf_bulk_helper_stubs.rb +443 -0
- data/spec/job/transform_spec.rb +257 -0
- data/spec/job_spec.rb +507 -0
- data/spec/loader_spec.rb +11 -0
- data/spec/parser_spec.rb +38 -0
- data/spec/sf_bulk_helper_spec.rb +117 -0
- data/spec/testing/data_stub_spec.rb +5 -3
- metadata +109 -27
- data/features/aggregate.feature +0 -42
- data/jobs/aggregate_job.rb +0 -31
- data/jobs/transforms/transform_jobs.rb +0 -4
- data/lib/remi/data_subject/csv_file.rb +0 -162
- data/lib/remi/data_subject/data_frame.rb +0 -52
- data/lib/remi/data_subject/postgres.rb +0 -134
- data/lib/remi/data_subject/salesforce.rb +0 -136
- data/lib/remi/data_subject/sftp_file.rb +0 -65
- data/lib/remi/extractor/file_system.rb +0 -92
- data/lib/remi/extractor/local_file.rb +0 -43
- data/lib/remi/extractor/s3_file.rb +0 -57
- data/lib/remi/extractor/sftp_file.rb +0 -83
- data/spec/data_subject/csv_file_spec.rb +0 -79
- data/spec/data_subject/data_frame.rb +0 -27
@@ -2,13 +2,13 @@ module Remi
|
|
2
2
|
module Testing
|
3
3
|
module DataStub
|
4
4
|
def stub_row_array
|
5
|
-
|
5
|
+
fields.values.map do |attribs|
|
6
6
|
stub_values(attribs)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
def empty_stub_df
|
11
|
-
self.df = Daru::DataFrame.new([], order:
|
11
|
+
self.df = Daru::DataFrame.new([], order: fields.keys)
|
12
12
|
end
|
13
13
|
|
14
14
|
def stub_df
|
data/lib/remi/version.rb
CHANGED
data/remi.gemspec
CHANGED
@@ -34,6 +34,9 @@ Gem::Specification.new do |s|
|
|
34
34
|
# s.add_runtime_dependency 'salesforce_bulk_api', ['0.0.12']
|
35
35
|
|
36
36
|
s.add_development_dependency 'iruby', ['0.2.7']
|
37
|
+
s.add_development_dependency 'yard', ['~> 0.9']
|
38
|
+
s.add_development_dependency 'redcarpet', ['~> 3.3']
|
39
|
+
s.add_development_dependency 'github-markup', ['~> 1.4']
|
37
40
|
|
38
41
|
s.files = `git ls-files`.split("\n")
|
39
42
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/spec/data_subject_spec.rb
CHANGED
@@ -1,23 +1,96 @@
|
|
1
1
|
require_relative 'remi_spec'
|
2
2
|
|
3
|
-
# VERY SPARSE TESTING! DO MORE!
|
4
|
-
|
5
3
|
describe DataSubject do
|
4
|
+
let(:data_subject) { DataSubject.new(name: :awesome_subject) }
|
5
|
+
|
6
|
+
context 'DSL' do
|
7
|
+
let(:dsl_data_subject) do
|
8
|
+
DataSubject.new(name: :awesome_dsl_subject) do
|
9
|
+
fields :id => {}
|
10
|
+
field_symbolizer :salesforce
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'defines the fields' do
|
15
|
+
expect(dsl_data_subject.dsl_eval.fields).to eq({ :id => {} })
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'sets the field symbolizer' do
|
19
|
+
expect(dsl_data_subject.dsl_eval.field_symbolizer).to eq(Remi::FieldSymbolizers[:salesforce])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has a name' do
|
24
|
+
expect(data_subject.name).to eq :awesome_subject
|
25
|
+
end
|
26
|
+
|
27
|
+
context '#df_type' do
|
28
|
+
it 'returns the dataframe type' do
|
29
|
+
expect(data_subject.df_type).to eq :daru
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'sets the dataframe type' do
|
33
|
+
expect { data_subject.df_type(:spark) }.to change {
|
34
|
+
data_subject.df_type
|
35
|
+
}.from(:daru).to(:spark)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context '#fields' do
|
40
|
+
it 'returns the field metadata' do
|
41
|
+
expect(data_subject.fields).to be_a Remi::Fields
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'sets the field metadata' do
|
45
|
+
expect { data_subject.fields({ :id => {} }) }.to change {
|
46
|
+
data_subject.fields
|
47
|
+
}.from({}).to({ :id => {} })
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context '#field_symbolizer' do
|
52
|
+
it 'returns the field symbolizer defined for this source' do
|
53
|
+
expect(data_subject.field_symbolizer).to eq Remi::FieldSymbolizers[:standard]
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'sets the field symbolizer' do
|
57
|
+
data_subject.field_symbolizer :salesforce
|
58
|
+
expect(data_subject.field_symbolizer).to eq Remi::FieldSymbolizers[:salesforce]
|
59
|
+
end
|
60
|
+
end
|
6
61
|
|
7
|
-
|
8
|
-
|
9
|
-
Remi::DataFrame::Daru
|
62
|
+
context '#df' do
|
63
|
+
it 'returns the dataframe associated with this subject' do
|
64
|
+
expect(data_subject.df).to be_a Remi::DataFrame::Daru
|
10
65
|
end
|
66
|
+
end
|
11
67
|
|
12
|
-
|
13
|
-
|
68
|
+
context '#df=' do
|
69
|
+
let(:reassigned_df) { Daru::DataFrame.new({ a: [1955] }) }
|
70
|
+
it 'reassigns the dataframe associated with this subject' do
|
71
|
+
data_subject.df = reassigned_df
|
72
|
+
expect(data_subject.df).to eq reassigned_df
|
14
73
|
end
|
15
74
|
|
75
|
+
it 'converts any non-remi dataframes to a remi dataframe' do
|
76
|
+
data_subject.df = reassigned_df
|
77
|
+
expect(data_subject.df).to be_a Remi::DataFrame::Daru
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context '#enforce_types' do
|
82
|
+
let(:dataframe) { Remi::DataFrame::Daru.new({ my_date: ['10/21/2015'] }) }
|
83
|
+
|
16
84
|
let(:fields) do
|
17
|
-
|
18
|
-
my_date:
|
85
|
+
{
|
86
|
+
my_date: { type: :date, in_format: '%m/%d/%Y' },
|
19
87
|
other_date: { type: :date, in_format: '%m/%d/%Y' }
|
20
|
-
}
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
before do
|
92
|
+
data_subject.fields = fields
|
93
|
+
data_subject.df = dataframe
|
21
94
|
end
|
22
95
|
|
23
96
|
it 'converts a date string to a date using an in_format' do
|
@@ -25,12 +98,22 @@ describe DataSubject do
|
|
25
98
|
expect(data_subject.df[:my_date].to_a).to eq [Date.new(2015, 10, 21)]
|
26
99
|
end
|
27
100
|
|
28
|
-
it '
|
101
|
+
it 'converts types when explicitly specified' do
|
102
|
+
data_subject.enforce_types(:date)
|
103
|
+
expect(data_subject.df[:my_date].to_a).to eq [Date.new(2015, 10, 21)]
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'does not do any conversion if the field has no type specified' do
|
29
107
|
fields[:my_date].delete(:type)
|
30
108
|
data_subject.enforce_types
|
31
109
|
expect(data_subject.df[:my_date].to_a).to eq ['10/21/2015']
|
32
110
|
end
|
33
111
|
|
112
|
+
it 'does not do any conversion if field metadata does not match the selected enforcement type' do
|
113
|
+
data_subject.enforce_types(:decimal)
|
114
|
+
expect(data_subject.df[:my_date].to_a).to eq ['10/21/2015']
|
115
|
+
end
|
116
|
+
|
34
117
|
it 'throws an error if the data does not conform to its type' do
|
35
118
|
dataframe[:my_date].recode! { |v| '2015-10-21' }
|
36
119
|
expect { data_subject.enforce_types }.to raise_error ArgumentError
|
@@ -42,3 +125,384 @@ describe DataSubject do
|
|
42
125
|
end
|
43
126
|
end
|
44
127
|
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
describe DataSource do
|
133
|
+
let(:data_source) { DataSource.new }
|
134
|
+
|
135
|
+
let(:my_extractor) { double('my_extractor') }
|
136
|
+
let(:my_extractor2) { double('my_extractor2') }
|
137
|
+
let(:my_parser) { Remi::Parser.new }
|
138
|
+
|
139
|
+
|
140
|
+
before do
|
141
|
+
allow(my_extractor).to receive(:extract) .and_return 'result_1'
|
142
|
+
allow(my_extractor2).to receive(:extract) .and_return 'result_2'
|
143
|
+
allow(my_parser).to receive(:parse)
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
context 'DSL' do
|
148
|
+
let(:dsl_data_source) do
|
149
|
+
scoped_my_extractor = my_extractor
|
150
|
+
scoped_my_extractor2 = my_extractor2
|
151
|
+
scoped_my_parser = my_parser
|
152
|
+
|
153
|
+
DataSource.new(name: :awesome_dsl_source) do
|
154
|
+
extractor scoped_my_extractor
|
155
|
+
extractor scoped_my_extractor2
|
156
|
+
parser scoped_my_parser
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'adds extractors to the list of extractors' do
|
161
|
+
expect(dsl_data_source.dsl_eval.extractors).to eq [my_extractor, my_extractor2]
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'sets the parser' do
|
165
|
+
expect(dsl_data_source.dsl_eval.parser).to eq my_parser
|
166
|
+
end
|
167
|
+
|
168
|
+
context '#df' do
|
169
|
+
it 'executes the DSL commands that have been declared' do
|
170
|
+
expect(my_extractor).to receive :extract
|
171
|
+
expect(my_extractor2).to receive :extract
|
172
|
+
expect(my_parser).to receive :parse
|
173
|
+
dsl_data_source.df
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context '#field_symbolizer' do
|
178
|
+
context 'field_symbolizer called before parser' do
|
179
|
+
let(:before_parser) do
|
180
|
+
scoped_my_parser = my_parser
|
181
|
+
DataSource.new do
|
182
|
+
field_symbolizer :salesforce
|
183
|
+
parser scoped_my_parser
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'is used to set the field_symbolizer of the parser' do
|
188
|
+
expect {
|
189
|
+
before_parser.dsl_eval
|
190
|
+
}.to change {
|
191
|
+
my_parser.field_symbolizer
|
192
|
+
}.from(Remi::FieldSymbolizers[:standard]).to(Remi::FieldSymbolizers[:salesforce])
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'field_symbolizer called after parser' do
|
197
|
+
let(:after_parser) do
|
198
|
+
scoped_my_parser = my_parser
|
199
|
+
DataSource.new do
|
200
|
+
parser scoped_my_parser
|
201
|
+
field_symbolizer :salesforce
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'sets the field symbolizer of the parser for any parsers defined above' do
|
206
|
+
expect {
|
207
|
+
after_parser.dsl_eval
|
208
|
+
}.to change {
|
209
|
+
my_parser.field_symbolizer
|
210
|
+
}.from(Remi::FieldSymbolizers[:standard]).to(Remi::FieldSymbolizers[:salesforce])
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context '#extractor' do
|
217
|
+
before { data_source.extractor 'my_extractor' }
|
218
|
+
|
219
|
+
it 'adds an extractor to the list of extractors' do
|
220
|
+
expect(data_source.extractors).to eq ['my_extractor']
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'allows for multiple extractors to be defined' do
|
224
|
+
data_source.extractor 'my_extractor2'
|
225
|
+
expect(data_source.extractors).to eq ['my_extractor', 'my_extractor2']
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context '#parser' do
|
230
|
+
let(:my_parser) { Remi::Parser.new }
|
231
|
+
|
232
|
+
context 'default parser' do
|
233
|
+
it 'uses the None parser' do
|
234
|
+
expect(data_source.parser).to be_a Parser::None
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'defining a parser' do
|
239
|
+
before { data_source.parser my_parser }
|
240
|
+
|
241
|
+
it 'sets the parser' do
|
242
|
+
expect(data_source.parser).to eq my_parser
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'only allows one parser to be defined' do
|
246
|
+
my_new_parser = my_parser.clone
|
247
|
+
data_source.parser my_new_parser
|
248
|
+
expect(data_source.parser).to eq my_new_parser
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'sets the context of parser' do
|
252
|
+
data_source.parser my_parser
|
253
|
+
expect(my_parser.context).to eq data_source
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context 'with parsers and extractors defined' do
|
259
|
+
before do
|
260
|
+
data_source.extractor my_extractor
|
261
|
+
data_source.extractor my_extractor2
|
262
|
+
data_source.parser my_parser
|
263
|
+
end
|
264
|
+
|
265
|
+
context '#extract' do
|
266
|
+
it 'extracts data from each extractor' do
|
267
|
+
expect(my_extractor).to receive :extract
|
268
|
+
expect(my_extractor2).to receive :extract
|
269
|
+
data_source.extract
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'collects the results of each extractor' do
|
273
|
+
expect(data_source.extract).to eq ['result_1', 'result_2']
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context '#parse' do
|
278
|
+
it 'uses the specified parser to parse the extracted data' do
|
279
|
+
expect(my_parser).to receive(:parse) .with('result_1', 'result_2')
|
280
|
+
data_source.parse
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context '#df' do
|
285
|
+
context 'a dataframe has not already been defined' do
|
286
|
+
|
287
|
+
it 'extracts' do
|
288
|
+
expect(data_source).to receive :extract
|
289
|
+
data_source.df
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'parses' do
|
293
|
+
expect(data_source).to receive :parse
|
294
|
+
data_source.df
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'a dataframe has already been defined' do
|
299
|
+
let(:dataframe) do
|
300
|
+
df = double('df')
|
301
|
+
allow(df).to receive :df_type
|
302
|
+
df
|
303
|
+
end
|
304
|
+
before { data_source.df = dataframe }
|
305
|
+
|
306
|
+
it 'simply returns the defined dataframe' do
|
307
|
+
expect(data_source.df).to eq dataframe
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'does not extract' do
|
311
|
+
expect(data_source).not_to receive :extract
|
312
|
+
data_source.df
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'does not parse' do
|
316
|
+
expect(data_source).not_to receive :parse
|
317
|
+
data_source.df
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
context '#reset', skip: 'todo' do
|
323
|
+
it 'clears the current dataframe' do
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'allows the source data to be extracted and parsed again' do
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
describe DataTarget do
|
334
|
+
let(:data_target) { DataTarget.new }
|
335
|
+
|
336
|
+
let(:my_encoder) { Remi::Encoder.new }
|
337
|
+
let(:my_loader) { double('my_loader') }
|
338
|
+
let(:my_loader2) { double('my_loader2') }
|
339
|
+
|
340
|
+
before do
|
341
|
+
allow(my_loader).to receive(:load)
|
342
|
+
allow(my_loader2).to receive(:load)
|
343
|
+
allow(my_encoder).to receive(:encode) .and_return 'encoded data'
|
344
|
+
end
|
345
|
+
|
346
|
+
context 'DSL' do
|
347
|
+
let(:dsl_data_target) do
|
348
|
+
scoped_my_encoder = my_encoder
|
349
|
+
scoped_my_loader = my_loader
|
350
|
+
scoped_my_loader2 = my_loader2
|
351
|
+
|
352
|
+
DataTarget.new do
|
353
|
+
encoder scoped_my_encoder
|
354
|
+
loader scoped_my_loader
|
355
|
+
loader scoped_my_loader2
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
it 'adds loaders to the list of loaders' do
|
360
|
+
expect(dsl_data_target.dsl_eval.loaders).to eq [my_loader, my_loader2]
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'sets the encoder' do
|
364
|
+
expect(dsl_data_target.dsl_eval.encoder).to eq my_encoder
|
365
|
+
end
|
366
|
+
|
367
|
+
context '#load' do
|
368
|
+
it 'executes the DSL commands that have been declared' do
|
369
|
+
df_double = double('df')
|
370
|
+
allow(df_double).to receive(:size) .and_return(1)
|
371
|
+
|
372
|
+
allow(dsl_data_target).to receive(:df) .and_return(df_double)
|
373
|
+
|
374
|
+
expect(my_encoder).to receive :encode
|
375
|
+
expect(my_loader).to receive :load
|
376
|
+
expect(my_loader2).to receive :load
|
377
|
+
dsl_data_target.load
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
|
382
|
+
context '#field_symbolizer' do
|
383
|
+
context 'field_symbolizer called before encoder' do
|
384
|
+
let(:before_encoder) do
|
385
|
+
scoped_my_encoder = my_encoder
|
386
|
+
DataTarget.new do
|
387
|
+
field_symbolizer :salesforce
|
388
|
+
encoder scoped_my_encoder
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'is used to set the field_symbolizer of the encoder' do
|
393
|
+
expect {
|
394
|
+
before_encoder.dsl_eval
|
395
|
+
}.to change {
|
396
|
+
my_encoder.field_symbolizer
|
397
|
+
}.from(Remi::FieldSymbolizers[:standard]).to(Remi::FieldSymbolizers[:salesforce])
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
context 'field_symbolizer called after encoder' do
|
402
|
+
let(:after_encoder) do
|
403
|
+
scoped_my_encoder = my_encoder
|
404
|
+
DataTarget.new do
|
405
|
+
encoder scoped_my_encoder
|
406
|
+
field_symbolizer :salesforce
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'sets the field symbolizer of the encoder for any encoders defined above' do
|
411
|
+
expect {
|
412
|
+
after_encoder.dsl_eval
|
413
|
+
}.to change {
|
414
|
+
my_encoder.field_symbolizer
|
415
|
+
}.from(Remi::FieldSymbolizers[:standard]).to(Remi::FieldSymbolizers[:salesforce])
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
context '#encoder' do
|
422
|
+
let(:my_encoder) { Remi::Encoder.new }
|
423
|
+
|
424
|
+
context 'default encoder' do
|
425
|
+
it 'uses the None encoder' do
|
426
|
+
expect(data_target.encoder).to be_a Encoder::None
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
context 'defining an encoder' do
|
431
|
+
before { data_target.encoder my_encoder }
|
432
|
+
|
433
|
+
it 'sets the encoder' do
|
434
|
+
expect(data_target.encoder).to eq my_encoder
|
435
|
+
end
|
436
|
+
|
437
|
+
it 'only allows one encoder to be defined' do
|
438
|
+
my_new_encoder = my_encoder.clone
|
439
|
+
data_target.encoder my_new_encoder
|
440
|
+
expect(data_target.encoder).to eq my_new_encoder
|
441
|
+
end
|
442
|
+
|
443
|
+
it 'sets the context of encoder' do
|
444
|
+
data_target.encoder my_encoder
|
445
|
+
expect(my_encoder.context).to eq data_target
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
context '#loader' do
|
451
|
+
before { data_target.loader 'my_loader' }
|
452
|
+
|
453
|
+
it 'adds a loader to the list of loaders' do
|
454
|
+
expect(data_target.loaders).to eq ['my_loader']
|
455
|
+
end
|
456
|
+
|
457
|
+
it 'allows for multiple loaders to be defined' do
|
458
|
+
data_target.loader 'my_loader2'
|
459
|
+
expect(data_target.loaders).to eq ['my_loader', 'my_loader2']
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
context '#load' do
|
464
|
+
before do
|
465
|
+
data_target.encoder my_encoder
|
466
|
+
data_target.loader my_loader
|
467
|
+
data_target.loader my_loader2
|
468
|
+
|
469
|
+
df_double = double('df')
|
470
|
+
allow(df_double).to receive(:size) .and_return(1)
|
471
|
+
|
472
|
+
allow(data_target).to receive(:df) .and_return(df_double)
|
473
|
+
end
|
474
|
+
|
475
|
+
it 'encodes data represented in the dataframe' do
|
476
|
+
expect(my_encoder).to receive(:encode).once
|
477
|
+
data_target.load
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'passes encoded data to each of the loaders' do
|
481
|
+
expect(my_loader).to receive(:load).with('encoded data')
|
482
|
+
expect(my_loader2).to receive(:load).with('encoded data')
|
483
|
+
data_target.load
|
484
|
+
end
|
485
|
+
|
486
|
+
it 'triggers a load for all of the loaders' do
|
487
|
+
expect(my_loader).to receive(:load).once
|
488
|
+
expect(my_loader2).to receive(:load).once
|
489
|
+
data_target.load
|
490
|
+
end
|
491
|
+
|
492
|
+
it 'does not trigger loads twice' do
|
493
|
+
expect(my_loader).to receive(:load).once
|
494
|
+
expect(my_loader2).to receive(:load).once
|
495
|
+
data_target.load
|
496
|
+
data_target.load
|
497
|
+
end
|
498
|
+
|
499
|
+
context '#load!' do
|
500
|
+
it 'triggers loads every time it is called' do
|
501
|
+
expect(my_loader).to receive(:load).twice
|
502
|
+
expect(my_loader2).to receive(:load).twice
|
503
|
+
data_target.load!
|
504
|
+
data_target.load!
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|