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 +4 -4
- data/README.md +41 -40
- data/changelog.md +4 -0
- data/data_list_converter.gemspec +2 -0
- data/lib/data_list_converter/base.rb +9 -1
- data/lib/data_list_converter/filters/count.rb +1 -0
- data/lib/data_list_converter/helper.rb +10 -0
- data/lib/data_list_converter/types/csv_file.rb +4 -2
- data/lib/data_list_converter/types/marshal.rb +4 -2
- data/lib/data_list_converter/types/records.rb +13 -6
- data/lib/data_list_converter/types/xls_file.rb +9 -6
- data/lib/data_list_converter/types/xlsx_file.rb +7 -5
- data/lib/data_list_converter/version.rb +1 -1
- data/test/base_test.rb +6 -0
- data/test/types_test.rb +31 -0
- metadata +29 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7862bf6ab71eb4187b03ba25e7bd199ea9d3eb51
|
4
|
+
data.tar.gz: f095138e55e9cc72c1691628c782a9c7ec5a203d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
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 |
|
74
|
-
|
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
|
-
|
77
|
-
item =
|
78
|
-
|
79
|
-
|
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
data/data_list_converter.gemspec
CHANGED
@@ -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
|
-
|
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
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
5
|
-
|
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
|
-
|
8
|
-
item =
|
9
|
-
|
10
|
-
|
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
|
-
|
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
|
-
|
25
|
-
|
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
|
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 |
|
44
|
-
|
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
|
-
|
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
|
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
|
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 |
|
64
|
-
|
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|
|
data/test/base_test.rb
CHANGED
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.
|
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
|