field_mapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3c5deabe6cc8ef7c58243cb797ebea59ad4affcb
4
+ data.tar.gz: 536688f17cc3afd08428f772cd49ecbdabd06dab
5
+ SHA512:
6
+ metadata.gz: 9e1599b63efea5c5e21366ddcb9797f00eee43118305e6bddb44cf93720abec31bf805780c0ce76a3ddd34f64f5a04a1f0148d9a462b7c17e19ad56409bfe210
7
+ data.tar.gz: 7ee6d66aa959a5e5e084820b0e64e2e28c23b8c30198e053f4b10b926c93aa7a45dfdfa627ee0d7c357b67ca3ffae20b1aad3d6cd61d75c8e59f0f93e352d8a9
@@ -0,0 +1,18 @@
1
+ require "active_support/all"
2
+ require "american_date"
3
+ require "money"
4
+ require "monetize"
5
+ require_relative "field_mapper/version"
6
+ require_relative "field_mapper/types/boolean"
7
+ require_relative "field_mapper/types/plat"
8
+ require_relative "field_mapper/types/list"
9
+ require_relative "field_mapper/standard/plat"
10
+ require_relative "field_mapper/custom/plat"
11
+ require_relative "field_mapper/standard/converter"
12
+ require_relative "field_mapper/custom/converter"
13
+
14
+ module FieldMapper
15
+ class << self
16
+ attr_accessor :logger
17
+ end
18
+ end
@@ -0,0 +1,118 @@
1
+ module FieldMapper
2
+ module Custom
3
+ class Converter
4
+
5
+ attr_reader(
6
+ :custom_plat,
7
+ :standard_plat,
8
+ :custom_instance
9
+ )
10
+
11
+ def initialize(custom_instance)
12
+ @custom_plat = custom_instance.class
13
+ @custom_instance = custom_instance
14
+ @standard_plat = custom_plat.standard_plat
15
+ end
16
+
17
+ def convert_to_standard
18
+ standard_instance = standard_plat.new
19
+
20
+ custom_plat.fields.each do |custom_field_name, custom_field|
21
+ if custom_field.standard_field.present?
22
+ raw_standard_value = get_raw_standard_value(
23
+ custom_field,
24
+ custom_instance[custom_field_name],
25
+ standard_instance
26
+ )
27
+ raw_standard_value = custom_field.standard_field.cast(raw_standard_value)
28
+ standard_instance[custom_field.standard_field.name] = raw_standard_value
29
+ end
30
+ end
31
+
32
+ [custom_instance, standard_instance].each do |instance|
33
+ instance.send(:after_convert, from: custom_instance, to: standard_instance)
34
+ end
35
+
36
+ standard_instance
37
+ end
38
+
39
+ def convert_to(custom_plat)
40
+ converter = FieldMapper::Standard::Converter.new(convert_to_standard)
41
+ converter.convert_to(custom_plat)
42
+ end
43
+
44
+ protected
45
+
46
+ def get_raw_standard_value(custom_field, raw_custom_value, standard_instance)
47
+ return nil if raw_custom_value.nil?
48
+
49
+ strategy = custom_field.flip_strategy(:custom_to_standard)
50
+ custom_flipper = custom_field.custom_flipper?(:custom_to_standard)
51
+
52
+ if !custom_flipper
53
+ if custom_field.plat?
54
+ return compute_raw_standard_value_for_plat(custom_field, raw_custom_value)
55
+ end
56
+
57
+ if custom_field.plat_list?
58
+ if custom_field.plat_list?
59
+ return compute_raw_standard_value_for_plat_list(custom_field, raw_custom_value)
60
+ end
61
+ end
62
+ end
63
+
64
+ if strategy == :find
65
+ if custom_field.type.is_a?(FieldMapper::Types::List)
66
+ return raw_custom_value.map do |single_raw_custom_value|
67
+ find_raw_standard_value(custom_field, single_raw_custom_value)
68
+ end
69
+ else
70
+ return find_raw_standard_value(custom_field, raw_custom_value)
71
+ end
72
+ end
73
+
74
+ compute_raw_standard_value(custom_field, raw_custom_value, standard_instance)
75
+ end
76
+
77
+ def find_raw_standard_value(custom_field, raw_custom_value)
78
+ return raw_custom_value unless custom_field.standard_field.has_values?
79
+
80
+ if custom_field.has_values?
81
+ custom_value = custom_field.find_value(raw_custom_value)
82
+ if custom_value.present?
83
+ custom_value.standard_value.value if custom_value.standard_value.present?
84
+ end
85
+ else
86
+ standard_value = custom_field.standard_field.find_value(raw_custom_value)
87
+ standard_value.value if standard_value.present?
88
+ end
89
+ end
90
+
91
+ def compute_raw_standard_value(custom_field, raw_custom_value, standard_instance)
92
+ raw_standard_value = custom_instance.instance_exec(
93
+ raw_custom_value,
94
+ standard_instance: standard_instance,
95
+ &custom_field.custom_to_standard
96
+ )
97
+
98
+ if !raw_standard_value.nil?
99
+ raw_standard_value = custom_field.standard_field.cast(raw_standard_value)
100
+ end
101
+
102
+ raw_standard_value
103
+ end
104
+
105
+ def compute_raw_standard_value_for_plat_list(custom_field, raw_custom_values)
106
+ raw_custom_values.map do |raw_custom_value|
107
+ compute_raw_standard_value_for_plat(custom_field, raw_custom_value)
108
+ end
109
+ end
110
+
111
+ def compute_raw_standard_value_for_plat(custom_field, raw_custom_value)
112
+ converter = FieldMapper::Custom::Converter.new(raw_custom_value)
113
+ converter.convert_to_standard
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,110 @@
1
+ require_relative "../standard/field"
2
+ require_relative "value"
3
+
4
+ module FieldMapper
5
+ module Custom
6
+ class Field < FieldMapper::Standard::Field
7
+
8
+ DefaultFlipper = -> (value, standard_instance: nil) { value }
9
+
10
+ attr_reader(
11
+ :name,
12
+ :type,
13
+ :desc,
14
+ :default,
15
+ :values,
16
+ :standard_field,
17
+ :custom_to_standard,
18
+ :standard_to_custom
19
+ )
20
+
21
+ def initialize(
22
+ name,
23
+ type: nil,
24
+ desc: nil,
25
+ default: nil,
26
+ standard_field: nil,
27
+ custom_to_standard: DefaultFlipper,
28
+ standard_to_custom: DefaultFlipper,
29
+ &block
30
+ )
31
+ type ||= standard_field.type unless standard_field.nil?
32
+ super name, type: type, desc: desc, default: default
33
+
34
+ @standard_field = standard_field
35
+ @custom_to_standard = custom_to_standard
36
+ @standard_to_custom = standard_to_custom
37
+
38
+ eigen = class << self; self; end
39
+ eigen.instance_eval do
40
+ define_method :custom_to_standard1, &custom_to_standard
41
+ define_method :standard_to_custom2, &standard_to_custom
42
+ end
43
+ end
44
+
45
+ def value(value, standard: nil, priority: nil)
46
+ @values ||= []
47
+ @values << FieldMapper::Custom::Value.new(
48
+ value,
49
+ field: self,
50
+ standard_value: standard,
51
+ priority: priority
52
+ )
53
+ @values.last
54
+ end
55
+
56
+ # Adds values to a Field instance that are defined in a CSV file.
57
+ #
58
+ # Intended use is from within a Plat class declaration.
59
+ # @example
60
+ # class ExamplePlat < FieldMapper::Standard::Plat
61
+ # field :example do
62
+ # load_values "/path/to/file.csv"
63
+ # end
64
+ # end
65
+ #
66
+ # The format of the CSV file should contain a two columns with a header row.
67
+ # NOTE: An optional priority column can also be included.
68
+ # @example
69
+ # custom_value,standard_value,priority
70
+ # "A",1,
71
+ # "B",2,true
72
+ # "C",2,
73
+ #
74
+ def load_values(path_to_csv)
75
+ CSV.foreach(path_to_csv, :headers => true) do |row|
76
+ value(
77
+ row["custom_value"],
78
+ standard: row["standard_value"],
79
+ priority: FieldMapper::Types::Boolean.parse(row["priority"])
80
+ )
81
+ end
82
+ end
83
+
84
+ def find_values_mapped_to_standard(standard_value)
85
+ values.select do |val|
86
+ val.standard_value == standard_value ||
87
+ val.standard_value.value == standard_value
88
+ end
89
+ end
90
+
91
+ def find_priority_value_mapped_to_standard(standard_value)
92
+ matches = find_values_mapped_to_standard(standard_value)
93
+ match = matches.find { |val| val.priority }
94
+ match ||= matches.first
95
+ end
96
+
97
+ def flip_strategy(direction)
98
+ return :compute if custom_flipper?(direction)
99
+ return :find if has_values?
100
+ return :find if standard_field.present? && standard_field.has_values?
101
+ :compute
102
+ end
103
+
104
+ def custom_flipper?(direction)
105
+ instance_variable_get("@#{direction}") != DefaultFlipper
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,60 @@
1
+ require_relative "../standard/plat"
2
+ require_relative "../errors"
3
+ require_relative "../name_helper"
4
+ require_relative "field"
5
+
6
+ module FieldMapper
7
+ module Custom
8
+ class Plat < FieldMapper::Standard::Plat
9
+
10
+ class << self
11
+ attr_reader :standard_plat
12
+
13
+ def set_standard(standard_plat)
14
+ @standard_plat = standard_plat
15
+ end
16
+
17
+ def field(
18
+ name,
19
+ type: nil,
20
+ desc: nil,
21
+ default: nil,
22
+ standard: nil,
23
+ custom_to_standard: FieldMapper::Custom::Field::DefaultFlipper,
24
+ standard_to_custom: FieldMapper::Custom::Field::DefaultFlipper,
25
+ &block
26
+ )
27
+ field_names[attr_name(name)] = name
28
+
29
+ field = fields[name] = FieldMapper::Custom::Field.new(
30
+ name,
31
+ type: type,
32
+ desc: desc,
33
+ default: default,
34
+ standard_field: standard_plat.fields[standard],
35
+ custom_to_standard: custom_to_standard,
36
+ standard_to_custom: standard_to_custom
37
+ )
38
+
39
+ field.instance_exec(&block) if block_given?
40
+
41
+ define_method(attr_name name) do
42
+ self[name]
43
+ end
44
+
45
+ define_method("#{attr_name name}=") do |value|
46
+ self[name] = value
47
+ end
48
+
49
+ define_method("custom_to_standard_#{name}", &custom_to_standard)
50
+ define_method("standard_to_custom_#{name}", &standard_to_custom)
51
+ end
52
+
53
+ def find_mapped_fields(standard_field)
54
+ fields.values.select { |field| field.standard_field == standard_field }
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,41 @@
1
+ require_relative "../errors"
2
+
3
+ module FieldMapper
4
+ module Custom
5
+ class Value < FieldMapper::Standard::Value
6
+ attr_reader(
7
+ :value,
8
+ :field,
9
+ :priority,
10
+ :standard_value
11
+ )
12
+
13
+ def initialize(
14
+ value,
15
+ field: nil,
16
+ priority: nil,
17
+ standard_value: nil
18
+ )
19
+ super value, field: field
20
+
21
+ if !standard_value.nil?
22
+ if field.standard_field.nil?
23
+ message = "[#{field.name}] [#{value}] is mapped to a standard but [#{field.name}] is not"
24
+ raise StandardFieldNotFound.new(message)
25
+ end
26
+
27
+ raw_standard_value = standard_value
28
+ standard_value = field.standard_field.find_value(standard_value)
29
+
30
+ if standard_value.nil?
31
+ message = "[#{field.name}] [#{value}] is mapped, but the standard [#{field.standard_field.name}] doesn't define the value [#{raw_standard_value}]"
32
+ raise StandardValueNotFound.new(message)
33
+ end
34
+ end
35
+
36
+ @priority = priority
37
+ @standard_value = standard_value
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ class StandardNotSet < StandardError; end
2
+ class StandardFieldNotFound < StandardError; end
3
+ class StandardValueNotFound < StandardError; end
4
+ class StandardMismatch < StandardError; end
5
+ class TypeNotSpecified < StandardError; end
6
+ class TypeNotSupported < StandardError; end
7
+ class FieldNotDefined < StandardError; end
8
+ class InvalidPlatType < StandardError; end
9
+ class InvalidListType < StandardError; end
10
+ class InvalidListValue < StandardError; end
11
+ class InvalidMarshal < StandardError; end
@@ -0,0 +1,24 @@
1
+ require "oj"
2
+
3
+ module FieldMapper
4
+ module Marshaller
5
+
6
+ OPTIONS = {
7
+ indent: 0,
8
+ circular: false,
9
+ class_cache: true,
10
+ escape: :json,
11
+ time: :unix,
12
+ create_id: "natefoo"
13
+ }
14
+
15
+ def marshal(value)
16
+ Oj.dump value, OPTIONS
17
+ end
18
+
19
+ def unmarshal(value)
20
+ Oj.load value, OPTIONS
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ module FieldMapper
2
+ module NameHelper
3
+
4
+ def attr_name(value)
5
+ value = value.to_s
6
+ @attr_names ||= {}
7
+ @attr_names[value] ||= begin
8
+ value.
9
+ gsub(/\W/, "_").
10
+ gsub(/[A-Z][A-Z]+/) { |match| "_#{match.downcase}_" }.
11
+ gsub(/[A-Z]/) { |match| "_#{match.downcase}" }.
12
+ gsub(/\A_|_\z/, "")
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,111 @@
1
+ module FieldMapper
2
+ module Standard
3
+ class Converter
4
+
5
+ attr_reader :standard_plat, :standard_instance
6
+
7
+ def initialize(standard_instance)
8
+ @standard_plat = standard_instance.class
9
+ @standard_instance = standard_instance
10
+ end
11
+
12
+ def convert_to(custom_plat)
13
+ raise StandardMismatch if custom_plat.standard_plat != standard_plat
14
+
15
+ custom_instance = custom_plat.new
16
+
17
+ standard_plat.fields.each do |standard_field_name, standard_field|
18
+ custom_fields = custom_plat.find_mapped_fields(standard_field)
19
+ custom_fields.each do |custom_field|
20
+ raw_custom_value = get_raw_custom_value(
21
+ custom_field,
22
+ standard_instance[standard_field_name],
23
+ custom_instance
24
+ )
25
+ raw_custom_value = custom_field.cast(raw_custom_value)
26
+ custom_instance[custom_field.name] = raw_custom_value
27
+ end
28
+ end
29
+
30
+ [standard_instance, custom_instance].each do |instance|
31
+ instance.send(:after_convert, from: standard_instance, to: custom_instance)
32
+ end
33
+
34
+ custom_instance
35
+ end
36
+
37
+ protected
38
+
39
+ def get_raw_custom_value(custom_field, raw_standard_value, custom_instance)
40
+ return nil if raw_standard_value.nil?
41
+
42
+ strategy = custom_field.flip_strategy(:standard_to_custom)
43
+ custom_flipper = custom_field.custom_flipper?(:standard_to_custom)
44
+
45
+ if !custom_flipper
46
+ if custom_field.plat?
47
+ return compute_raw_custom_value_for_plat(custom_field, raw_standard_value)
48
+ end
49
+
50
+ if custom_field.plat_list?
51
+ if custom_field.plat_list?
52
+ return compute_raw_custom_value_for_plat_list(custom_field, raw_standard_value)
53
+ end
54
+ end
55
+ end
56
+
57
+ if strategy == :find
58
+ if custom_field.type.is_a?(FieldMapper::Types::List)
59
+ return raw_standard_value.map do |single_raw_standard_value|
60
+ find_raw_custom_value(custom_field, single_raw_standard_value)
61
+ end
62
+ else
63
+ return find_raw_custom_value(custom_field, raw_standard_value)
64
+ end
65
+ end
66
+
67
+ compute_raw_custom_value(custom_field, raw_standard_value, custom_instance)
68
+ end
69
+
70
+ def find_raw_custom_value(custom_field, raw_standard_value)
71
+ return raw_standard_value unless custom_field.has_values?
72
+
73
+ if !custom_field.standard_field.has_values?
74
+ custom_value = custom_field.find_value(raw_standard_value)
75
+ return nil if custom_value.nil?
76
+ return custom_value.value
77
+ end
78
+
79
+ custom_value = custom_field.find_priority_value_mapped_to_standard(raw_standard_value)
80
+ return nil if custom_value.nil?
81
+ custom_value.value
82
+ end
83
+
84
+ def compute_raw_custom_value(custom_field, raw_standard_value, custom_instance)
85
+ raw_custom_value = custom_instance.instance_exec(
86
+ raw_standard_value,
87
+ standard_instance: standard_instance,
88
+ &custom_field.standard_to_custom
89
+ )
90
+
91
+ if !raw_custom_value.nil?
92
+ raw_custom_value = custom_field.cast(raw_custom_value)
93
+ end
94
+ raw_custom_value
95
+ end
96
+
97
+ def compute_raw_custom_value_for_plat_list(custom_field, raw_standard_values)
98
+ raw_standard_values.map do |raw_standard_value|
99
+ compute_raw_custom_value_for_plat(custom_field, raw_standard_value)
100
+ end
101
+ end
102
+
103
+ def compute_raw_custom_value_for_plat(custom_field, raw_standard_value)
104
+ converter = FieldMapper::Standard::Converter.new(raw_standard_value)
105
+ converter.convert_to(custom_field.type.type)
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+