xls 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/xls CHANGED
@@ -11,7 +11,41 @@ program :description, 'A command line utility for working with data in Excel.'
11
11
 
12
12
 
13
13
  ################################################################################
14
- # Processing
14
+ #
15
+ # Enumeration
16
+ #
17
+ ################################################################################
18
+
19
+ command :"enumerate" do |c|
20
+ c.syntax = 'xls enumerate FILE'
21
+ c.description = 'Executes Ruby code on each cell of a workbook.'
22
+ c.option('--selection SELECTION', 'The Excel style selection to work within.')
23
+ c.option('-e CODE', 'The code to execute for each cell.')
24
+ c.when_called do|args, options|
25
+ # Open input file.
26
+ abort("Input file required") if args.length == 0
27
+ workbook = Spreadsheet.open(args.first)
28
+
29
+ # Convert Ruby source to procs.
30
+ abort("Enumerator code required") if options.e.nil?
31
+ procs = options.e.is_a?(String) ? [options.e] : options.e
32
+ procs.map! {|source| eval("lambda { |cell, col_index, row_index| #{source} }")}
33
+
34
+ # Run enumerator.
35
+ enumerator = Xls::Enumerator.new()
36
+ enumerator.selection = Xls::Selection.parse(options.selection.upcase) unless options.selection.nil?
37
+ enumerator.procs = procs
38
+ enumerator.process(workbook)
39
+ end
40
+ end
41
+
42
+
43
+
44
+
45
+ ################################################################################
46
+ #
47
+ # Transformation
48
+ #
15
49
  ################################################################################
16
50
 
17
51
  command :columnize do |c|
@@ -21,15 +55,16 @@ command :columnize do |c|
21
55
  c.option('--fixed-columns COLUMNS', 'The columns that should stay fixed.')
22
56
  c.when_called do|args, options|
23
57
  # Open input file.
58
+ abort("Output file required") if options.output.nil?
24
59
  abort("Input file required") if args.length == 0
25
- workbook = Spreadsheet.open(args.first)
60
+ input = Spreadsheet.open(args.first)
26
61
 
27
62
  # Run columnizer.
28
63
  columnizer = Xls::Columnizer.new()
29
64
  columnizer.fixed_columns = options.fixed_columns.to_s.split(",")
30
- columnizer.execute(workbook)
65
+ output = columnizer.process(input)
31
66
 
32
- # Write output.
33
- workbook.write(options.output || $stdout)
67
+ # Write output to file.
68
+ output.write(options.output)
34
69
  end
35
70
  end
data/lib/xls.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'spreadsheet'
2
+ require 'tempfile'
2
3
 
3
4
  require 'xls/columnizer'
5
+ require 'xls/enumerator'
6
+ require 'xls/selection'
4
7
  require 'xls/version'
5
8
 
6
9
  class Xls
@@ -0,0 +1,61 @@
1
+ class Xls
2
+ class Enumerator
3
+ ############################################################################
4
+ #
5
+ # Constructor
6
+ #
7
+ ############################################################################
8
+
9
+ def initialize(options={})
10
+ self.selection = options[:selection]
11
+ self.procs = options[:procs] || []
12
+ end
13
+
14
+
15
+ ############################################################################
16
+ #
17
+ # Attributes
18
+ #
19
+ ############################################################################
20
+
21
+ # The selection to enumerate over.
22
+ attr_accessor :selection
23
+
24
+ # A list of procs to run on each cell.
25
+ attr_accessor :procs
26
+
27
+
28
+ ############################################################################
29
+ #
30
+ # Methods
31
+ #
32
+ ############################################################################
33
+
34
+ # Executes a set of procs on each cell in a selection.
35
+ #
36
+ # @param [Workbook] input The input workbook.
37
+ def process(input)
38
+ # Loop over each worksheet.
39
+ (0...input.sheet_count).each do |sheet_index|
40
+ sheet = input.worksheet(sheet_index)
41
+
42
+ # Loop over each row.
43
+ sheet.each do |row|
44
+ next unless selection.nil? || selection.rows.nil? || selection.rows.cover?(row.idx)
45
+
46
+ # Loop over each cell.
47
+ row.each_with_index do |cell, col_index|
48
+ next unless selection.nil? || selection.columns.nil? || selection.columns.cover?(col_index)
49
+
50
+ # Run each proc.
51
+ procs.each do |proc|
52
+ proc.call(cell.to_s, col_index, row.idx)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ return nil
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,99 @@
1
+ class Xls
2
+ class Selection
3
+ ############################################################################
4
+ #
5
+ # Error Classes
6
+ #
7
+ ############################################################################
8
+
9
+ class SelectionFormatError < StandardError; end
10
+
11
+
12
+ ############################################################################
13
+ #
14
+ # Static Methods
15
+ #
16
+ ############################################################################
17
+
18
+ # Parses an Excel style [COLUMN][ROW]:[COLUMN][ROW] format into a
19
+ # selection.
20
+ #
21
+ # @param [String] str The Excel-style selection.
22
+ #
23
+ # @return [Selection] A selection object.
24
+ def self.parse(str)
25
+ m, tl_col, tl_row, br_col, br_row = *str.to_s.match(/^([A-Z]+)?(\d+)?(?::([A-Z]+)?(\d+)?)?$/)
26
+ raise SelectionFormatError.new("Invalid selection: #{str}") if m.nil?
27
+
28
+ # Default bottom-right for single cell selection.
29
+ br_col = tl_col if br_col.nil?
30
+ br_row = tl_row if br_row.nil?
31
+
32
+ # Convert column letters to numbers.
33
+ columns = nil
34
+ if !tl_col.nil? && !br_col.nil?
35
+ tl_col = col_to_index(tl_col)
36
+ br_col = col_to_index(br_col)
37
+ tl_col, br_col = [tl_col, br_col].min, [tl_col, br_col].max
38
+ columns = (tl_col..br_col)
39
+ end
40
+
41
+ # Convert rows to zero-based indices.
42
+ rows = nil
43
+ if !tl_row.nil? && !br_row.nil?
44
+ tl_row = tl_row.to_i - 1
45
+ br_row = br_row.to_i - 1
46
+ tl_row, br_row = [tl_row, br_row].min, [tl_row, br_row].max
47
+ rows = (tl_row..br_row)
48
+ end
49
+
50
+ # Return a selection object.
51
+ return Xls::Selection.new(columns, rows)
52
+ end
53
+
54
+ # Converts column letters to integer indices.
55
+ def self.col_to_index(letters)
56
+ value = 0
57
+ letters.upcase.split('').each_with_index do |letter, index|
58
+ value = value + ((letter.ord - "A".ord) * (26 ** index))
59
+ end
60
+ return value
61
+ end
62
+
63
+
64
+ ############################################################################
65
+ #
66
+ # Constructor
67
+ #
68
+ ############################################################################
69
+
70
+ def initialize(columns, rows)
71
+ self.columns = columns
72
+ self.rows = rows
73
+ end
74
+
75
+
76
+ ############################################################################
77
+ #
78
+ # Attributes
79
+ #
80
+ ############################################################################
81
+
82
+ # A range of row indices that the selection covers.
83
+ attr_accessor :rows
84
+
85
+ # A range of column indices that the selection covers.
86
+ attr_accessor :columns
87
+
88
+ # An array of indicies (top-level column, top-left row, bottom-right
89
+ # column, bottom-right row).
90
+ def indices
91
+ return [
92
+ columns.nil? ? nil : columns.begin,
93
+ rows.nil? ? nil : rows.begin,
94
+ columns.nil? ? nil : columns.end,
95
+ rows.nil? ? nil : rows.end
96
+ ]
97
+ end
98
+ end
99
+ end
@@ -1,3 +1,3 @@
1
1
  class Xls
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class TestEnumerator < MiniTest::Unit::TestCase
4
+ def setup
5
+ @enumerator = Xls::Enumerator.new
6
+ end
7
+
8
+ ######################################
9
+ # Execute
10
+ ######################################
11
+
12
+ def test_enumerate
13
+ my_arr = []
14
+ input = Spreadsheet.open('fixtures/enumerator/basic.xls')
15
+ @enumerator.procs = [
16
+ lambda {|cell, col, row| my_arr << cell.to_s},
17
+ lambda {|cell, col, row| my_arr << '0'},
18
+ ]
19
+ @enumerator.process(input)
20
+ assert_equal ["a", "0", "b", "0", "c", "0", "d", "0", "e", "0", "f", "0", "g", "0", "h", "0", "i", "0"], my_arr
21
+ end
22
+
23
+ def test_enumerate_with_selection
24
+ my_arr = []
25
+ input = Spreadsheet.open('fixtures/enumerator/basic.xls')
26
+ @enumerator.procs = [lambda {|cell, col, row| my_arr << cell.to_s}]
27
+ @enumerator.selection = Xls::Selection.parse("B2:C3")
28
+ @enumerator.process(input)
29
+ assert_equal ['e', 'f', 'h', 'i'], my_arr
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class TestSelection < MiniTest::Unit::TestCase
4
+ ######################################
5
+ # Parsing
6
+ ######################################
7
+
8
+ def test_parse_top_left_cell
9
+ assert_equal [0, 0, 0, 0], Xls::Selection.parse("A1").indices
10
+ assert_equal [0, 0, 0, 0], Xls::Selection.parse("A1:A1").indices
11
+ end
12
+
13
+ def test_parse_single_cell
14
+ assert_equal [2, 7, 2, 7], Xls::Selection.parse("C8").indices
15
+ end
16
+
17
+ def test_parse_range
18
+ assert_equal [2, 7, 4, 9], Xls::Selection.parse("C8:E10").indices
19
+ end
20
+
21
+ def test_parse_inverse_range
22
+ assert_equal [2, 7, 4, 9], Xls::Selection.parse("E10:C8").indices
23
+ assert_equal [2, 7, 4, 9], Xls::Selection.parse("C10:E8").indices
24
+ end
25
+
26
+ def test_parse_columns_only
27
+ assert_equal [2, nil, 2, nil], Xls::Selection.parse("C").indices
28
+ assert_equal [2, nil, 4, nil], Xls::Selection.parse("C:E").indices
29
+ end
30
+
31
+ def test_parse_rows_only
32
+ assert_equal [nil, 2, nil, 2], Xls::Selection.parse("3").indices
33
+ assert_equal [nil, 4, nil, 7], Xls::Selection.parse("5:8").indices
34
+ end
35
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xls
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -132,10 +132,14 @@ extensions: []
132
132
  extra_rdoc_files: []
133
133
  files:
134
134
  - lib/xls/columnizer.rb
135
+ - lib/xls/enumerator.rb
136
+ - lib/xls/selection.rb
135
137
  - lib/xls/version.rb
136
138
  - lib/xls.rb
137
139
  - README.md
138
140
  - test/columnizer_test.rb
141
+ - test/enumerator_test.rb
142
+ - test/selection_test.rb
139
143
  - test/test_helper.rb
140
144
  - bin/xls
141
145
  homepage: http://github.com/benbjohnson/xls
@@ -164,4 +168,6 @@ specification_version: 3
164
168
  summary: A command line utilty for working with data in Excel.
165
169
  test_files:
166
170
  - test/columnizer_test.rb
171
+ - test/enumerator_test.rb
172
+ - test/selection_test.rb
167
173
  - test/test_helper.rb