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,66 @@
|
|
|
1
|
+
require 'stockboy/exceptions'
|
|
2
|
+
require 'stockboy/source_record'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
|
|
6
|
+
# This is an abstract class to help set up common named translations
|
|
7
|
+
#
|
|
8
|
+
# A Translator receives a source record and transforms selected attributes to
|
|
9
|
+
# another format or type. The entire record context is passed to the
|
|
10
|
+
# translator so that other fields can be compared, split, or recombined
|
|
11
|
+
# (instead of just getting the single attribute value without context)
|
|
12
|
+
#
|
|
13
|
+
# == Interface
|
|
14
|
+
#
|
|
15
|
+
# To implement a translator type, you must:
|
|
16
|
+
#
|
|
17
|
+
# * Initialize with the attribute name to which it applies.
|
|
18
|
+
# * Implement a +translate+ method that returns the value for the attribute
|
|
19
|
+
# it is transforming.
|
|
20
|
+
# * Use +field_value(context, field_key)+ to access the input value in the
|
|
21
|
+
# translate method.
|
|
22
|
+
#
|
|
23
|
+
# @abstract
|
|
24
|
+
#
|
|
25
|
+
class Translator
|
|
26
|
+
|
|
27
|
+
# Field from the record context to which the translation will apply
|
|
28
|
+
#
|
|
29
|
+
attr_reader :field_key
|
|
30
|
+
|
|
31
|
+
# Initialize a new translator for an attribute
|
|
32
|
+
#
|
|
33
|
+
# @param [Symbol] key Mapped attribute name to be translated
|
|
34
|
+
#
|
|
35
|
+
def initialize(key)
|
|
36
|
+
@field_key = key
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Perform translation on a record attribute
|
|
40
|
+
#
|
|
41
|
+
# @param [SourceRecord, MappedRecord, Hash] context
|
|
42
|
+
# The record to which the translation will be applied
|
|
43
|
+
#
|
|
44
|
+
def call(context)
|
|
45
|
+
context = OpenStruct.new(context) if context.is_a? Hash
|
|
46
|
+
translate(context)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# String representation for a more helpful representation
|
|
50
|
+
#
|
|
51
|
+
def inspect
|
|
52
|
+
"#<#{self.class.name||'Stockboy::Translator'} (#{@field_key})>"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def field_value(context, field_key)
|
|
58
|
+
context.send field_key if context.respond_to? field_key
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def translate(context)
|
|
62
|
+
raise NoMethodError, "def #{self.class}#translate needs implementation"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Garbage
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2012-01-01
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2012-02-02
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Garbage
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# file exists!
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
2
|
+
<soapenv:Body>
|
|
3
|
+
<MultiNamespacedEntryResponse xmlns="http://www.example.com/BusinessRulesEngine/xsd">
|
|
4
|
+
<history>
|
|
5
|
+
<ns10:case xmlns:ns10="http://www.example.com/Common/xsd">
|
|
6
|
+
<ns10:logTime>2010-09-21T18:22:01.558+10:00</ns10:logTime>
|
|
7
|
+
<ns10:logType>Notes Log</ns10:logType>
|
|
8
|
+
<ns10:logText>test</ns10:logText>
|
|
9
|
+
</ns10:case>
|
|
10
|
+
<ns11:case xmlns:ns11="http://www.example.com/Common/xsd">
|
|
11
|
+
<ns11:logTime>2010-09-21T18:22:07.038+10:00</ns11:logTime>
|
|
12
|
+
<ns11:logType>Notes Log</ns11:logType>
|
|
13
|
+
<ns11:logText>another test</ns11:logText>
|
|
14
|
+
</ns11:case>
|
|
15
|
+
</history>
|
|
16
|
+
</MultiNamespacedEntryResponse>
|
|
17
|
+
</soapenv:Body>
|
|
18
|
+
</soapenv:Envelope>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<MultiNamespacedEntryResponse xmlns="http://www.example.com/BusinessRulesEngine/xsd">
|
|
2
|
+
<history>
|
|
3
|
+
<ns10:case xmlns:ns10="http://www.example.com/Common/xsd">
|
|
4
|
+
<ns10:logTime>2010-09-21T18:22:01.558+10:00</ns10:logTime>
|
|
5
|
+
<ns10:logType>Notes Log</ns10:logType>
|
|
6
|
+
<ns10:logText>test</ns10:logText>
|
|
7
|
+
</ns10:case>
|
|
8
|
+
<ns11:case xmlns:ns11="http://www.example.com/Common/xsd">
|
|
9
|
+
<ns11:logTime>2010-09-21T18:22:07.038+10:00</ns11:logTime>
|
|
10
|
+
<ns11:logType>Notes Log</ns11:logType>
|
|
11
|
+
<ns11:logText>another test</ns11:logText>
|
|
12
|
+
</ns11:case>
|
|
13
|
+
</history>
|
|
14
|
+
</MultiNamespacedEntryResponse>
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'pry'
|
|
2
|
+
require 'pry-debugger'
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
require 'savon'
|
|
5
|
+
require 'savon/mock/spec_helper'
|
|
6
|
+
# require 'vcr'
|
|
7
|
+
|
|
8
|
+
$:.unshift File.expand_path('../lib/stockboy/lib', __FILE__)
|
|
9
|
+
|
|
10
|
+
RSpec.configure do |config|
|
|
11
|
+
config.include Savon::SpecHelper
|
|
12
|
+
config.mock_with :rspec
|
|
13
|
+
spec_fixtures = File.expand_path("fixtures", File.dirname(__FILE__))
|
|
14
|
+
config.add_setting :fixture_path, default: Pathname(spec_fixtures)
|
|
15
|
+
|
|
16
|
+
config.before :suite do
|
|
17
|
+
require 'stockboy/configuration'
|
|
18
|
+
Stockboy.configure do |c|
|
|
19
|
+
c.logger = Logger.new(StringIO.new)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# VCR.configure do |c|
|
|
26
|
+
# c.cassette_library_dir = 'fixtures/vcr_cassettes'
|
|
27
|
+
# # c.hook_into :fakeweb # or :fakeweb
|
|
28
|
+
# end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/attribute_map'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe AttributeMap do
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
AttributeMap.new do
|
|
9
|
+
email
|
|
10
|
+
updated_at from: 'statusDate', as: [proc{ |v| Date.parse(v) }]
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe ".new" do
|
|
15
|
+
it "initializes from hash attribute" do
|
|
16
|
+
row = Attribute.new(:email, "email", [])
|
|
17
|
+
map = AttributeMap.new(:email => row)
|
|
18
|
+
map[:email].should == row
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "captures same destination as default" do
|
|
23
|
+
subject[:email].should == Attribute.new(:email, "email", [])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "sets source from string to string" do
|
|
27
|
+
map = AttributeMap.new { updated_at from: "statusDate" }
|
|
28
|
+
map[:updated_at].from.should == "statusDate"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "sets source from symbol to string" do
|
|
32
|
+
map = AttributeMap.new { updated_at from: :statusDate }
|
|
33
|
+
map[:updated_at].from.should == "statusDate"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "sets source from number to number" do
|
|
37
|
+
map = AttributeMap.new { email from: 12 }
|
|
38
|
+
map[:email].from.should == 12
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "sets callable translators" do
|
|
42
|
+
subject[:updated_at].translators.first.call("2012-01-01").should == Date.new(2012,1,1)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "has attr accessors" do
|
|
46
|
+
subject.email.should be_a Attribute
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "raises error for undefined attrs" do
|
|
50
|
+
expect {subject.foobar}.to raise_error(NoMethodError)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "is enumerable" do
|
|
54
|
+
subject.map(&:from).should == ["email", "statusDate"]
|
|
55
|
+
subject.map(&:to).should == [:email, :updated_at]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/attribute'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe Attribute do
|
|
6
|
+
it "describes its attrs" do
|
|
7
|
+
attr = Attribute.new :outfield, "infield", [:one, :two]
|
|
8
|
+
attr.inspect.should == %{#<Stockboy::Attribute to=:outfield, from="infield", translators=[:one, :two]>}
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/candidate_record'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe CandidateRecord do
|
|
6
|
+
|
|
7
|
+
let(:hash_attrs) do
|
|
8
|
+
{'id' => '1',
|
|
9
|
+
'full_name' => 'Arthur Dent',
|
|
10
|
+
'email' => 'adent@example.com',
|
|
11
|
+
'birthday' => '1980-01-01'}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "initialize" do
|
|
15
|
+
let(:map) { AttributeMap.new { id; email } }
|
|
16
|
+
|
|
17
|
+
it "takes a hash and attributes map" do
|
|
18
|
+
record = CandidateRecord.new(hash_attrs, map)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "#to_hash" do
|
|
23
|
+
it "remaps attributes" do
|
|
24
|
+
map = AttributeMap.new { name from: 'full_name' }
|
|
25
|
+
subject = CandidateRecord.new(hash_attrs, map).to_hash
|
|
26
|
+
subject.should == { :name => 'Arthur Dent' }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "converts String subclasses to clean strings" do
|
|
30
|
+
stub_const 'Nori::StringWithAttributes', Class.new(String)
|
|
31
|
+
map = AttributeMap.new { full_name }
|
|
32
|
+
hash_attrs['full_name'] = Nori::StringWithAttributes.new('Arthur')
|
|
33
|
+
subject = CandidateRecord.new(hash_attrs, map).to_hash
|
|
34
|
+
subject[:full_name].class.should == String
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "#raw_hash" do
|
|
39
|
+
it "remaps attributes" do
|
|
40
|
+
map = AttributeMap.new { name from: 'full_name' }
|
|
41
|
+
subject = CandidateRecord.new(hash_attrs, map).raw_hash
|
|
42
|
+
subject.should == { :name => 'Arthur Dent' }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "does not translate attributes" do
|
|
46
|
+
map = AttributeMap.new { birthday as: ->(r) { Date.parse(r.birthday) } }
|
|
47
|
+
subject = CandidateRecord.new(hash_attrs, map).raw_hash
|
|
48
|
+
subject.should == { :birthday => "1980-01-01" }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "attribute translation" do
|
|
53
|
+
subject(:hash) { CandidateRecord.new(hash_attrs, map).to_hash }
|
|
54
|
+
|
|
55
|
+
context "from lambda" do
|
|
56
|
+
let(:map) { AttributeMap.new{ birthday as: ->(r){ Date.parse(r.birthday) } } }
|
|
57
|
+
it { should == {birthday: Date.new(1980,1,1)} }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context "from symbol lookup" do
|
|
61
|
+
before { Stockboy::Translations.register :date, ->(r){ Date.parse(r.birthday) } }
|
|
62
|
+
let(:map) { AttributeMap.new{ birthday :as => :date } }
|
|
63
|
+
it { should == {birthday: Date.new(1980,1,1)} }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "chaining" do
|
|
67
|
+
let(:map) { AttributeMap.new{ id as: [->(r){r.id.next}, ->(r){r.id.next}] } }
|
|
68
|
+
it { should == {id: '3'} }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context "with exception" do
|
|
72
|
+
let(:map) { AttributeMap.new{ id as: [->(r){r.id.to_i}, ->(r){r.id / 0}] } }
|
|
73
|
+
it { should == {id: nil} }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context "dynamic without an input field" do
|
|
77
|
+
let(:map) { AttributeMap.new{ generated as: [->(r){ "from lambda" }] } }
|
|
78
|
+
it { should == {generated: "from lambda"} }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe "#to_model" do
|
|
83
|
+
it "should instantiate a new model" do
|
|
84
|
+
model = Class.new(OpenStruct)
|
|
85
|
+
model.should_receive(:new).with({id: '1', name: 'Arthur Dent'})
|
|
86
|
+
map = AttributeMap.new { id; name from: 'full_name' }
|
|
87
|
+
subject = CandidateRecord.new(hash_attrs, map)
|
|
88
|
+
|
|
89
|
+
subject.to_model(model)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe "#input" do
|
|
94
|
+
describe "[]" do
|
|
95
|
+
it "fetches raw values for raw input keys" do
|
|
96
|
+
map = AttributeMap.new { name from: 'full_name' }
|
|
97
|
+
subject = CandidateRecord.new(hash_attrs, map)
|
|
98
|
+
subject.input['full_name'].should == 'Arthur Dent'
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "accesses fields by mapped name before translation" do
|
|
103
|
+
map = AttributeMap.new { name from: 'full_name', as: ->(r){ r.name.upcase } }
|
|
104
|
+
subject = CandidateRecord.new(hash_attrs, map)
|
|
105
|
+
subject.input.name.should == 'Arthur Dent'
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe "#output" do
|
|
110
|
+
describe "[]" do
|
|
111
|
+
it "fetches translated values for raw input keys" do
|
|
112
|
+
map = AttributeMap.new { name from: 'full_name' }
|
|
113
|
+
subject = CandidateRecord.new(hash_attrs, map)
|
|
114
|
+
subject.output.name.should == 'Arthur Dent'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "#partition" do
|
|
120
|
+
subject do
|
|
121
|
+
CandidateRecord.new({'name' =>'Arthur'}, AttributeMap.new { name })
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "returns first matched filter key" do
|
|
125
|
+
key = subject.partition(zeta: proc{ |raw| raw.name =~ /Z/ },
|
|
126
|
+
alpha: proc{ |raw| raw.name =~ /A/ })
|
|
127
|
+
key.should == :alpha
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "returns a match for translated block argument" do
|
|
131
|
+
map = AttributeMap.new { name as: ->(r){ r.name.downcase } }
|
|
132
|
+
subject = CandidateRecord.new({'name' =>'Arthur'}, map)
|
|
133
|
+
|
|
134
|
+
key = subject.partition(down: proc{ |raw,out| out.name[0] == "a" })
|
|
135
|
+
key.should == :down
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "returns nil when raw field is unmatched" do
|
|
139
|
+
key = subject.partition({beta: proc{ |raw| raw.name =~ /B/ }})
|
|
140
|
+
key.should be_nil
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "returns nil when translated field is unmatched" do
|
|
144
|
+
key = subject.partition({beta: proc{ |raw,out| out.name =~ /B/ }})
|
|
145
|
+
key.should be_nil
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/configuration'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe Configuration do
|
|
6
|
+
|
|
7
|
+
subject(:config) { Stockboy::Configuration.new }
|
|
8
|
+
|
|
9
|
+
it "yields a config block" do
|
|
10
|
+
Stockboy::Configuration.new do |c|
|
|
11
|
+
c.should be_a Stockboy::Configuration
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "is accessible from top namespace" do
|
|
16
|
+
Stockboy.configuration.should be_a Stockboy::Configuration
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
specify "#template_load_paths" do
|
|
20
|
+
config.template_load_paths.clear
|
|
21
|
+
config.template_load_paths << "/some_path"
|
|
22
|
+
config.template_load_paths.should == ["/some_path"]
|
|
23
|
+
config.template_load_paths = ["/other_path"]
|
|
24
|
+
config.template_load_paths.should == ["/other_path"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'stockboy/configurator'
|
|
3
|
+
|
|
4
|
+
module Stockboy
|
|
5
|
+
describe Configurator do
|
|
6
|
+
|
|
7
|
+
let(:provider_class) { OpenStruct }
|
|
8
|
+
let(:reader_class) { OpenStruct }
|
|
9
|
+
|
|
10
|
+
describe "#initialize" do
|
|
11
|
+
it "evaluates string config" do
|
|
12
|
+
expect_any_instance_of(Configurator).to receive(:provider).with(:ftp)
|
|
13
|
+
Configurator.new("provider :ftp")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "evaluates block config" do
|
|
17
|
+
expect_any_instance_of(Configurator).to receive(:provider).with(:ftp)
|
|
18
|
+
Configurator.new do
|
|
19
|
+
provider :ftp
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "#provider" do
|
|
25
|
+
before do
|
|
26
|
+
Providers.register(:ftp, provider_class)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "registers with a symbol" do
|
|
30
|
+
subject.provider :ftp
|
|
31
|
+
subject.config[:provider].should be_a(provider_class)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "registers with a class" do
|
|
35
|
+
subject.provider provider_class
|
|
36
|
+
subject.config[:provider].should be_a(provider_class)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "initializes arguments" do
|
|
40
|
+
provider_class.should_receive(:new).with(password:'foo')
|
|
41
|
+
subject.provider :ftp, password: 'foo'
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "#reader" do
|
|
46
|
+
before do
|
|
47
|
+
Readers.register(:csv, reader_class)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "registers with a symbol" do
|
|
51
|
+
subject.reader :csv
|
|
52
|
+
subject.config[:reader].should be_a(reader_class)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "registers with a class" do
|
|
56
|
+
subject.reader reader_class
|
|
57
|
+
subject.config[:reader].should be_a(reader_class)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "initializes arguments" do
|
|
61
|
+
reader_stub = double(:reader)
|
|
62
|
+
reader_class.should_receive(:new).with(col_sep: '|').and_return(reader_stub)
|
|
63
|
+
subject.reader reader_class, col_sep: '|'
|
|
64
|
+
subject.config[:reader].should == reader_stub
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe "#attributes" do
|
|
69
|
+
it "initializes a block" do
|
|
70
|
+
attribute_map = double
|
|
71
|
+
AttributeMap.should_receive(:new).and_return(attribute_map)
|
|
72
|
+
subject.attributes &proc{}
|
|
73
|
+
subject.config[:attributes].should be attribute_map
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe "#on" do
|
|
78
|
+
|
|
79
|
+
let(:job) { double(:job, reset: true, process: true) }
|
|
80
|
+
|
|
81
|
+
it "initializes a block" do
|
|
82
|
+
subject.on :reprocess do |job, *args|
|
|
83
|
+
job.reset
|
|
84
|
+
job.process
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
subject.config[:triggers][:reprocess][0].should be_a Proc
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "#filter" do
|
|
93
|
+
it "initializes a callable" do
|
|
94
|
+
filter_stub = double(call: true)
|
|
95
|
+
subject.filter :pass, filter_stub
|
|
96
|
+
subject.config[:filters][:pass].should == filter_stub
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "initializes a block" do
|
|
100
|
+
subject.filter :pass do |r|
|
|
101
|
+
true if r == 42
|
|
102
|
+
end
|
|
103
|
+
subject.config[:filters][:pass].call(42).should == true
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe "#to_job" do
|
|
108
|
+
before do
|
|
109
|
+
Providers.register :test_prov, provider_class
|
|
110
|
+
Readers.register :test_read, reader_class
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "returns a Job instance" do
|
|
114
|
+
subject.provider :test_prov
|
|
115
|
+
subject.reader :test_read
|
|
116
|
+
subject.attributes &proc{}
|
|
117
|
+
|
|
118
|
+
job = subject.to_job
|
|
119
|
+
job.should be_a(Job)
|
|
120
|
+
job.provider.should be_a(provider_class)
|
|
121
|
+
job.reader.should be_a(reader_class)
|
|
122
|
+
job.attributes.should be_a(AttributeMap)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
end
|