excel_to_code 0.3.17 → 0.3.18.beta.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.
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