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,41 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Convert ISO-8601 and other recognized date-like strings to +Date+
6
+ #
7
+ # == Job template DSL
8
+ #
9
+ # Registered as +:date+. Use with:
10
+ #
11
+ # attributes do
12
+ # check_in as: :date
13
+ # end
14
+ #
15
+ # @example
16
+ # date = Stockboy::Translator::Date.new
17
+ #
18
+ # record.check_in = "2012-01-01"
19
+ # date.translate(record, :check_in) # => #<Date 2012-01-01>
20
+ #
21
+ # record.check_in = "Jan 1, 2012"
22
+ # date.translate(record, :check_in) # => #<Date 2012-01-01>
23
+ #
24
+ class Date < Stockboy::Translator
25
+
26
+ # @return [Date]
27
+ #
28
+ def translate(context)
29
+ value = field_value(context, field_key)
30
+ return nil if value.blank?
31
+
32
+ case value
33
+ when ::String then ::Date.parse(value)
34
+ when ::Time, ::DateTime then ::Date.new(value.year, value.month, value.day)
35
+ when ::Date then value
36
+ else nil
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Convert numeric strings to +BigDecimal+
6
+ #
7
+ # == Job template DSL
8
+ #
9
+ # Registered as +:decimal+. Use with:
10
+ #
11
+ # attributes do
12
+ # check_in as: :decimal
13
+ # end
14
+ #
15
+ # @example
16
+ # dec = Stockboy::Translator::Date.new
17
+ #
18
+ # record.cost = "256.99"
19
+ # dec.translate(record, :cost) # => #<BigDecimal 256.99>
20
+ #
21
+ class Decimal < Stockboy::Translator
22
+
23
+ # @return [BigDecimal]
24
+ #
25
+ def translate(context)
26
+ value = field_value(context, field_key)
27
+ return nil if value.blank?
28
+
29
+ BigDecimal.new(value, 10)
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translate missing values to empty string
6
+ #
7
+ # This is a useful fallback for translation errors.
8
+ #
9
+ # == Job template DSL
10
+ #
11
+ # Registered as +:or_empty+. Use with:
12
+ #
13
+ # attributes do
14
+ # product_code as: [->(r){raise "Invalid"}, :or_empty]
15
+ # end
16
+ #
17
+ # @example
18
+ # str = Stockboy::Translator::DefaultEmptyString.new
19
+ #
20
+ # record.product_code = "ITEM"
21
+ # str.translate(record, :product_code) # => "ITEM"
22
+ #
23
+ # record.product_code = nil
24
+ # str.translate(record, :product_code) # => ""
25
+ #
26
+ class DefaultEmptyString < Stockboy::Translator
27
+
28
+ # @return [String]
29
+ #
30
+ def translate(context)
31
+ value = field_value(context, field_key)
32
+ return "" if (value).blank?
33
+
34
+ return value
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translate missing values to boolean false
6
+ #
7
+ # This is a useful fallback for translation errors from boolean fields.
8
+ #
9
+ # == Job template DSL
10
+ #
11
+ # Registered as +:or_false+. Use with:
12
+ #
13
+ # attributes do
14
+ # active as: [:boolean, :or_false]
15
+ # end
16
+ #
17
+ # @example
18
+ # bool = Stockboy::Translator::Boolean.new
19
+ #
20
+ # record.active = nil
21
+ # bool.translate(record, :active) # => false
22
+ #
23
+ # record.active = false
24
+ # bool.translate(record, :active) # => false
25
+ #
26
+ # record.active = true
27
+ # bool.translate(record, :active) # => true
28
+ #
29
+ class DefaultFalse < Stockboy::Translator
30
+
31
+ # @return [Boolean]
32
+ #
33
+ def translate(context)
34
+ value = field_value(context, field_key)
35
+
36
+ return false if value.nil?
37
+ return value
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translate missing values to nil
6
+ #
7
+ # This is a useful fallback for empty values that should be cleared to nil.
8
+ #
9
+ # == Job template DSL
10
+ #
11
+ # Registered as +:or_nil+. Use with:
12
+ #
13
+ # attributes do
14
+ # product_code as: [->(r){raise "Invalid"}, :or_nil]
15
+ # end
16
+ #
17
+ # @example
18
+ # str = Stockboy::Translator::DefaultNil.new
19
+ #
20
+ # record.product_code = "ITEM"
21
+ # str.translate(record, :product_code) # => "ITEM"
22
+ #
23
+ # record.product_code = ""
24
+ # str.translate(record, :product_code) # => nil
25
+ #
26
+ class DefaultNil < Stockboy::Translator
27
+
28
+ # @return [Object, NilClass]
29
+ #
30
+ def translate(context)
31
+ value = field_value(context, field_key)
32
+ return nil if (value).blank?
33
+
34
+ return value
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translate missing values to boolean true
6
+ #
7
+ # This is a useful fallback for translation errors from boolean fields.
8
+ #
9
+ # == Job template DSL
10
+ #
11
+ # Registered as +:or_true+. Use with:
12
+ #
13
+ # attributes do
14
+ # active as: [:boolean, :or_true]
15
+ # end
16
+ #
17
+ # @example
18
+ # bool = Stockboy::Translator::Boolean.new
19
+ #
20
+ # record.active = nil
21
+ # bool.translate(record, :active) # => true
22
+ #
23
+ # record.active = false
24
+ # bool.translate(record, :active) # => false
25
+ #
26
+ # record.active = true
27
+ # bool.translate(record, :active) # => true
28
+ #
29
+ class DefaultTrue < Stockboy::Translator
30
+
31
+ # @return [Boolean]
32
+ #
33
+ def translate(context)
34
+ value = field_value(context, field_key)
35
+
36
+ return true if value.nil?
37
+ return value
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translate missing values to numeric zero
6
+ #
7
+ # This is a useful fallback for translation errors.
8
+ #
9
+ # == Job template DSL
10
+ #
11
+ # Registered as +:or_zero+. Use with:
12
+ #
13
+ # attributes do
14
+ # cost as: [->(r){raise "Invalid"}, :or_zero]
15
+ # end
16
+ #
17
+ # @example
18
+ # zero = Stockboy::Translator::DefaultZero.new
19
+ #
20
+ # record.cost = 256
21
+ # zero.translate(record, :cost) # => 256
22
+ #
23
+ # record.cost = nil
24
+ # zero.translate(record, :cost) # => 0
25
+ #
26
+ # record.cost = ""
27
+ # zero.translate(record, :cost) # => 0
28
+ #
29
+ class DefaultZero < Stockboy::Translator
30
+
31
+ # @return [Fixnum]
32
+ #
33
+ def translate(context)
34
+ value = field_value(context, field_key)
35
+ return 0 if value.blank?
36
+
37
+ return value
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translate string values to +Fixnum+
6
+ #
7
+ # == Job template DSL
8
+ #
9
+ # Registered as +:integer+. Use with:
10
+ #
11
+ # attributes do
12
+ # children as: :integer
13
+ # end
14
+ #
15
+ # @example
16
+ # num = Stockboy::Translator::Integer.new
17
+ #
18
+ # record.children = "2"
19
+ # num.translate(record, :children) # => 2
20
+ #
21
+ class Integer < Stockboy::Translator
22
+
23
+ # @return [Fixnum]
24
+ #
25
+ def translate(context)
26
+ value = field_value(context, field_key)
27
+ return nil if value.blank?
28
+
29
+ value.to_i
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Cleans string values by stripping surrounding whitespace
6
+ #
7
+ # == Job template DSL
8
+ #
9
+ # Registered as +:string+. Use with:
10
+ #
11
+ # attributes do
12
+ # name as: :string
13
+ # end
14
+ #
15
+ # @example
16
+ # str = Stockboy::Translator::String.new
17
+ #
18
+ # record.name = "Arthur "
19
+ # str.translate(record, :name) # => "Arthur"
20
+ #
21
+ class String < Stockboy::Translator
22
+
23
+ # @return [String]
24
+ #
25
+ def translate(context)
26
+ value = field_value(context, field_key)
27
+ return "" if value.blank?
28
+
29
+ value.strip
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Convert ISO-8601 and other recognized time-like strings to +Time+
6
+ #
7
+ # Uses +ActiveSupport::TimeWithZone+ if available.
8
+ #
9
+ # == Job template DSL
10
+ #
11
+ # Registered as +:time+. Use with:
12
+ #
13
+ # attributes do
14
+ # arriving as: :time
15
+ # end
16
+ #
17
+ # @example
18
+ # time = Stockboy::Translator::Time.new
19
+ #
20
+ # record.arriving = "2012-01-01 12:34:56 UTC"
21
+ # time.translate(record, :arriving) # => #<Time 2012-01-01 12:34:56>
22
+ #
23
+ class Time < Stockboy::Translator
24
+
25
+ # @return [Time]
26
+ #
27
+ def translate(context)
28
+ value = field_value(context, field_key)
29
+ return nil if (value).blank?
30
+
31
+ clock.parse(value).to_time
32
+ end
33
+
34
+ private
35
+
36
+ def clock
37
+ ::Time.respond_to?(:zone) && ::Time.zone || ::DateTime
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translates numeric dates provided in UK (DMY) order
6
+ #
7
+ # Priority is given to small-endian (UK) order:
8
+ #
9
+ # * DD-MM-YYYY
10
+ # * DD-MM-YY
11
+ # * DD/MM/YYYY
12
+ # * DD/MM/YY
13
+ #
14
+ # == Job template DSL
15
+ #
16
+ # Registered as +:uk_date+. Use with:
17
+ #
18
+ # attributes do
19
+ # check_in as: :uk_date
20
+ # end
21
+ #
22
+ # @example
23
+ # date = Stockboy::Translator::UKDate.new
24
+ #
25
+ # record.check_in = "1/2/12"
26
+ # date.translate(record, :check_in) # => #<Date 2012-02-01>
27
+ #
28
+ class UKDate < Stockboy::Translator
29
+
30
+ # @return [Date]
31
+ #
32
+ def translate(context)
33
+ value = field_value(context, field_key)
34
+ return nil if value.blank?
35
+
36
+ ::Date.strptime(value, date_format(value))
37
+ end
38
+
39
+ private
40
+
41
+ def date_format(value)
42
+ x = value.include?(?/) ? ?/ : ?-
43
+ if value =~ %r"\d{1,2}(?:/|-)\d{1,2}(?:/|-)\d{2}$"
44
+ "%d#{x}%m#{x}%y"
45
+ else
46
+ "%d#{x}%m#{x}%Y"
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,51 @@
1
+ require 'stockboy/translator'
2
+
3
+ module Stockboy::Translations
4
+
5
+ # Translates numeric dates provided in US (MDY) order
6
+ #
7
+ # Priority is given to middle-endian (US) order:
8
+ #
9
+ # * MM-DD-YYYY
10
+ # * MM-DD-YY
11
+ # * MM/DD/YYYY
12
+ # * MM/DD/YY
13
+ #
14
+ # == Job template DSL
15
+ #
16
+ # Registered as +:us_date+. Use with:
17
+ #
18
+ # attributes do
19
+ # check_in as: :us_date
20
+ # end
21
+ #
22
+ # @example
23
+ # date = Stockboy::Translator::USDate.new
24
+ #
25
+ # record.check_in = "2-1-12"
26
+ # date.translate(record, :check_in) # => #<Date 2012-02-01>
27
+ #
28
+ class USDate < Stockboy::Translator
29
+
30
+ # @return [Date]
31
+ #
32
+ def translate(context)
33
+ value = field_value(context, field_key)
34
+ return nil if value.blank?
35
+
36
+ ::Date.strptime(value, date_format(value))
37
+ end
38
+
39
+ private
40
+
41
+ def date_format(value)
42
+ x = value.include?(?/) ? ?/ : ?-
43
+ if value =~ %r"\d{1,2}(?:/|-)\d{1,2}(?:/|-)\d{4}"
44
+ "%m#{x}%d#{x}%Y"
45
+ else
46
+ "%m#{x}%d#{x}%y"
47
+ end
48
+ end
49
+
50
+ end
51
+ end