stockboy 0.5.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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +5 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +12 -0
- data/Guardfile +10 -0
- data/LICENSE +21 -0
- data/README.md +293 -0
- data/Rakefile +30 -0
- data/lib/stockboy.rb +80 -0
- data/lib/stockboy/attribute.rb +11 -0
- data/lib/stockboy/attribute_map.rb +74 -0
- data/lib/stockboy/candidate_record.rb +130 -0
- data/lib/stockboy/configuration.rb +62 -0
- data/lib/stockboy/configurator.rb +176 -0
- data/lib/stockboy/dsl.rb +68 -0
- data/lib/stockboy/exceptions.rb +3 -0
- data/lib/stockboy/filter.rb +58 -0
- data/lib/stockboy/filter_chain.rb +41 -0
- data/lib/stockboy/filters.rb +11 -0
- data/lib/stockboy/filters/missing_email.rb +37 -0
- data/lib/stockboy/job.rb +241 -0
- data/lib/stockboy/mapped_record.rb +59 -0
- data/lib/stockboy/provider.rb +238 -0
- data/lib/stockboy/providers.rb +11 -0
- data/lib/stockboy/providers/file.rb +135 -0
- data/lib/stockboy/providers/ftp.rb +205 -0
- data/lib/stockboy/providers/http.rb +123 -0
- data/lib/stockboy/providers/imap.rb +290 -0
- data/lib/stockboy/providers/soap.rb +120 -0
- data/lib/stockboy/railtie.rb +28 -0
- data/lib/stockboy/reader.rb +59 -0
- data/lib/stockboy/readers.rb +11 -0
- data/lib/stockboy/readers/csv.rb +115 -0
- data/lib/stockboy/readers/fixed_width.rb +121 -0
- data/lib/stockboy/readers/spreadsheet.rb +144 -0
- data/lib/stockboy/readers/xml.rb +155 -0
- data/lib/stockboy/registry.rb +42 -0
- data/lib/stockboy/source_record.rb +43 -0
- data/lib/stockboy/string_pool.rb +35 -0
- data/lib/stockboy/template_file.rb +44 -0
- data/lib/stockboy/translations.rb +70 -0
- data/lib/stockboy/translations/boolean.rb +58 -0
- data/lib/stockboy/translations/date.rb +41 -0
- data/lib/stockboy/translations/decimal.rb +33 -0
- data/lib/stockboy/translations/default_empty_string.rb +38 -0
- data/lib/stockboy/translations/default_false.rb +41 -0
- data/lib/stockboy/translations/default_nil.rb +38 -0
- data/lib/stockboy/translations/default_true.rb +41 -0
- data/lib/stockboy/translations/default_zero.rb +41 -0
- data/lib/stockboy/translations/integer.rb +33 -0
- data/lib/stockboy/translations/string.rb +33 -0
- data/lib/stockboy/translations/time.rb +41 -0
- data/lib/stockboy/translations/uk_date.rb +51 -0
- data/lib/stockboy/translations/us_date.rb +51 -0
- data/lib/stockboy/translator.rb +66 -0
- data/lib/stockboy/version.rb +3 -0
- data/spec/fixtures/.gitkeep +0 -0
- data/spec/fixtures/files/a_garbage.csv +1 -0
- data/spec/fixtures/files/test_data-20120101.csv +1 -0
- data/spec/fixtures/files/test_data-20120202.csv +1 -0
- data/spec/fixtures/files/z_garbage.csv +1 -0
- data/spec/fixtures/jobs/test_job.rb +1 -0
- data/spec/fixtures/soap/get_list/fault.xml +8 -0
- data/spec/fixtures/soap/get_list/success.xml +18 -0
- data/spec/fixtures/spreadsheets/test_data.xls +0 -0
- data/spec/fixtures/spreadsheets/test_row_options.xls +0 -0
- data/spec/fixtures/xml/body.xml +14 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/stockboy/attribute_map_spec.rb +59 -0
- data/spec/stockboy/attribute_spec.rb +11 -0
- data/spec/stockboy/candidate_record_spec.rb +150 -0
- data/spec/stockboy/configuration_spec.rb +28 -0
- data/spec/stockboy/configurator_spec.rb +127 -0
- data/spec/stockboy/filter_chain_spec.rb +40 -0
- data/spec/stockboy/filter_spec.rb +41 -0
- data/spec/stockboy/filters/missing_email_spec.rb +26 -0
- data/spec/stockboy/filters_spec.rb +38 -0
- data/spec/stockboy/job_spec.rb +238 -0
- data/spec/stockboy/mapped_record_spec.rb +30 -0
- data/spec/stockboy/provider_spec.rb +34 -0
- data/spec/stockboy/providers/file_spec.rb +116 -0
- data/spec/stockboy/providers/ftp_spec.rb +143 -0
- data/spec/stockboy/providers/http_spec.rb +94 -0
- data/spec/stockboy/providers/imap_spec.rb +76 -0
- data/spec/stockboy/providers/soap_spec.rb +107 -0
- data/spec/stockboy/providers_spec.rb +38 -0
- data/spec/stockboy/readers/csv_spec.rb +68 -0
- data/spec/stockboy/readers/fixed_width_spec.rb +52 -0
- data/spec/stockboy/readers/spreadsheet_spec.rb +121 -0
- data/spec/stockboy/readers/xml_spec.rb +94 -0
- data/spec/stockboy/readers_spec.rb +30 -0
- data/spec/stockboy/source_record_spec.rb +19 -0
- data/spec/stockboy/template_file_spec.rb +30 -0
- data/spec/stockboy/translations/boolean_spec.rb +48 -0
- data/spec/stockboy/translations/date_spec.rb +38 -0
- data/spec/stockboy/translations/decimal_spec.rb +23 -0
- data/spec/stockboy/translations/default_empty_string_spec.rb +32 -0
- data/spec/stockboy/translations/default_false_spec.rb +25 -0
- data/spec/stockboy/translations/default_nil_spec.rb +32 -0
- data/spec/stockboy/translations/default_true_spec.rb +25 -0
- data/spec/stockboy/translations/default_zero_spec.rb +32 -0
- data/spec/stockboy/translations/integer_spec.rb +22 -0
- data/spec/stockboy/translations/string_spec.rb +22 -0
- data/spec/stockboy/translations/time_spec.rb +27 -0
- data/spec/stockboy/translations/uk_date_spec.rb +37 -0
- data/spec/stockboy/translations/us_date_spec.rb +37 -0
- data/spec/stockboy/translations_spec.rb +55 -0
- data/spec/stockboy/translator_spec.rb +27 -0
- data/stockboy.gemspec +32 -0
- metadata +305 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/filter_chain'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe FilterChain do
|
|
6
|
+
|
|
7
|
+
let(:filter1) { double("Filter") }
|
|
8
|
+
let(:filter2) { double("Filter", reset: true) }
|
|
9
|
+
|
|
10
|
+
it "initializes keys and values from a hash" do
|
|
11
|
+
chain = FilterChain.new(no_angels: filter1, no_daleks: filter2)
|
|
12
|
+
chain.keys.should == [:no_angels, :no_daleks]
|
|
13
|
+
chain.values.should == [filter1, filter2]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "#reset" do
|
|
17
|
+
let(:chain) { FilterChain.new(no_angels: filter1, no_daleks: filter2) }
|
|
18
|
+
|
|
19
|
+
it "calls reset on all members" do
|
|
20
|
+
filter2.should_receive(:reset)
|
|
21
|
+
chain.reset
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "returns a hash of filter keys to empty arrays" do
|
|
25
|
+
empty_records = chain.reset
|
|
26
|
+
empty_records.should == {no_angels: [], no_daleks: []}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "#prepend" do
|
|
31
|
+
it "adds filters to the front of the chain" do
|
|
32
|
+
chain = FilterChain.new(filter1: double)
|
|
33
|
+
chain.prepend(filter0: double)
|
|
34
|
+
chain.keys.should == [:filter0, :filter1]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/filter'
|
|
3
|
+
|
|
4
|
+
class FishFilter < Stockboy::Filter
|
|
5
|
+
def filter(raw, translated)
|
|
6
|
+
return true if raw.species =~ /ichtus/
|
|
7
|
+
return true if translated.species =~ /fish/
|
|
8
|
+
return nil
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Stockboy
|
|
13
|
+
describe Filter do
|
|
14
|
+
|
|
15
|
+
describe "#call" do
|
|
16
|
+
let(:empty_values) { double.as_null_object }
|
|
17
|
+
subject(:filter) { FishFilter.new }
|
|
18
|
+
|
|
19
|
+
context "matching raw value" do
|
|
20
|
+
it "returns true for match" do
|
|
21
|
+
filter.call(double(species:"babylichtus"), empty_values).should be_true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "returns false for no match" do
|
|
25
|
+
filter.call(double(species:"triceratops"), empty_values).should be_false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "matching translated value" do
|
|
30
|
+
it "returns true for match" do
|
|
31
|
+
filter.call(empty_values, double(species:"babelfish")).should be_true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "returns false for no match" do
|
|
35
|
+
filter.call(empty_values, double(species:"rhinoceros")).should be_false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/filters/missing_email'
|
|
3
|
+
|
|
4
|
+
describe Stockboy::Filters::MissingEmail do
|
|
5
|
+
subject(:filter) { described_class.new(:e) }
|
|
6
|
+
it 'allows email addresses' do
|
|
7
|
+
record = OpenStruct.new(e: 'me@example.com')
|
|
8
|
+
filter.call(record, record).should be_false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'catches empty strings' do
|
|
12
|
+
record = OpenStruct.new(e: '')
|
|
13
|
+
filter.call(record, record).should be_true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'catches hyphen placeholders' do
|
|
17
|
+
record = OpenStruct.new(e: '-')
|
|
18
|
+
filter.call(record, record).should be_true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'uses translated output value' do
|
|
22
|
+
input = OpenStruct.new(e: '', other: 'me@example.com')
|
|
23
|
+
output = OpenStruct.new(e: input.other)
|
|
24
|
+
filter.call(input, output).should be_false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/filters'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe Filters do
|
|
6
|
+
|
|
7
|
+
let(:filter) { double("filter") }
|
|
8
|
+
|
|
9
|
+
describe ".register" do
|
|
10
|
+
it "registers a key and class" do
|
|
11
|
+
Filters.register(:invalid, filter).should === filter
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe ".find" do
|
|
16
|
+
it "returns a filter class" do
|
|
17
|
+
Filters.register(:invalid, filter)
|
|
18
|
+
Filters.find(:invalid).should === filter
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe ".[]" do
|
|
23
|
+
it "returns a filter class" do
|
|
24
|
+
Filters.register(:invalid, filter)
|
|
25
|
+
Filters[:invalid].should === filter
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe ".all" do
|
|
30
|
+
it "returns all registered filters" do
|
|
31
|
+
Filters.register(:invalid, filter)
|
|
32
|
+
Filters.register(:semivalid, filter)
|
|
33
|
+
Filters.all.should include(invalid: filter, semivalid: filter)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/job'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe Job do
|
|
6
|
+
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 }
|
|
9
|
+
|
|
10
|
+
let(:job_template) {
|
|
11
|
+
<<-END.gsub(/^ {6}/,'')
|
|
12
|
+
provider :ftp do
|
|
13
|
+
username 'foo'
|
|
14
|
+
password 'bar'
|
|
15
|
+
host 'ftp.example.com'
|
|
16
|
+
end
|
|
17
|
+
format :csv
|
|
18
|
+
filter :blank_name do |r|
|
|
19
|
+
false if r.name.blank?
|
|
20
|
+
end
|
|
21
|
+
attributes do
|
|
22
|
+
name from: 'userName'
|
|
23
|
+
email from: 'email'
|
|
24
|
+
updated_at from: 'statusDate', as: [:date]
|
|
25
|
+
end
|
|
26
|
+
on :cleanup do |job|
|
|
27
|
+
job.provider.delete_data
|
|
28
|
+
end
|
|
29
|
+
on :cleanup do |job|
|
|
30
|
+
"log: " << job.all_records.size
|
|
31
|
+
end
|
|
32
|
+
END
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
before do
|
|
36
|
+
Stockboy.configuration.template_load_paths = [jobs_path]
|
|
37
|
+
|
|
38
|
+
allow(Stockboy::Providers).to receive(:find) { provider_stub }
|
|
39
|
+
allow(Stockboy::Readers).to receive(:find) { reader_stub }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
its(:filters) { should be_a Hash }
|
|
43
|
+
|
|
44
|
+
describe "#define" do
|
|
45
|
+
before do
|
|
46
|
+
allow(File).to receive(:read)
|
|
47
|
+
.with("#{jobs_path}/test_job.rb")
|
|
48
|
+
.and_return job_template
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "returns an instance of Job" do
|
|
52
|
+
Job.define("test_job").should be_a Job
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "yields the defined job" do
|
|
56
|
+
yielded = nil
|
|
57
|
+
job = Job.define("test_job") { |j| yielded = j }
|
|
58
|
+
job.should be_a Job
|
|
59
|
+
job.should be yielded
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should read a file from a path" do
|
|
63
|
+
File.should_receive(:read).with("#{jobs_path}/test_job.rb")
|
|
64
|
+
Job.define("test_job")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "assigns a registered provider from a symbol" do
|
|
68
|
+
job = Job.define("test_job")
|
|
69
|
+
job.provider.should == provider_stub
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "assigns a registered reader from a symbol" do
|
|
73
|
+
Stockboy::Readers.should_receive(:find)
|
|
74
|
+
.with(:csv)
|
|
75
|
+
.and_return(reader_stub)
|
|
76
|
+
job = Job.define("test_job")
|
|
77
|
+
job.reader.should == reader_stub
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "assigns attributes from a block" do
|
|
81
|
+
job = Job.define("test_job")
|
|
82
|
+
job.attributes.map(&:to).should == [:name, :email, :updated_at]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "assigns triggers into their associated array from a block" do
|
|
86
|
+
job = Job.define("test_job")
|
|
87
|
+
job.triggers[:cleanup].size.should == 2
|
|
88
|
+
job.triggers[:cleanup].each { |t| t.should be_a Proc }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "#process" do
|
|
93
|
+
let(:attribute_map) { AttributeMap.new { name } }
|
|
94
|
+
|
|
95
|
+
subject(:job) do
|
|
96
|
+
Job.new(provider: double(:provider, data:"", errors:[]),
|
|
97
|
+
attributes: attribute_map)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "records total received record count" do
|
|
101
|
+
job.reader = double(parse: [{"name"=>"A"},{"name"=>"B"}])
|
|
102
|
+
|
|
103
|
+
job.process
|
|
104
|
+
job.total_records.should == 2
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "partitions records by filter" do
|
|
108
|
+
job.reader = double(parse: [{"name"=>"A"},{"name"=>"B"}])
|
|
109
|
+
job.filters = {alpha: proc{ |r| r.name =~ /A/ }}
|
|
110
|
+
|
|
111
|
+
job.process
|
|
112
|
+
job.records[:alpha].length.should == 1
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "keeps unfiltered_records" do
|
|
116
|
+
job.reader = double(parse: [{"name"=>"A"}])
|
|
117
|
+
job.filters = {zeta: proc{ |r| r.name =~ /Z/ }}
|
|
118
|
+
|
|
119
|
+
job.process
|
|
120
|
+
job.unfiltered_records.length.should == 1
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "keeps all_records" do
|
|
124
|
+
job.reader = double(parse: [{"name"=>"A"},{"name"=>"Z"}])
|
|
125
|
+
job.filters = {alpha: proc{ |r| r.name =~ /A/ }}
|
|
126
|
+
|
|
127
|
+
job.process
|
|
128
|
+
job.all_records.length.should == 2
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "resets filters between runs" do
|
|
132
|
+
|
|
133
|
+
class CountingFilter
|
|
134
|
+
attr_reader :matches
|
|
135
|
+
define_method(:initialize) { |pattern| @pattern, @matches = /A/, 0 }
|
|
136
|
+
define_method(:call) { |_, output| @matches += 1 if output.name =~ @pattern }
|
|
137
|
+
define_method(:reset) { @matches = 0 }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
job.reader = double(parse: [{"name"=>"A"},{"name"=>"Z"}])
|
|
141
|
+
job.filters = {alpha: counter = CountingFilter.new(/A/)}
|
|
142
|
+
|
|
143
|
+
counter.matches.should == 0
|
|
144
|
+
2.times { job.process }
|
|
145
|
+
counter.matches.should == 1
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "has empty partitions" do
|
|
149
|
+
job.filters = {alpha: proc{ |r| r.name =~ /A/ }, beta: proc{ |r| r.name =~ /B/ }}
|
|
150
|
+
job.records.should == {alpha: [], beta: []}
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
describe "#record_counts" do
|
|
155
|
+
let(:attribute_map) { AttributeMap.new { name } }
|
|
156
|
+
|
|
157
|
+
subject(:job) do
|
|
158
|
+
Job.new(provider: double(:provider, data:"", errors:[]),
|
|
159
|
+
attributes: attribute_map)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context "before processing" do
|
|
163
|
+
it "should be empty" do
|
|
164
|
+
job.record_counts.should == {}
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "returns a hash of counts by filtered record partition" do
|
|
169
|
+
job.filters = {
|
|
170
|
+
alpha: proc{ |r| r.name =~ /^A/ },
|
|
171
|
+
zeta: proc{ |r| r.name =~ /^Z/ }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
job.reader = double(parse: [{"name"=>"Arthur"}, {"name"=>"Abc"}, {"name"=>"Zaphod"}])
|
|
175
|
+
job.process
|
|
176
|
+
|
|
177
|
+
job.record_counts.should == {alpha: 2, zeta: 1}
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe "#processed?" do
|
|
182
|
+
subject(:job) do
|
|
183
|
+
Job.new(provider: provider_stub,
|
|
184
|
+
reader: reader_stub,
|
|
185
|
+
attributes: AttributeMap.new)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "indicates if the job has been processed" do
|
|
189
|
+
job.processed?.should be_false
|
|
190
|
+
job.process
|
|
191
|
+
job.processed?.should be_true
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
describe "#trigger" do
|
|
196
|
+
|
|
197
|
+
let(:provider_stub) { double(delete_data: true) }
|
|
198
|
+
|
|
199
|
+
subject(:job) do
|
|
200
|
+
Job.new(
|
|
201
|
+
provider: provider_stub,
|
|
202
|
+
triggers: {
|
|
203
|
+
success: [proc { |j| j.provider.delete_data },
|
|
204
|
+
proc { |j, stats| stats[:count] = 1 if stats }]
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "should yield itself to each trigger" do
|
|
210
|
+
provider_stub.should_receive(:delete_data).once
|
|
211
|
+
job.trigger(:success)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "should yield args to each trigger" do
|
|
215
|
+
stats = {}
|
|
216
|
+
job.trigger(:success, stats)
|
|
217
|
+
stats[:count].should == 1
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
describe "#method_missing" do
|
|
223
|
+
|
|
224
|
+
subject(:job) { Job.new(triggers: {cleanup: proc{|_|}})}
|
|
225
|
+
|
|
226
|
+
it "should call a named trigger" do
|
|
227
|
+
expect(job).to receive(:trigger).with(:cleanup, "trash")
|
|
228
|
+
job.cleanup("trash")
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "should raise an error for unknown trigger keys" do
|
|
232
|
+
expect { job.wobble }.to raise_error NoMethodError
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/mapped_record'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe MappedRecord do
|
|
6
|
+
subject(:record) do
|
|
7
|
+
MappedRecord.new(:full_name => 'Arthur Dent')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "accesses initialized fields from hash" do
|
|
11
|
+
record.full_name.should == 'Arthur Dent'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "does not redefine accessor methods" do
|
|
15
|
+
record1 = MappedRecord.new(:full_name => 'Arthur Dent')
|
|
16
|
+
record2 = MappedRecord.new(:full_name => 'Arthur Dent')
|
|
17
|
+
|
|
18
|
+
record1.method(:full_name).owner.should ==
|
|
19
|
+
record2.method(:full_name).owner
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "only has its own accessor methods" do
|
|
23
|
+
record1 = MappedRecord.new(:first_name => 'Arthur')
|
|
24
|
+
record2 = MappedRecord.new(:last_name => 'Dent')
|
|
25
|
+
|
|
26
|
+
record1.should_not respond_to(:last_name)
|
|
27
|
+
record2.should_not respond_to(:first_name)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/provider'
|
|
3
|
+
|
|
4
|
+
class ProviderSubclass < Stockboy::Provider
|
|
5
|
+
attr_accessor :foo
|
|
6
|
+
def validate
|
|
7
|
+
errors.add_on_empty(:foo, "Foo is empty")
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Stockboy
|
|
12
|
+
describe Provider do
|
|
13
|
+
|
|
14
|
+
describe "#errors" do
|
|
15
|
+
its(:errors) { should be_empty }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#logger" do
|
|
19
|
+
its(:logger) { should respond_to :error }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "abstract method" do
|
|
23
|
+
subject { Class.new(Provider).new }
|
|
24
|
+
|
|
25
|
+
it "raises error for unimplemented #validate" do
|
|
26
|
+
expect{ subject.send :validate }.to raise_error(NoMethodError)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "raises error for unimplemented #fetch_data" do
|
|
30
|
+
expect{ subject.send :fetch_data }.to raise_error(NoMethodError)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|