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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 9084ee54795b124c1f8d696f121f9bf2c157d203
|
|
4
|
+
data.tar.gz: e55ec14784707d3c7faa55339a23d2f27832f33d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b2aee64506bd8ac04e4e8cd110fe882b6722e11eeae34ddcb7bfb2f1882615a1d9b82f621ee01ef45ae234ad98b2019bbdfd1e7ec2d2dd6f911e160d30ab4e32
|
|
7
|
+
data.tar.gz: 70429f68f99fbfb65dfa8cc24bb2c0e20a4a49b6a33b3147ab9e8feeb542fff794d2f45ce3d94d2ab9a168998d52ca7d07881b6b5a8b23aaaf7ed786946b831d
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.yardopts
ADDED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.0 / 2013-12-03
|
|
4
|
+
|
|
5
|
+
[FEATURE] YARD documentation throughout
|
|
6
|
+
[FEATURE] Triggers for invoking actions in job context
|
|
7
|
+
[FEATURE] Add generic `delete_data` method for cleanup of matched files
|
|
8
|
+
[ENHANCEMENT] Expose provider `client` for reuse
|
|
9
|
+
[ENHANCEMENT] Expose provider `matching_file` for reuse
|
|
10
|
+
[BUGFIX] Add missing file validations
|
|
11
|
+
|
|
12
|
+
## 0.4.3 / 2013-11-22
|
|
13
|
+
|
|
14
|
+
[ENHANCEMENT] Optimize CSV memory usage with shared hash keys
|
|
15
|
+
[BUGFIX] Missed a required file for SOAP/XML
|
|
16
|
+
|
|
17
|
+
## 0.4.2 / 2013-11-21
|
|
18
|
+
|
|
19
|
+
[ENHANCEMENT] Use consistent conversion for XML hash keys
|
|
20
|
+
|
|
21
|
+
## 0.4.1 / 2013-11-19
|
|
22
|
+
|
|
23
|
+
First post!
|
|
24
|
+
|
data/Gemfile
ADDED
data/Guardfile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# A sample Guardfile
|
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
|
3
|
+
|
|
4
|
+
group :specs do
|
|
5
|
+
guard 'rspec' do
|
|
6
|
+
watch(%r{^spec/.+_spec\.rb$})
|
|
7
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
|
8
|
+
watch('spec/spec_helper.rb') { "spec" }
|
|
9
|
+
end
|
|
10
|
+
end
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2013 Andrew Vit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Stockboy
|
|
2
|
+
|
|
3
|
+
Stockboy helps you receive and unpack data onto your shelves. You might
|
|
4
|
+
consider using it to synchronize data exported from external sources, or
|
|
5
|
+
migrating your own data from legacy systems. (TL;DR, Stockboy is a Ruby
|
|
6
|
+
[DSL][dsl] for doing [ETL][etl].)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Goals
|
|
10
|
+
|
|
11
|
+
Stockboy was originally developed at [Guestfolio][gf] to help synchronize data
|
|
12
|
+
from many external systems that export periodic reports in various incompatible
|
|
13
|
+
ways. Each data source might vary orthogonally on:
|
|
14
|
+
|
|
15
|
+
* __Where the data resides:__
|
|
16
|
+
whether a SOAP service, sent to an IMAP mailbox, an FTP server, or simply a
|
|
17
|
+
local file.
|
|
18
|
+
* __How the data is formatted:__
|
|
19
|
+
whether CSV, Excel, XML, JSON, or some other obscure format.
|
|
20
|
+
* __How the records are structured:__
|
|
21
|
+
what fields are included, and how they are named.
|
|
22
|
+
* __What format the fields are:__
|
|
23
|
+
such as different date formats (DMY vs. MDY), whether names are "first,
|
|
24
|
+
last", or what do do with missing values.
|
|
25
|
+
* __Which records to process:__
|
|
26
|
+
selecting whether records are incomplete, or valid and needing to be added,
|
|
27
|
+
updated or deleted.
|
|
28
|
+
|
|
29
|
+
The goal of Stockboy is to provide a clean, but flexible DSL for declaring
|
|
30
|
+
these configurations and keeping them external to your application, letting
|
|
31
|
+
your app standardize on handling one common interface for the many different
|
|
32
|
+
sources.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
Following your defined job template (see below), a Stockboy job will process
|
|
38
|
+
incoming data into abstract "records". Stockboy leaves it up to your
|
|
39
|
+
application to decide what to do with them.
|
|
40
|
+
|
|
41
|
+
job = Job.define("my_template")
|
|
42
|
+
|
|
43
|
+
job.process
|
|
44
|
+
records = job.records #=> Hash of records sorted by filter key
|
|
45
|
+
other = job.unfiltered_records #=> Array of records unmatched by a filter
|
|
46
|
+
all = job.all_records #=> Array
|
|
47
|
+
|
|
48
|
+
Yielding processed results to a block is also supported:
|
|
49
|
+
|
|
50
|
+
job.process do |records, unfiltered|
|
|
51
|
+
records[:updated].each { |r| YourModel.create(r.attributes) }
|
|
52
|
+
records[:no_data].each { |r| log.warn "No data for #{r.id}" }
|
|
53
|
+
unfiltered_records.each { |r| log.info "Skipping: #{r.raw_hash}" }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
### Records
|
|
57
|
+
|
|
58
|
+
Each record exposes both the source values and the mapped output values
|
|
59
|
+
according to your defined mapping. Typically the mapped fields should
|
|
60
|
+
correspond to the actual attributes on your application models. These can be
|
|
61
|
+
accessed as individual methods, or by converting the record to a hash.
|
|
62
|
+
|
|
63
|
+
record.input["RawEmailField"] # => "ARTHUR@EXAMPLE.COM"
|
|
64
|
+
record.output.email # => "arthur@example.com"
|
|
65
|
+
|
|
66
|
+
record.to_hash or record.attributes
|
|
67
|
+
#=> {check_in: #<Time ...>, location_id: 123, first_name: "Arthur", ...}
|
|
68
|
+
|
|
69
|
+
record.to_model(YourModel) or YourModel.new(record.attributes)
|
|
70
|
+
#=> #<YourModel ...>
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## Job Template DSL
|
|
74
|
+
|
|
75
|
+
Stockboy job templates are defined in Ruby but are simple and abstract enough
|
|
76
|
+
to be considered more _configuration_ than _code_. They should reside in the
|
|
77
|
+
[template load path](#stockboy-configuration) for easy loading. Once defined,
|
|
78
|
+
job templates are parsed and loaded at runtime, so they can be added or updated
|
|
79
|
+
separately without needing to restart a long-running process, e.g. Rails or
|
|
80
|
+
Sidekiq.
|
|
81
|
+
|
|
82
|
+
Writing a job template requires you to declare three parts:
|
|
83
|
+
|
|
84
|
+
### Example
|
|
85
|
+
|
|
86
|
+
# config/stockboy_jobs/my_template.rb
|
|
87
|
+
|
|
88
|
+
provider :ftp do
|
|
89
|
+
host "example.com"
|
|
90
|
+
username "mystore"
|
|
91
|
+
password "123456"
|
|
92
|
+
file_name "dailyreport-*.csv"
|
|
93
|
+
file_pick :first
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
reader :csv do
|
|
97
|
+
headers true
|
|
98
|
+
col_sep "|"
|
|
99
|
+
encoding "Windows-1252"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
attributes do
|
|
103
|
+
email from: 'RawEmailAddress'
|
|
104
|
+
first_name as: proc{ |r| r['Full-Name'].split(' ').first }
|
|
105
|
+
last_name as: proc{ |r| r['Full-Name'].split(' ').last }
|
|
106
|
+
birthdate as: [:time]
|
|
107
|
+
score as: [:integer, :default_zero]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
filter(:invalid_email) do |input, _|
|
|
111
|
+
not(input.email.include?('@') or input['EmailAddress'] == '')
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
filter(:missing_code) do |_, output|
|
|
115
|
+
output.product_code.nil?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
Looking at the parts of this template:
|
|
119
|
+
|
|
120
|
+
### 1. Get it with a provider
|
|
121
|
+
|
|
122
|
+
The provider block describes the connection parameters for finding and fetching
|
|
123
|
+
data, which is returned as a raw string blob. It can handle some complexity to
|
|
124
|
+
determine which file to pick from an email attachment or FTP directory, for
|
|
125
|
+
example.
|
|
126
|
+
|
|
127
|
+
See: [File][file], [FTP][ftp], [HTTP][http], [IMAP][imap], [SOAP][soap]
|
|
128
|
+
|
|
129
|
+
[file]: lib/stockboy/providers/file.rb
|
|
130
|
+
[ftp]: lib/stockboy/providers/ftp.rb
|
|
131
|
+
[http]: lib/stockboy/providers/http.rb
|
|
132
|
+
[imap]: lib/stockboy/providers/imap.rb
|
|
133
|
+
[soap]: lib/stockboy/providers/soap.rb
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
### 2. Parse it with a reader
|
|
137
|
+
|
|
138
|
+
The reader block describes how to turn the raw string from the provider into
|
|
139
|
+
sets of fields. This extracts the raw data tokens, which we can then map to our
|
|
140
|
+
application's domain.
|
|
141
|
+
|
|
142
|
+
See: [CSV][csv], [Fixed-Width][fix], [Spreadsheet][xls], [XML][xml]
|
|
143
|
+
|
|
144
|
+
[csv]: lib/stockboy/readers/csv.rb
|
|
145
|
+
[fix]: lib/stockboy/readers/fixed_width.rb
|
|
146
|
+
[xls]: lib/stockboy/readers/spreadsheet.rb
|
|
147
|
+
[xml]: lib/stockboy/readers/xml.rb
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### 3. Collect it into attributes
|
|
151
|
+
|
|
152
|
+
The attributes block is the main part of the template definition. This
|
|
153
|
+
describes which fields to extract from the parsed data, and how to represent
|
|
154
|
+
each value in the output record. The output attributes are defined by calling
|
|
155
|
+
the attribute's name plus two options:
|
|
156
|
+
|
|
157
|
+
#### from:
|
|
158
|
+
When the field name from the source doesn't match the desired attribute name,
|
|
159
|
+
this option should be used to name the correct field to read from the source
|
|
160
|
+
record.
|
|
161
|
+
|
|
162
|
+
#### as:
|
|
163
|
+
By default, attributes are returned as the original raw string data value, but
|
|
164
|
+
translators can be applied to change the input to any format. Acceptable
|
|
165
|
+
options include a symbol for a built-in translator (e.g. `:date`) or any Proc
|
|
166
|
+
or callable object responding to `call(source_record)`.
|
|
167
|
+
|
|
168
|
+
Translator blocks can access record fields as either:
|
|
169
|
+
|
|
170
|
+
| Indexes for raw input fields | Methods for final attribute names |
|
|
171
|
+
| :-------------------------------: | :-------------------------------: |
|
|
172
|
+
| `->(r){ r['RawEmail'].downcase }` | `->(r){ r.email.downcase }` |
|
|
173
|
+
|
|
174
|
+
Since the entire record context is passed, you can combine multiple input
|
|
175
|
+
fields into one attribute (e.g. combining date plus time). You can also define
|
|
176
|
+
two attributes that extract different data from the same field, e.g. splitting
|
|
177
|
+
a full name field into first and last.
|
|
178
|
+
|
|
179
|
+
Translations are applied in order when given as an array. Since translators are
|
|
180
|
+
designed to handle invalid data, they will catch exceptions and return a `nil`
|
|
181
|
+
so it's a good idea to have default values at the end of the chain.
|
|
182
|
+
|
|
183
|
+
#### Built-in attribute translators:
|
|
184
|
+
|
|
185
|
+
* [`:boolean`][bool]
|
|
186
|
+
Common true/false strings to `True` or `False` (e.g. '1'/'0' or 't'/'f')
|
|
187
|
+
* [`:date`][date]
|
|
188
|
+
ISO-8601 or common strings to `Date` (e.g. "2012-12-21" or "Dec 12, 2012")
|
|
189
|
+
* [`:uk_date`][ukda]
|
|
190
|
+
Date strings from UK format to `Date` (e.g. "DD/MM/YY")
|
|
191
|
+
* [`:us_date`][usda]
|
|
192
|
+
Date strings from US format to `Date` (e.g. "MM/DD/YY")
|
|
193
|
+
* [`:decimal`][deci]
|
|
194
|
+
Numeric strings to `BigDecimal` (e.g. prices)
|
|
195
|
+
* [`:integer`][intg]
|
|
196
|
+
Numeric strings to `Fixnum` integers
|
|
197
|
+
* [`:string`][stri]
|
|
198
|
+
Clean strings with leading/trailing whitespace trimmed
|
|
199
|
+
* [`:or_empty`][dest]
|
|
200
|
+
Returns `""` for blank values
|
|
201
|
+
* [`:or_nil`][dest]
|
|
202
|
+
Returns `nil` for blank values
|
|
203
|
+
* [`:or_zero`][dzer]
|
|
204
|
+
Returns `0` for blank values
|
|
205
|
+
|
|
206
|
+
[bool]: lib/stockboy/translators/boolean.rb
|
|
207
|
+
[date]: lib/stockboy/translators/date.rb
|
|
208
|
+
[deci]: lib/stockboy/translators/decimal.rb
|
|
209
|
+
[dest]: lib/stockboy/translators/default_empty_string.rb
|
|
210
|
+
[dnil]: lib/stockboy/translators/default_nil.rb
|
|
211
|
+
[dzer]: lib/stockboy/translators/default_zero.rb
|
|
212
|
+
[intg]: lib/stockboy/translators/integer.rb
|
|
213
|
+
[stri]: lib/stockboy/translators/string.rb
|
|
214
|
+
[time]: lib/stockboy/translators/time.rb
|
|
215
|
+
[ukda]: lib/stockboy/translators/uk_date.rb
|
|
216
|
+
[usda]: lib/stockboy/translators/us_date.rb
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
### 4. Funnel it with filters
|
|
220
|
+
|
|
221
|
+
Filters are optional, but they are very helpful for funneling the data into
|
|
222
|
+
your workflow. For example, you may need to partition records for different
|
|
223
|
+
handling based on a status field.
|
|
224
|
+
|
|
225
|
+
Filters are applied in the order that they are declared. The first filter that
|
|
226
|
+
returns `true` when traversing a record will capture it. Records that fall
|
|
227
|
+
through all the filters without matching anything are considered "unfiltered".
|
|
228
|
+
|
|
229
|
+
job.process
|
|
230
|
+
job.records[:update] #=> Array
|
|
231
|
+
job.unfiltered_records #=> Array
|
|
232
|
+
job.all_records #=> Array
|
|
233
|
+
|
|
234
|
+
Filters can inspect records either pre- or post-translation. Often you just
|
|
235
|
+
need to look at the raw input parameters, but it's also possible to get the
|
|
236
|
+
output values from the second block parameter:
|
|
237
|
+
|
|
238
|
+
filter(:example) do |input, output|
|
|
239
|
+
input["RawEmailAddress"] =~ /gmail/ or output.bounce_count > 1
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Installation
|
|
245
|
+
|
|
246
|
+
Add `gem 'stockboy'` to your Gemfile and run `bundle install`.
|
|
247
|
+
|
|
248
|
+
Supported on Ruby 1.9+.
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
<a name="stockboy-configuration"></a>
|
|
252
|
+
## Configuration
|
|
253
|
+
|
|
254
|
+
When loaded under a Rails app, Stockboy will look for `config/stockboy.rb` for
|
|
255
|
+
self-configuration if it's present.
|
|
256
|
+
|
|
257
|
+
### Template Load Paths
|
|
258
|
+
|
|
259
|
+
Template load paths are intended for storing your defined job templates for
|
|
260
|
+
different data sources. (`config/stockboy_jobs/` is the default when loaded in
|
|
261
|
+
a Rails app; else it must be defined.)
|
|
262
|
+
|
|
263
|
+
Stockboy.configuration do |config|
|
|
264
|
+
config.template_load_paths = ['config/job_imports', 'config/log_imports']
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
### Register Custom Providers / Readers
|
|
268
|
+
|
|
269
|
+
Beyond the standard providers (`:ftp`, `:soap`, etc.) and readers (`:csv`,
|
|
270
|
+
`:xml`), you can register your own for fetching or parsing data from different
|
|
271
|
+
sources. (Contributions welcome.)
|
|
272
|
+
|
|
273
|
+
Stockboy::Readers.register :m3u, PlaylistReader
|
|
274
|
+
Stockboy::Providers.register :gopher, GopherProvider
|
|
275
|
+
Stockboy::Translations.register :product_code, YourProductCodeTranslator
|
|
276
|
+
|
|
277
|
+
See the [Reader][reader], [Provider][provider], and [Translator][translator]
|
|
278
|
+
for details on implementing your own custom classes.
|
|
279
|
+
|
|
280
|
+
[provider]: lib/stockboy/provider.rb
|
|
281
|
+
[reader]: lib/stockboy/reader.rb
|
|
282
|
+
[translator]: lib/stockboy/translator.rb
|
|
283
|
+
|
|
284
|
+
## Development
|
|
285
|
+
|
|
286
|
+
Contributions and pull requests are welcome.
|
|
287
|
+
|
|
288
|
+
bundle install
|
|
289
|
+
bundle exec rake # runs tests
|
|
290
|
+
|
|
291
|
+
[gf]: http://guestfolio.com/
|
|
292
|
+
[etl]: https://en.wikipedia.org/wiki/Extract,_transform,_load
|
|
293
|
+
[dsl]: https://en.wikipedia.org/wiki/Domain-specific_language
|
data/Rakefile
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Bundler
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
require "bundler/gem_tasks"
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# RSpec
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require "rspec/core/rake_task"
|
|
12
|
+
RSpec::Core::RakeTask.new
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# YARD
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'yard'
|
|
19
|
+
require "yard/rake/yardoc_task"
|
|
20
|
+
YARD::Rake::YardocTask.new do |t|
|
|
21
|
+
# t.options += ['--title', "Stockboy Documentation"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# Stockboy
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
task :default => :spec
|
|
29
|
+
|
|
30
|
+
task :test => :spec
|
data/lib/stockboy.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'stockboy/version'
|
|
2
|
+
require 'stockboy/exceptions'
|
|
3
|
+
require 'stockboy/dsl'
|
|
4
|
+
require 'stockboy/job'
|
|
5
|
+
|
|
6
|
+
# Registries
|
|
7
|
+
require 'stockboy/translations'
|
|
8
|
+
require 'stockboy/providers'
|
|
9
|
+
require 'stockboy/readers'
|
|
10
|
+
require 'stockboy/filters'
|
|
11
|
+
|
|
12
|
+
# Translations
|
|
13
|
+
require 'stockboy/translations/default_empty_string'
|
|
14
|
+
require 'stockboy/translations/default_false'
|
|
15
|
+
require 'stockboy/translations/default_true'
|
|
16
|
+
require 'stockboy/translations/default_nil'
|
|
17
|
+
require 'stockboy/translations/default_zero'
|
|
18
|
+
require 'stockboy/translations/boolean'
|
|
19
|
+
require 'stockboy/translations/integer'
|
|
20
|
+
require 'stockboy/translations/decimal'
|
|
21
|
+
require 'stockboy/translations/time'
|
|
22
|
+
require 'stockboy/translations/date'
|
|
23
|
+
require 'stockboy/translations/us_date'
|
|
24
|
+
require 'stockboy/translations/uk_date'
|
|
25
|
+
|
|
26
|
+
# Filters
|
|
27
|
+
require 'stockboy/filters/missing_email'
|
|
28
|
+
|
|
29
|
+
# Providers
|
|
30
|
+
require 'stockboy/providers/ftp'
|
|
31
|
+
require 'stockboy/providers/http'
|
|
32
|
+
require 'stockboy/providers/imap'
|
|
33
|
+
require 'stockboy/providers/soap'
|
|
34
|
+
require 'stockboy/providers/file'
|
|
35
|
+
|
|
36
|
+
# Readers
|
|
37
|
+
require 'stockboy/readers/csv'
|
|
38
|
+
require 'stockboy/readers/xml'
|
|
39
|
+
require 'stockboy/readers/fixed_width'
|
|
40
|
+
require 'stockboy/readers/spreadsheet'
|
|
41
|
+
|
|
42
|
+
module Stockboy
|
|
43
|
+
|
|
44
|
+
module Filters
|
|
45
|
+
register :missing_email, MissingEmail
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module Providers
|
|
49
|
+
register :file, File
|
|
50
|
+
register :ftp, FTP
|
|
51
|
+
register :http, HTTP
|
|
52
|
+
register :soap, SOAP
|
|
53
|
+
register :imap, IMAP
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
module Readers
|
|
57
|
+
register :csv, CSV
|
|
58
|
+
register :xml, XML
|
|
59
|
+
register :fixed_width, FixedWidth
|
|
60
|
+
register :spreadsheet, Spreadsheet
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module Translations
|
|
64
|
+
register :or_false, DefaultFalse
|
|
65
|
+
register :or_true, DefaultTrue
|
|
66
|
+
register :or_nil, DefaultNil
|
|
67
|
+
register :or_empty, DefaultEmptyString
|
|
68
|
+
register :or_zero, DefaultZero
|
|
69
|
+
register :boolean, Boolean
|
|
70
|
+
register :integer, Integer
|
|
71
|
+
register :decimal, Decimal
|
|
72
|
+
register :time, Time
|
|
73
|
+
register :date, Date
|
|
74
|
+
register :us_date, USDate
|
|
75
|
+
register :uk_date, UKDate
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
require 'stockboy/railtie' if defined? Rails
|