data_list_converter 0.3.10 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85c9410c6b8c64a1af696f42485e098f43f432c2
4
- data.tar.gz: 930b7bb74e9d441e183451d4329e639c06aa3cdf
3
+ metadata.gz: 7862bf6ab71eb4187b03ba25e7bd199ea9d3eb51
4
+ data.tar.gz: f095138e55e9cc72c1691628c782a9c7ec5a203d
5
5
  SHA512:
6
- metadata.gz: b53cb6e80ac57b256b74100421b12d14c9e1f57bee172807bb0f6437efe27e2c2c8915705d52b0e1ff01855188a6e4a3ac274138f7623cbec648a187ba349631
7
- data.tar.gz: c87df4a93536be36f7aec7d88c3c93325b39fe03ab09414d4d1533024569e6d550f46cfff724df48bd39612bd6b52727473acbe20b1fdd273b92194b4f9286fc
6
+ metadata.gz: dfaa0989bafc3ae7e8d8675827b5728dd0476e1f62f79021b121407af2fa05ee4b47456f1db22aa46eb3aadfb4549a4ca3d0cf0c85bd0f8e6334c5105b36f1aa
7
+ data.tar.gz: f9056d920a5164dc109490c809fd8d57174ffcc30d6851f52cb676937befce297e42ff89c702b60b2d2b825c3edc55b8b744538744296bb6c83c36e4a1bcf9ad
data/README.md CHANGED
@@ -22,61 +22,73 @@ DataListConverter.convert(:xls_file, :multi_sheet_item_data, {filename: 'result.
22
22
  You can also add filter to this process:
23
23
 
24
24
  ```ruby
25
- filters = [
26
- # filter with default options
27
- :limit,
28
- # filter with options
29
- {limit: {size: 2}},
30
- # multiple filters
31
- [{limit: {size: 12}},
32
- {count: {size: 4}}],
33
- ]
34
- filters.map do |filter|
35
- data = [{name: "james"}] * 10
36
- DataListConverter.convert(:item_data, :table_data, data, table_iterator: {filter: filter})
37
- end
25
+ data = (1..20).map{|i| {name: "user-#{i}", age: i+20}}
26
+ # filter with default options (limit 10)
27
+ DataListConverter.convert(:item_data, :table_data, data, item_iterator: {filter: :limit})
28
+ # filter with options
29
+ DataListConverter.convert(:item_data, :table_data, data, item_iterator: {filter: {limit: {size: 2}}})
30
+ # multiple filters
31
+ DataListConverter.convert(:item_data, :table_data, data, item_iterator: {filter: [{limit: {size: 12}}, {count: {size: 4}}]})
38
32
  ```
39
33
 
40
- Please read [the source code](https://github.com/halida/data_list_converter/blob/master/lib/data_list_converter/) for more information,
41
- also you can check [test examples](https://github.com/halida/data_list_converter/blob/master/test/).
42
-
43
34
  ## Data Types
44
35
 
36
+ Default data types:
37
+
45
38
  - **item_data** like: `[{name: 'James', age: '22'}, ...]`, keys should be symbol.
46
39
  - **item_iterator** iterator for item_data, used like: iter.call{|item| out << item}
47
40
  - **table_data** like: `[["name", "age"], ["James", "22"], ["Bob", "33"], ...]`
48
41
  - **table_iterator** iterator for table_data
49
- - **csv_file** file in csv format
50
- - **xls_file** file in excel format, should install `spreadsheet` gem, and `require 'data_list_converter/types/xls_file'`
51
- - **xlsx_file** file in excel xml format, should install `rubyXL` gem, and `require 'data_list_converter/types/xlsx_file'`
52
42
  - **multi_sheet** Contains several data with sheets:
53
43
  - **multi_sheet_table_iterator**: like: `{sheet1: table_iterator1, sheet2: table_iterator2}`
54
44
  - **multi_sheet_table_data**: like: `{sheet1: [['name', 'age'], ...], sheet2: ...}`
55
45
  - **multi_sheet_item_iterator**: like: `{sheet1: item_iterator1, sheet2: item_iterator2}`
56
46
  - **multi_sheet_item_data**: like: `{sheet1: [{name: 'James', age: 32}], sheet2: ...}`
57
- - **records** ActiveRecord records, usage: `DataListConverter.convert(:records, :item_data, Users.where(condition), item_iterator: {columns: [:name, :age]})`
58
47
 
48
+ Plugin data types, should required first by `require 'data_list_converter/types/#{type}'`
49
+
50
+ - **csv_file** file in csv format
51
+ - **xls_file** file in excel format, should install `spreadsheet` gem first
52
+ - **xlsx_file** file in excel xml format, should install `rubyXL` gem first
53
+ - **records** ActiveRecord records
54
+
55
+ Please check [test examples](https://github.com/halida/data_list_converter/blob/master/test/types_test.rb) to see how to use those types.
59
56
 
60
57
  ## Filters
61
58
 
62
- **item_iterator/table_iterator limit**: limit item_iterator result counts, usage: `DataListConverter.convert(:item_data, :table_data, item_data, item_iterator: {filter: {limit: {size: 2}}})`
59
+ **item_iterator/table_iterator limit**: limit item_iterator result counts, usage: `DataListConverter.convert(:item_data, :table_data, item_data, item_iterator: {filter: {limit: {size: 2}}})`, default limit size is 10.
63
60
 
64
- **item_iterator count**: count item_iterator items, usage: `DataListConverter.convert(:xls_file, :item_data, {filename: 'result.xls'}, item_iterator: {filter: {count: {size: 10}}})`, it will print current item counts every `size`.
61
+ **item_iterator count**: count item_iterator items, usage: `DataListConverter.convert(:xls_file, :item_data, {filename: 'result.xls'}, item_iterator: {filter: {count: {size: 10}}})`, it will print current item counts every `size`, please [see here](https://github.com/halida/data_list_converter/blob/master/lib/data_list_converter/filters/count.rb) for more options.
65
62
 
66
- Please check more [test examples](https://github.com/halida/data_list_converter/blob/master/test/filters_test.rb)
63
+ Please see [test examples](https://github.com/halida/data_list_converter/blob/master/test/filters_test.rb) to learn how to use filter.
64
+
65
+ ## helpers
66
+
67
+ - **types**: Get current valid types.
68
+ - **routes**: Get current valid routes.
69
+ - **file_types**: Get current file types, which is the types has `_file` suffix.
70
+ - **get_file_format**: Get file type by filename, which compare file extension with `file_types`. `DataListConverter.get_file_format('xxx.xls') == :xls_file`
71
+ - **save_to_file**: Save data to file, it will use `get_file_format` to find proper file format. `DataListConverter.save_to_file(filename, data, data_format=:item_data)`
72
+ - **load_from_file**: Get data from file, it will use `get_file_format` to find proper file format. `DataListConverter.load_from_file(filename, data_format=:item_data)`
73
+ - **unify_item_data_keys**: Sometimes in the `item_data` list, each data keys don't exactly same, so use this function to fix it, example: `DataListConverter.unify_item_data_keys([{a: 12}, {b: 11}]) == [{a: 12, b: nil}, {a: nil, b: 11}]`.
74
+ - **flatten**: Flatten multi level item_data list into one level, example: `DataListConverter.flatten({a: {b: 12}, c: {d: {e: 11}}}) == {:"a:b"=>12, :"c:d:e"=>11}`, can change seperator: `DataListConverter.flatten(data, '_')`
67
75
 
68
76
  ## Extend
69
77
 
70
78
  You can add your own data types and filters, example:
71
79
 
72
80
  ```ruby
73
- DataListConverter.register_converter(:records, :item_iterator) do |records, options|
74
- columns = options[:columns]
81
+ DataListConverter.register_converter(:records, :item_iterator) do |input, options|
82
+ query = self.parameter(input, :query, :input)
83
+ columns = self.parameter(input, :columns, :input)
84
+ display = input[:display] || columns
85
+
75
86
  lambda { |&block|
76
- records.find_each do |record|
77
- item = columns.map do |column|
78
- [column.first.to_sym, record.send(column[1])]
79
- end.to_h
87
+ query.pluck(*columns).each do |data|
88
+ item = {}
89
+ data.each_with_index do |d, i|
90
+ item[display[i]] = d
91
+ end
80
92
  block.call(item)
81
93
  end
82
94
  }
@@ -94,14 +106,3 @@ DataListConverter.register_filter(:item_iterator, :limit) do |proc, options|
94
106
  }
95
107
  end
96
108
  ```
97
-
98
-
99
- ## Todo
100
-
101
- - check type exists
102
- - route not found, list all routes
103
- - register can bind method again
104
- - better API
105
- - better error message
106
- - load file/save file with auto format by extname
107
- - report error when cannot find type
data/changelog.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.4
2
+
3
+ Add parameter check, type check, change record type API.
4
+
1
5
  ## 0.3
2
6
 
3
7
  Refactor.
@@ -17,6 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.add_development_dependency 'spreadsheet', '~> 1.0'
18
18
  s.add_development_dependency 'rubyXL', '~> 3.3'
19
19
  s.add_development_dependency 'pry', '~> 0.10.1'
20
+ s.add_development_dependency 'sqlite3', '~> 1.3'
21
+ s.add_development_dependency 'activerecord', '~> 4.2'
20
22
 
21
23
  s.files = `git ls-files`.split("\n")
22
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -21,6 +21,7 @@ class DataListConverter
21
21
  puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}\t#{msg}"
22
22
  end
23
23
 
24
+ # register_converter(:item_data, :item_iterator){ |data, options| ... }
24
25
  def register_converter(from_type, to_type, &block)
25
26
  @route_map = nil # clear cache
26
27
  CONVERTERS[[from_type, to_type]] = block
@@ -91,7 +92,11 @@ class DataListConverter
91
92
  # If we want to convert between types, like: convert item_data into csv_file,
92
93
  # we need find all the intermidate data type, like: [:item_data, :item_iterator, :table_iterator, :csv_file]
93
94
  def find_route(from_type, to_type)
95
+ [from_type, to_type].each do |type|
96
+ raise Exception, "cannot find type: #{type}" unless self.types.include?(type)
97
+ end
94
98
  raise Exception, "from_type should not equal to to_type: #{from_type}" if from_type == to_type
99
+
95
100
  # map wide search
96
101
  checked = Set.new
97
102
  checking = Set.new([from_type])
@@ -124,7 +129,10 @@ class DataListConverter
124
129
  checking += Set.new(next_nodes) - checked
125
130
  end
126
131
  end
127
- raise Exception, "Route not found: #{from_type} -> #{to_type}"
132
+
133
+ log = ["Route not found: #{from_type} -> #{to_type}", "Current routes:"]
134
+ log += self.routes.map{|from, to| "#{from} -> #{to}"}
135
+ raise Exception, log.join("\n")
128
136
  end
129
137
 
130
138
  # convert adjacency list into quick lookup hash
@@ -5,6 +5,7 @@ class DataListConverter
5
5
  msg_format = options[:msg] || "on %{count}"
6
6
  total_format = options[:total] || "total: %{total}"
7
7
  out = options[:out] || STDOUT
8
+
8
9
  total = 1
9
10
  lambda { |&block|
10
11
  proc.call do |item|
@@ -23,6 +23,10 @@ class DataListConverter
23
23
  CONVERTERS.keys.flatten.uniq.sort
24
24
  end
25
25
 
26
+ def self.routes
27
+ CONVERTERS.keys
28
+ end
29
+
26
30
  def self.file_types
27
31
  matcher = /(.*)_file$/
28
32
  DataListConverter.types.select do |type|
@@ -69,4 +73,10 @@ class DataListConverter
69
73
  end
70
74
  end
71
75
 
76
+ def self.parameter(data, key, type)
77
+ raise Exception, "`#{type}` should be hash, not `#{data.class}`: #{data}" unless data.kind_of?(Hash)
78
+ raise Exception, "Need `#{key}` for `#{type}`, current: #{data}" if not data.has_key?(key)
79
+ data.fetch(key)
80
+ end
81
+
72
82
  end
@@ -3,7 +3,8 @@ require 'csv'
3
3
  class DataListConverter
4
4
  self.register_converter(:csv_file, :table_iterator) do |input, options|
5
5
  lambda { |&block|
6
- CSV.open(input[:filename]) do |csv|
6
+ filename = self.parameter(input, :filename, :input)
7
+ CSV.open(filename) do |csv|
7
8
  csv.each do |row|
8
9
  block.call(row)
9
10
  end
@@ -12,7 +13,8 @@ class DataListConverter
12
13
  end
13
14
 
14
15
  self.register_converter(:table_iterator, :csv_file) do |proc, options|
15
- CSV.open(options[:filename], 'wb', force_quotes: true) do |csv|
16
+ filename = self.parameter(options, :filename, :csv_file)
17
+ CSV.open(filename, 'wb', force_quotes: true) do |csv|
16
18
  proc.call do |row|
17
19
  csv << row
18
20
  end
@@ -1,13 +1,15 @@
1
1
  class DataListConverter
2
2
 
3
3
  def self.marshal_file_to_data(input, options=nil)
4
- File.open(input[:filename]) do |f|
4
+ filename = self.parameter(input, :filename, :input)
5
+ File.open(filename) do |f|
5
6
  Marshal.load(f)
6
7
  end
7
8
  end
8
9
 
9
10
  def self.marshal_data_to_file(data, options)
10
- File.open(options[:filename], 'w+') do |f|
11
+ filename = self.parameter(options, :filename, :marshal)
12
+ File.open(filename, 'w+') do |f|
11
13
  Marshal.dump(data, f)
12
14
  end
13
15
  options[:filename]
@@ -1,13 +1,20 @@
1
1
  # ActiveRecords
2
2
  class DataListConverter
3
3
 
4
- self.register_converter(:records, :item_iterator) do |records, options|
5
- columns = options[:columns]
4
+ # columns = [:table_column1, :table_column2, ...]
5
+ # display = [:display_name1, :display_name2, ...]
6
+ # convert(:records, :item_data, query: query, columns: columns, display: display)
7
+ self.register_converter(:records, :item_iterator) do |input, options|
8
+ query = self.parameter(input, :query, :input)
9
+ columns = self.parameter(input, :columns, :input)
10
+ display = input[:display] || columns
11
+
6
12
  lambda { |&block|
7
- records.find_each do |record|
8
- item = columns.map do |column|
9
- [column[0].to_sym, record.send(column[1])]
10
- end.to_h
13
+ query.pluck(*columns).each do |data|
14
+ item = {}
15
+ data.each_with_index do |d, i|
16
+ item[display[i]] = d
17
+ end
11
18
  block.call(item)
12
19
  end
13
20
  }
@@ -5,7 +5,8 @@ class DataListConverter
5
5
 
6
6
  self.register_converter(:xls_file, :table_iterator) do |input, options|
7
7
  lambda { |&block|
8
- book = Spreadsheet.open(input[:filename])
8
+ filename = self.parameter(input, :filename, :input)
9
+ book = Spreadsheet.open(filename)
9
10
  sheet = book.worksheet input[:sheet] || 0
10
11
  sheet.each do |row|
11
12
  block.call(row.to_a)
@@ -21,8 +22,9 @@ class DataListConverter
21
22
  sheet.row(i).push *row
22
23
  i += 1
23
24
  end
24
- book.write(options[:filename])
25
- options[:filename]
25
+ filename = self.parameter(options, :filename, :xls_file)
26
+ book.write(filename)
27
+ filename
26
28
  end
27
29
 
28
30
  self.register_converter(:multi_sheet_table_iterator, :xls_file) do |data, options|
@@ -35,13 +37,14 @@ class DataListConverter
35
37
  i += 1
36
38
  end
37
39
  end
38
- filename = options[:filename]
40
+ filename = self.parameter(options, :filename, :xls_file)
39
41
  book.write(filename)
40
42
  filename
41
43
  end
42
44
 
43
- self.register_converter(:xls_file, :multi_sheet_table_iterator) do |data, options|
44
- book = Spreadsheet.open(data[:filename])
45
+ self.register_converter(:xls_file, :multi_sheet_table_iterator) do |input, options|
46
+ filename = self.parameter(input, :filename, :input)
47
+ book = Spreadsheet.open(filename)
45
48
  book.worksheets.map do |sheet|
46
49
  iterator = lambda { |&block|
47
50
  sheet.each do |row|
@@ -5,7 +5,8 @@ class DataListConverter
5
5
 
6
6
  self.register_converter(:xlsx_file, :table_iterator) do |input, options|
7
7
  lambda { |&block|
8
- book = RubyXL::Parser.parse(input[:filename])
8
+ filename = self.parameter(input, :filename, :input)
9
+ book = RubyXL::Parser.parse(filename)
9
10
  sheet = book.worksheets[input[:sheet] || 0]
10
11
  sheet.each do |row|
11
12
  next unless row
@@ -26,7 +27,7 @@ class DataListConverter
26
27
  end
27
28
  i += 1
28
29
  end
29
- filename = options[:filename]
30
+ filename = self.parameter(options, :filename, :xlsx_file)
30
31
  book.write(filename)
31
32
  filename
32
33
  end
@@ -55,13 +56,14 @@ class DataListConverter
55
56
  i += 1
56
57
  end
57
58
  end
58
- filename = options[:filename]
59
+ filename = self.parameter(options, :filename, :xlsx_file)
59
60
  book.write(filename)
60
61
  filename
61
62
  end
62
63
 
63
- self.register_converter(:xlsx_file, :multi_sheet_table_iterator) do |data, options|
64
- book = RubyXL::Parser.parse(data[:filename])
64
+ self.register_converter(:xlsx_file, :multi_sheet_table_iterator) do |input, options|
65
+ filename = self.parameter(input, :filename, :input)
66
+ book = RubyXL::Parser.parse(filename)
65
67
  book.worksheets.map do |sheet|
66
68
  iterator = lambda { |&block|
67
69
  sheet.each do |row|
@@ -1,3 +1,3 @@
1
1
  class DataListConverter
2
- VERSION = "0.3.10".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
data/test/base_test.rb CHANGED
@@ -40,6 +40,12 @@ describe DataListConverter do
40
40
  string.string.must_equal ".4\n.8\n.12\n"
41
41
  end
42
42
 
43
+ it 'test data format exists' do
44
+ -> {
45
+ DataListConverter.convert(:item_data, :ppp, {a: 12})
46
+ }.must_raise Exception
47
+ end
48
+
43
49
  end
44
50
 
45
51
  end
data/test/types_test.rb CHANGED
@@ -99,5 +99,36 @@ describe DataListConverter do
99
99
  end
100
100
  end
101
101
  end
102
+
103
+ describe :records do
104
+ specify do
105
+ require 'sqlite3'
106
+ require 'active_record'
107
+
108
+ ActiveRecord::Base.establish_connection(
109
+ adapter: 'sqlite3',
110
+ database: ':memory:'
111
+ )
112
+
113
+ ActiveRecord::Schema.define do
114
+ create_table :users, force: true do |t|
115
+ t.string :name
116
+ t.integer :age
117
+ end
118
+ end
119
+
120
+ class User < ActiveRecord::Base; end
121
+ (1..10).each{ |i| User.create(name: "user-#{i}", age: i+20) }
122
+
123
+ query = User.where("age > 25 and age < 27")
124
+ columns = [:name, :age]
125
+ @c.convert(:records, :item_data, query: query, columns: columns).
126
+ must_equal([{name: "user-6", age: 26}])
127
+
128
+ display = [:n, :a]
129
+ @c.convert(:records, :item_data, query: query, columns: columns, display: display).
130
+ must_equal([{n: "user-6", a: 26}])
131
+ end
132
+ end
102
133
 
103
134
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_list_converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - linjunhalida
@@ -80,6 +80,34 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.10.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.2'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.2'
83
111
  description: Data List Converter is a tool to convert data between different formats.
84
112
  email:
85
113
  - linjunhalida@gmail.com