Class: DataListConverter

Inherits:
Object
  • Object
show all
Defined in:
lib/data_list_converter/base.rb,
lib/data_list_converter/types/basic.rb,
lib/data_list_converter/filters/count.rb,
lib/data_list_converter/filters/limit.rb,
lib/data_list_converter/types/records.rb,
lib/data_list_converter/types/csv_file.rb,
lib/data_list_converter/types/xls_file.rb,
lib/data_list_converter/types/xlsx_file.rb,
lib/data_list_converter/filters/remove_debug.rb

Overview

csv_file

Constant Summary collapse

CONVERTERS =
{}
FILTERS =
{}

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.debugObject

Returns the value of attribute debug.



10
11
12
# File 'lib/data_list_converter/base.rb', line 10

def debug
  @debug
end

Class Method Details

.convert(from_type, to_type, from_value, options = {}) ⇒ Object

Example: convert(:item_iterator, :item_data, iter) convert(:item_iterator, :csv_file, iter, csv_file: ‘result.csv’) convert(:csv_file, :item_data, ‘result.csv’)

can add filter: filter = :limit filter = {size: 2} filter = [{size: 12}, {size: 4}] convert(:item_iterator, :table_data, iter, table_iterator: filter)



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/data_list_converter/base.rb', line 48

def convert(from_type, to_type, from_value, options={})
  methods = []
  add_filter = lambda { |type|
    filters = (options[type] || {}).delete(:filter)
    return unless filters
    methods += normalize_filters(type, filters)
  }

  route = find_route(from_type, to_type)
  add_filter.call(route[0])

  self.log("route: #{route}")
  (0..(route.length-2)).map do |i|
    from_type, to_type = route[i], route[i+1]
    method = CONVERTERS[[from_type, to_type]]
    raise "cannot find converter #{from_type} -> #{to_type}" unless method
    methods.push([method, options[to_type] || {}])
    add_filter.call(to_type)
  end

  self.log("methods: #{methods}")
  methods.inject(from_value) do |v, method|
    method, args = method
    method.call(v, args)
  end
end

.data_to_iterator(data, options = {}) ⇒ Object



43
44
45
46
47
48
49
# File 'lib/data_list_converter/types/basic.rb', line 43

def self.data_to_iterator(data, options={})
  lambda { |&block|
    data.each do |d|
      block.call(d)
    end
  }
end

.find_route(from_type, to_type) ⇒ Object

One type of data can be converted into any other types, we have a list of convert methods: CONVERTERS If we want to convert between types, like: convert item_data into csv_file, we need find all the intermidate data type, like: [:item_data, :item_iterator, :table_iterator, :csv_file]

Raises:

  • (Exception)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/data_list_converter/base.rb', line 97

def find_route(from_type, to_type)
  raise Exception, "from_type should not equal to to_type: #{from_type}" if from_type == to_type
  # map wide search
  checked = Set.new
  checking = Set.new([from_type])
  directions = {}

  while not checking.empty?
    current_node = checking.first

    next_nodes = route_map[current_node]
    # mark direction from from_type
    next_nodes.each do |node|
      # first marked is the shortest
      directions[node] ||= current_node
    end

    if next_nodes.include?(to_type)
      # get route
      start = to_type
      route = [start]
      while start != from_type
        previous = directions[start]
        raise "cannot find previous for #{start} in #{directions}" if not previous
        route.push(previous)
        start = previous
      end
      return route.reverse
    else
      checking.delete(current_node)
      checked.add(current_node)
      checking += Set.new(next_nodes) - checked
    end
  end
  raise Exception, "Route not found: #{from_type} -> #{to_type}"
end

.iterator_limit(proc, options) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
# File 'lib/data_list_converter/filters/limit.rb', line 2

def self.iterator_limit(proc, options)
  limit_size = options[:size] || 10
  lambda { |&block|
    limit = 0
    proc.call do |item|
      block.call(item)
      limit += 1
      break if limit >= limit_size
    end
  }
end

.iterator_to_data(proc, options = {}) ⇒ Object



33
34
35
36
37
# File 'lib/data_list_converter/types/basic.rb', line 33

def self.iterator_to_data(proc, options={})
  out = []
  proc.call { |d| out << d }
  out
end

.log(msg) ⇒ Object



19
20
21
22
# File 'lib/data_list_converter/base.rb', line 19

def log(msg)
  return unless debug
  puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}\t#{msg}"
end

.normalize_filters(type, filters) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/data_list_converter/base.rb', line 75

def normalize_filters(type, filters)
  # filter list as array
  filters = [filters] unless filters.kind_of?(Array)
  filters.map do |v|
    # fix filter arguments
    case v
    # {:limit, {count: 12}} => [:limit, {count: 12}]
    when Hash; v.first
    # :debug => [:debug, {}]
    when Symbol, String; [v, {}]
    else; v
    end
  end.map do |name, args|
    method = FILTERS[type][name] rescue raise("cannot find method for type #{type} filter #{name}")
    [method, args]
  end
end

.on_debugObject



12
13
14
15
16
17
# File 'lib/data_list_converter/base.rb', line 12

def on_debug
  self.debug = true
  yield
ensure
  self.debug = false
end

.register_converter(from_type, to_type, method) ⇒ Object



28
29
30
31
# File 'lib/data_list_converter/base.rb', line 28

def register_converter(from_type, to_type, method)
  @route_map = nil # clear cache
  CONVERTERS[[from_type, to_type]] = method
end

.register_filter(type, name, method) ⇒ Object



33
34
35
36
# File 'lib/data_list_converter/base.rb', line 33

def register_filter(type, name, method)
  FILTERS[type] ||= {}
  FILTERS[type][name] = method
end

.route_mapObject

convert adjacency list into quick lookup hash



135
136
137
138
139
140
141
142
143
144
145
# File 'lib/data_list_converter/base.rb', line 135

def route_map
  @route_map ||= \
  begin
    CONVERTERS.keys.
      inject({}) do |map, item|
      map[item.first] ||= []
      map[item.first] += [item[1]]
      map
    end
  end
end

.typesObject



24
25
26
# File 'lib/data_list_converter/base.rb', line 24

def types
  CONVERTERS.keys.flatten.uniq.sort
end