data_maps 0.1.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 +14 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +48 -0
- data/LICENSE.txt +22 -0
- data/README.md +264 -0
- data/Rakefile +9 -0
- data/data_maps.gemspec +27 -0
- data/lib/data_maps/concerns/factory.rb +31 -0
- data/lib/data_maps/condition.rb +81 -0
- data/lib/data_maps/converter/affixes.rb +35 -0
- data/lib/data_maps/converter/base.rb +12 -0
- data/lib/data_maps/converter/bool.rb +15 -0
- data/lib/data_maps/converter/keys.rb +23 -0
- data/lib/data_maps/converter/map.rb +24 -0
- data/lib/data_maps/converter/numeric.rb +28 -0
- data/lib/data_maps/converter/ruby.rb +20 -0
- data/lib/data_maps/converter/string.rb +15 -0
- data/lib/data_maps/errors/invalid_data.rb +6 -0
- data/lib/data_maps/executable.rb +33 -0
- data/lib/data_maps/filtered_value.rb +16 -0
- data/lib/data_maps/mapper.rb +25 -0
- data/lib/data_maps/mapping.rb +102 -0
- data/lib/data_maps/statement.rb +80 -0
- data/lib/data_maps/then/base.rb +12 -0
- data/lib/data_maps/then/convert.rb +25 -0
- data/lib/data_maps/then/filter.rb +16 -0
- data/lib/data_maps/then/set.rb +15 -0
- data/lib/data_maps/version.rb +3 -0
- data/lib/data_maps/when/base.rb +12 -0
- data/lib/data_maps/when/comparison.rb +99 -0
- data/lib/data_maps/when/empty.rb +15 -0
- data/lib/data_maps/when/regex.rb +23 -0
- data/lib/data_maps.rb +13 -0
- data/spec/data_maps/concerns/factory_spec.rb +54 -0
- data/spec/data_maps/condition_spec.rb +104 -0
- data/spec/data_maps/converter/affixes_spec.rb +119 -0
- data/spec/data_maps/converter/base_spec.rb +21 -0
- data/spec/data_maps/converter/bool_spec.rb +11 -0
- data/spec/data_maps/converter/keys_spec.rb +25 -0
- data/spec/data_maps/converter/map_spec.rb +45 -0
- data/spec/data_maps/converter/numeric_spec.rb +81 -0
- data/spec/data_maps/converter/ruby_spec.rb +15 -0
- data/spec/data_maps/converter/string_spec.rb +14 -0
- data/spec/data_maps/executable_spec.rb +23 -0
- data/spec/data_maps/filtered_value_spec.rb +12 -0
- data/spec/data_maps/mapper_spec.rb +38 -0
- data/spec/data_maps/mapping_spec.rb +192 -0
- data/spec/data_maps/statement_spec.rb +94 -0
- data/spec/data_maps/then/base_spec.rb +21 -0
- data/spec/data_maps/then/convert_spec.rb +28 -0
- data/spec/data_maps/then/filter_spec.rb +13 -0
- data/spec/data_maps/then/set_spec.rb +11 -0
- data/spec/data_maps/version_spec.rb +8 -0
- data/spec/data_maps/when/base_spec.rb +21 -0
- data/spec/data_maps/when/comparison_spec.rb +129 -0
- data/spec/data_maps/when/empty_spec.rb +29 -0
- data/spec/data_maps/when/regex_spec.rb +31 -0
- data/spec/spec_helper.rb +7 -0
- metadata +199 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module DataMaps
|
2
|
+
module Converter
|
3
|
+
# Converts numeric values
|
4
|
+
#
|
5
|
+
# @since 0.0.1
|
6
|
+
class String < Base
|
7
|
+
# The execute method to convert the given data into string
|
8
|
+
#
|
9
|
+
# @param [mixed] data
|
10
|
+
def execute(data)
|
11
|
+
data.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DataMaps
|
2
|
+
# Base class for executables (converter, when, then)
|
3
|
+
#
|
4
|
+
# @since 0.0.1
|
5
|
+
# @abstract
|
6
|
+
# @attr_reader @option the given option
|
7
|
+
class Executable
|
8
|
+
attr_reader :option
|
9
|
+
|
10
|
+
# Initializer
|
11
|
+
#
|
12
|
+
# @param [mixed] option The given options
|
13
|
+
def initialize(option)
|
14
|
+
@option = option
|
15
|
+
|
16
|
+
self.after_initialize if self.respond_to? :after_initialize
|
17
|
+
end
|
18
|
+
|
19
|
+
# The execute method to apply checks or mutations on the given data
|
20
|
+
#
|
21
|
+
# @param [mixed] data
|
22
|
+
def execute(data)
|
23
|
+
raise NotImplementedError.new("Please implement the execute method for your #{self.class.name}")
|
24
|
+
end
|
25
|
+
|
26
|
+
# Helper method to check if all the executable in a collection are valid objects of self
|
27
|
+
#
|
28
|
+
# @param [Array] collection
|
29
|
+
def self.valid_collection?(collection)
|
30
|
+
collection.is_a?(Array) && collection.all?{ |w| w.is_a?(self) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module DataMaps
|
2
|
+
# A filtered value
|
3
|
+
#
|
4
|
+
# @since 0.0.1
|
5
|
+
# @attr_reader [mixed] value
|
6
|
+
class FilteredValue
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
# Initializer for FilteredValue
|
10
|
+
#
|
11
|
+
# @param [mixed] value The original value
|
12
|
+
def initialize(value)
|
13
|
+
@value = value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMaps
|
2
|
+
# The base mapper class which handles all mapping logic
|
3
|
+
#
|
4
|
+
# @since 0.0.1
|
5
|
+
# @attr [Mapping] mapping
|
6
|
+
class Mapper
|
7
|
+
# Attribute Accessors
|
8
|
+
attr_accessor :mapping
|
9
|
+
|
10
|
+
# Initializer for the Mapper class
|
11
|
+
#
|
12
|
+
# @param [Mapping] mapping the mapping which will used to map data
|
13
|
+
# @raise [ArgumentError] when mapping is not a correct mapping object
|
14
|
+
def initialize(mapping)
|
15
|
+
raise ArgumentError.new('The mapping should be a DataMaps::Mapping::Base') unless mapping.is_a? DataMaps::Mapping
|
16
|
+
|
17
|
+
@mapping = mapping
|
18
|
+
end
|
19
|
+
|
20
|
+
# Execute
|
21
|
+
def convert(data)
|
22
|
+
mapping.execute(data.stringify_keys)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module DataMaps
|
2
|
+
# The mapping class which defines a mapping
|
3
|
+
#
|
4
|
+
# @since 0.0.1
|
5
|
+
# attr_reader [Hash] mapping the compiled mapping
|
6
|
+
# attr_reader [Hash] mapping_hash the mapping description
|
7
|
+
class Mapping
|
8
|
+
attr_reader :mapping, :mapping_hash
|
9
|
+
|
10
|
+
# Initializer for the Mapping class
|
11
|
+
#
|
12
|
+
# @param [Hash] mapping_hash
|
13
|
+
#
|
14
|
+
# @raise [ArgumentError] when the given mapping_hash is not a Hash
|
15
|
+
def initialize(mapping_hash = {})
|
16
|
+
raise ArgumentError.new('The mapping_hash must be a Hash') unless mapping_hash.is_a? Hash
|
17
|
+
|
18
|
+
@mapping = {}
|
19
|
+
@mapping_hash = mapping_hash.with_indifferent_access
|
20
|
+
end
|
21
|
+
|
22
|
+
# Compile the mapping statements, this will lazily called on first use
|
23
|
+
#
|
24
|
+
def compile
|
25
|
+
unless @_compiled
|
26
|
+
# iterate over the mapping_hash and initialize mapping for each key
|
27
|
+
mapping_hash.each do |destination, map|
|
28
|
+
@mapping[destination] = _create_statement(destination, map)
|
29
|
+
end
|
30
|
+
|
31
|
+
@_compiled = true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Validate the mapping statements, this is a compiling without save the compiled mapping
|
36
|
+
def valid?
|
37
|
+
true if validate rescue false
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate
|
41
|
+
mapping_hash.each &method(:_create_statement)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Getter to get the statement for a destination_field
|
45
|
+
#
|
46
|
+
# @param [String|Symbol] destination the field name to receive statement for
|
47
|
+
# @raise [KeyError] when the destination_field isn't present in map
|
48
|
+
def get_statement_for(destination)
|
49
|
+
compile
|
50
|
+
|
51
|
+
raise KeyError.new("The map has no statement for field: #{destination}") unless mapping.has_key?(destination)
|
52
|
+
|
53
|
+
mapping[destination]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Allow iterations over all statements
|
57
|
+
#
|
58
|
+
# @param [Block] &block the block to execute for each map statement
|
59
|
+
# @return [Enumerator|self] return the enumerator if no block given or self
|
60
|
+
def each_statement
|
61
|
+
compile
|
62
|
+
|
63
|
+
return enum_for(:each_statement) unless block_given? # return Enumerator
|
64
|
+
|
65
|
+
mapping.each do |destination, statement|
|
66
|
+
yield destination, statement
|
67
|
+
end
|
68
|
+
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Execute mapping on the given data
|
73
|
+
#
|
74
|
+
# @param [Hash] data
|
75
|
+
# @return [Hash] the mapped data
|
76
|
+
def execute(data)
|
77
|
+
result = {}
|
78
|
+
each_statement do |destination, statement|
|
79
|
+
key, value = statement.execute(data)
|
80
|
+
result[key] = value unless value.is_a? DataMaps::FilteredValue
|
81
|
+
end
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
# Create a mapping statement
|
89
|
+
#
|
90
|
+
# @protected
|
91
|
+
#
|
92
|
+
# @param [String] destination The destination field
|
93
|
+
# @param [String|Hash] mapping
|
94
|
+
#
|
95
|
+
# @return [Statement] executable statement
|
96
|
+
def _create_statement(destination, mapping)
|
97
|
+
mapping = { from: mapping } if mapping.is_a? String
|
98
|
+
mapping[:to] = destination
|
99
|
+
DataMaps::Statement.create_from_map(mapping)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module DataMaps
|
2
|
+
# A mapping statement
|
3
|
+
#
|
4
|
+
# @since 0.0.1
|
5
|
+
# @attr_reader [String] from the source data
|
6
|
+
# @attr_reader [String] to the destination data
|
7
|
+
# @attr_reader [Array] conditions a array of conditions
|
8
|
+
# @attr_reader [Array] converter a array of converter
|
9
|
+
class Statement
|
10
|
+
attr_reader :from, :to, :conditions, :converter
|
11
|
+
|
12
|
+
# Create statement from a mapping hash
|
13
|
+
#
|
14
|
+
# @param [Hash] mapping
|
15
|
+
#
|
16
|
+
# @return [Statement]
|
17
|
+
def self.create_from_map(mapping)
|
18
|
+
self.new(
|
19
|
+
mapping[:from],
|
20
|
+
mapping[:to],
|
21
|
+
DataMaps::Condition.create_from_map(mapping[:conditions] || []),
|
22
|
+
DataMaps::Converter.create_from_map(mapping[:converter] || {})
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
# The statement initializer
|
27
|
+
#
|
28
|
+
# @param [String] from
|
29
|
+
# @param [String] to
|
30
|
+
# @param [Array] conditions
|
31
|
+
# @param [Array] converter
|
32
|
+
def initialize(from, to, conditions, converter)
|
33
|
+
raise ArgumentError.new('Statement needs a source field') unless from.present?
|
34
|
+
raise ArgumentError.new('Conditions must be an array of DataMaps::Condition') unless conditions.is_a?(Array) && conditions.all?{ |c| c.is_a?(DataMaps::Condition) }
|
35
|
+
raise ArgumentError.new('Converter must be an array of DataMaps::Converter') unless DataMaps::Converter::Base.valid_collection?(converter)
|
36
|
+
|
37
|
+
@from = from
|
38
|
+
@to = to
|
39
|
+
@conditions = conditions
|
40
|
+
@converter = converter
|
41
|
+
end
|
42
|
+
|
43
|
+
# Execute the statement on the given data
|
44
|
+
#
|
45
|
+
# @param [mixed] data
|
46
|
+
# @return [Array] key and value of the result
|
47
|
+
def execute(data)
|
48
|
+
data = from.is_a?(Array) ? Hash[from.map{ |f| [f, data[f.to_s]] }] : data[from.to_s]
|
49
|
+
|
50
|
+
data = execute_conditions(data)
|
51
|
+
data = execute_converter(data)
|
52
|
+
|
53
|
+
[to, data]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Execute conditions
|
57
|
+
#
|
58
|
+
# @param [mixed] data
|
59
|
+
# @return [mixed] mutated data
|
60
|
+
def execute_conditions(data)
|
61
|
+
conditions.each do |condition|
|
62
|
+
data = condition.execute(data)
|
63
|
+
end
|
64
|
+
|
65
|
+
data
|
66
|
+
end
|
67
|
+
|
68
|
+
# Execute converter
|
69
|
+
#
|
70
|
+
# @param [mixed] data
|
71
|
+
# @return [mixed] mutated data
|
72
|
+
def execute_converter(data)
|
73
|
+
converter.each do |converter|
|
74
|
+
data = converter.execute(data)
|
75
|
+
end
|
76
|
+
|
77
|
+
data
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMaps
|
2
|
+
module Then
|
3
|
+
# A then to convert values
|
4
|
+
#
|
5
|
+
# @since 0.0.1
|
6
|
+
class Convert < Base
|
7
|
+
attr_reader :converter
|
8
|
+
|
9
|
+
def after_initialize
|
10
|
+
@converter = DataMaps::Converter.create_from_map(@option)
|
11
|
+
end
|
12
|
+
|
13
|
+
# The execute method which returns the converted data
|
14
|
+
#
|
15
|
+
# @param [mixed] data
|
16
|
+
def execute(data)
|
17
|
+
converter.each do |converter|
|
18
|
+
data = converter.execute(data)
|
19
|
+
end
|
20
|
+
|
21
|
+
data
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module DataMaps
|
2
|
+
module When
|
3
|
+
# Condition to check for greater than
|
4
|
+
#
|
5
|
+
# @since 0.0.1
|
6
|
+
class Gt < Base
|
7
|
+
# Check if data is greater than the option
|
8
|
+
#
|
9
|
+
# @param [mixed] data
|
10
|
+
def execute(data)
|
11
|
+
data > option
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Condition to check for greater or equal than
|
16
|
+
#
|
17
|
+
# @since 0.0.1
|
18
|
+
class Gte < Base
|
19
|
+
# Check if data is greater or equal than the option
|
20
|
+
#
|
21
|
+
# @param [mixed] data
|
22
|
+
def execute(data)
|
23
|
+
data >= option
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Condition to check for lower than
|
28
|
+
#
|
29
|
+
# @since 0.0.1
|
30
|
+
class Lt < Base
|
31
|
+
# Check if data is greater than the option
|
32
|
+
#
|
33
|
+
# @param [mixed] data
|
34
|
+
def execute(data)
|
35
|
+
data < option
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Condition to check for lower or equal than
|
40
|
+
#
|
41
|
+
# @since 0.0.1
|
42
|
+
class Lte < Base
|
43
|
+
# Check if data is greater than the option
|
44
|
+
#
|
45
|
+
# @param [mixed] data
|
46
|
+
def execute(data)
|
47
|
+
data <= option
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Condition to check equality
|
52
|
+
#
|
53
|
+
# @since 0.0.1
|
54
|
+
class Eq < Base
|
55
|
+
# Check if data equals option
|
56
|
+
#
|
57
|
+
# @param [mixed] data
|
58
|
+
def execute(data)
|
59
|
+
data == option
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Condition to check no equality
|
64
|
+
#
|
65
|
+
# @since 0.0.1
|
66
|
+
class Neq < Base
|
67
|
+
# Check if data not equals option
|
68
|
+
#
|
69
|
+
# @param [mixed] data
|
70
|
+
def execute(data)
|
71
|
+
data != option
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Condition to check is in
|
76
|
+
#
|
77
|
+
# @since 0.0.1
|
78
|
+
class In < Base
|
79
|
+
# Check if data is part of option
|
80
|
+
#
|
81
|
+
# @param [mixed] data
|
82
|
+
def execute(data)
|
83
|
+
option.include?(data)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Condition to check is not in
|
88
|
+
#
|
89
|
+
# @since 0.0.1
|
90
|
+
class Nin < Base
|
91
|
+
# Check if data is not part of option
|
92
|
+
#
|
93
|
+
# @param [mixed] data
|
94
|
+
def execute(data)
|
95
|
+
!option.include?(data)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DataMaps
|
2
|
+
module When
|
3
|
+
# Condition to check for empty data
|
4
|
+
#
|
5
|
+
# @since 0.0.1
|
6
|
+
class Empty < Base
|
7
|
+
# Check if data is empty? and return true if this equals the option
|
8
|
+
#
|
9
|
+
# @param [mixed] data
|
10
|
+
def execute(data)
|
11
|
+
data.empty? == option
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DataMaps
|
2
|
+
module When
|
3
|
+
# Condition to check for an regular expression
|
4
|
+
#
|
5
|
+
# @since 0.0.1
|
6
|
+
# @attr_reader @regex the given regex
|
7
|
+
class Regex < Base
|
8
|
+
attr_reader :regex
|
9
|
+
|
10
|
+
# After initialize callback
|
11
|
+
def after_initialize
|
12
|
+
@regex = Regexp.new(option)
|
13
|
+
end
|
14
|
+
|
15
|
+
# The check method to evaluate condition on given data
|
16
|
+
#
|
17
|
+
# @param [mixed] data
|
18
|
+
def execute(data)
|
19
|
+
!!@regex.match(data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/data_maps.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Require gem stuff
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
# Require all project files
|
5
|
+
Dir.glob(File.join(__dir__, 'data_maps', 'executable.rb'), &method(:require))
|
6
|
+
Dir.glob(File.join(__dir__, 'data_maps', '{concerns,errors}', '*.rb'), &method(:require))
|
7
|
+
Dir.glob(File.join(__dir__, 'data_maps', '{converter,then,when}', 'base.rb'), &method(:require))
|
8
|
+
Dir.glob(File.join(__dir__, 'data_maps', '{converter,then,when}', '*.rb'), &method(:require))
|
9
|
+
Dir.glob(File.join(__dir__, 'data_maps', '*.rb'), &method(:require))
|
10
|
+
|
11
|
+
module DataMaps
|
12
|
+
# Nothing to do here :)
|
13
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMaps::Concerns::Factory do
|
4
|
+
|
5
|
+
module MyModule
|
6
|
+
extend DataMaps::Concerns::Factory
|
7
|
+
|
8
|
+
class A
|
9
|
+
def initialize(option); end
|
10
|
+
end
|
11
|
+
|
12
|
+
class B
|
13
|
+
def initialize(option); end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'module respond_to factory class method' do
|
18
|
+
expect(MyModule).to respond_to :factory
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#factory' do
|
22
|
+
it 'raise error if constant doesn\'t exists in the module' do
|
23
|
+
expect{ MyModule.factory('c', nil) }.to raise_error ArgumentError
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns instance of the given class' do
|
27
|
+
expect(MyModule.factory('a', nil)).to be_a MyModule::A
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'works with symbols too' do
|
31
|
+
expect(MyModule.factory(:a, nil)).to be_a MyModule::A
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'pass option to the new class' do
|
35
|
+
option = 1
|
36
|
+
expect(MyModule::A).to receive(:new).with(option)
|
37
|
+
|
38
|
+
MyModule.factory('A', option)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#create_from_map' do
|
43
|
+
it 'raises an error if mapping isn\'t a hash' do
|
44
|
+
expect{ MyModule.create_from_map([]) }.to raise_error ArgumentError
|
45
|
+
expect{ MyModule.create_from_map('something') }.to raise_error ArgumentError
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'calls the factory method' do
|
49
|
+
mapping = { a: :b }
|
50
|
+
expect(MyModule).to receive(:factory).with(:a, :b).and_call_original
|
51
|
+
MyModule.create_from_map(mapping)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMaps::Condition do
|
4
|
+
describe '::create_from_map' do
|
5
|
+
it 'creates a new Condition' do
|
6
|
+
mapping = [
|
7
|
+
{ when: { empty: true }, then: { filter: true } }
|
8
|
+
]
|
9
|
+
|
10
|
+
expect(DataMaps::When).to receive(:create_from_map).with(mapping.first[:when]).and_call_original
|
11
|
+
expect(DataMaps::Then).to receive(:create_from_map).with(mapping.first[:then]).and_call_original
|
12
|
+
|
13
|
+
expect(DataMaps::Condition).to receive(:new).with([DataMaps::When::Empty], [DataMaps::Then::Filter])
|
14
|
+
|
15
|
+
DataMaps::Condition.create_from_map(mapping)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'arguments' do
|
20
|
+
it 'can\'t be initialized without whens' do
|
21
|
+
expect{ DataMaps::Condition.new(nil, []) }.to raise_error ArgumentError
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can\'t be initialized with wrong whens' do
|
25
|
+
expect{ DataMaps::Condition.new(['a', 5], []) }.to raise_error ArgumentError
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can\'t be initialized without thens' do
|
29
|
+
expect{ DataMaps::Condition.new([], nil) }.to raise_error ArgumentError
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'can\'t be initialized with wrong thens' do
|
33
|
+
expect{ DataMaps::Condition.new([], ['b', 6]) }.to raise_error ArgumentError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#can_break?' do
|
38
|
+
it 'returns false' do
|
39
|
+
condition = DataMaps::Condition.new([], [])
|
40
|
+
expect(condition.can_break?).to be_falsey
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns true if there is a Then::Filter present' do
|
44
|
+
condition = DataMaps::Condition.new([], [DataMaps::Then::Filter.new(true)])
|
45
|
+
expect(condition.can_break?).to be_truthy
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#execute' do
|
50
|
+
let(:condition) { DataMaps::Condition.new([DataMaps::When::Base.new(nil)], [DataMaps::Then::Base.new(nil)]) }
|
51
|
+
let(:data) { double(Object) }
|
52
|
+
|
53
|
+
it 'returns original data when check is false' do
|
54
|
+
expect(condition).to receive(:check).with(data).and_return(false)
|
55
|
+
expect(condition.execute(data)).to be data
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns modified data when check is true and can_break? is false' do
|
59
|
+
expect(condition).to receive(:check).with(data).and_return(true)
|
60
|
+
expect(condition).to receive(:can_break?).and_return(false)
|
61
|
+
expect(condition).to receive(:result).with(data).and_return('modified value')
|
62
|
+
expect(condition.execute(data)).to eq 'modified value'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns a FilteredValue when check is true and can_break? is true' do
|
66
|
+
expect(condition).to receive(:check).with(data).and_return(true)
|
67
|
+
expect(condition).to receive(:can_break?).and_return(true)
|
68
|
+
expect(condition.execute(data)).to be_a DataMaps::FilteredValue
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#check' do
|
73
|
+
let(:condition) { DataMaps::Condition.new([DataMaps::When::Base.new(nil), DataMaps::When::Base.new(nil)], []) }
|
74
|
+
let(:data) { double(Object) }
|
75
|
+
|
76
|
+
it 'returns true if all whens are true' do
|
77
|
+
expect(condition.whens[0]).to receive(:execute).with(data).and_return(true)
|
78
|
+
expect(condition.whens[1]).to receive(:execute).with(data).and_return(true)
|
79
|
+
|
80
|
+
expect(condition.check(data)).to be_truthy
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns false if a when is false' do
|
84
|
+
expect(condition.whens[0]).to receive(:execute).with(data).and_return(true)
|
85
|
+
expect(condition.whens[1]).to receive(:execute).with(data).and_return(false)
|
86
|
+
|
87
|
+
expect(condition.check(data)).to be_falsey
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#result' do
|
92
|
+
let(:condition) { DataMaps::Condition.new([], [DataMaps::Then::Base.new(nil), DataMaps::Then::Base.new(nil)]) }
|
93
|
+
let(:data) { double(Object) }
|
94
|
+
let(:data2) { double(Object) }
|
95
|
+
let(:data3) { double(Object) }
|
96
|
+
|
97
|
+
it 'calls execute for each then with the mutated data' do
|
98
|
+
expect(condition.thens[0]).to receive(:execute).ordered.with(data).and_return(data2)
|
99
|
+
expect(condition.thens[1]).to receive(:execute).ordered.with(data2).and_return(data3)
|
100
|
+
|
101
|
+
expect(condition.result(data)).to be data3
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|