sycsvpro 0.0.1
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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +20 -0
- data/README.md +188 -0
- data/README.rdoc +44 -0
- data/Rakefile +44 -0
- data/bin/sycsvpro +208 -0
- data/features/step_definitions/sycsvpro_steps.rb +6 -0
- data/features/support/env.rb +15 -0
- data/features/sycsvpro.feature +8 -0
- data/html/Dsl.html +201 -0
- data/html/Object.html +116 -0
- data/html/README_rdoc.html +178 -0
- data/html/Sycsvpro/Analyzer.html +239 -0
- data/html/Sycsvpro/Calculator.html +354 -0
- data/html/Sycsvpro/Collector.html +281 -0
- data/html/Sycsvpro/ColumnFilter.html +165 -0
- data/html/Sycsvpro/Counter.html +397 -0
- data/html/Sycsvpro/Extractor.html +269 -0
- data/html/Sycsvpro/Filter.html +349 -0
- data/html/Sycsvpro/Header.html +228 -0
- data/html/Sycsvpro/Mapper.html +288 -0
- data/html/Sycsvpro/Profiler.html +234 -0
- data/html/Sycsvpro/RowFilter.html +162 -0
- data/html/Sycsvpro.html +141 -0
- data/html/created.rid +17 -0
- data/html/fonts/Lato-Light.ttf +0 -0
- data/html/fonts/Lato-LightItalic.ttf +0 -0
- data/html/fonts/Lato-Regular.ttf +0 -0
- data/html/fonts/Lato-RegularItalic.ttf +0 -0
- data/html/fonts/SourceCodePro-Bold.ttf +0 -0
- data/html/fonts/SourceCodePro-Regular.ttf +0 -0
- data/html/fonts.css +167 -0
- data/html/images/add.png +0 -0
- data/html/images/arrow_up.png +0 -0
- data/html/images/brick.png +0 -0
- data/html/images/brick_link.png +0 -0
- data/html/images/bug.png +0 -0
- data/html/images/bullet_black.png +0 -0
- data/html/images/bullet_toggle_minus.png +0 -0
- data/html/images/bullet_toggle_plus.png +0 -0
- data/html/images/date.png +0 -0
- data/html/images/delete.png +0 -0
- data/html/images/find.png +0 -0
- data/html/images/loadingAnimation.gif +0 -0
- data/html/images/macFFBgHack.png +0 -0
- data/html/images/package.png +0 -0
- data/html/images/page_green.png +0 -0
- data/html/images/page_white_text.png +0 -0
- data/html/images/page_white_width.png +0 -0
- data/html/images/plugin.png +0 -0
- data/html/images/ruby.png +0 -0
- data/html/images/tag_blue.png +0 -0
- data/html/images/tag_green.png +0 -0
- data/html/images/transparent.png +0 -0
- data/html/images/wrench.png +0 -0
- data/html/images/wrench_orange.png +0 -0
- data/html/images/zoom.png +0 -0
- data/html/index.html +202 -0
- data/html/js/darkfish.js +140 -0
- data/html/js/jquery.js +18 -0
- data/html/js/navigation.js +142 -0
- data/html/js/search.js +109 -0
- data/html/js/search_index.js +1 -0
- data/html/js/searcher.js +228 -0
- data/html/rdoc.css +580 -0
- data/html/table_of_contents.html +236 -0
- data/lib/sycsvpro/analyzer.rb +40 -0
- data/lib/sycsvpro/calculator.rb +94 -0
- data/lib/sycsvpro/collector.rb +60 -0
- data/lib/sycsvpro/column_filter.rb +23 -0
- data/lib/sycsvpro/counter.rb +74 -0
- data/lib/sycsvpro/dsl.rb +37 -0
- data/lib/sycsvpro/extractor.rb +39 -0
- data/lib/sycsvpro/filter.rb +98 -0
- data/lib/sycsvpro/header.rb +29 -0
- data/lib/sycsvpro/mapper.rb +53 -0
- data/lib/sycsvpro/profiler.rb +26 -0
- data/lib/sycsvpro/row_filter.rb +20 -0
- data/lib/sycsvpro/version.rb +5 -0
- data/lib/sycsvpro.rb +9 -0
- data/spec/sycsvpro/analyze_spec.rb +23 -0
- data/spec/sycsvpro/calculator_spec.rb +45 -0
- data/spec/sycsvpro/collector_spec.rb +27 -0
- data/spec/sycsvpro/counter_spec.rb +51 -0
- data/spec/sycsvpro/extractor_spec.rb +27 -0
- data/spec/sycsvpro/files/mappings +6 -0
- data/spec/sycsvpro/files/profile.rb +42 -0
- data/spec/sycsvpro/mapper_spec.rb +33 -0
- data/spec/sycsvpro/profiler_spec.rb +32 -0
- data/sycsvpro.gemspec +24 -0
- data/sycsvpro.rdoc +29 -0
- metadata +215 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
# Operating csv files
|
|
4
|
+
module Sycsvpro
|
|
5
|
+
|
|
6
|
+
# Creates a new filter that can be extended by sub-classes. A sub-class needs to override the
|
|
7
|
+
# process method
|
|
8
|
+
class Filter
|
|
9
|
+
|
|
10
|
+
# When date are used as filters the date format has to be provided
|
|
11
|
+
attr_reader :date_format
|
|
12
|
+
# Filter for rows and columns
|
|
13
|
+
attr_reader :filter
|
|
14
|
+
# Pattern that is used as a filter
|
|
15
|
+
attr_reader :pattern
|
|
16
|
+
# Comparison that is used as a filter
|
|
17
|
+
attr_reader :pivot
|
|
18
|
+
|
|
19
|
+
# Creates a new filter
|
|
20
|
+
def initialize(values, options={})
|
|
21
|
+
@date_format = options[:df] || "%Y-%m-%d"
|
|
22
|
+
@filter = []
|
|
23
|
+
@pattern = []
|
|
24
|
+
@pivot = {}
|
|
25
|
+
create_filter(values)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Creates the filters based on the given patterns
|
|
29
|
+
def method_missing(id, *args, &block)
|
|
30
|
+
return equal($1, args, block) if id =~ /^(\d+)$/
|
|
31
|
+
return range($1, $2, args, block) if id =~ /^(\d+)-(\d+)$/
|
|
32
|
+
return regex($1, args, block) if id =~ /^\/(.*)\/$/
|
|
33
|
+
return col_regex($1, $2, args, block) if id =~ /^(\d+):\/(.*)\/$/
|
|
34
|
+
return date($1, $2, $3, args, block) if id =~ /^(\d+):(<|=|>)(\d+.\d+.\d+)/
|
|
35
|
+
return date_range($1, $2, $3, args, block) if id =~ /^(\d+):(\d+.\d+.\d+.)-(\d+.\d+.\d+)$/
|
|
36
|
+
super
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Processes the filter. Needs to be overridden by the sub-class
|
|
40
|
+
def process(object, options={})
|
|
41
|
+
raise 'Needs to be overridden by sub class'
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Yields the column value and whether the filter matches the column
|
|
45
|
+
def pivot_each_column(values=[])
|
|
46
|
+
pivot.each do |column, parameters|
|
|
47
|
+
yield column, eval(parameters[:operation].gsub('[value]', values[parameters[:col].to_i]))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# Creates a filter based on the provided rows and columns
|
|
54
|
+
def create_filter(values)
|
|
55
|
+
values.split(',').each { |f| send(f) } unless values.nil?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Adds a single value to the filter
|
|
59
|
+
def equal(value, args, block)
|
|
60
|
+
filter << value.to_i unless filter.index(value.to_i)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Adds a range to the filter
|
|
64
|
+
def range(start_value, end_value, args, block)
|
|
65
|
+
filter << (start_value.to_i..end_value.to_i).to_a
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Adds a regex to the pattern filter
|
|
69
|
+
def regex(value, args, block)
|
|
70
|
+
pattern << value unless pattern.index(value)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Adds a comparisson filter
|
|
74
|
+
def col_regex(col, r, args, block)
|
|
75
|
+
operation = "'[value]' =~ Regexp.new('#{r}')"
|
|
76
|
+
pivot[r] = { col: col, operation: operation }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Adds a date filter
|
|
80
|
+
def date(col, comparator, date, args, block)
|
|
81
|
+
comparator = '==' if comparator == '='
|
|
82
|
+
operation = "Date.strptime(\"[value]\", \"#{date_format}\") #{comparator} " +
|
|
83
|
+
"Date.strptime(\"#{date}\", \"#{date_format}\")"
|
|
84
|
+
pivot["#{comparator}#{date}"] = { col: col, operation: operation }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Adds a date range filter
|
|
88
|
+
def date_range(col, start_date, end_date, args, block)
|
|
89
|
+
operation = " Date.strptime(\"#{start_date}\", \"#{date_format}\") " +
|
|
90
|
+
"<= Date.strptime(\"[value]\", \"#{date_format}\") && " +
|
|
91
|
+
" Date.strptime(\"[value]\", \"#{date_format}\") " +
|
|
92
|
+
"<= Date.strptime(\"#{end_date}\", \"#{date_format}\")"
|
|
93
|
+
pivot["#{start_date}-#{end_date}"] = { col: col, operation: operation }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require_relative 'filter'
|
|
2
|
+
|
|
3
|
+
# Operating csv files
|
|
4
|
+
module Sycsvpro
|
|
5
|
+
|
|
6
|
+
# Creates a header
|
|
7
|
+
class Header < Filter
|
|
8
|
+
|
|
9
|
+
# Header columns
|
|
10
|
+
attr_reader :header_cols
|
|
11
|
+
|
|
12
|
+
# Create a new header
|
|
13
|
+
def initialize(header)
|
|
14
|
+
unless header.nil? or header.empty?
|
|
15
|
+
@header_cols = header.split(',')
|
|
16
|
+
else
|
|
17
|
+
@header_cols = []
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns the header
|
|
22
|
+
def process(line)
|
|
23
|
+
return "" if @header_cols.empty?
|
|
24
|
+
@header_cols[0] = line.split(';')
|
|
25
|
+
@header_cols.flatten.join(';')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Operating csv files
|
|
2
|
+
module Sycsvpro
|
|
3
|
+
|
|
4
|
+
# Map values to new values described in a mapping file
|
|
5
|
+
class Mapper
|
|
6
|
+
|
|
7
|
+
# infile contains the data that is operated on
|
|
8
|
+
attr_reader :infile
|
|
9
|
+
# outfile is the file where the result is written to
|
|
10
|
+
attr_reader :outfile
|
|
11
|
+
# file that contains the mappings from existing column values to new values
|
|
12
|
+
attr_reader :mapper
|
|
13
|
+
# filter that is used for rows
|
|
14
|
+
attr_reader :row_filter
|
|
15
|
+
# filter that is used for columns
|
|
16
|
+
attr_reader :col_filter
|
|
17
|
+
|
|
18
|
+
# Creates new mapper
|
|
19
|
+
def initialize(options={})
|
|
20
|
+
@infile = options[:infile]
|
|
21
|
+
@outfile = options[:outfile]
|
|
22
|
+
@row_filter = RowFilter.new(options[:row_filter])
|
|
23
|
+
@col_filter = ColumnFilter.new(options[:col_filter])
|
|
24
|
+
@mapper = {}
|
|
25
|
+
init_mapper(options[:mapping])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Executes the mapper
|
|
29
|
+
def execute
|
|
30
|
+
File.open(outfile, 'w') do |out|
|
|
31
|
+
File.new(infile, 'r').each_with_index do |line, index|
|
|
32
|
+
result = col_filter.process(row_filter.process(line, row: index))
|
|
33
|
+
next if result.chomp.empty? or result.nil?
|
|
34
|
+
mapper.each do |from, to|
|
|
35
|
+
result = result.chomp.gsub(/(?<=^|;)#{from}(?=;|$)/, to)
|
|
36
|
+
end
|
|
37
|
+
out.puts result
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Initializes the mappings
|
|
45
|
+
def init_mapper(file)
|
|
46
|
+
File.new(file, 'r').each_line do |line|
|
|
47
|
+
from, to = line.chomp.split(':')
|
|
48
|
+
mapper[from] = to
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative 'dsl'
|
|
2
|
+
|
|
3
|
+
# Operating csv files
|
|
4
|
+
module Sycsvpro
|
|
5
|
+
|
|
6
|
+
# A profiler takes a Ruby script and executes the provided method in the script
|
|
7
|
+
class Profiler
|
|
8
|
+
|
|
9
|
+
include Dsl
|
|
10
|
+
|
|
11
|
+
# Ruby script file
|
|
12
|
+
attr_reader :pro_file
|
|
13
|
+
|
|
14
|
+
# Creates a new profiler
|
|
15
|
+
def initialize(pro_file)
|
|
16
|
+
require pro_file
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Executes the provided method in the Ruby script
|
|
20
|
+
def execute(method)
|
|
21
|
+
send(method)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require_relative 'filter'
|
|
2
|
+
|
|
3
|
+
# Operating csv files
|
|
4
|
+
module Sycsvpro
|
|
5
|
+
|
|
6
|
+
# Filters rows based on provided patterns
|
|
7
|
+
class RowFilter < Filter
|
|
8
|
+
|
|
9
|
+
# Processes the filter on the given row
|
|
10
|
+
def process(object, options={})
|
|
11
|
+
filtered = (!filter.flatten.uniq.index(options[:row]).nil? or filter.empty?)
|
|
12
|
+
pattern.each do |p|
|
|
13
|
+
filtered = (filtered or !(object =~ Regexp.new(p)).nil?)
|
|
14
|
+
end
|
|
15
|
+
filtered ? object : nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
data/lib/sycsvpro.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require 'sycsvpro/version.rb'
|
|
2
|
+
require 'sycsvpro/analyzer.rb'
|
|
3
|
+
require 'sycsvpro/extractor.rb'
|
|
4
|
+
require 'sycsvpro/profiler.rb'
|
|
5
|
+
require 'sycsvpro/counter.rb'
|
|
6
|
+
require 'sycsvpro/collector.rb'
|
|
7
|
+
require 'sycsvpro/mapper.rb'
|
|
8
|
+
require 'sycsvpro/header.rb'
|
|
9
|
+
require 'sycsvpro/calculator.rb'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'sycsvpro/analyzer.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Analyzer do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@in_file = File.join(File.dirname(__FILE__), "files/in.csv")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should analyze infile" do
|
|
12
|
+
analyzer = Analyzer.new(@in_file)
|
|
13
|
+
result = analyzer.result
|
|
14
|
+
result.cols.should =~ ['customer', 'contract-number', 'expires-on', 'machine',
|
|
15
|
+
'product1', 'product2']
|
|
16
|
+
result.col_count.should eq 6
|
|
17
|
+
result.row_count.should eq 5
|
|
18
|
+
result.sample_row.should eq "Fink;1234;20.12.2015;f1;con123;dri222"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'sycsvpro/calculator.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Calculator do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@in_file = File.join(File.dirname(__FILE__), "files/machines.csv")
|
|
9
|
+
@out_file = File.join(File.dirname(__FILE__), "files/machines_out.csv")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should operate on existing row" do
|
|
13
|
+
rows = "2-8"
|
|
14
|
+
cols = "3:*3,4:*4+1"
|
|
15
|
+
calculator = Calculator.new(infile: @in_file, outfile: @out_file, rows: rows, cols: cols)
|
|
16
|
+
calculator.execute
|
|
17
|
+
|
|
18
|
+
result = ["Fink;2;2;3;5", "Haas;3;3;3;5.0", "Gent;4;4;3;5", "Rank;5;5;3;5"]
|
|
19
|
+
|
|
20
|
+
File.new(@out_file, 'r').each_with_index do |line, index|
|
|
21
|
+
expect(line.chomp).to eq result[index]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should add additional rows" do
|
|
26
|
+
header = "*,drives,motors"
|
|
27
|
+
rows = "1-8"
|
|
28
|
+
cols = "5:c3+c4,6:c3*2"
|
|
29
|
+
calculator = Calculator.new(infile: @in_file, outfile: @out_file,
|
|
30
|
+
header: header, rows: rows, cols: cols)
|
|
31
|
+
calculator.execute
|
|
32
|
+
|
|
33
|
+
result = ["customer;machines;controls;contracts;visits;drives;motors",
|
|
34
|
+
"Fink;2;2;1;1;2;2",
|
|
35
|
+
"Haas;3;3;1;1.0;2.0;2",
|
|
36
|
+
"Gent;4;4;1;1;2;2",
|
|
37
|
+
"Rank;5;5;1;1;2;2"]
|
|
38
|
+
|
|
39
|
+
File.new(@out_file, 'r').each_with_index do |line, index|
|
|
40
|
+
expect(line.chomp).to eq result[index]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'sycsvpro/collector.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Collector do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@in_file = File.join(File.dirname(__FILE__), "files/in.csv")
|
|
9
|
+
@out_file = File.join(File.dirname(__FILE__), "files/out.csv")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should collect and categorize values" do
|
|
13
|
+
collector = Collector.new(infile: @in_file, outfile: @out_file,
|
|
14
|
+
cols: "customer:0+products:4,5", rows: "1-20")
|
|
15
|
+
collector.execute
|
|
16
|
+
|
|
17
|
+
result = ['[customer]', 'Fink', 'Gent', 'Haas', 'Rank',
|
|
18
|
+
'[products]', 'con123', 'con332', 'con333',
|
|
19
|
+
'dri111', 'dri222', 'dri321']
|
|
20
|
+
File.open(@out_file).each_with_index do |line, index|
|
|
21
|
+
line.chomp.should eq result[index]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'sycsvpro/counter.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Counter do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@in_file = File.join(File.dirname(__FILE__), "files/in.csv")
|
|
9
|
+
@out_file = File.join(File.dirname(__FILE__), "files/out.csv")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should count columns" do
|
|
13
|
+
counter = Counter.new(infile: @in_file, outfile: @out_file, rows: "1-10", cols: "4,5",
|
|
14
|
+
key: "0")
|
|
15
|
+
|
|
16
|
+
counter.execute
|
|
17
|
+
|
|
18
|
+
result = [ "customer;con123;con332;con333;dri111;dri222;dri321",
|
|
19
|
+
"Fink;1;0;1;0;1;1",
|
|
20
|
+
"Haas;0;1;0;1;0;0",
|
|
21
|
+
"Gent;1;0;0;1;0;0",
|
|
22
|
+
"Rank;0;1;0;0;0;1" ]
|
|
23
|
+
|
|
24
|
+
File.open(@out_file).each_with_index do |line, index|
|
|
25
|
+
line.chomp.should eq result[index]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should count date coloms" do
|
|
31
|
+
counter = Counter.new(infile: @in_file, outfile: @out_file, rows: "1-10",
|
|
32
|
+
cols: "2:<1.1.2013,2:1.1.2013-31.12.2014,2:>31.12.2014", key: "0",
|
|
33
|
+
df: "%d.%m.%Y")
|
|
34
|
+
|
|
35
|
+
counter.execute
|
|
36
|
+
|
|
37
|
+
result = [ "customer;1.1.2013-31.12.2014;<1.1.2013;>31.12.2014",
|
|
38
|
+
"Fink;0;0;2",
|
|
39
|
+
"Haas;0;1;0",
|
|
40
|
+
"Gent;1;0;0",
|
|
41
|
+
"Rank;1;0;0" ]
|
|
42
|
+
|
|
43
|
+
File.open(@out_file).each_with_index do |line, index|
|
|
44
|
+
line.chomp.should eq result[index]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'sycsvpro/extractor.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Extractor do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@in_file = File.join(File.dirname(__FILE__), "files/in.csv")
|
|
9
|
+
@out_file = File.join(File.dirname(__FILE__), "files/out.csv")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should extract rows and columns" do
|
|
13
|
+
extractor = Extractor.new(infile: @in_file, outfile: @out_file, rows: "2-4", cols: "1,3")
|
|
14
|
+
|
|
15
|
+
extractor.execute
|
|
16
|
+
|
|
17
|
+
result = ["3322;h1", "4323;g1", "3342;f2"]
|
|
18
|
+
|
|
19
|
+
File.open(@out_file).each_with_index do |line, index|
|
|
20
|
+
line.chomp.should eq result[index]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# This is an example of a sycsvpro DSL to process a CSV file
|
|
2
|
+
|
|
3
|
+
def calc
|
|
4
|
+
|
|
5
|
+
customers = {}
|
|
6
|
+
heading = []
|
|
7
|
+
|
|
8
|
+
rows infile: "./spec/sycsvpro/files/in.csv",
|
|
9
|
+
row_filter: "1-20",
|
|
10
|
+
key_column: 0,
|
|
11
|
+
machine_column: 3,
|
|
12
|
+
data_columns: [4,5] do |key, machine, columns|
|
|
13
|
+
customer = customers[key] || customers[key] = { name: key, products: Hash.new(0) }
|
|
14
|
+
columns.each do |column|
|
|
15
|
+
heading << column if heading.index(column).nil?
|
|
16
|
+
customer[:products][column] += 1
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# puts heading.sort.join('-')
|
|
21
|
+
|
|
22
|
+
=begin
|
|
23
|
+
customers.each do |k,v|
|
|
24
|
+
print k
|
|
25
|
+
heading.sort.each do |h|
|
|
26
|
+
print " #{v[:products][h]} "
|
|
27
|
+
end
|
|
28
|
+
puts
|
|
29
|
+
end
|
|
30
|
+
=end
|
|
31
|
+
|
|
32
|
+
write_to "./spec/sycsvpro/files/out.csv" do |out|
|
|
33
|
+
out.puts (["customer"] + heading.sort).join(';')
|
|
34
|
+
customers.each do |k,v|
|
|
35
|
+
line = [k]
|
|
36
|
+
heading.sort.each do |h|
|
|
37
|
+
line << v[:products][h]
|
|
38
|
+
end
|
|
39
|
+
out.puts line.join(';')
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'sycsvpro/mapper.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Mapper do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@in_file = File.join(File.dirname(__FILE__), "files/in.csv")
|
|
9
|
+
@out_file = File.join(File.dirname(__FILE__), "files/out.csv")
|
|
10
|
+
@mappings = File.join(File.dirname(__FILE__), "files/mappings")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should map values to new values" do
|
|
14
|
+
mapper = Mapper.new(infile: @in_file, outfile: @out_file, mapping: @mappings)
|
|
15
|
+
|
|
16
|
+
mapper.execute
|
|
17
|
+
|
|
18
|
+
result = [ "customer;contract-number;expires-on;machine;product1;product2",
|
|
19
|
+
"Fink;1234;20.12.2015;f1;control123;drive222",
|
|
20
|
+
"Haas;3322;1.10.2011;h1;control332;drive111",
|
|
21
|
+
"Gent;4323;1.3.2014;g1;control123;drive111",
|
|
22
|
+
"Fink;3342;30.12.2016;f2;control333;drive321",
|
|
23
|
+
"Rank;3232;1.5.2013;r1;control332;drive321" ]
|
|
24
|
+
|
|
25
|
+
File.open(@out_file).each_with_index do |line, index|
|
|
26
|
+
line.chomp.should eq result[index]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'sycsvpro/profiler.rb'
|
|
2
|
+
|
|
3
|
+
module Sycsvpro
|
|
4
|
+
|
|
5
|
+
describe Profiler do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@profile = File.join(File.dirname(__FILE__), "files/profile.rb")
|
|
9
|
+
@method = "calc"
|
|
10
|
+
@out_file = File.join(File.dirname(__FILE__), "files/out.csv")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should execute the profile file" do
|
|
14
|
+
profiler = Profiler.new(@profile)
|
|
15
|
+
|
|
16
|
+
profiler.execute(@method)
|
|
17
|
+
|
|
18
|
+
result = [ "customer;con123;con332;con333;dri111;dri222;dri321",
|
|
19
|
+
"Fink;1;0;1;0;1;1",
|
|
20
|
+
"Haas;0;1;0;1;0;0",
|
|
21
|
+
"Gent;1;0;0;1;0;0",
|
|
22
|
+
"Rank;0;1;0;0;0;1" ]
|
|
23
|
+
|
|
24
|
+
File.open(@out_file).each_with_index do |line, index|
|
|
25
|
+
line.chomp.should eq result[index]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
data/sycsvpro.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Ensure we require the local version and not one we might have installed already
|
|
2
|
+
require File.join([File.dirname(__FILE__),'lib','sycsvpro','version.rb'])
|
|
3
|
+
spec = Gem::Specification.new do |s|
|
|
4
|
+
s.name = 'sycsvpro'
|
|
5
|
+
s.version = Sycsvpro::VERSION
|
|
6
|
+
s.author = 'Pierre Sugar'
|
|
7
|
+
s.email = 'pierre@sugaryourcoffee.de'
|
|
8
|
+
s.homepage = 'https://github.com/sugaryourcoffee/syc-svpro'
|
|
9
|
+
s.platform = Gem::Platform::RUBY
|
|
10
|
+
s.summary = 'Processing of csv files'
|
|
11
|
+
s.files = `git ls-files`.split("
|
|
12
|
+
")
|
|
13
|
+
s.require_paths << 'lib'
|
|
14
|
+
s.has_rdoc = true
|
|
15
|
+
s.extra_rdoc_files = ['README.rdoc','sycsvpro.rdoc']
|
|
16
|
+
s.rdoc_options << '--title' << 'sycsvpro' << '--main' << 'README.rdoc' << '-ri'
|
|
17
|
+
s.bindir = 'bin'
|
|
18
|
+
s.executables << 'sycsvpro'
|
|
19
|
+
s.add_development_dependency('rake')
|
|
20
|
+
s.add_development_dependency('rdoc')
|
|
21
|
+
s.add_development_dependency('aruba')
|
|
22
|
+
s.add_development_dependency('rspec')
|
|
23
|
+
s.add_runtime_dependency('gli','2.9.0')
|
|
24
|
+
end
|
data/sycsvpro.rdoc
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
= sycsvpro
|
|
2
|
+
|
|
3
|
+
NAME
|
|
4
|
+
sycsvpro - Processing CSV files
|
|
5
|
+
|
|
6
|
+
SYNOPSIS
|
|
7
|
+
sycsvpro [global options] command [command options] [arguments...]
|
|
8
|
+
|
|
9
|
+
VERSION
|
|
10
|
+
0.0.1
|
|
11
|
+
|
|
12
|
+
GLOBAL OPTIONS
|
|
13
|
+
-f, --file=FILE - CSV file to operate on (default: none)
|
|
14
|
+
--help - Show this message
|
|
15
|
+
-o, --out=OUT_FILE - CSV file to write the result to (default: none)
|
|
16
|
+
--version - Display the program version
|
|
17
|
+
|
|
18
|
+
COMMANDS
|
|
19
|
+
analyze - Analyze the CSV file regarding columns, rows and content
|
|
20
|
+
calc - Process math operations on columns
|
|
21
|
+
collect - Collect values of specified rows and columns from the file and group them in
|
|
22
|
+
categories
|
|
23
|
+
count - Counts the occurences of column values. Uses column values as headings with count as
|
|
24
|
+
values. Columns with a condition will be added as new columns and the condition will
|
|
25
|
+
be set as column name
|
|
26
|
+
execute - Executes the code provided in a file
|
|
27
|
+
extract - Extract specified rows and columns from the file
|
|
28
|
+
help - Shows a list of commands or help for one command
|
|
29
|
+
map - Map values in columns to new values
|