excel_to_code 0.3.17 → 0.3.18.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +67 -34
  3. data/bin/excel_to_c +8 -78
  4. data/bin/excel_to_go +41 -0
  5. data/bin/excel_to_ruby +2 -69
  6. data/src/commands.rb +2 -0
  7. data/src/commands/common_command_line_options.rb +81 -0
  8. data/src/commands/excel_to_c.rb +3 -0
  9. data/src/commands/excel_to_go.rb +91 -0
  10. data/src/commands/excel_to_x.rb +77 -11
  11. data/src/compile.rb +1 -0
  12. data/src/compile/c/a.out +0 -0
  13. data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
  14. data/src/compile/c/compile_to_c.rb +2 -0
  15. data/src/compile/c/excel_to_c_runtime.c +691 -145
  16. data/src/compile/c/excel_to_c_runtime_test.c +226 -20
  17. data/src/compile/c/map_formulae_to_c.rb +62 -23
  18. data/src/compile/c/run_c_unit_tests +3 -0
  19. data/src/compile/cd.rb +6 -0
  20. data/src/compile/go.rb +3 -0
  21. data/src/compile/go/compile_to_go.rb +85 -0
  22. data/src/compile/go/compile_to_go_test.rb +73 -0
  23. data/src/compile/go/excel.go +171 -0
  24. data/src/compile/go/excel_test.go +54 -0
  25. data/src/compile/go/map_values_to_go.rb +67 -0
  26. data/src/compile/ruby/map_formulae_to_ruby.rb +30 -12
  27. data/src/excel/excel_functions.rb +26 -1
  28. data/src/excel/excel_functions/ceiling.rb +23 -0
  29. data/src/excel/excel_functions/countif.rb +15 -0
  30. data/src/excel/excel_functions/countifs.rb +10 -0
  31. data/src/excel/excel_functions/floor.rb +14 -0
  32. data/src/excel/excel_functions/hyperlink.rb +9 -0
  33. data/src/excel/excel_functions/na.rb +7 -0
  34. data/src/excel/excel_functions/not.rb +13 -0
  35. data/src/excel/excel_functions/or.rb +30 -0
  36. data/src/excel/excel_functions/product.rb +8 -0
  37. data/src/excel/excel_functions/rate.rb +16 -0
  38. data/src/excel/excel_functions/replace.rb +13 -0
  39. data/src/excel/excel_functions/scurve.rb +73 -0
  40. data/src/excel/excel_functions/sqrt.rb +11 -0
  41. data/src/excel/excel_functions/string_argument.rb +37 -0
  42. data/src/excel/excel_functions/sumifs.rb +19 -8
  43. data/src/excel/excel_functions/text.rb +3 -3
  44. data/src/excel/formula_peg.rb +1 -1
  45. data/src/excel/formula_peg.txt +2 -3
  46. data/src/excel/table.rb +15 -15
  47. data/src/excel_to_code.rb +1 -4
  48. data/src/extract/extract_data_from_worksheet.rb +8 -1
  49. data/src/rewrite/ast_expand_array_formulae.rb +4 -0
  50. data/src/rewrite/caching_formula_parser.rb +16 -11
  51. data/src/simplify.rb +1 -0
  52. data/src/simplify/inline_formulae.rb +16 -0
  53. data/src/simplify/replace_arithmetic_on_ranges.rb +14 -1
  54. data/src/simplify/replace_arrays_with_single_cells.rb +42 -15
  55. data/src/simplify/replace_cell_addresses_with_references.rb +70 -0
  56. data/src/simplify/replace_column_with_column_number.rb +8 -1
  57. data/src/simplify/replace_table_references.rb +40 -19
  58. data/src/simplify/simplify_arithmetic.rb +15 -10
  59. data/src/version.rb +4 -0
  60. metadata +115 -43
  61. data/TODO +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a6c7853f4e0ce66da8f073d561bbd0dabd2a390d
4
- data.tar.gz: b9e44bda2488d15ede19254374a9b19fb1320762
2
+ SHA256:
3
+ metadata.gz: 295445022d29e71173d548f2fbfae87804c2fc19f6ba111c5efdec35657cf7a6
4
+ data.tar.gz: 025fd8e7080d061732be7f357ff242e2fb51fe64bb985c33c2703b8ae342cf01
5
5
  SHA512:
6
- metadata.gz: aed1ca40db11c54a816035989e1f68427028dbd2ed3c7328e134efa225842b52c72e6db1df32090d75a45da8d95caa29102b52a028d413ff397ecd946d4dfed9
7
- data.tar.gz: 87131c81c57f7d7705833b0f18f14e797fb553c304367f47c688c1c6593feaebd9589e278fbb92792add54442cdfa833508187ff090fd60169754f9332c0486a
6
+ metadata.gz: 6049e42f81bcecf1942c68141cc735406f0227c59c77d0008249bc8e7c3f7480f9090b554ceb62ab27a519861cc00a11c0ccd2673b89de91213fbd90336a12fd
7
+ data.tar.gz: aa5aba794f98a99481171bf0753f090495f556c8da38a9ff37be8a1c0994fe92b9df15a9bf1f5f787120a23061c17ca6436cf486b2844dbbd628b4cc7cfe4d80
data/README.md CHANGED
@@ -1,50 +1,83 @@
1
- # excel_to_code
1
+ # Excel to Code
2
2
 
3
- Converts some excel spreadsheets (.xlsx, not .xls) into some other programming languages (currently ruby or c).
4
- This allows the excel spreadsheets to be run programatically, without excel.
3
+ [![Tests Passing](https://travis-ci.org/tamc/excel_to_code.svg?branch=master)](https://travis-ci.org/tamc/excel_to_code)
5
4
 
6
- Its cannonical source is at http://github.com/tamc/excel_to_code
5
+ excel_to_c - roughly translate some Excel files into C.
7
6
 
8
- # Running excel_to_code
7
+ excel_to_ruby - roughly translate some Excel files into Ruby.
9
8
 
10
- To just have a go:
9
+ This allows spreadsheets to be:
11
10
 
12
- ./bin/excel_to_c <excel_file_name>
13
-
14
- NB:For small spreadsheets this will take a minute or so. For large spreadsheets it is best to run it overnight.
15
-
16
- for more detail:
17
-
18
- ./bin/excel_to_c --compile --run-tests --settable <name of input worksheet> --prune-except <name of output worksheet> <excel file name>
19
-
20
- this should work:
11
+ 1. Embedded in other programs, such as web servers, or optimisers
12
+ 2. Without depending on any Microsoft code
13
+
14
+ For example, running [these commands](examples/simple/compile.sh) turns [this spreadsheet](examples/simple/simple.xlsx) into [this Ruby code](examples/simple/ruby/simple.rb) or [this C code](examples/simple/c/simple.c).
21
15
 
22
- ./bin/excel_to_c --help
16
+ # Install
23
17
 
24
- # Testing excel_to_code
18
+ Requires Ruby. Install by:
25
19
 
26
- 1. Make sure you have ruby 1.9.2 or later installed
27
- 2. gem install bundler # May need to use sudo
28
- 3. bundle
29
- 4. rspec spec/*
20
+ gem install excel_to_code
30
21
 
31
- To test the C runtime:
32
- 1. cd src/compile/c
33
- 2. cc excel_to_c_runtime
34
- 3. ./a.out
22
+ # Run
35
23
 
36
- # Hacking excel_to_code
24
+ To just have a go:
25
+
26
+ excel_to_c <excel_file_name>
27
+
28
+ This will produce a file called excelspreadsheet.c
29
+
30
+ For a more complex spreadsheet:
31
+
32
+ excel_to_c --compile --run-tests --settable <name of input worksheet> --prune-except <name of output worksheet> <excel file name>
33
+
34
+ See the full list of options:
37
35
 
38
- There are some how to guides in the doc folder.
36
+ excel_to_c --help
39
37
 
40
- # Limitations
38
+ # Gotchas, limitations and bugs
41
39
 
42
- 1. Not tested at all on Windows
43
- 2. INDIRECT and OFFSET formula must be convertable at runtime into a standard formula
44
- 3. Doesn't implement all functions (see doc/Which_functions_are_implemented.md)
40
+ 0. No custom functions, no macros for generating results
41
+ 1. Results are cached. So you must call reset(), then set values, then read values.
42
+ 2. It must be possible to replace INDIRECT and OFFSET formula with standard references at compile time (e.g., INDIRECT("A"&"1") is fine, INDIRECT(userInput&"3") is not.
43
+ 3. Doesn't implement all functions. [See which functions are implemented](docs/Which_functions_are_implemented.md).
45
44
  4. Doesn't implement references that involve range unions and lists (but does implement standard ranges)
46
45
  5. Sometimes gives cells as being empty, when excel would give the cell as having a numeric value of zero
47
- 6. The generated C version does not multithread and will give bad results if you try
48
- 7. The generated code uses floating point, rather than fully precise arithmetic, so results can differ slightly
46
+ 6. The generated C version does not multithread and will give bad results if you try.
47
+ 7. The generated code uses floating point, rather than fully precise arithmetic, so results can differ slightly.
49
48
  8. The generated code uses the sprintf approach to rounding (even-odd) rather than excel's 0.5 rounds away from zero.
50
- 90. Ranges like this: Sheet1!A10:Sheet1!B20 and 3D ranges don't work
49
+ 9. Ranges like this: Sheet1!A10:Sheet1!B20 and 3D ranges don't work.
50
+
51
+ Report bugs: <https://github.com/tamc/excel_to_code/issues>
52
+
53
+ # Changelog
54
+
55
+ See [Changes](CHANGES.md).
56
+
57
+ # License
58
+
59
+ See [License](LICENSE.md)
60
+
61
+ # Hacking
62
+
63
+ Source code: <https://github.com/tamc/excel_to_code>
64
+
65
+ Documentation:
66
+
67
+ * [Installing from source](docs/installing_from_source.md)
68
+ * [Structure of this project](docs/structure_of_this_project.md)
69
+ * [How does the calculation work](docs/how_does_the_calculation_work.md)
70
+ * [How to fix parsing errors](docs/How_to_fix_parsing_errors.md)
71
+ * [How to implement a new Excel function](docs/How_to_add_a_missing_function.md)
72
+
73
+ Some notes on how Excel works under the hood:
74
+
75
+ * [The Excel file structure](docs/implementation/excel_file_structure.md)
76
+ * [Relationships](docs/implementation/relationships.md)
77
+ * [Workbooks](docs/implementation/workbook.md)
78
+ * [Worksheets](docs/implementation/worksheets.md)
79
+ * [Cells](docs/implementation/cell.md)
80
+ * [Tables](docs/implementation/tables.md)
81
+ * [Shared Strings](docs/implementation/shared_strings.md)
82
+ * [Array formulae](docs/implementation/array_formulae.md)
83
+
data/bin/excel_to_c CHANGED
@@ -5,98 +5,28 @@ require_relative '../src/excel_to_code'
5
5
  command = ExcelToC.new
6
6
 
7
7
  opts = OptionParser.new do |opts|
8
- opts.banner = <<-END
9
-
10
- A command to approximately translate excel files into c code.
11
-
12
- Usage: excel_to_c [options] input_excel_file <output_directory>
13
- input_excel_file the name of a .xlsx excel file (i.e., produced by Excel 2007+, not a .xls file)
14
- output_directory the name of a folder in which to place the generated code. If not specified will have the same name as the input_excel_file, without the .xlsx
15
-
16
- Support: http://github.com/tamc/excel_to_code
17
- END
18
-
19
- opts.separator ""
20
- opts.separator "Specific options:"
8
+ CommonCommandLineOptions.set(command: command, options: opts, generates: "C", extension: "c")
21
9
 
22
- opts.on('-v','--version', 'Prints the version number of this code') do
23
- puts ExcelToCode.version
24
- exit
25
- end
26
-
27
- opts.on('-o','--output-name NAME','Filename to give to c version of code (and associated ruby interface). Defaults to a folder with the same name as the excel file.') do |name|
28
- command.output_name = name
29
- end
30
-
31
- opts.on('-c','--compile',"Compile the generated code (where relevant)") do
10
+ opts.on('-c','--compile',"Compile the C") do
32
11
  command.actually_compile_code = true
33
12
  end
34
13
 
35
- opts.on('-r','--run-tests',"Compile the generated code and then run the tests") do
36
- command.actually_run_tests = true
14
+ opts.on('--[no-]makefile', 'Generate a makefile. Default: no.') do |b|
15
+ command.create_makefile = b
37
16
  end
38
17
 
39
- opts.on('-n','--named-references',"Transfer named references from spreadsheet to generated code") do
40
- command.named_references_that_can_be_set_at_runtime = :where_possible
41
- command.named_references_to_keep = :all
42
- end
43
-
44
- opts.on('-s','--settable WORKSHEET','Make it possible to set the values of cells in this worksheet at runtime. By default no values are settable.') do |sheet|
45
- command.cells_that_can_be_set_at_runtime = { sheet => :all }
46
- end
47
-
48
- opts.on('-p','--prune-except WORKSHEET',"Remove all cells except those on this worksheet, or that are required to calculate values on that worksheet. By default keeps all cells.") do |sheet|
49
- command.cells_to_keep = { sheet => :all }
50
- end
51
18
 
52
- opts.on('--isolate WORKSHEET', "Only performs translation and optimiation of that one worksheet. Useful for debugging an incorrect translation of a large worksheet") do |sheet|
53
- command.isolate = sheet
54
- end
55
-
56
- opts.on('-d','--debug', "Does not perform final optimisations of spreadsheet, leaving the resulting code more similar to the original worksheet, but potentially slower") do |sheet|
57
- command.should_inline_formulae_that_are_only_used_once = false
58
- command.extract_repeated_parts_of_formulae = false
19
+ opts.on('--[no-]rakefile', 'Generate a rakefile. Default: yes.') do |b|
20
+ command.create_rakefile = b
59
21
  end
60
22
 
61
- opts.on('--makefile', 'Generate a makefile') do
62
- command.create_makefile = true
63
- end
64
-
65
- opts.on('--no-makefile', 'Do not generate a makefile (default)') do
66
- command.create_makefile = false
67
- end
68
-
69
- opts.on('--rakefile', 'Generate a rakefile (default)') do
70
- command.create_rakefile = true
71
- end
72
-
73
- opts.on('--no-rakefile', 'Do not generate a rakefile') do
74
- command.create_rakefile = false
75
- end
76
-
77
- opts.on('--write-tests-in-c', "Write tests in pure C (normally written in ruby") do
23
+ opts.on('--write-tests-in-c', "Write tests in C. Default: Ruby.") do
78
24
  command.write_tests_in_c = true
79
25
  end
80
-
81
- opts.on("-h", "--help", "Show this message") do
82
- puts opts
83
- exit
84
- end
85
26
  end
86
27
 
87
- begin
88
- opts.parse!(ARGV)
89
- rescue OptionParser::ParseError => e
90
- STDERR.puts e.message, "\n", opts
28
+ unless CommonCommandLineOptions.parse(options: opts, command: command, arguments: ARGV)
91
29
  exit(-1)
92
30
  end
93
31
 
94
- unless ARGV.size > 0
95
- puts opts
96
- exit(-1)
97
- end
98
-
99
- command.excel_file = ARGV[0]
100
- command.output_directory = ARGV[1] if ARGV[1]
101
-
102
32
  command.go!
data/bin/excel_to_go ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require_relative '../src/excel_to_code'
4
+
5
+ $stderr.puts
6
+ $stderr.puts "WARNING: excel_to_go is unfinished"
7
+ $stderr.puts
8
+
9
+ command = ExcelToGo.new
10
+
11
+ opts = OptionParser.new do |opts|
12
+ CommonCommandLineOptions.set(command: command, options: opts, generates: "Go", extension: "go")
13
+
14
+ opts.banner += <<~END
15
+
16
+ \nA note on GOPATH: The generated go file has a dependency, excel.go, which has no further
17
+ dependencies outside of the core Go packages. This dependency is copied into the same destination
18
+ as the generated go file. The tricky bit is how the generated go file can import excel.go
19
+ given that Go does not like relative references in import statements.
20
+
21
+ You can either:
22
+
23
+ 1. Manually specify the import statement to use with the --import-excel-go [PATH] switch
24
+ 2. Let excel_to_go guess the right path. It will do this by:
25
+ a. If [output_directory] is under GOPATH, calculating the path relative to GOPATH.
26
+ b. If [output_directory] has src/ somewhere in its path, calculating the path relative to that
27
+ c. Falling back to 'excel.go' which you will then have to manually fix.
28
+
29
+ END
30
+
31
+ opts.on('--import-excel-go [PATH]', 'Manually set the path to be used to import excel.go') do |p|
32
+ command.excel_go_lib = p
33
+ end
34
+
35
+ end
36
+
37
+ unless CommonCommandLineOptions.parse(options: opts, command: command, arguments: ARGV)
38
+ exit(-1)
39
+ end
40
+
41
+ command.go!
data/bin/excel_to_ruby CHANGED
@@ -5,78 +5,11 @@ require_relative '../src/excel_to_code'
5
5
  command = ExcelToRuby.new
6
6
 
7
7
  opts = OptionParser.new do |opts|
8
- opts.banner = <<-END
9
-
10
- A command to approximately translate excel files into c code.
11
-
12
- Usage: excel_to_ruby [options] input_excel_file <output_directory>
13
- input_excel_file the name of a .xlsx excel file (i.e., produced by Excel 2007+, not a .xls file)
14
- output_directory the name of a folder in which to place the generated code. If not specified will have the same name as the input_excel_file, without the .xlsx
15
-
16
- Support: http://github.com/tamc/excel_to_code
17
- END
18
-
19
- opts.separator ""
20
- opts.separator "Specific options:"
21
-
22
- opts.on('-v','--version', 'Prints the version number of this code') do
23
- puts ExcelToCode.version
24
- exit
25
- end
26
-
27
- opts.on('-o','--output-name NAME','Filename to give to c version of code (and associated ruby interface). Defaults to a folder with the same name as the excel file.') do |name|
28
- command.output_name = name
29
- end
30
-
31
- opts.on('-c','--compile',"Compile the generated code (where relevant)") do
32
- command.actually_compile_code = true
33
- end
34
-
35
- opts.on('-r','--run-tests',"Compile the generated code and then run the tests") do
36
- command.actually_run_tests = true
37
- end
38
-
39
- opts.on('-n','--named-references',"Transfer named references from spreadsheet to generated code") do
40
- command.named_references_that_can_be_set_at_runtime = :where_possible
41
- command.named_references_to_keep = :all
42
- end
43
-
44
- opts.on('-s','--settable WORKSHEET','Make it possible to set the values of cells in this worksheet at runtime. By default no values are settable.') do |sheet|
45
- command.cells_that_can_be_set_at_runtime = { sheet => :all }
46
- end
47
-
48
- opts.on('-p','--prune-except WORKSHEET',"Remove all cells except those on this worksheet, or that are required to calculate values on that worksheet. By default keeps all cells.") do |sheet|
49
- command.cells_to_keep = { sheet => :all }
50
- end
51
-
52
- opts.on('--isolate WORKSHEET', "Only performs translation and optimiation of that one worksheet. Useful for debugging an incorrect translation of a large worksheet") do |sheet|
53
- command.isolate = sheet
54
- end
55
-
56
- opts.on('-d','--debug', "Does not perform final optimisations of spreadsheet, leaving the resulting code more similar to the original worksheet, but potentially slower") do |sheet|
57
- command.should_inline_formulae_that_are_only_used_once = false
58
- command.extract_repeated_parts_of_formulae = false
59
- end
60
-
61
- opts.on("-h", "--help", "Show this message") do
62
- puts opts
63
- exit
64
- end
65
- end
66
-
67
- begin
68
- opts.parse!(ARGV)
69
- rescue OptionParser::ParseError => e
70
- STDERR.puts e.message, "\n", opts
71
- exit(-1)
8
+ CommonCommandLineOptions.set(command: command, options: opts, generates: "Ruby", extension: "rb")
72
9
  end
73
10
 
74
- unless ARGV.size > 0
75
- puts opts
11
+ unless CommonCommandLineOptions.parse(options: opts, command: command, arguments: ARGV)
76
12
  exit(-1)
77
13
  end
78
14
 
79
- command.excel_file = ARGV[0]
80
- command.output_directory = ARGV[1] if ARGV[1]
81
-
82
15
  command.go!
data/src/commands.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require_relative "commands/excel_to_x"
2
2
  require_relative "commands/excel_to_ruby"
3
3
  require_relative "commands/excel_to_c"
4
+ require_relative "commands/excel_to_go"
4
5
  require_relative "commands/excel_to_test"
6
+ require_relative "commands/common_command_line_options"
@@ -0,0 +1,81 @@
1
+ class CommonCommandLineOptions
2
+ def self.set(command:, options:, generates:, extension:)
3
+ banner = <<-EOT
4
+ #{$0} [options] <excel_file> [output_directory]
5
+
6
+ Roughly translate some Excel files into plain #{generates}
7
+
8
+ http://github.com/tamc/excel_to_code
9
+ EOT
10
+
11
+ options.separator "Options:"
12
+
13
+ options.banner = banner.split("\n").map(&:strip).join("\n")
14
+
15
+ options.on_tail('-v', '--version', '') do
16
+ puts ExcelToCode.version
17
+ exit
18
+ end
19
+
20
+ options.on('-o', '--output-name NAME', "Name the generated code files. Default excelspreadsheet.#{extension}") do |name|
21
+ command.output_name = name
22
+ end
23
+
24
+ options.on('-r', '--run-tests', "Test whether the #{generates} matches the Excel.") do
25
+ command.actually_run_tests = true
26
+ end
27
+
28
+ options.on('-n', '--named-references', "Include Excel named references as variables in the #{generates}.") do
29
+ command.named_references_that_can_be_set_at_runtime = :where_possible
30
+ command.named_references_to_keep = :all
31
+ end
32
+
33
+ options.on('-s', '--settable INPUT_WORKSHEET', "Translate value cells in INPUT_WORKSHEET as settable variables in the #{generates}.") do |sheet|
34
+
35
+ command.cells_that_can_be_set_at_runtime = { sheet => :all }
36
+ end
37
+
38
+ options.on('-p', '--prune-except OUTPUT_WORKSHEET', 'Only translate OUTPUT_WORKSHEET and the cells its results depend on.') do |sheet|
39
+ command.cells_to_keep = { sheet => :all }
40
+ end
41
+
42
+ options.on('--isolate FAULTY_WORKSHEET', 'Only translate FAULTY_WORKSHEET. Useful for debugging.') do |sheet|
43
+ command.isolate = sheet
44
+ end
45
+
46
+ options.on('-d', '--debug', "Fewer optimisations; the #{generates} should be more similar to the original Excel.") do
47
+ command.should_inline_formulae_that_are_only_used_once = false
48
+ command.extract_repeated_parts_of_formulae = false
49
+ end
50
+
51
+ options.on('--persevere', "Continue through some errors in order to fully appreciate the scale of problems in the Excel.") do
52
+ command.persevere = true
53
+ end
54
+
55
+ options.on_tail('-h', '--help', '') do
56
+ puts options
57
+ exit
58
+ end
59
+
60
+ options.set_summary_width 35
61
+
62
+ end
63
+
64
+ def self.parse(options:, command:, arguments:)
65
+ begin
66
+ options.parse!(arguments)
67
+ rescue OptionParser::ParseError => e
68
+ STDERR.puts e.message, "\n", options
69
+ return false
70
+ end
71
+
72
+ unless arguments.size > 0
73
+ puts options
74
+ return false
75
+ end
76
+
77
+ command.excel_file = arguments[0]
78
+ command.output_directory = arguments[1] if arguments[1]
79
+ return true
80
+ end
81
+ end