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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +5 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +24 -0
  6. data/Gemfile +12 -0
  7. data/Guardfile +10 -0
  8. data/LICENSE +21 -0
  9. data/README.md +293 -0
  10. data/Rakefile +30 -0
  11. data/lib/stockboy.rb +80 -0
  12. data/lib/stockboy/attribute.rb +11 -0
  13. data/lib/stockboy/attribute_map.rb +74 -0
  14. data/lib/stockboy/candidate_record.rb +130 -0
  15. data/lib/stockboy/configuration.rb +62 -0
  16. data/lib/stockboy/configurator.rb +176 -0
  17. data/lib/stockboy/dsl.rb +68 -0
  18. data/lib/stockboy/exceptions.rb +3 -0
  19. data/lib/stockboy/filter.rb +58 -0
  20. data/lib/stockboy/filter_chain.rb +41 -0
  21. data/lib/stockboy/filters.rb +11 -0
  22. data/lib/stockboy/filters/missing_email.rb +37 -0
  23. data/lib/stockboy/job.rb +241 -0
  24. data/lib/stockboy/mapped_record.rb +59 -0
  25. data/lib/stockboy/provider.rb +238 -0
  26. data/lib/stockboy/providers.rb +11 -0
  27. data/lib/stockboy/providers/file.rb +135 -0
  28. data/lib/stockboy/providers/ftp.rb +205 -0
  29. data/lib/stockboy/providers/http.rb +123 -0
  30. data/lib/stockboy/providers/imap.rb +290 -0
  31. data/lib/stockboy/providers/soap.rb +120 -0
  32. data/lib/stockboy/railtie.rb +28 -0
  33. data/lib/stockboy/reader.rb +59 -0
  34. data/lib/stockboy/readers.rb +11 -0
  35. data/lib/stockboy/readers/csv.rb +115 -0
  36. data/lib/stockboy/readers/fixed_width.rb +121 -0
  37. data/lib/stockboy/readers/spreadsheet.rb +144 -0
  38. data/lib/stockboy/readers/xml.rb +155 -0
  39. data/lib/stockboy/registry.rb +42 -0
  40. data/lib/stockboy/source_record.rb +43 -0
  41. data/lib/stockboy/string_pool.rb +35 -0
  42. data/lib/stockboy/template_file.rb +44 -0
  43. data/lib/stockboy/translations.rb +70 -0
  44. data/lib/stockboy/translations/boolean.rb +58 -0
  45. data/lib/stockboy/translations/date.rb +41 -0
  46. data/lib/stockboy/translations/decimal.rb +33 -0
  47. data/lib/stockboy/translations/default_empty_string.rb +38 -0
  48. data/lib/stockboy/translations/default_false.rb +41 -0
  49. data/lib/stockboy/translations/default_nil.rb +38 -0
  50. data/lib/stockboy/translations/default_true.rb +41 -0
  51. data/lib/stockboy/translations/default_zero.rb +41 -0
  52. data/lib/stockboy/translations/integer.rb +33 -0
  53. data/lib/stockboy/translations/string.rb +33 -0
  54. data/lib/stockboy/translations/time.rb +41 -0
  55. data/lib/stockboy/translations/uk_date.rb +51 -0
  56. data/lib/stockboy/translations/us_date.rb +51 -0
  57. data/lib/stockboy/translator.rb +66 -0
  58. data/lib/stockboy/version.rb +3 -0
  59. data/spec/fixtures/.gitkeep +0 -0
  60. data/spec/fixtures/files/a_garbage.csv +1 -0
  61. data/spec/fixtures/files/test_data-20120101.csv +1 -0
  62. data/spec/fixtures/files/test_data-20120202.csv +1 -0
  63. data/spec/fixtures/files/z_garbage.csv +1 -0
  64. data/spec/fixtures/jobs/test_job.rb +1 -0
  65. data/spec/fixtures/soap/get_list/fault.xml +8 -0
  66. data/spec/fixtures/soap/get_list/success.xml +18 -0
  67. data/spec/fixtures/spreadsheets/test_data.xls +0 -0
  68. data/spec/fixtures/spreadsheets/test_row_options.xls +0 -0
  69. data/spec/fixtures/xml/body.xml +14 -0
  70. data/spec/spec_helper.rb +28 -0
  71. data/spec/stockboy/attribute_map_spec.rb +59 -0
  72. data/spec/stockboy/attribute_spec.rb +11 -0
  73. data/spec/stockboy/candidate_record_spec.rb +150 -0
  74. data/spec/stockboy/configuration_spec.rb +28 -0
  75. data/spec/stockboy/configurator_spec.rb +127 -0
  76. data/spec/stockboy/filter_chain_spec.rb +40 -0
  77. data/spec/stockboy/filter_spec.rb +41 -0
  78. data/spec/stockboy/filters/missing_email_spec.rb +26 -0
  79. data/spec/stockboy/filters_spec.rb +38 -0
  80. data/spec/stockboy/job_spec.rb +238 -0
  81. data/spec/stockboy/mapped_record_spec.rb +30 -0
  82. data/spec/stockboy/provider_spec.rb +34 -0
  83. data/spec/stockboy/providers/file_spec.rb +116 -0
  84. data/spec/stockboy/providers/ftp_spec.rb +143 -0
  85. data/spec/stockboy/providers/http_spec.rb +94 -0
  86. data/spec/stockboy/providers/imap_spec.rb +76 -0
  87. data/spec/stockboy/providers/soap_spec.rb +107 -0
  88. data/spec/stockboy/providers_spec.rb +38 -0
  89. data/spec/stockboy/readers/csv_spec.rb +68 -0
  90. data/spec/stockboy/readers/fixed_width_spec.rb +52 -0
  91. data/spec/stockboy/readers/spreadsheet_spec.rb +121 -0
  92. data/spec/stockboy/readers/xml_spec.rb +94 -0
  93. data/spec/stockboy/readers_spec.rb +30 -0
  94. data/spec/stockboy/source_record_spec.rb +19 -0
  95. data/spec/stockboy/template_file_spec.rb +30 -0
  96. data/spec/stockboy/translations/boolean_spec.rb +48 -0
  97. data/spec/stockboy/translations/date_spec.rb +38 -0
  98. data/spec/stockboy/translations/decimal_spec.rb +23 -0
  99. data/spec/stockboy/translations/default_empty_string_spec.rb +32 -0
  100. data/spec/stockboy/translations/default_false_spec.rb +25 -0
  101. data/spec/stockboy/translations/default_nil_spec.rb +32 -0
  102. data/spec/stockboy/translations/default_true_spec.rb +25 -0
  103. data/spec/stockboy/translations/default_zero_spec.rb +32 -0
  104. data/spec/stockboy/translations/integer_spec.rb +22 -0
  105. data/spec/stockboy/translations/string_spec.rb +22 -0
  106. data/spec/stockboy/translations/time_spec.rb +27 -0
  107. data/spec/stockboy/translations/uk_date_spec.rb +37 -0
  108. data/spec/stockboy/translations/us_date_spec.rb +37 -0
  109. data/spec/stockboy/translations_spec.rb +55 -0
  110. data/spec/stockboy/translator_spec.rb +27 -0
  111. data/stockboy.gemspec +32 -0
  112. 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
@@ -0,0 +1,3 @@
1
+ module Stockboy
2
+ VERSION = "0.5.0"
3
+ 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,8 @@
1
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <soap:Body>
3
+ <soap:Fault>
4
+ <faultcode>soap:Server</faultcode>
5
+ <faultstring>Fault occurred while processing.</faultstring>
6
+ </soap:Fault>
7
+ </soap:Body>
8
+ </soap:Envelope>
@@ -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>
@@ -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>
@@ -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