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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +48 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +264 -0
  9. data/Rakefile +9 -0
  10. data/data_maps.gemspec +27 -0
  11. data/lib/data_maps/concerns/factory.rb +31 -0
  12. data/lib/data_maps/condition.rb +81 -0
  13. data/lib/data_maps/converter/affixes.rb +35 -0
  14. data/lib/data_maps/converter/base.rb +12 -0
  15. data/lib/data_maps/converter/bool.rb +15 -0
  16. data/lib/data_maps/converter/keys.rb +23 -0
  17. data/lib/data_maps/converter/map.rb +24 -0
  18. data/lib/data_maps/converter/numeric.rb +28 -0
  19. data/lib/data_maps/converter/ruby.rb +20 -0
  20. data/lib/data_maps/converter/string.rb +15 -0
  21. data/lib/data_maps/errors/invalid_data.rb +6 -0
  22. data/lib/data_maps/executable.rb +33 -0
  23. data/lib/data_maps/filtered_value.rb +16 -0
  24. data/lib/data_maps/mapper.rb +25 -0
  25. data/lib/data_maps/mapping.rb +102 -0
  26. data/lib/data_maps/statement.rb +80 -0
  27. data/lib/data_maps/then/base.rb +12 -0
  28. data/lib/data_maps/then/convert.rb +25 -0
  29. data/lib/data_maps/then/filter.rb +16 -0
  30. data/lib/data_maps/then/set.rb +15 -0
  31. data/lib/data_maps/version.rb +3 -0
  32. data/lib/data_maps/when/base.rb +12 -0
  33. data/lib/data_maps/when/comparison.rb +99 -0
  34. data/lib/data_maps/when/empty.rb +15 -0
  35. data/lib/data_maps/when/regex.rb +23 -0
  36. data/lib/data_maps.rb +13 -0
  37. data/spec/data_maps/concerns/factory_spec.rb +54 -0
  38. data/spec/data_maps/condition_spec.rb +104 -0
  39. data/spec/data_maps/converter/affixes_spec.rb +119 -0
  40. data/spec/data_maps/converter/base_spec.rb +21 -0
  41. data/spec/data_maps/converter/bool_spec.rb +11 -0
  42. data/spec/data_maps/converter/keys_spec.rb +25 -0
  43. data/spec/data_maps/converter/map_spec.rb +45 -0
  44. data/spec/data_maps/converter/numeric_spec.rb +81 -0
  45. data/spec/data_maps/converter/ruby_spec.rb +15 -0
  46. data/spec/data_maps/converter/string_spec.rb +14 -0
  47. data/spec/data_maps/executable_spec.rb +23 -0
  48. data/spec/data_maps/filtered_value_spec.rb +12 -0
  49. data/spec/data_maps/mapper_spec.rb +38 -0
  50. data/spec/data_maps/mapping_spec.rb +192 -0
  51. data/spec/data_maps/statement_spec.rb +94 -0
  52. data/spec/data_maps/then/base_spec.rb +21 -0
  53. data/spec/data_maps/then/convert_spec.rb +28 -0
  54. data/spec/data_maps/then/filter_spec.rb +13 -0
  55. data/spec/data_maps/then/set_spec.rb +11 -0
  56. data/spec/data_maps/version_spec.rb +8 -0
  57. data/spec/data_maps/when/base_spec.rb +21 -0
  58. data/spec/data_maps/when/comparison_spec.rb +129 -0
  59. data/spec/data_maps/when/empty_spec.rb +29 -0
  60. data/spec/data_maps/when/regex_spec.rb +31 -0
  61. data/spec/spec_helper.rb +7 -0
  62. 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,6 @@
1
+ module DataMaps
2
+ module Errors
3
+ class InvalidDataError < StandardError
4
+ end
5
+ end
6
+ 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,12 @@
1
+ module DataMaps
2
+ module Then
3
+ extend DataMaps::Concerns::Factory
4
+
5
+ # Base class for then's
6
+ #
7
+ # @since 0.0.1
8
+ # @abstract
9
+ class Base < DataMaps::Executable
10
+ end
11
+ end
12
+ 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,16 @@
1
+ module DataMaps
2
+ module Then
3
+ # A then to filter values
4
+ #
5
+ # @since 0.0.1
6
+ class Filter < Base
7
+ # Return the original data
8
+ #
9
+ # @param [mixed] data
10
+ # @return [mixed] data
11
+ def execute(data)
12
+ data
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module DataMaps
2
+ module Then
3
+ # A then to set a value
4
+ #
5
+ # @since 0.0.1
6
+ class Set < Base
7
+ # The execute method which returns the converted data
8
+ #
9
+ # @param [mixed] data
10
+ def execute(data)
11
+ option
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module DataMaps
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,12 @@
1
+ module DataMaps
2
+ module When
3
+ extend DataMaps::Concerns::Factory
4
+
5
+ # Base class for when's
6
+ #
7
+ # @since 0.0.1
8
+ # @abstract
9
+ class Base < DataMaps::Executable
10
+ end
11
+ end
12
+ 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