Module: HashEngine::Transform

Includes:
Actions, AddError, CSVParse, Fetchers, Format
Included in:
HashEngine
Defined in:
lib/hash_engine/transform.rb

Constant Summary collapse

DEFAULT_INSTRUCTIONS =
{'default_value'  => '',
'allow_nil'      => false,
'suppress_nil'   => true,
'allow_blank'    => false,
'suppress_blank' => true,
'long_error'     => true,
'copy_source'    => false,
'delimiter'      => DEFAULT_DELIMITER,
'quiet'          => false }

Constants included from CSVParse

CSVParse::DEFAULT_DELIMITER, CSVParse::QUOTED_FIELD, CSVParse::QUOTE_CHAR

Instance Method Summary collapse

Methods included from CSVParse

#parse_line

Methods included from Fetchers

#add_fetcher, #fetcher, #fetchers, #valid_fetcher?

Methods included from AddError

#add_error

Methods included from Actions

#action, #actions, #add_action, #valid_action?

Methods included from Format

#add_format, #format, #formats

Instance Method Details

#blank_check(instructions, value) ⇒ Object



30
31
32
# File 'lib/hash_engine/transform.rb', line 30

def blank_check(instructions, value)
  instructions['allow_blank'] == false && value.is_a?(String) && value !~ /\S/
end

#concat(data, fetched) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/hash_engine/transform.rb', line 131

def concat(data, fetched)
  if data.nil?
    fetched
  elsif data.is_a?(Array) && fetched.is_a?(Array)
    data + fetched
  elsif data.is_a?(Array) 
    data.push fetched
  elsif fetched.is_a?(Array)
    fetched.unshift(data)
  else
    [data, fetched]
  end
end

#conditional_eval(field_name, instructions, source_data, error_array) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/hash_engine/transform.rb', line 145

def conditional_eval(field_name, instructions, source_data, error_array)
  left_operand = get_value("#{field_name}_conditional_eval_left_operand",
                           instructions['left_operand'], source_data, error_array)
  right_operand = get_value("#{field_name}_conditional_eval_right_operand",
                            instructions['right_operand'], source_data, error_array)
  if conditional(instructions['operator'], left_operand, right_operand)
    get_value("#{field_name}_conditional_eval_true_instructions",
              instructions['true_instructions'], source_data, error_array)
  else
    get_value("#{field_name}_conditional_eval_false_instructions",
              instructions['false_instructions'], source_data, error_array)
  end
end

#csv_transform(data_string, passed_instructions, additional_data = {}) ⇒ Object

Given String:

ok|http://www.domain.com|1234567890

Given Instructions:

deliminator: '|'
hash_keys:
  - status:
      lookup_map:
        ok: accepted
        decline: reject
        default: error
  - payload:
  - uuid:

Return:

status: accepted
payload: http://www.domain.com
uuid: 1234567890


99
100
101
102
103
104
105
106
107
108
# File 'lib/hash_engine/transform.rb', line 99

def csv_transform(data_string, passed_instructions, additional_data={})
  instructions = DEFAULT_INSTRUCTIONS.merge(passed_instructions)
  result = {:error => ["Missing CSV instructions"]}
  if instructions['header']
    result = parse_line data_string, instructions['header'], instructions['delimiter']
    result = transform(result.merge(additional_data), instructions) if result[:error].empty?
  end
  result.delete(:error) if instructions['quiet']
  result
end

#default_or_suppress(value, field_name, field_hash, instructions, result) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/hash_engine/transform.rb', line 46

def default_or_suppress(value, field_name, field_hash, instructions, result)
  if (nil_check(instructions, value) || blank_check(instructions, value)) && 
     required_check(field_hash) then
    add_error(result[:error], "required field '#{field_name}' missing", field_name)
    result[field_name] = instructions['default_value']
  else
    unless suppress_nil(instructions, value) || suppress_blank(instructions, value)
      result[field_name] = value
    end
  end
end

#get_value(field_name, field_data, source_data, error_array) ⇒ Object



185
186
187
188
189
190
191
192
193
194
# File 'lib/hash_engine/transform.rb', line 185

def get_value(field_name, field_data, source_data, error_array)
  case field_data
  when Array
    process_instructions(field_name, field_data, source_data, error_array)
  when Hash
    simple_instructions(field_name, field_data, source_data, error_array)
  else
    fetcher('input', field_data, source_data)
  end
end

#nil_check(instructions, value) ⇒ Object



26
27
28
# File 'lib/hash_engine/transform.rb', line 26

def nil_check(instructions, value)
  instructions['allow_nil'] == false && value.nil?
end

#process_instructions(field_name, instruction_array, source_data, error_array) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/hash_engine/transform.rb', line 159

def process_instructions(field_name, instruction_array, source_data, error_array)
  data = nil
  instruction_array.each do |instruction_hash|
    (instruction, instruction_data) = instruction_hash.first
    # puts "  Evaluating instruction: #{instruction} with instruction_data: #{instruction_data}"
    case
    when instruction == 'subgroup'
      fetched = get_value(field_name, instruction_data, source_data, error_array)
      data = concat(data, fetched)
    when instruction == 'conditional_eval'
      fetched = conditional_eval(field_name, instruction_data, source_data, error_array)
      data = concat(data, fetched)
    when valid_fetcher?(instruction)
      fetched = fetcher(instruction, instruction_data, source_data)
      data = concat(data, fetched)
    when valid_action?(instruction)
      data = action(instruction, instruction_data, data)
    else
      add_error(error_array, "Invalid operation '#{instruction_hash.inspect}' in transform for field '#{field_name}'", field_name)
      data = nil
      break
    end
  end
  data
end

#required_check(field_hash) ⇒ Object



34
35
36
# File 'lib/hash_engine/transform.rb', line 34

def required_check(field_hash)
  !(field_hash['optional'] == true)
end

#simple_instructions(field_name, field_hash, source_data, error_array) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/hash_engine/transform.rb', line 111

def simple_instructions(field_name, field_hash, source_data, error_array)
  instructions = []
  field_hash.each_pair do |key, value|
    case
    when key == 'conditional_eval'
      instructions.unshift(key => value)
    when key == 'subgroup'
      instructions.unshift(key => value)
    when valid_fetcher?(key)
      instructions.unshift(key => value)
    when valid_action?(key)
      instructions.push(key => value)
    else
      add_error(error_array, "Invalid operation '#{key.inspect}' in transform for field '#{field_name}'", field_name)
      data = nil
    end
  end
  process_instructions(field_name, instructions, source_data, error_array)
end

#suppress_blank(instructions, value) ⇒ Object



42
43
44
# File 'lib/hash_engine/transform.rb', line 42

def suppress_blank(instructions, value)
  instructions['suppress_blank'] == true && value.is_a?(String) && value !~ /\S/
end

#suppress_nil(instructions, value) ⇒ Object



38
39
40
# File 'lib/hash_engine/transform.rb', line 38

def suppress_nil(instructions, value)
  instructions['suppress_nil'] == true && value.nil?
end

#transform(data, passed_instructions) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/hash_engine/transform.rb', line 58

def transform(data, passed_instructions)
  instructions = DEFAULT_INSTRUCTIONS.merge(passed_instructions)
  if instructions['fields']
    # continue
    result = if instructions['copy_source']
               data.merge(:error => [])
             else 
               {:error => []}
             end
    result[:error].push(instructions['long_error'] ? :long : :short)
    instructions['fields'].each_pair do |field_name, field_hash|
      value = get_value(field_name, field_hash, data, result[:error])
      default_or_suppress(value, field_name, field_hash, instructions, result)
    end
    # remove the :long/:short instruction
    result[:error].shift
  else
    result = {:error => ["Missing instructions"]}
  end
  result.delete(:error) if instructions['quiet']
  result
end