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.
@@ -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(:provider_stub) { double(:ftp).as_null_object }
8
- let(:reader_stub) { double(:csv).as_null_object }
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) { provider_stub }
39
- allow(Stockboy::Readers).to receive(:find) { reader_stub }
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 == provider_stub
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(reader_stub)
98
+ .and_return(TestReader)
76
99
  job = Job.define("test_job")
77
- job.reader.should == reader_stub
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: double(:provider, data:"", errors:[]),
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 = double(parse: [{"name"=>"A"},{"name"=>"B"}])
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: double(:provider, data:"", errors:[]),
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: provider_stub,
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: provider_stub,
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
- provider_stub.should_receive(:delete_data).once
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
- errors.add_on_empty(:foo, "Foo is empty")
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.messages.should be_empty
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 == false
59
- provider.errors[:base].should_not be_empty
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) { Time.now - 60 }
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 Time.now - 86400
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[:response].should include "No new files since #{recently}"
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.messages.should be_empty
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.include?(:host).should be_true
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.include?(:file_name).should be_true
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.keys.should include(:method)
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.keys.should include(:uri)
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.messages.should be_empty
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[:response].should include "IMAP connection error"
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.keys.should include(:endpoint)
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
@@ -29,5 +29,5 @@ Gem::Specification.new do |s|
29
29
  s.add_runtime_dependency "savon", ">= 2.3.0"
30
30
  s.add_runtime_dependency "httpi"
31
31
  s.add_runtime_dependency "mail"
32
- s.add_runtime_dependency "activemodel", ">= 3.0"
32
+ s.add_runtime_dependency "activesupport", ">= 3.0"
33
33
  end
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.6.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-02-07 00:00:00.000000000 Z
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: activemodel
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