stockboy 0.6.0 → 0.7.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/.rspec +0 -2
- data/.travis.yml +1 -0
- data/CHANGELOG.md +7 -0
- data/README.md +31 -4
- data/lib/stockboy/attribute_map.rb +18 -14
- data/lib/stockboy/candidate_record.rb +12 -13
- data/lib/stockboy/configurator.rb +76 -38
- data/lib/stockboy/filters.rb +9 -0
- data/lib/stockboy/job.rb +28 -5
- data/lib/stockboy/provider.rb +9 -25
- data/lib/stockboy/provider_repeater.rb +64 -0
- data/lib/stockboy/providers/file.rb +7 -6
- data/lib/stockboy/providers/ftp.rb +7 -6
- data/lib/stockboy/providers/http.rb +3 -2
- data/lib/stockboy/providers/imap.rb +7 -5
- data/lib/stockboy/providers/soap.rb +79 -3
- data/lib/stockboy/registry.rb +11 -0
- data/lib/stockboy/translator.rb +1 -0
- data/lib/stockboy/version.rb +1 -1
- data/spec/stockboy/attribute_map_spec.rb +13 -2
- data/spec/stockboy/configurator_spec.rb +21 -0
- data/spec/stockboy/job_spec.rb +44 -19
- data/spec/stockboy/provider_repeater_spec.rb +80 -0
- data/spec/stockboy/provider_spec.rb +22 -2
- data/spec/stockboy/providers/file_spec.rb +7 -7
- data/spec/stockboy/providers/ftp_spec.rb +3 -3
- data/spec/stockboy/providers/http_spec.rb +4 -2
- data/spec/stockboy/providers/imap_spec.rb +2 -2
- data/spec/stockboy/providers/soap_spec.rb +7 -2
- data/stockboy.gemspec +1 -1
- metadata +6 -3
data/spec/stockboy/job_spec.rb
CHANGED
@@ -1,11 +1,31 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'stockboy/job'
|
3
3
|
|
4
|
+
class TestProvider
|
5
|
+
attr_reader :data, :errors
|
6
|
+
def initialize(opts)
|
7
|
+
@data = opts[:data] || ""
|
8
|
+
@errors = opts[:errors] || []
|
9
|
+
end
|
10
|
+
def clear
|
11
|
+
@data = nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestReader
|
16
|
+
def initialize(opts)
|
17
|
+
@parse = opts[:parse] || []
|
18
|
+
end
|
19
|
+
def parse(data)
|
20
|
+
@parse
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
4
24
|
module Stockboy
|
5
25
|
describe Job do
|
6
26
|
let(:jobs_path) { RSpec.configuration.fixture_path.join('jobs') }
|
7
|
-
let(:
|
8
|
-
let(:
|
27
|
+
let(:provider) { provider_double }
|
28
|
+
let(:reader) { reader_double }
|
9
29
|
|
10
30
|
let(:job_template) {
|
11
31
|
<<-END.gsub(/^ {6}/,'')
|
@@ -35,8 +55,8 @@ module Stockboy
|
|
35
55
|
before do
|
36
56
|
Stockboy.configuration.template_load_paths = [jobs_path]
|
37
57
|
|
38
|
-
allow(Stockboy::Providers).to receive(:find) {
|
39
|
-
allow(Stockboy::Readers).to receive(:find)
|
58
|
+
allow(Stockboy::Providers).to receive(:find) { TestProvider }
|
59
|
+
allow(Stockboy::Readers).to receive(:find) { TestReader }
|
40
60
|
end
|
41
61
|
|
42
62
|
its(:filters) { should be_a Hash }
|
@@ -65,16 +85,19 @@ module Stockboy
|
|
65
85
|
end
|
66
86
|
|
67
87
|
it "assigns a registered provider from a symbol" do
|
88
|
+
Stockboy::Providers.should_receive(:find)
|
89
|
+
.with(:ftp)
|
90
|
+
.and_return(TestProvider)
|
68
91
|
job = Job.define("test_job")
|
69
|
-
job.provider.should
|
92
|
+
job.provider.should be_a TestProvider
|
70
93
|
end
|
71
94
|
|
72
95
|
it "assigns a registered reader from a symbol" do
|
73
96
|
Stockboy::Readers.should_receive(:find)
|
74
97
|
.with(:csv)
|
75
|
-
.and_return(
|
98
|
+
.and_return(TestReader)
|
76
99
|
job = Job.define("test_job")
|
77
|
-
job.reader.should
|
100
|
+
job.reader.should be_a TestReader
|
78
101
|
end
|
79
102
|
|
80
103
|
it "assigns attributes from a block" do
|
@@ -93,12 +116,11 @@ module Stockboy
|
|
93
116
|
let(:attribute_map) { AttributeMap.new { name } }
|
94
117
|
|
95
118
|
subject(:job) do
|
96
|
-
Job.new(provider:
|
97
|
-
attributes: attribute_map)
|
119
|
+
Job.new(provider: provider, attributes: attribute_map)
|
98
120
|
end
|
99
121
|
|
100
122
|
it "records total received record count" do
|
101
|
-
job.reader =
|
123
|
+
job.reader = reader_double(parse: [{"name"=>"A"},{"name"=>"B"}])
|
102
124
|
|
103
125
|
job.process
|
104
126
|
job.total_records.should == 2
|
@@ -155,8 +177,7 @@ module Stockboy
|
|
155
177
|
let(:attribute_map) { AttributeMap.new { name } }
|
156
178
|
|
157
179
|
subject(:job) do
|
158
|
-
Job.new(provider:
|
159
|
-
attributes: attribute_map)
|
180
|
+
Job.new(provider: provider, attributes: attribute_map)
|
160
181
|
end
|
161
182
|
|
162
183
|
context "before processing" do
|
@@ -180,9 +201,7 @@ module Stockboy
|
|
180
201
|
|
181
202
|
describe "#processed?" do
|
182
203
|
subject(:job) do
|
183
|
-
Job.new(provider:
|
184
|
-
reader: reader_stub,
|
185
|
-
attributes: AttributeMap.new)
|
204
|
+
Job.new(provider: provider, reader: reader, attributes: AttributeMap.new)
|
186
205
|
end
|
187
206
|
|
188
207
|
it "indicates if the job has been processed" do
|
@@ -194,11 +213,9 @@ module Stockboy
|
|
194
213
|
|
195
214
|
describe "#trigger" do
|
196
215
|
|
197
|
-
let(:provider_stub) { double(delete_data: true) }
|
198
|
-
|
199
216
|
subject(:job) do
|
200
217
|
Job.new(
|
201
|
-
provider:
|
218
|
+
provider: provider,
|
202
219
|
triggers: {
|
203
220
|
success: [proc { |j| j.provider.delete_data },
|
204
221
|
proc { |j, stats| stats[:count] = 1 if stats }]
|
@@ -207,11 +224,12 @@ module Stockboy
|
|
207
224
|
end
|
208
225
|
|
209
226
|
it "should yield itself to each trigger" do
|
210
|
-
|
227
|
+
expect(job.provider).to receive(:delete_data).once
|
211
228
|
job.trigger(:success)
|
212
229
|
end
|
213
230
|
|
214
231
|
it "should yield args to each trigger" do
|
232
|
+
expect(job.provider).to receive(:delete_data).once
|
215
233
|
stats = {}
|
216
234
|
job.trigger(:success, stats)
|
217
235
|
stats[:count].should == 1
|
@@ -234,5 +252,12 @@ module Stockboy
|
|
234
252
|
|
235
253
|
end
|
236
254
|
|
255
|
+
def provider_double(opts={})
|
256
|
+
TestProvider.new(opts)
|
257
|
+
end
|
258
|
+
|
259
|
+
def reader_double(opts={})
|
260
|
+
TestReader.new(opts)
|
261
|
+
end
|
237
262
|
end
|
238
263
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stockboy/provider_repeater'
|
3
|
+
|
4
|
+
class PaginatedProviderSubclass < Stockboy::Provider
|
5
|
+
attr_accessor :page
|
6
|
+
def validate
|
7
|
+
true
|
8
|
+
end
|
9
|
+
def fetch_data
|
10
|
+
@data = "TEST,DATA,#{page}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Stockboy
|
15
|
+
describe ProviderRepeater do
|
16
|
+
|
17
|
+
let(:provider) { PaginatedProviderSubclass.new }
|
18
|
+
|
19
|
+
describe "#data" do
|
20
|
+
let(:repeater) {
|
21
|
+
ProviderRepeater.new(provider) do |output, provider|
|
22
|
+
1.upto 3 do |i|
|
23
|
+
provider.page = i
|
24
|
+
output << provider
|
25
|
+
end
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
it "yields each data set" do
|
30
|
+
calls = []
|
31
|
+
repeater.data { |data| calls << data[-1] }
|
32
|
+
calls.should == ["1", "2", "3"]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#each" do
|
38
|
+
|
39
|
+
context "without a block" do
|
40
|
+
let(:repeater) { ProviderRepeater.new(provider) }
|
41
|
+
|
42
|
+
it "yields the provider once" do
|
43
|
+
provider.page = 42
|
44
|
+
calls = []
|
45
|
+
repeater.each do |nth_provider|
|
46
|
+
calls << nth_provider
|
47
|
+
end
|
48
|
+
calls.map(&:page).should == [42]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when it passes a non-provider" do
|
53
|
+
let(:repeater) {
|
54
|
+
ProviderRepeater.new(provider) do |output, provider|
|
55
|
+
output << nil
|
56
|
+
end
|
57
|
+
}
|
58
|
+
|
59
|
+
it "should raise a helpful error" do
|
60
|
+
expect { repeater.each { |provider| } }.to raise_error(
|
61
|
+
"expected Provider, got NilClass" )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when it is defined with yield" do
|
66
|
+
let(:repeater) {
|
67
|
+
ProviderRepeater.new(provider) do |output, provider|
|
68
|
+
yield provider
|
69
|
+
end
|
70
|
+
}
|
71
|
+
|
72
|
+
it "should raise a helpful error" do
|
73
|
+
expect { repeater.data { |data| } }.to raise_error(
|
74
|
+
"use output << provider instead of yield" )
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -2,9 +2,11 @@ require 'spec_helper'
|
|
2
2
|
require 'stockboy/provider'
|
3
3
|
|
4
4
|
class ProviderSubclass < Stockboy::Provider
|
5
|
-
attr_accessor :foo
|
6
5
|
def validate
|
7
|
-
|
6
|
+
true
|
7
|
+
end
|
8
|
+
def fetch_data
|
9
|
+
@data = "TEST,DATA"
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
@@ -30,5 +32,23 @@ module Stockboy
|
|
30
32
|
expect{ subject.send :fetch_data }.to raise_error(NoMethodError)
|
31
33
|
end
|
32
34
|
end
|
35
|
+
|
36
|
+
describe "#data" do
|
37
|
+
subject(:provider) { ProviderSubclass.new(foo: true) }
|
38
|
+
|
39
|
+
it "fetches data when there is none" do
|
40
|
+
expect(provider).to receive(:fetch_data).once.and_call_original
|
41
|
+
2.times do
|
42
|
+
provider.data.should == "TEST,DATA"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "yields data to a block" do
|
47
|
+
provider.data do |data|
|
48
|
+
data.should == "TEST,DATA"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
33
53
|
end
|
34
54
|
end
|
@@ -23,7 +23,7 @@ module Stockboy
|
|
23
23
|
|
24
24
|
describe ".new" do
|
25
25
|
it "has no errors" do
|
26
|
-
provider.errors.
|
26
|
+
provider.errors.should be_empty
|
27
27
|
end
|
28
28
|
|
29
29
|
it "accepts block initialization" do
|
@@ -55,8 +55,8 @@ module Stockboy
|
|
55
55
|
it "fails with an error if the file doesn't exist" do
|
56
56
|
provider.file_name = "missing-file.csv"
|
57
57
|
provider.data.should be_nil
|
58
|
-
provider.valid?.should
|
59
|
-
provider.errors
|
58
|
+
provider.valid?.should be_false
|
59
|
+
provider.errors.first.should match /not found/
|
60
60
|
end
|
61
61
|
|
62
62
|
it "finds last matching file from string glob" do
|
@@ -76,16 +76,16 @@ module Stockboy
|
|
76
76
|
end
|
77
77
|
|
78
78
|
context "with :since validation" do
|
79
|
-
let(:recently)
|
79
|
+
let(:recently) { Time.now - 60 }
|
80
|
+
let(:last_week) { Time.now - 86400 }
|
80
81
|
|
81
82
|
it "skips old files" do
|
82
|
-
expect_any_instance_of(::File).to receive(:mtime).and_return
|
83
|
-
provider.file_dir = RSpec.configuration.fixture_path.join("files")
|
83
|
+
expect_any_instance_of(::File).to receive(:mtime).and_return last_week
|
84
84
|
provider.file_name = '*.csv'
|
85
85
|
provider.since = recently
|
86
86
|
|
87
87
|
provider.data.should be_nil
|
88
|
-
provider.errors
|
88
|
+
provider.errors.first.should == "no new files since #{recently}"
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
@@ -32,7 +32,7 @@ module Stockboy
|
|
32
32
|
|
33
33
|
describe ".new" do
|
34
34
|
it "has no errors" do
|
35
|
-
subject.errors.
|
35
|
+
subject.errors.should be_empty
|
36
36
|
end
|
37
37
|
|
38
38
|
it "accepts block initialization" do
|
@@ -67,14 +67,14 @@ module Stockboy
|
|
67
67
|
provider.host = nil
|
68
68
|
provider.data
|
69
69
|
|
70
|
-
provider.errors.
|
70
|
+
provider.errors.first.should match /host/
|
71
71
|
end
|
72
72
|
|
73
73
|
it "adds an error on missing file_name" do
|
74
74
|
provider.file_name = nil
|
75
75
|
provider.data
|
76
76
|
|
77
|
-
provider.errors.
|
77
|
+
provider.errors.first.should match /file_name/
|
78
78
|
end
|
79
79
|
|
80
80
|
it "downloads the last matching file" do
|
@@ -58,15 +58,17 @@ module Stockboy
|
|
58
58
|
|
59
59
|
describe "validation" do
|
60
60
|
it "should not be valid without a method" do
|
61
|
+
provider.uri = "http://example.com"
|
61
62
|
provider.method = nil
|
62
63
|
provider.should_not be_valid
|
63
|
-
provider.errors.
|
64
|
+
provider.errors.first.should match /method/
|
64
65
|
end
|
65
66
|
|
66
67
|
it "should not be valid without a uri" do
|
67
68
|
provider.uri = ""
|
69
|
+
provider.method = :get
|
68
70
|
provider.should_not be_valid
|
69
|
-
provider.errors.
|
71
|
+
provider.errors.first.should match /uri/
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -39,7 +39,7 @@ module Stockboy
|
|
39
39
|
|
40
40
|
describe ".new" do
|
41
41
|
it "has no errors" do
|
42
|
-
provider.errors.
|
42
|
+
provider.errors.should be_empty
|
43
43
|
end
|
44
44
|
|
45
45
|
it "accepts block initialization" do
|
@@ -108,7 +108,7 @@ module Stockboy
|
|
108
108
|
it "closes connections when catching exceptions" do
|
109
109
|
net_imap = expect_connection("hhh", "uuu", "ppp", "UNBOX")
|
110
110
|
provider.client { |i| raise Net::IMAP::Error }
|
111
|
-
provider.errors
|
111
|
+
provider.errors.first.should match /IMAP connection error/
|
112
112
|
end
|
113
113
|
|
114
114
|
end
|
@@ -52,7 +52,7 @@ module Stockboy
|
|
52
52
|
context "without a WSDL document" do
|
53
53
|
it "has error for blank endpoint & WSDL namespace" do
|
54
54
|
provider.valid?
|
55
|
-
provider.errors.
|
55
|
+
provider.errors.first.should match /endpoint/
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
@@ -88,10 +88,15 @@ module Stockboy
|
|
88
88
|
provider.data
|
89
89
|
end
|
90
90
|
|
91
|
-
it "returns hash data on success" do
|
91
|
+
it "returns hash data on success by default" do
|
92
92
|
should be_a Hash
|
93
93
|
end
|
94
94
|
|
95
|
+
it "returns xml data on success with an xml response_format" do
|
96
|
+
provider.response_format = :xml
|
97
|
+
should be_a String
|
98
|
+
end
|
99
|
+
|
95
100
|
it "uses string keys" do
|
96
101
|
response.keys.each { |k| k.should be_a String }
|
97
102
|
end
|
data/stockboy.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stockboy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Vit
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: activesupport
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - '>='
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- lib/stockboy/job.rb
|
142
142
|
- lib/stockboy/mapped_record.rb
|
143
143
|
- lib/stockboy/provider.rb
|
144
|
+
- lib/stockboy/provider_repeater.rb
|
144
145
|
- lib/stockboy/providers.rb
|
145
146
|
- lib/stockboy/providers/file.rb
|
146
147
|
- lib/stockboy/providers/ftp.rb
|
@@ -198,6 +199,7 @@ files:
|
|
198
199
|
- spec/stockboy/filters_spec.rb
|
199
200
|
- spec/stockboy/job_spec.rb
|
200
201
|
- spec/stockboy/mapped_record_spec.rb
|
202
|
+
- spec/stockboy/provider_repeater_spec.rb
|
201
203
|
- spec/stockboy/provider_spec.rb
|
202
204
|
- spec/stockboy/providers/file_spec.rb
|
203
205
|
- spec/stockboy/providers/ftp_spec.rb
|
@@ -277,6 +279,7 @@ test_files:
|
|
277
279
|
- spec/stockboy/filters_spec.rb
|
278
280
|
- spec/stockboy/job_spec.rb
|
279
281
|
- spec/stockboy/mapped_record_spec.rb
|
282
|
+
- spec/stockboy/provider_repeater_spec.rb
|
280
283
|
- spec/stockboy/provider_spec.rb
|
281
284
|
- spec/stockboy/providers/file_spec.rb
|
282
285
|
- spec/stockboy/providers/ftp_spec.rb
|