efo_nelfo 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/lib/efo_nelfo/errors.rb +1 -0
- data/lib/efo_nelfo/post_head_type.rb +4 -8
- data/lib/efo_nelfo/post_type.rb +9 -1
- data/lib/efo_nelfo/properties.rb +121 -0
- data/lib/efo_nelfo/property.rb +70 -131
- data/lib/efo_nelfo/property_types.rb +47 -0
- data/lib/efo_nelfo/reader/csv.rb +3 -1
- data/lib/efo_nelfo/v40/vl.rb +17 -0
- data/lib/efo_nelfo/v40/vx.rb +18 -5
- data/lib/efo_nelfo/version.rb +1 -1
- data/lib/efo_nelfo.rb +2 -0
- data/spec/csv_writer_spec.rb +1 -1
- data/spec/post_type_spec.rb +20 -12
- data/spec/properties_spec.rb +149 -0
- data/spec/property_spec.rb +148 -99
- data/spec/vl_spec.rb +36 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64cdaf33e1a391067ac19395f549997d497faa45
|
4
|
+
data.tar.gz: 247909b6de770da10400d1ba2ff6ac8ad16b2a2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3dbe7d16a9b78ee13b12a6ee47657481376a9bc73017f1d83caa11e22759f6f3e838d9b0878f7615ecd10b9cfe58af7355716863d215a53cdfbe247b82890a4
|
7
|
+
data.tar.gz: 035aaa3183fd806377ccc9ca7bcabb6a6e5fbd0f174d5625ef831ae89fb0e9054b78a5af7c55c58282bf5ff3f41c0d8bdc003bd3432a58d958eb2988f5ad3e2a
|
data/README.md
CHANGED
@@ -2,14 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem for parsing and writing EfoNelfo documents.
|
4
4
|
|
5
|
-
Supported versions:
|
5
|
+
Supported EfoNelfo versions:
|
6
6
|
|
7
7
|
* 4.0
|
8
8
|
|
9
9
|
Supported formats:
|
10
10
|
|
11
|
-
* Bestilling
|
12
|
-
|
11
|
+
* Bestilling (BH, BL, BT)
|
12
|
+
* Vareformat (VH, VL, VX, VA)
|
13
|
+
* Rabatt (RH, RL)
|
13
14
|
|
14
15
|
## Usage
|
15
16
|
|
@@ -19,8 +20,8 @@ Importing a CSV file:
|
|
19
20
|
|
20
21
|
Exporting CSV:
|
21
22
|
|
22
|
-
# order = EfoNelfo::V40::
|
23
|
-
# order.add EfoNelfo::V40::
|
23
|
+
# order = EfoNelfo::V40::VH.new
|
24
|
+
# order.add EfoNelfo::V40::VL.new item_number: '442', order_number: 'abc'
|
24
25
|
# order.to_csv
|
25
26
|
|
26
27
|
|
@@ -31,7 +32,6 @@ Exporting CSV:
|
|
31
32
|
* Support more versions
|
32
33
|
* Support XML
|
33
34
|
|
34
|
-
|
35
35
|
## Resources
|
36
36
|
|
37
37
|
* http://www.efo.no/Portals/5/docs/ImplementasjonsGuide%20EFONELFO%204.0.pdf
|
data/lib/efo_nelfo/errors.rb
CHANGED
@@ -8,6 +8,10 @@ module EfoNelfo
|
|
8
8
|
base.send :property, :version, alias: :Versjon, limit: 3, default: base.version
|
9
9
|
end
|
10
10
|
|
11
|
+
def [](index)
|
12
|
+
lines[index]
|
13
|
+
end
|
14
|
+
|
11
15
|
def add(post_type)
|
12
16
|
if has_association? post_type
|
13
17
|
find_association(post_type) << post_type
|
@@ -18,13 +22,5 @@ module EfoNelfo
|
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
def to_csv
|
22
|
-
CSV.generate EfoNelfo::Reader::CSV::CSV_OPTIONS do |csv|
|
23
|
-
to_a.each do |row|
|
24
|
-
csv << row unless row.empty?
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
25
|
end
|
30
26
|
end
|
data/lib/efo_nelfo/post_type.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module EfoNelfo
|
2
2
|
|
3
3
|
class PostType
|
4
|
-
include EfoNelfo::
|
4
|
+
include EfoNelfo::Properties
|
5
5
|
include EfoNelfo::HasMany
|
6
6
|
|
7
7
|
class << self
|
@@ -49,6 +49,14 @@ module EfoNelfo
|
|
49
49
|
self.class.version
|
50
50
|
end
|
51
51
|
|
52
|
+
def to_csv
|
53
|
+
CSV.generate EfoNelfo::Reader::CSV::CSV_OPTIONS do |csv|
|
54
|
+
to_a.each do |row|
|
55
|
+
csv << row unless row.empty?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
52
60
|
end
|
53
61
|
|
54
62
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module EfoNelfo
|
2
|
+
|
3
|
+
module Properties
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize_attributes(*args)
|
10
|
+
if args && args.first.is_a?(Hash)
|
11
|
+
args.first.each do |attr, value|
|
12
|
+
send "#{attr}=", value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns all properties
|
18
|
+
def properties
|
19
|
+
@properties ||= initialize_properties
|
20
|
+
end
|
21
|
+
alias :attributes :properties
|
22
|
+
|
23
|
+
# Returns true if the given property exists
|
24
|
+
def has_property?(name)
|
25
|
+
properties.include? name
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns all property values as array formatted for csv
|
29
|
+
def to_a
|
30
|
+
properties.values.map &:to_csv
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def initialize_properties
|
36
|
+
self.class.properties.inject({}) do |hash,(name,options)|
|
37
|
+
hash[name] = EfoNelfo::Property.new(name, options)
|
38
|
+
hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module ClassMethods
|
43
|
+
# Creates an attribute with given name.
|
44
|
+
#
|
45
|
+
# Options
|
46
|
+
# - type String, Integer etc. Default is String
|
47
|
+
# - required whether attribute is required. Default is false
|
48
|
+
# - limit Length the attribute can be. Default is nil
|
49
|
+
# - alias Norwegian alias name for the attribute
|
50
|
+
#
|
51
|
+
def property(name, options={})
|
52
|
+
options = {
|
53
|
+
type: :string,
|
54
|
+
required: false,
|
55
|
+
}.update options
|
56
|
+
|
57
|
+
name = name.to_sym
|
58
|
+
alias_name = options.delete(:alias)
|
59
|
+
|
60
|
+
# ensure all options are valid
|
61
|
+
EfoNelfo::Property.validate_options! options
|
62
|
+
|
63
|
+
# ensure property is unique
|
64
|
+
raise EfoNelfo::DuplicateProperty if properties.has_key?(name)
|
65
|
+
|
66
|
+
# setup getters and setters
|
67
|
+
create_reader_for(name, options)
|
68
|
+
create_setter_for(name, options) unless options[:read_only]
|
69
|
+
create_question_for(name) if options[:type] == :boolean
|
70
|
+
create_alias_for(name, alias_name, options) if alias_name
|
71
|
+
|
72
|
+
properties[name] = options
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns all properties defined for the class
|
76
|
+
def properties
|
77
|
+
@_properties ||= {}
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Creates an attribute accessor for the property
|
83
|
+
def create_reader_for(name, options)
|
84
|
+
define_method name do
|
85
|
+
attributes[name].value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Creates an attribute setter for the property
|
90
|
+
def create_setter_for(name, options)
|
91
|
+
define_method "#{name}=" do |value|
|
92
|
+
attributes[name].value = value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a name? accessor for the property
|
97
|
+
# Only applies to boolean types
|
98
|
+
def create_question_for(name)
|
99
|
+
define_method "#{name}?" do
|
100
|
+
attributes[name].value == true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Create an alias getter/setter for the property
|
105
|
+
def create_alias_for(name, alias_name, options)
|
106
|
+
define_method(alias_name) do
|
107
|
+
send name
|
108
|
+
end
|
109
|
+
|
110
|
+
unless options[:read_only]
|
111
|
+
define_method("#{alias_name}=") do |val|
|
112
|
+
send "#{name}=", val
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/lib/efo_nelfo/property.rb
CHANGED
@@ -1,155 +1,94 @@
|
|
1
|
-
|
1
|
+
using EfoNelfo::PropertyTypes
|
2
2
|
|
3
|
-
|
3
|
+
module EfoNelfo
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
class Property
|
6
|
+
VALID_OPTIONS = [:type, :required, :limit, :read_only, :default, :decimals]
|
7
|
+
VALID_TYPES = [:string, :integer, :boolean, :date]
|
8
8
|
|
9
|
-
|
10
|
-
if args && args.first.is_a?(Hash)
|
11
|
-
args.first.each do |attr, value|
|
12
|
-
send "#{attr}=", value
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def attributes
|
18
|
-
@attributes ||= initialize_default_attributes
|
19
|
-
end
|
9
|
+
attr_reader :name, :options, :value
|
20
10
|
|
21
|
-
def
|
22
|
-
|
11
|
+
def self.validate_options!(options)
|
12
|
+
invalid_options = options.keys - VALID_OPTIONS
|
13
|
+
raise EfoNelfo::UnknownPropertyOption.new("Invalid options: #{invalid_options.join(',')}") if invalid_options.any?
|
14
|
+
raise EfoNelfo::InvalidPropertyType.new("Valid types are #{VALID_TYPES.join(',')}") unless VALID_TYPES.include?(options[:type])
|
23
15
|
end
|
24
16
|
|
25
|
-
def
|
26
|
-
properties.include? property
|
27
|
-
end
|
17
|
+
def initialize(name, defaults={})
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
|
19
|
+
options = {
|
20
|
+
type: :string,
|
21
|
+
required: false,
|
22
|
+
default: nil,
|
23
|
+
read_only: false,
|
24
|
+
decimals: nil,
|
25
|
+
limit: 100
|
26
|
+
}
|
27
|
+
options.update(defaults) if defaults.is_a?(Hash)
|
32
28
|
|
33
|
-
|
29
|
+
self.class.validate_options! options
|
34
30
|
|
35
|
-
|
36
|
-
|
31
|
+
@name = name
|
32
|
+
@options = options
|
33
|
+
@value = options[:default]
|
37
34
|
end
|
38
35
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
36
|
+
# Assign a value to the property
|
37
|
+
# The value is converted to whatever specified by options[:type]
|
38
|
+
# Examples:
|
39
|
+
# (boolean) value = 'J' # => true
|
40
|
+
# (boolean) value = false # => false
|
41
|
+
# (date) value = '20120101' # => Date.new(2012,1,1)
|
42
|
+
# (integer) value = '2' # => 2
|
43
|
+
# (string) value = 'foo' # => 'foo'
|
44
|
+
def value=(new_value)
|
45
|
+
return nil if readonly?
|
46
|
+
|
47
|
+
@value = case
|
48
|
+
when boolean?
|
49
|
+
new_value.nil? || new_value == true || new_value == 'J' || new_value == 'j' || new_value == '' ? true : false
|
50
|
+
when date?
|
51
|
+
new_value.is_a?(Date) ? new_value : Date.parse(new_value) rescue nil
|
52
|
+
when integer?
|
53
|
+
new_value.nil? ? nil : new_value.to_i
|
48
54
|
else
|
49
|
-
|
50
|
-
end
|
51
|
-
when :boolean
|
52
|
-
value.nil? || value == true || value == 'J' || value == '' ? true : false
|
53
|
-
else
|
54
|
-
value
|
55
|
+
new_value
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
|
-
#
|
59
|
-
def
|
60
|
-
|
61
|
-
if respond_to?("format_#{attr}")
|
62
|
-
value = send "format_#{attr}"
|
63
|
-
else
|
64
|
-
value = send attr
|
65
|
-
|
66
|
-
type = properties[attr][:type]
|
67
|
-
|
68
|
-
value = case type
|
69
|
-
when :date
|
70
|
-
value ? value.strftime("%Y%m%d") : nil
|
71
|
-
when :boolean
|
72
|
-
value == true ? "J" : nil
|
73
|
-
else
|
74
|
-
value
|
75
|
-
end
|
76
|
-
end
|
77
|
-
value.respond_to?(:encode) ? value.encode(Encoding::ISO_8859_1) : value
|
59
|
+
# returns formatted value suitable for csv output
|
60
|
+
def to_csv
|
61
|
+
output = value.to_csv
|
78
62
|
end
|
79
63
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
def property(name, options={})
|
90
|
-
|
91
|
-
options = {
|
92
|
-
type: :string,
|
93
|
-
required: false,
|
94
|
-
}.update options
|
95
|
-
|
96
|
-
name = name.to_sym
|
97
|
-
|
98
|
-
# ensure all options are valid
|
99
|
-
valid_options = [:type, :required, :limit, :read_only, :alias, :default]
|
100
|
-
invalid_options = options.keys - valid_options
|
101
|
-
raise EfoNelfo::UnknownPropertyOption.new("Invalid option for #{name}: #{invalid_options.join(',')}") if invalid_options.any?
|
102
|
-
|
103
|
-
# Store property info in @properties
|
104
|
-
raise EfoNelfo::DuplicateProperty if properties.has_key?(name)
|
105
|
-
properties[name] = options
|
106
|
-
|
107
|
-
create_reader_for(name, options)
|
108
|
-
create_setter_for(name, options) unless options[:read_only]
|
109
|
-
create_question_for(name) if options[:type] == :boolean
|
110
|
-
create_alias_for(name, options) if options[:alias]
|
111
|
-
end
|
112
|
-
|
113
|
-
# Returns all properties
|
114
|
-
def properties
|
115
|
-
@_properties ||= {}
|
116
|
-
end
|
117
|
-
|
118
|
-
private
|
119
|
-
|
120
|
-
# Creates an attribute accessor for name
|
121
|
-
def create_reader_for(name, options)
|
122
|
-
define_method name do
|
123
|
-
attributes[name]
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# Creates an attribute setter for name
|
128
|
-
def create_setter_for(name, options)
|
129
|
-
define_method "#{name}=" do |value|
|
130
|
-
attributes[name] = format_value(value, options[:type])
|
131
|
-
end
|
132
|
-
end
|
64
|
+
# Returns integer to floating point based on specified decimals
|
65
|
+
# Example:
|
66
|
+
# If decimal is set to 4, and the value is 4000
|
67
|
+
# then to_f returns 0.4
|
68
|
+
def to_f
|
69
|
+
return nil if value.nil?
|
70
|
+
value.to_f.with_decimals decimals
|
71
|
+
end
|
72
|
+
alias :to_decimal :to_f
|
133
73
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
139
|
-
end
|
74
|
+
# Returns true if the property is read only
|
75
|
+
def readonly?
|
76
|
+
options[:read_only]
|
77
|
+
end
|
140
78
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
79
|
+
# Returns true if the property is required
|
80
|
+
# Note: this is not in use yet
|
81
|
+
def required?
|
82
|
+
options[:required]
|
83
|
+
end
|
145
84
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
151
|
-
end
|
85
|
+
def boolean?; type == :boolean; end
|
86
|
+
def date?; type == :date; end
|
87
|
+
def integer?; type == :integer; end
|
88
|
+
def string?; type == :string; end
|
152
89
|
|
90
|
+
def method_missing(*args)
|
91
|
+
options.has_key?(args.first) ? options[args.first] : super
|
153
92
|
end
|
154
93
|
|
155
94
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module EfoNelfo
|
2
|
+
module PropertyTypes
|
3
|
+
refine NilClass do
|
4
|
+
def to_csv
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
refine TrueClass do
|
10
|
+
def to_csv
|
11
|
+
'J'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
refine FalseClass do
|
16
|
+
def to_csv
|
17
|
+
'N'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
refine String do
|
22
|
+
def to_csv
|
23
|
+
to_s.encode EfoNelfo::Reader::CSV::ENCODING
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
refine Date do
|
28
|
+
def to_csv
|
29
|
+
strftime("%Y%m%d")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
refine Fixnum do
|
34
|
+
def to_csv
|
35
|
+
to_i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
refine Float do
|
40
|
+
def with_decimals(decimals)
|
41
|
+
decimals.nil? ? self : self * (1.0/10**decimals.to_i)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/lib/efo_nelfo/reader/csv.rb
CHANGED
@@ -4,6 +4,8 @@ module EfoNelfo
|
|
4
4
|
module Reader
|
5
5
|
|
6
6
|
class CSV
|
7
|
+
ENCODING = Encoding::ISO_8859_1
|
8
|
+
|
7
9
|
CSV_OPTIONS = {
|
8
10
|
col_sep: ';',
|
9
11
|
headers: false,
|
@@ -17,7 +19,7 @@ module EfoNelfo
|
|
17
19
|
|
18
20
|
def initialize(options)
|
19
21
|
if options[:filename]
|
20
|
-
@data = File.read(options[:filename], encoding:
|
22
|
+
@data = File.read(options[:filename], encoding: ENCODING)
|
21
23
|
else
|
22
24
|
@data = options[:data]
|
23
25
|
end
|
data/lib/efo_nelfo/v40/vl.rb
CHANGED
@@ -33,6 +33,23 @@ module EfoNelfo
|
|
33
33
|
info.map(&:image).compact
|
34
34
|
end
|
35
35
|
|
36
|
+
[ :weight, :dimension, :volume, :fdv, :hms ].each do |key|
|
37
|
+
define_method key do
|
38
|
+
pick key
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns array of urls extracted from VX lines
|
43
|
+
def urls
|
44
|
+
info.map(&:value).select { |u| u.match %r{\Ahttps?://} }
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def pick(method)
|
50
|
+
vx = info.select(&"#{method}?".to_sym).compact.first
|
51
|
+
vx && vx.send(method)
|
52
|
+
end
|
36
53
|
end
|
37
54
|
end
|
38
55
|
end
|
data/lib/efo_nelfo/v40/vx.rb
CHANGED
@@ -5,12 +5,25 @@ module EfoNelfo
|
|
5
5
|
property :field, alias: :FeltId, limit: 10, required: true
|
6
6
|
property :value, alias: :Verdi, limit: 70, required: true
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
FIELD_MAPPINGS = {
|
9
|
+
image: "BILDE",
|
10
|
+
weight: "VEKT",
|
11
|
+
dimension: "DIMENSJON",
|
12
|
+
fdv: "FDV",
|
13
|
+
hms: "HMS",
|
14
|
+
volume: "VOLUM"
|
15
|
+
}
|
16
|
+
|
17
|
+
FIELD_MAPPINGS.each do |key, field_value|
|
18
|
+
# Add methods like def image?; field == 'BILDE'; end
|
19
|
+
define_method "#{key}?" do
|
20
|
+
field == field_value
|
21
|
+
end
|
11
22
|
|
12
|
-
|
13
|
-
|
23
|
+
# Add methods like: def image; value if image?; end
|
24
|
+
define_method "#{key}" do
|
25
|
+
self.value if send("#{key}?")
|
26
|
+
end
|
14
27
|
end
|
15
28
|
|
16
29
|
end
|
data/lib/efo_nelfo/version.rb
CHANGED
data/lib/efo_nelfo.rb
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
# Common stuff
|
4
4
|
require 'efo_nelfo/version'
|
5
5
|
require 'efo_nelfo/errors'
|
6
|
+
require 'efo_nelfo/property_types'
|
6
7
|
require 'efo_nelfo/property'
|
8
|
+
require 'efo_nelfo/properties'
|
7
9
|
require 'efo_nelfo/collection'
|
8
10
|
require 'efo_nelfo/has_many'
|
9
11
|
require 'efo_nelfo/post_type'
|
data/spec/csv_writer_spec.rb
CHANGED
data/spec/post_type_spec.rb
CHANGED
@@ -4,15 +4,15 @@ describe EfoNelfo::PostType do
|
|
4
4
|
|
5
5
|
module EfoNelfo
|
6
6
|
module V21
|
7
|
-
class
|
8
|
-
property :post_type
|
9
|
-
property :version
|
7
|
+
class AB < EfoNelfo::PostType
|
8
|
+
property :post_type, default: 'AB'
|
9
|
+
property :version, default: '21'
|
10
10
|
property :seller_id
|
11
|
-
has_many :lines, :post_type => "
|
11
|
+
has_many :lines, :post_type => "XY"
|
12
12
|
end
|
13
13
|
|
14
|
-
class
|
15
|
-
property :post_type
|
14
|
+
class XY < EfoNelfo::PostType
|
15
|
+
property :post_type, default: 'XY'
|
16
16
|
property :order_number
|
17
17
|
end
|
18
18
|
end
|
@@ -21,27 +21,35 @@ describe EfoNelfo::PostType do
|
|
21
21
|
describe "versioning" do
|
22
22
|
|
23
23
|
it ".version_from_class returns the version" do
|
24
|
-
EfoNelfo::V21::
|
24
|
+
EfoNelfo::V21::AB.version_from_class.must_equal "21"
|
25
25
|
end
|
26
26
|
|
27
27
|
it ".version returns the version as a number" do
|
28
|
-
EfoNelfo::V21::
|
28
|
+
EfoNelfo::V21::AB.version.must_equal "2.1"
|
29
29
|
end
|
30
30
|
|
31
31
|
it ".version_to_namespace converts version to module name" do
|
32
|
-
EfoNelfo::V21::
|
32
|
+
EfoNelfo::V21::AB.version_to_namespace("2.1").must_equal "21"
|
33
33
|
end
|
34
34
|
|
35
35
|
end
|
36
36
|
|
37
|
+
describe "to_csv" do
|
38
|
+
it "converts the posttype to csv" do
|
39
|
+
pt = EfoNelfo::V21::AB.new seller_id: '123'
|
40
|
+
pt.lines << EfoNelfo::V21::XY.new(order_number: '41')
|
41
|
+
pt.to_csv.must_match /AB;21;123.+XY;41/m
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
37
45
|
describe ".from" do
|
38
46
|
let(:hash) {
|
39
47
|
{
|
40
|
-
post_type: "
|
48
|
+
post_type: "AB",
|
41
49
|
version: "2.1",
|
42
50
|
seller_id: "123",
|
43
51
|
lines: [
|
44
|
-
{ post_type: "
|
52
|
+
{ post_type: "XY", order_number: "666-2" }
|
45
53
|
]
|
46
54
|
}
|
47
55
|
}
|
@@ -49,7 +57,7 @@ describe EfoNelfo::PostType do
|
|
49
57
|
let(:pt) { EfoNelfo::PostType.from hash }
|
50
58
|
|
51
59
|
it "converts the hash into a valid posttype" do
|
52
|
-
pt.must_be_instance_of EfoNelfo::V21::
|
60
|
+
pt.must_be_instance_of EfoNelfo::V21::AB
|
53
61
|
pt.seller_id.must_equal "123"
|
54
62
|
end
|
55
63
|
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe EfoNelfo::Properties do
|
5
|
+
|
6
|
+
class Foo
|
7
|
+
include EfoNelfo::Properties
|
8
|
+
property :foo, alias: "Føbar", limit: 3, default: 'I am foo'
|
9
|
+
property :bar
|
10
|
+
property :date, type: :date
|
11
|
+
property :number, type: :integer
|
12
|
+
property :doable, type: :boolean, default: false
|
13
|
+
property :immutable, read_only: true, default: 'NO'
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:obj) { Foo.new }
|
17
|
+
|
18
|
+
it "raises an error if trying to add duplicate property" do
|
19
|
+
lambda {
|
20
|
+
class Bar
|
21
|
+
include EfoNelfo::Properties
|
22
|
+
property :foo
|
23
|
+
property :foo
|
24
|
+
end
|
25
|
+
}.must_raise EfoNelfo::DuplicateProperty
|
26
|
+
end
|
27
|
+
|
28
|
+
it "raises an error if trying to assign an unsupported option" do
|
29
|
+
lambda {
|
30
|
+
class Bar
|
31
|
+
include EfoNelfo::Properties
|
32
|
+
property :lame, funny: true
|
33
|
+
end
|
34
|
+
}.must_raise EfoNelfo::UnknownPropertyOption
|
35
|
+
end
|
36
|
+
|
37
|
+
it "adds a getter method for :foo" do
|
38
|
+
obj.foo.must_equal 'I am foo'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "adds a setter method for :foo" do
|
42
|
+
obj.foo = 'Test'
|
43
|
+
obj.foo.must_equal 'Test'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "adds a question method for boolean types" do
|
47
|
+
obj.doable?.must_equal false
|
48
|
+
obj.doable = true
|
49
|
+
obj.doable?.must_equal true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "won't do any encoding conversions" do
|
53
|
+
obj.foo = 'Sjøhest'
|
54
|
+
obj.foo.encoding.name.must_equal 'UTF-8'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "adds an alias getter and setter for foo" do
|
58
|
+
obj.foo = 'Test'
|
59
|
+
obj.Føbar.must_equal 'Test'
|
60
|
+
obj.Føbar = 'Hacked'
|
61
|
+
obj.Føbar.must_equal 'Hacked'
|
62
|
+
obj.foo.must_equal 'Hacked'
|
63
|
+
end
|
64
|
+
|
65
|
+
it "assigns default values" do
|
66
|
+
obj.bar.must_be_nil
|
67
|
+
obj.foo.must_equal 'I am foo'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "can be assigned nil values" do
|
71
|
+
obj.number = nil
|
72
|
+
obj.number.must_be_nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it "readonly attributes cannot be changed" do
|
76
|
+
lambda { obj.immutable = 'test' }.must_raise NoMethodError
|
77
|
+
obj.immutable.must_equal 'NO'
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "property types" do
|
81
|
+
describe ":date" do
|
82
|
+
it "converts strings to dates" do
|
83
|
+
obj.date = "20100504"
|
84
|
+
obj.date.must_be_kind_of Date
|
85
|
+
end
|
86
|
+
|
87
|
+
it "accepts a Date" do
|
88
|
+
obj.date = Date.new 2010, 5, 4
|
89
|
+
obj.date.must_be_kind_of Date
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
it "handles :integer" do
|
95
|
+
obj.number = "2"
|
96
|
+
obj.number.must_equal 2
|
97
|
+
end
|
98
|
+
|
99
|
+
describe ":boolean" do
|
100
|
+
it "returns true when assigning blank string" do
|
101
|
+
obj.doable = ''
|
102
|
+
obj.doable?.must_equal true
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns true when assigning nil" do
|
106
|
+
obj.doable = nil
|
107
|
+
obj.doable?.must_equal true
|
108
|
+
end
|
109
|
+
|
110
|
+
it "returns true when assigning 'J'" do
|
111
|
+
obj.doable = 'J'
|
112
|
+
obj.doable?.must_equal true
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns false" do
|
116
|
+
obj.doable = false
|
117
|
+
obj.doable?.must_equal false
|
118
|
+
|
119
|
+
obj.doable = 'N'
|
120
|
+
obj.doable?.must_equal false
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
it ".properties contains hash of options" do
|
128
|
+
Foo.properties[:foo].must_be_kind_of Hash
|
129
|
+
end
|
130
|
+
|
131
|
+
it "#properties contains hash of EfoNelfo::Property objects" do
|
132
|
+
Foo.new.properties[:foo].must_be_kind_of EfoNelfo::Property
|
133
|
+
end
|
134
|
+
|
135
|
+
it "#has_property? returns true when property exists" do
|
136
|
+
obj.has_property?(:foo).must_equal true
|
137
|
+
obj.has_property?(:bullshit).must_equal false
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#to_a" do
|
141
|
+
it "returns array of all attributes in correct order" do
|
142
|
+
obj.date = Date.new 2012, 5, 30
|
143
|
+
obj.number = 3
|
144
|
+
obj.doable = true
|
145
|
+
obj.to_a.must_equal ["I am foo", nil, "20120530", 3, "J", "NO"]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/spec/property_spec.rb
CHANGED
@@ -1,144 +1,193 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe EfoNelfo::Property do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
subject { EfoNelfo::Property.new :foo, options }
|
5
|
+
let(:options) { nil }
|
6
|
+
|
7
|
+
describe "initializing with options" do
|
8
|
+
let(:options) { { type: :integer, limit: 15, decimals: 4, default: 5, required: true } }
|
9
|
+
|
10
|
+
it { subject.name.must_equal :foo }
|
11
|
+
it { subject.default.must_equal 5 }
|
12
|
+
it { subject.limit.must_equal 15 }
|
13
|
+
it { subject.type.must_equal :integer }
|
14
|
+
it { subject.required.must_equal true }
|
15
|
+
it { subject.decimals.must_equal 4 }
|
16
|
+
it { subject.value.must_equal 5 }
|
17
|
+
|
18
|
+
it "raises an error when assigning to unknown type" do
|
19
|
+
lambda {
|
20
|
+
EfoNelfo::Property.new :name, type: :get_lost
|
21
|
+
}.must_raise EfoNelfo::InvalidPropertyType
|
22
|
+
end
|
14
23
|
end
|
15
24
|
|
16
|
-
|
25
|
+
describe "initializing without options" do
|
26
|
+
let(:options) { nil }
|
17
27
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
}.must_raise EfoNelfo::DuplicateProperty
|
28
|
+
it { subject.name.must_equal :foo }
|
29
|
+
it { subject.default.must_be_nil }
|
30
|
+
it { subject.limit.must_equal 100 }
|
31
|
+
it { subject.type.must_equal :string }
|
32
|
+
it { subject.required.must_equal false }
|
33
|
+
it { subject.decimals.must_be_nil }
|
34
|
+
it { subject.value.must_be_nil }
|
26
35
|
end
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
class Bar
|
31
|
-
include EfoNelfo::Property
|
32
|
-
property :lame, funny: true
|
33
|
-
end
|
34
|
-
}.must_raise EfoNelfo::UnknownPropertyOption
|
35
|
-
end
|
37
|
+
describe "setter" do
|
38
|
+
let(:property) { EfoNelfo::Property.new :name, type: type }
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
describe "when type is string" do
|
41
|
+
let(:type) { :string }
|
42
|
+
it "is just a string" do
|
43
|
+
property.value = 'New value'
|
44
|
+
property.value.must_equal 'New value'
|
45
|
+
end
|
46
|
+
end
|
41
47
|
|
42
|
-
|
43
|
-
|
44
|
-
obj.foo.encoding.name.must_equal 'UTF-8'
|
45
|
-
end
|
48
|
+
describe "when type is boolean" do
|
49
|
+
let(:type) { :boolean }
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
obj.Føbar = 'Hacked'
|
51
|
-
obj.Føbar.must_equal 'Hacked'
|
52
|
-
obj.foo.must_equal 'Hacked'
|
53
|
-
end
|
51
|
+
it "accepts boolean" do
|
52
|
+
property.value = true
|
53
|
+
property.value.must_equal true
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
55
|
+
property.value = false
|
56
|
+
property.value.must_equal false
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
59
|
+
it "accepts J/N" do
|
60
|
+
property.value = 'J'
|
61
|
+
property.value.must_equal true
|
64
62
|
|
65
|
-
|
66
|
-
|
67
|
-
obj.immutable.must_equal 'NO'
|
68
|
-
end
|
63
|
+
property.value = 'j'
|
64
|
+
property.value.must_equal true
|
69
65
|
|
70
|
-
|
71
|
-
|
72
|
-
it "converts strings to dates" do
|
73
|
-
obj.date = "20100504"
|
74
|
-
obj.date.must_be_kind_of Date
|
66
|
+
property.value = 'N'
|
67
|
+
property.value.must_equal false
|
75
68
|
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "when type is date" do
|
72
|
+
let(:type) { :date }
|
76
73
|
|
77
74
|
it "accepts a Date" do
|
78
|
-
|
79
|
-
|
75
|
+
property.value = Date.new(2013, 11, 21)
|
76
|
+
property.value.must_equal Date.new(2013, 11, 21)
|
80
77
|
end
|
81
78
|
|
82
|
-
|
79
|
+
it "accepts a string" do
|
80
|
+
property.value = "20131121"
|
81
|
+
property.value.must_equal Date.new(2013, 11, 21)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "invalid dates becomes nil" do
|
85
|
+
property.value = 'invalid date'
|
86
|
+
property.value.must_be_nil
|
87
|
+
end
|
83
88
|
|
84
|
-
it "handles :integer" do
|
85
|
-
obj.number = "2"
|
86
|
-
obj.number.must_equal 2
|
87
89
|
end
|
88
90
|
|
89
|
-
describe "
|
90
|
-
|
91
|
-
obj.doable = ''
|
92
|
-
obj.doable?.must_equal true
|
93
|
-
end
|
91
|
+
describe "when type is integer" do
|
92
|
+
let(:type) { :integer }
|
94
93
|
|
95
|
-
it "
|
96
|
-
|
97
|
-
|
94
|
+
it "accepts a number" do
|
95
|
+
property.value = '2'
|
96
|
+
property.value.must_equal 2
|
98
97
|
end
|
99
98
|
|
100
|
-
it "
|
101
|
-
|
102
|
-
|
99
|
+
it "floats are rounded" do
|
100
|
+
property.value = 200.5
|
101
|
+
property.value.must_equal 200
|
103
102
|
end
|
104
103
|
|
105
|
-
it "
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
obj.doable = 'N'
|
110
|
-
obj.doable?.must_equal false
|
104
|
+
it "nil becomes nil" do
|
105
|
+
property.value = nil
|
106
|
+
property.value.must_be_nil
|
111
107
|
end
|
112
108
|
|
113
109
|
end
|
114
110
|
|
111
|
+
end
|
115
112
|
|
113
|
+
it "#value= is ignored if the property is readonly" do
|
114
|
+
prop = EfoNelfo::Property.new(:name, read_only: true, default: 'untouchable')
|
115
|
+
prop.value = 'hey'
|
116
|
+
prop.value.must_equal 'untouchable'
|
116
117
|
end
|
117
118
|
|
118
|
-
|
119
|
-
|
119
|
+
it "#value= converts booleans to proper value" do
|
120
|
+
prop = EfoNelfo::Property.new(:name, type: :boolean)
|
121
|
+
prop.value = 'J'
|
122
|
+
prop.value.must_equal true
|
120
123
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
+
prop.value = 'N'
|
125
|
+
prop.value.must_equal false
|
126
|
+
end
|
124
127
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
+
it "#to_f returns the value with decimals" do
|
129
|
+
prop = EfoNelfo::Property.new(:name, decimals: 4)
|
130
|
+
prop.value = 4000
|
131
|
+
prop.to_f.must_equal 0.4
|
132
|
+
end
|
133
|
+
|
134
|
+
it "#to_f doesn't fail when decimals is nil" do
|
135
|
+
subject.value = "100"
|
136
|
+
subject.to_f.must_equal 100.0
|
128
137
|
end
|
129
138
|
|
130
|
-
it "#
|
131
|
-
|
132
|
-
|
139
|
+
it "#to_f returns nil when value is NaN" do
|
140
|
+
subject.value = nil
|
141
|
+
subject.to_f.must_be_nil
|
133
142
|
end
|
134
143
|
|
135
|
-
describe "#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
144
|
+
describe "#to_csv" do
|
145
|
+
def make_property(value, options={})
|
146
|
+
p = EfoNelfo::Property.new :name, options.merge(type: type)
|
147
|
+
p.value = value
|
148
|
+
p.to_csv
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "type is :string" do
|
152
|
+
let(:type) { :string }
|
153
|
+
it { make_property("A string").must_equal "A string" }
|
154
|
+
it { make_property(nil).must_equal nil }
|
155
|
+
it { make_property("Sjøhest").encoding.must_equal Encoding::ISO_8859_1 }
|
141
156
|
end
|
157
|
+
|
158
|
+
describe "type is :integer" do
|
159
|
+
let(:type) { :integer }
|
160
|
+
it { make_property(2).must_equal 2 }
|
161
|
+
it { make_property(100, type: :integer, decimals: 4).must_equal 100 }
|
162
|
+
it { make_property(nil, type: :integer, decimals: 2).must_equal nil }
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "type is :boolean" do
|
166
|
+
let(:type) { :boolean }
|
167
|
+
it { make_property(true).must_equal 'J' }
|
168
|
+
it { make_property(false).must_equal 'N' }
|
169
|
+
it { make_property(nil).must_equal 'J' }
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "type is :date" do
|
173
|
+
let(:type) { :date }
|
174
|
+
it { make_property(Date.new(2013, 11, 21)).must_equal '20131121' }
|
175
|
+
it { make_property("20131121").must_equal "20131121" }
|
176
|
+
it { make_property("not a date").must_be_nil }
|
177
|
+
it { make_property(nil).must_be_nil }
|
178
|
+
end
|
179
|
+
|
142
180
|
end
|
143
181
|
|
182
|
+
it "raises error when initializing with unknown make_property" do
|
183
|
+
lambda {
|
184
|
+
EfoNelfo::Property.new :name, { foo: 'illegal' }
|
185
|
+
}.must_raise EfoNelfo::UnknownPropertyOption
|
186
|
+
end
|
187
|
+
|
188
|
+
it ".validate_options! raises error when passing invalid options" do
|
189
|
+
lambda {
|
190
|
+
EfoNelfo::Property.validate_options! foo: 'bar'
|
191
|
+
}.must_raise EfoNelfo::UnknownPropertyOption
|
192
|
+
end
|
144
193
|
end
|
data/spec/vl_spec.rb
CHANGED
@@ -4,6 +4,42 @@ describe EfoNelfo::V40::VL do
|
|
4
4
|
|
5
5
|
let(:vl) { EfoNelfo::V40::VL.new }
|
6
6
|
|
7
|
+
it "#weight returns the weight in gram" do
|
8
|
+
vl.info << { field: 'VEKT', value: 250 }
|
9
|
+
vl.weight.must_equal 250
|
10
|
+
end
|
11
|
+
|
12
|
+
it "#weight returns nil when weight is not present" do
|
13
|
+
vl.weight.must_be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "#dimension returns nil when dimension isn't present" do
|
17
|
+
vl.dimension.must_be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "#dimension returns the dimension of the object" do
|
21
|
+
vl.info << { field: 'VEKT', value: '10' }
|
22
|
+
vl.info << { field: 'DIMENSJON', value: '2x10x20' }
|
23
|
+
vl.dimension.must_equal '2x10x20'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "#volume returns the volume" do
|
27
|
+
vl.info << { field: 'VOLUM', value: '1'}
|
28
|
+
vl.info << { field: 'DIMENSJON', value: '2x10x20' }
|
29
|
+
vl.volume.must_equal '1'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "#volume returns nil when object doesn't have volume" do
|
33
|
+
vl.volume.must_be_nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "#urls returns list of vx lines containing a url" do
|
37
|
+
vl.info << { field: 'FOO', value: 'http://localhost/one?two'}
|
38
|
+
vl.info << { field: 'BAR', value: 'http://foo.example.com/one/two/three'}
|
39
|
+
vl.info << { field: 'FOO', value: 'http-not-a-url' }
|
40
|
+
vl.urls.must_equal [ 'http://localhost/one?two', 'http://foo.example.com/one/two/three']
|
41
|
+
end
|
42
|
+
|
7
43
|
describe "#images" do
|
8
44
|
it "returns nil when there are no images available" do
|
9
45
|
vl.images.must_be_empty
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: efo_nelfo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gudleik Rasch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -128,7 +128,9 @@ files:
|
|
128
128
|
- lib/efo_nelfo/has_many.rb
|
129
129
|
- lib/efo_nelfo/post_head_type.rb
|
130
130
|
- lib/efo_nelfo/post_type.rb
|
131
|
+
- lib/efo_nelfo/properties.rb
|
131
132
|
- lib/efo_nelfo/property.rb
|
133
|
+
- lib/efo_nelfo/property_types.rb
|
132
134
|
- lib/efo_nelfo/reader/csv.rb
|
133
135
|
- lib/efo_nelfo/v40/bh.rb
|
134
136
|
- lib/efo_nelfo/v40/bl.rb
|
@@ -144,6 +146,7 @@ files:
|
|
144
146
|
- spec/csv_writer_spec.rb
|
145
147
|
- spec/efo_nelfo_spec.rb
|
146
148
|
- spec/post_type_spec.rb
|
149
|
+
- spec/properties_spec.rb
|
147
150
|
- spec/property_spec.rb
|
148
151
|
- spec/samples/B028579.594.csv
|
149
152
|
- spec/samples/B028579.595.csv
|
@@ -179,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
179
182
|
version: '0'
|
180
183
|
requirements: []
|
181
184
|
rubyforge_project:
|
182
|
-
rubygems_version: 2.0.
|
185
|
+
rubygems_version: 2.0.3
|
183
186
|
signing_key:
|
184
187
|
specification_version: 4
|
185
188
|
summary: Parser for EFONELFO format
|
@@ -188,6 +191,7 @@ test_files:
|
|
188
191
|
- spec/csv_writer_spec.rb
|
189
192
|
- spec/efo_nelfo_spec.rb
|
190
193
|
- spec/post_type_spec.rb
|
194
|
+
- spec/properties_spec.rb
|
191
195
|
- spec/property_spec.rb
|
192
196
|
- spec/samples/B028579.594.csv
|
193
197
|
- spec/samples/B028579.595.csv
|