xls 0.1.1 → 0.1.2

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.
data/bin/xls CHANGED
@@ -16,29 +16,38 @@ program :description, 'A command line utility for working with data in Excel.'
16
16
  #
17
17
  ################################################################################
18
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)
19
+ def build_enumerator_command(action, description)
20
+ command action do |c|
21
+ c.syntax = "xls #{action.to_s} FILE"
22
+ c.description = description
23
+ c.option('-s SELECTION', 'The Excel style selection to work within.')
24
+ c.option('-e CODE', 'The code to execute for each cell.')
25
+ c.option('--use-headers', 'Whether to use the first row as a header row.')
26
+ c.option('--output FILE', 'The path to the output file.') unless action == :each
27
+ c.when_called do|args, options|
28
+ abort("Input file required") if args.length == 0
29
+ abort("Output file required") if action != :each && options.e.nil?
30
+ abort("Execution code required") if options.e.nil?
28
31
 
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)
32
+ # Run enumerator.
33
+ workbook = Spreadsheet.open(args.first)
34
+ enumerator = Xls::Enumerator.new()
35
+ enumerator.action = action
36
+ enumerator.use_headers = options.use_headers
37
+ enumerator.selection = Xls::Selection.parse(options.s.upcase) unless options.s.nil?
38
+ enumerator.proc = options.e
39
+ enumerator.process(workbook)
40
+
41
+ # Write output to file.
42
+ workbook.write(options.output) if action != :each
43
+ end
39
44
  end
40
45
  end
41
46
 
47
+ build_enumerator_command(:each, 'Executes Ruby code on each cell of a workbook.')
48
+ build_enumerator_command(:map, 'Maps output of Ruby code on each cell.')
49
+ build_enumerator_command(:select, 'Keeps each cell where the code evaluates true.')
50
+ build_enumerator_command(:reject, 'Keeps each cell where the code evaluates false.')
42
51
 
43
52
 
44
53
 
@@ -50,7 +59,7 @@ end
50
59
 
51
60
  command :columnize do |c|
52
61
  c.syntax = 'xls columnize FILE'
53
- c.description = 'Converts a worksheet formatted as table into 2-column rows using header/value.'
62
+ c.description = 'Converts table into 2-column rows table.'
54
63
  c.option('--output FILE', 'The path to the output file.')
55
64
  c.option('--fixed-columns COLUMNS', 'The columns that should stay fixed.')
56
65
  c.when_called do|args, options|
@@ -8,7 +8,7 @@ class Xls
8
8
 
9
9
  def initialize(options={})
10
10
  self.selection = options[:selection]
11
- self.procs = options[:procs] || []
11
+ self.proc = options[:proc]
12
12
  end
13
13
 
14
14
 
@@ -18,12 +18,18 @@ class Xls
18
18
  #
19
19
  ############################################################################
20
20
 
21
+ # The action to perform on each cell of data (:none, :map, :select, :reject).
22
+ attr_accessor :action
23
+
21
24
  # The selection to enumerate over.
22
25
  attr_accessor :selection
23
26
 
24
- # A list of procs to run on each cell.
25
- attr_accessor :procs
26
-
27
+ # The proc to run on each cell.
28
+ attr_accessor :proc
29
+
30
+ # A flag stating if headers should be used.
31
+ attr_accessor :use_headers
32
+
27
33
 
28
34
  ############################################################################
29
35
  #
@@ -31,25 +37,32 @@ class Xls
31
37
  #
32
38
  ############################################################################
33
39
 
34
- # Executes a set of procs on each cell in a selection.
40
+ # Executes a proc on each cell in a selection.
35
41
  #
36
42
  # @param [Workbook] input The input workbook.
37
43
  def process(input)
38
44
  # Loop over each worksheet.
39
45
  (0...input.sheet_count).each do |sheet_index|
40
46
  sheet = input.worksheet(sheet_index)
47
+ headers = sheet.row(0)
41
48
 
42
49
  # Loop over each row.
43
- sheet.each do |row|
50
+ sheet.each(use_headers ? 1 : 0) do |row|
44
51
  next unless selection.nil? || selection.rows.nil? || selection.rows.cover?(row.idx)
45
52
 
46
53
  # Loop over each cell.
47
54
  row.each_with_index do |cell, col_index|
48
55
  next unless selection.nil? || selection.columns.nil? || selection.columns.cover?(col_index)
49
56
 
50
- # Run each proc.
51
- procs.each do |proc|
52
- proc.call(cell.to_s, col_index, row.idx)
57
+ # Run proc and retrieve the results.
58
+ header = (use_headers ? headers[col_index].to_s : '')
59
+ result = cell_binding(cell.to_s, col_index, row.idx, header).eval(proc)
60
+
61
+ # Perform an action if one is specified.
62
+ case action
63
+ when :map then row[col_index] = result.to_s
64
+ when :select then row[col_index] = '' unless result
65
+ when :reject then row[col_index] = '' if result
53
66
  end
54
67
  end
55
68
  end
@@ -57,5 +70,15 @@ class Xls
57
70
 
58
71
  return nil
59
72
  end
73
+
74
+
75
+ ####################################
76
+ # Bindings
77
+ ####################################
78
+
79
+ # Returns the context in which cell procs are run.
80
+ def cell_binding(text, col, row, header)
81
+ return binding
82
+ end
60
83
  end
61
84
  end
@@ -1,3 +1,3 @@
1
1
  class Xls
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -9,23 +9,42 @@ class TestEnumerator < MiniTest::Unit::TestCase
9
9
  # Execute
10
10
  ######################################
11
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
12
+ def test_map_enumerate
13
+ workbook = Spreadsheet.open('fixtures/enumerator/basic.xls')
14
+ @enumerator.action = :map
15
+ @enumerator.proc = "text.to_s + '!'"
16
+ @enumerator.process(workbook)
17
+ assert_worksheet [
18
+ ['a!', 'b!', 'c!'],
19
+ ['d!', 'e!', 'f!'],
20
+ ['g!', 'h!', 'i!'],
21
+ ],
22
+ workbook.worksheet(0)
21
23
  end
22
24
 
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
25
+ def test_select_enumerate
26
+ workbook = Spreadsheet.open('fixtures/enumerator/basic.xls')
27
+ @enumerator.action = :select
28
+ @enumerator.proc = "text.to_s.ord % 2 == 0"
29
+ @enumerator.process(workbook)
30
+ assert_worksheet [
31
+ ['', 'b', ''],
32
+ ['d', '', 'f'],
33
+ ['', 'h', ''],
34
+ ],
35
+ workbook.worksheet(0)
36
+ end
37
+
38
+ def test_reject_enumerate
39
+ workbook = Spreadsheet.open('fixtures/enumerator/basic.xls')
40
+ @enumerator.action = :reject
41
+ @enumerator.proc = "text.to_s.ord % 2 == 0"
42
+ @enumerator.process(workbook)
43
+ assert_worksheet [
44
+ ['a', '', 'c'],
45
+ ['', 'e', ''],
46
+ ['g', '', 'i'],
47
+ ],
48
+ workbook.worksheet(0)
30
49
  end
31
50
  end
@@ -10,8 +10,8 @@ class MiniTest::Unit::TestCase
10
10
  worksheet.each do |row|
11
11
  act << row.map {|cell| cell.to_s.strip }
12
12
  end
13
- exp = exp.map {|row| row.map {|cell| '%-10s' % cell.to_s}.join('').strip}.join("\n")
14
- act = act.map {|row| row.map {|cell| '%-10s' % cell.to_s}.join('').strip}.join("\n")
13
+ exp = exp.map {|row| row.map {|cell| '%-10s' % cell.to_s}.join('').rstrip}.join("\n")
14
+ act = act.map {|row| row.map {|cell| '%-10s' % cell.to_s}.join('').rstrip}.join("\n")
15
15
  assert_equal(exp, act, msg)
16
16
  end
17
17
  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.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: