csv_plus_plus 0.1.1 → 0.1.3
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 +4 -4
- data/README.md +18 -63
- data/{CHANGELOG.md → docs/CHANGELOG.md} +17 -0
- data/lib/csv_plus_plus/benchmarked_compiler.rb +112 -0
- data/lib/csv_plus_plus/cell.rb +46 -24
- data/lib/csv_plus_plus/cli.rb +44 -17
- data/lib/csv_plus_plus/cli_flag.rb +1 -2
- data/lib/csv_plus_plus/color.rb +42 -11
- data/lib/csv_plus_plus/compiler.rb +178 -0
- data/lib/csv_plus_plus/entities/ast_builder.rb +50 -0
- data/lib/csv_plus_plus/entities/boolean.rb +40 -0
- data/lib/csv_plus_plus/entities/builtins.rb +58 -0
- data/lib/csv_plus_plus/entities/cell_reference.rb +231 -0
- data/lib/csv_plus_plus/entities/date.rb +63 -0
- data/lib/csv_plus_plus/entities/entity.rb +50 -0
- data/lib/csv_plus_plus/entities/entity_with_arguments.rb +57 -0
- data/lib/csv_plus_plus/entities/function.rb +45 -0
- data/lib/csv_plus_plus/entities/function_call.rb +50 -0
- data/lib/csv_plus_plus/entities/number.rb +48 -0
- data/lib/csv_plus_plus/entities/runtime_value.rb +43 -0
- data/lib/csv_plus_plus/entities/string.rb +42 -0
- data/lib/csv_plus_plus/entities/variable.rb +37 -0
- data/lib/csv_plus_plus/entities.rb +40 -0
- data/lib/csv_plus_plus/error/error.rb +20 -0
- data/lib/csv_plus_plus/error/formula_syntax_error.rb +37 -0
- data/lib/csv_plus_plus/error/modifier_syntax_error.rb +75 -0
- data/lib/csv_plus_plus/error/modifier_validation_error.rb +69 -0
- data/lib/csv_plus_plus/error/syntax_error.rb +71 -0
- data/lib/csv_plus_plus/error/writer_error.rb +17 -0
- data/lib/csv_plus_plus/error.rb +10 -2
- data/lib/csv_plus_plus/google_api_client.rb +11 -2
- data/lib/csv_plus_plus/google_options.rb +23 -18
- data/lib/csv_plus_plus/lexer/lexer.rb +17 -6
- data/lib/csv_plus_plus/lexer/tokenizer.rb +6 -1
- data/lib/csv_plus_plus/lexer.rb +24 -0
- data/lib/csv_plus_plus/modifier/conditional_formatting.rb +18 -0
- data/lib/csv_plus_plus/modifier/data_validation.rb +138 -0
- data/lib/csv_plus_plus/modifier/expand.rb +61 -0
- data/lib/csv_plus_plus/modifier/google_sheet_modifier.rb +133 -0
- data/lib/csv_plus_plus/modifier/modifier.rb +222 -0
- data/lib/csv_plus_plus/modifier/modifier_validator.rb +243 -0
- data/lib/csv_plus_plus/modifier/rubyxl_modifier.rb +84 -0
- data/lib/csv_plus_plus/modifier.rb +82 -150
- data/lib/csv_plus_plus/options.rb +64 -19
- data/lib/csv_plus_plus/{language → parser}/cell_value.tab.rb +25 -25
- data/lib/csv_plus_plus/{language → parser}/code_section.tab.rb +86 -95
- data/lib/csv_plus_plus/parser/modifier.tab.rb +478 -0
- data/lib/csv_plus_plus/row.rb +53 -15
- data/lib/csv_plus_plus/runtime/can_define_references.rb +87 -0
- data/lib/csv_plus_plus/runtime/can_resolve_references.rb +209 -0
- data/lib/csv_plus_plus/runtime/graph.rb +68 -0
- data/lib/csv_plus_plus/runtime/position_tracker.rb +231 -0
- data/lib/csv_plus_plus/runtime/references.rb +110 -0
- data/lib/csv_plus_plus/runtime/runtime.rb +126 -0
- data/lib/csv_plus_plus/runtime.rb +42 -0
- data/lib/csv_plus_plus/source_code.rb +66 -0
- data/lib/csv_plus_plus/template.rb +63 -36
- data/lib/csv_plus_plus/version.rb +2 -1
- data/lib/csv_plus_plus/writer/base_writer.rb +30 -5
- data/lib/csv_plus_plus/writer/csv.rb +11 -9
- data/lib/csv_plus_plus/writer/excel.rb +9 -2
- data/lib/csv_plus_plus/writer/file_backer_upper.rb +7 -4
- data/lib/csv_plus_plus/writer/google_sheet_builder.rb +88 -45
- data/lib/csv_plus_plus/writer/google_sheets.rb +79 -29
- data/lib/csv_plus_plus/writer/open_document.rb +6 -1
- data/lib/csv_plus_plus/writer/rubyxl_builder.rb +103 -33
- data/lib/csv_plus_plus/writer.rb +39 -9
- data/lib/csv_plus_plus.rb +41 -15
- metadata +44 -30
- data/lib/csv_plus_plus/code_section.rb +0 -101
- data/lib/csv_plus_plus/expand.rb +0 -18
- data/lib/csv_plus_plus/graph.rb +0 -62
- data/lib/csv_plus_plus/language/ast_builder.rb +0 -68
- data/lib/csv_plus_plus/language/benchmarked_compiler.rb +0 -65
- data/lib/csv_plus_plus/language/builtins.rb +0 -46
- data/lib/csv_plus_plus/language/compiler.rb +0 -152
- data/lib/csv_plus_plus/language/entities/boolean.rb +0 -33
- data/lib/csv_plus_plus/language/entities/cell_reference.rb +0 -33
- data/lib/csv_plus_plus/language/entities/entity.rb +0 -86
- data/lib/csv_plus_plus/language/entities/function.rb +0 -35
- data/lib/csv_plus_plus/language/entities/function_call.rb +0 -37
- data/lib/csv_plus_plus/language/entities/number.rb +0 -36
- data/lib/csv_plus_plus/language/entities/runtime_value.rb +0 -28
- data/lib/csv_plus_plus/language/entities/string.rb +0 -31
- data/lib/csv_plus_plus/language/entities/variable.rb +0 -25
- data/lib/csv_plus_plus/language/entities.rb +0 -28
- data/lib/csv_plus_plus/language/references.rb +0 -70
- data/lib/csv_plus_plus/language/runtime.rb +0 -205
- data/lib/csv_plus_plus/language/scope.rb +0 -192
- data/lib/csv_plus_plus/language/syntax_error.rb +0 -66
- data/lib/csv_plus_plus/modifier.tab.rb +0 -907
- data/lib/csv_plus_plus/writer/google_sheet_modifier.rb +0 -56
- data/lib/csv_plus_plus/writer/rubyxl_modifier.rb +0 -59
data/lib/csv_plus_plus/writer.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require_relative './writer/base_writer'
|
|
@@ -7,18 +8,47 @@ require_relative './writer/google_sheets'
|
|
|
7
8
|
require_relative './writer/open_document'
|
|
8
9
|
|
|
9
10
|
module CSVPlusPlus
|
|
10
|
-
# Various strategies for writing to various formats (excel, google sheets, CSV
|
|
11
|
+
# Various strategies for writing to various formats (excel, google sheets, CSV & OpenDocument (not yet implemented))
|
|
11
12
|
module Writer
|
|
12
|
-
|
|
13
|
-
def self.writer(options)
|
|
14
|
-
return ::CSVPlusPlus::Writer::GoogleSheets.new(options) if options.google
|
|
13
|
+
extend ::T::Sig
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
sig do
|
|
16
|
+
params(
|
|
17
|
+
options: ::CSVPlusPlus::Options,
|
|
18
|
+
runtime: ::CSVPlusPlus::Runtime::Runtime
|
|
19
|
+
).returns(
|
|
20
|
+
::T.any(
|
|
21
|
+
::CSVPlusPlus::Writer::CSV,
|
|
22
|
+
::CSVPlusPlus::Writer::Excel,
|
|
23
|
+
::CSVPlusPlus::Writer::GoogleSheets,
|
|
24
|
+
::CSVPlusPlus::Writer::OpenDocument
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
# Return an instance of a writer depending on the given +options+
|
|
29
|
+
#
|
|
30
|
+
# @param options [Options] The supplied options.
|
|
31
|
+
# @param runtime [Runtime] The current runtime.
|
|
32
|
+
#
|
|
33
|
+
# @return [Writer::CSV | Writer::Excel | Writer::GoogleSheets | Writer::OpenDocument]
|
|
34
|
+
# rubocop:disable Metrics/MethodLength
|
|
35
|
+
def self.writer(options, runtime)
|
|
36
|
+
output_format = options.output_format
|
|
37
|
+
case output_format
|
|
38
|
+
when ::CSVPlusPlus::Options::OutputFormat::CSV then ::CSVPlusPlus::Writer::CSV.new(options, runtime)
|
|
39
|
+
when ::CSVPlusPlus::Options::OutputFormat::Excel then ::CSVPlusPlus::Writer::Excel.new(options, runtime)
|
|
40
|
+
when ::CSVPlusPlus::Options::OutputFormat::GoogleSheets then ::CSVPlusPlus::Writer::GoogleSheets.new(
|
|
41
|
+
options,
|
|
42
|
+
runtime
|
|
43
|
+
)
|
|
44
|
+
when ::CSVPlusPlus::Options::OutputFormat::OpenDocument then ::CSVPlusPlus::Writer::OpenDocument.new(
|
|
45
|
+
options,
|
|
46
|
+
runtime
|
|
47
|
+
)
|
|
48
|
+
else
|
|
49
|
+
::T.absurd(output_format)
|
|
21
50
|
end
|
|
22
51
|
end
|
|
52
|
+
# rubocop:enable Metrics/MethodLength
|
|
23
53
|
end
|
|
24
54
|
end
|
data/lib/csv_plus_plus.rb
CHANGED
|
@@ -1,30 +1,54 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
4
|
+
require 'sorbet-runtime'
|
|
5
|
+
|
|
6
|
+
require 'benchmark'
|
|
7
|
+
require 'csv'
|
|
8
|
+
require 'fileutils'
|
|
3
9
|
require 'google/apis/drive_v3'
|
|
4
10
|
require 'google/apis/sheets_v4'
|
|
5
11
|
require 'googleauth'
|
|
12
|
+
require 'optparse'
|
|
13
|
+
require 'pathname'
|
|
6
14
|
require 'rubyXL'
|
|
7
15
|
require 'rubyXL/convenience_methods'
|
|
8
16
|
require 'set'
|
|
17
|
+
require 'tempfile'
|
|
18
|
+
|
|
19
|
+
require_relative 'csv_plus_plus/source_code'
|
|
20
|
+
|
|
21
|
+
require_relative 'csv_plus_plus/runtime'
|
|
22
|
+
|
|
23
|
+
require_relative 'csv_plus_plus/cli_flag'
|
|
24
|
+
require_relative 'csv_plus_plus/entities'
|
|
25
|
+
require_relative 'csv_plus_plus/error'
|
|
9
26
|
|
|
10
27
|
require_relative 'csv_plus_plus/cell'
|
|
11
28
|
require_relative 'csv_plus_plus/cli'
|
|
12
|
-
require_relative 'csv_plus_plus/code_section'
|
|
13
29
|
require_relative 'csv_plus_plus/color'
|
|
14
|
-
require_relative 'csv_plus_plus/error'
|
|
15
|
-
require_relative 'csv_plus_plus/language/builtins'
|
|
16
|
-
require_relative 'csv_plus_plus/language/compiler'
|
|
17
|
-
require_relative 'csv_plus_plus/language/runtime'
|
|
18
|
-
require_relative 'csv_plus_plus/language/syntax_error'
|
|
19
30
|
require_relative 'csv_plus_plus/modifier'
|
|
20
|
-
|
|
31
|
+
|
|
32
|
+
require_relative 'csv_plus_plus/parser/cell_value.tab'
|
|
33
|
+
require_relative 'csv_plus_plus/parser/code_section.tab'
|
|
34
|
+
require_relative 'csv_plus_plus/parser/modifier.tab'
|
|
35
|
+
|
|
36
|
+
require_relative 'csv_plus_plus/compiler'
|
|
37
|
+
|
|
38
|
+
require_relative 'csv_plus_plus/google_options'
|
|
39
|
+
require_relative 'csv_plus_plus/lexer'
|
|
21
40
|
require_relative 'csv_plus_plus/options'
|
|
22
41
|
require_relative 'csv_plus_plus/row'
|
|
23
42
|
require_relative 'csv_plus_plus/template'
|
|
24
43
|
require_relative 'csv_plus_plus/writer'
|
|
25
44
|
|
|
45
|
+
require_relative 'csv_plus_plus/benchmarked_compiler'
|
|
46
|
+
|
|
26
47
|
# A programming language for writing rich CSV files
|
|
27
48
|
module CSVPlusPlus
|
|
49
|
+
extend ::T::Sig
|
|
50
|
+
|
|
51
|
+
sig { params(input: ::String, filename: ::T.nilable(::String), options: ::CSVPlusPlus::Options).void }
|
|
28
52
|
# Parse the input into a +Template+ and write it to the desired format
|
|
29
53
|
#
|
|
30
54
|
# @param input [String] The csvpp input to compile
|
|
@@ -33,25 +57,27 @@ module CSVPlusPlus
|
|
|
33
57
|
def self.apply_template_to_sheet!(input, filename, options)
|
|
34
58
|
warn(options.verbose_summary) if options.verbose
|
|
35
59
|
|
|
36
|
-
runtime = ::CSVPlusPlus::
|
|
60
|
+
runtime = ::CSVPlusPlus::Runtime.new(source_code: ::CSVPlusPlus::SourceCode.new(input:, filename:))
|
|
37
61
|
|
|
38
|
-
::CSVPlusPlus::
|
|
62
|
+
::CSVPlusPlus::Compiler.with_compiler(options:, runtime:) do |compiler|
|
|
39
63
|
template = compiler.compile_template
|
|
40
|
-
|
|
41
64
|
warn(template.verbose_summary) if options.verbose
|
|
42
65
|
|
|
43
|
-
write_template(template
|
|
66
|
+
write_template(template:, compiler:, options:)
|
|
44
67
|
end
|
|
45
68
|
end
|
|
46
69
|
|
|
70
|
+
sig do
|
|
71
|
+
params(compiler: ::CSVPlusPlus::Compiler, options: ::CSVPlusPlus::Options, template: ::CSVPlusPlus::Template).void
|
|
72
|
+
end
|
|
47
73
|
# Write the results (and possibly make a backup) of a compiled +template+
|
|
48
74
|
#
|
|
49
|
-
# @param template [Template] The compiled template
|
|
50
75
|
# @param compiler [Compiler] The compiler currently in use
|
|
51
76
|
# @param options [Options] The options we're running with
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
compiler.outputting! do
|
|
77
|
+
# @param template [Template] The compiled template
|
|
78
|
+
def self.write_template(compiler:, options:, template:)
|
|
79
|
+
compiler.outputting! do |runtime|
|
|
80
|
+
output = ::CSVPlusPlus::Writer.writer(options, runtime)
|
|
55
81
|
output.write_backup if options.backup
|
|
56
82
|
output.write(template)
|
|
57
83
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: csv_plus_plus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrick Carroll
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-04-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: google-apis-drive_v3
|
|
@@ -118,48 +118,64 @@ executables:
|
|
|
118
118
|
extensions: []
|
|
119
119
|
extra_rdoc_files: []
|
|
120
120
|
files:
|
|
121
|
-
- CHANGELOG.md
|
|
122
121
|
- README.md
|
|
123
122
|
- bin/csv++
|
|
124
123
|
- bin/csvpp
|
|
124
|
+
- docs/CHANGELOG.md
|
|
125
125
|
- lib/csv_plus_plus.rb
|
|
126
|
+
- lib/csv_plus_plus/benchmarked_compiler.rb
|
|
126
127
|
- lib/csv_plus_plus/cell.rb
|
|
127
128
|
- lib/csv_plus_plus/cli.rb
|
|
128
129
|
- lib/csv_plus_plus/cli_flag.rb
|
|
129
|
-
- lib/csv_plus_plus/code_section.rb
|
|
130
130
|
- lib/csv_plus_plus/color.rb
|
|
131
|
+
- lib/csv_plus_plus/compiler.rb
|
|
132
|
+
- lib/csv_plus_plus/entities.rb
|
|
133
|
+
- lib/csv_plus_plus/entities/ast_builder.rb
|
|
134
|
+
- lib/csv_plus_plus/entities/boolean.rb
|
|
135
|
+
- lib/csv_plus_plus/entities/builtins.rb
|
|
136
|
+
- lib/csv_plus_plus/entities/cell_reference.rb
|
|
137
|
+
- lib/csv_plus_plus/entities/date.rb
|
|
138
|
+
- lib/csv_plus_plus/entities/entity.rb
|
|
139
|
+
- lib/csv_plus_plus/entities/entity_with_arguments.rb
|
|
140
|
+
- lib/csv_plus_plus/entities/function.rb
|
|
141
|
+
- lib/csv_plus_plus/entities/function_call.rb
|
|
142
|
+
- lib/csv_plus_plus/entities/number.rb
|
|
143
|
+
- lib/csv_plus_plus/entities/runtime_value.rb
|
|
144
|
+
- lib/csv_plus_plus/entities/string.rb
|
|
145
|
+
- lib/csv_plus_plus/entities/variable.rb
|
|
131
146
|
- lib/csv_plus_plus/error.rb
|
|
132
|
-
- lib/csv_plus_plus/
|
|
147
|
+
- lib/csv_plus_plus/error/error.rb
|
|
148
|
+
- lib/csv_plus_plus/error/formula_syntax_error.rb
|
|
149
|
+
- lib/csv_plus_plus/error/modifier_syntax_error.rb
|
|
150
|
+
- lib/csv_plus_plus/error/modifier_validation_error.rb
|
|
151
|
+
- lib/csv_plus_plus/error/syntax_error.rb
|
|
152
|
+
- lib/csv_plus_plus/error/writer_error.rb
|
|
133
153
|
- lib/csv_plus_plus/google_api_client.rb
|
|
134
154
|
- lib/csv_plus_plus/google_options.rb
|
|
135
|
-
- lib/csv_plus_plus/graph.rb
|
|
136
|
-
- lib/csv_plus_plus/language/ast_builder.rb
|
|
137
|
-
- lib/csv_plus_plus/language/benchmarked_compiler.rb
|
|
138
|
-
- lib/csv_plus_plus/language/builtins.rb
|
|
139
|
-
- lib/csv_plus_plus/language/cell_value.tab.rb
|
|
140
|
-
- lib/csv_plus_plus/language/code_section.tab.rb
|
|
141
|
-
- lib/csv_plus_plus/language/compiler.rb
|
|
142
|
-
- lib/csv_plus_plus/language/entities.rb
|
|
143
|
-
- lib/csv_plus_plus/language/entities/boolean.rb
|
|
144
|
-
- lib/csv_plus_plus/language/entities/cell_reference.rb
|
|
145
|
-
- lib/csv_plus_plus/language/entities/entity.rb
|
|
146
|
-
- lib/csv_plus_plus/language/entities/function.rb
|
|
147
|
-
- lib/csv_plus_plus/language/entities/function_call.rb
|
|
148
|
-
- lib/csv_plus_plus/language/entities/number.rb
|
|
149
|
-
- lib/csv_plus_plus/language/entities/runtime_value.rb
|
|
150
|
-
- lib/csv_plus_plus/language/entities/string.rb
|
|
151
|
-
- lib/csv_plus_plus/language/entities/variable.rb
|
|
152
|
-
- lib/csv_plus_plus/language/references.rb
|
|
153
|
-
- lib/csv_plus_plus/language/runtime.rb
|
|
154
|
-
- lib/csv_plus_plus/language/scope.rb
|
|
155
|
-
- lib/csv_plus_plus/language/syntax_error.rb
|
|
156
155
|
- lib/csv_plus_plus/lexer.rb
|
|
157
156
|
- lib/csv_plus_plus/lexer/lexer.rb
|
|
158
157
|
- lib/csv_plus_plus/lexer/tokenizer.rb
|
|
159
158
|
- lib/csv_plus_plus/modifier.rb
|
|
160
|
-
- lib/csv_plus_plus/modifier.
|
|
159
|
+
- lib/csv_plus_plus/modifier/conditional_formatting.rb
|
|
160
|
+
- lib/csv_plus_plus/modifier/data_validation.rb
|
|
161
|
+
- lib/csv_plus_plus/modifier/expand.rb
|
|
162
|
+
- lib/csv_plus_plus/modifier/google_sheet_modifier.rb
|
|
163
|
+
- lib/csv_plus_plus/modifier/modifier.rb
|
|
164
|
+
- lib/csv_plus_plus/modifier/modifier_validator.rb
|
|
165
|
+
- lib/csv_plus_plus/modifier/rubyxl_modifier.rb
|
|
161
166
|
- lib/csv_plus_plus/options.rb
|
|
167
|
+
- lib/csv_plus_plus/parser/cell_value.tab.rb
|
|
168
|
+
- lib/csv_plus_plus/parser/code_section.tab.rb
|
|
169
|
+
- lib/csv_plus_plus/parser/modifier.tab.rb
|
|
162
170
|
- lib/csv_plus_plus/row.rb
|
|
171
|
+
- lib/csv_plus_plus/runtime.rb
|
|
172
|
+
- lib/csv_plus_plus/runtime/can_define_references.rb
|
|
173
|
+
- lib/csv_plus_plus/runtime/can_resolve_references.rb
|
|
174
|
+
- lib/csv_plus_plus/runtime/graph.rb
|
|
175
|
+
- lib/csv_plus_plus/runtime/position_tracker.rb
|
|
176
|
+
- lib/csv_plus_plus/runtime/references.rb
|
|
177
|
+
- lib/csv_plus_plus/runtime/runtime.rb
|
|
178
|
+
- lib/csv_plus_plus/source_code.rb
|
|
163
179
|
- lib/csv_plus_plus/template.rb
|
|
164
180
|
- lib/csv_plus_plus/version.rb
|
|
165
181
|
- lib/csv_plus_plus/writer.rb
|
|
@@ -168,11 +184,9 @@ files:
|
|
|
168
184
|
- lib/csv_plus_plus/writer/excel.rb
|
|
169
185
|
- lib/csv_plus_plus/writer/file_backer_upper.rb
|
|
170
186
|
- lib/csv_plus_plus/writer/google_sheet_builder.rb
|
|
171
|
-
- lib/csv_plus_plus/writer/google_sheet_modifier.rb
|
|
172
187
|
- lib/csv_plus_plus/writer/google_sheets.rb
|
|
173
188
|
- lib/csv_plus_plus/writer/open_document.rb
|
|
174
189
|
- lib/csv_plus_plus/writer/rubyxl_builder.rb
|
|
175
|
-
- lib/csv_plus_plus/writer/rubyxl_modifier.rb
|
|
176
190
|
homepage: https://github.com/patrickomatic/csv-plus-plus
|
|
177
191
|
licenses:
|
|
178
192
|
- MIT
|
|
@@ -182,7 +196,7 @@ metadata:
|
|
|
182
196
|
github_repo: git://github.com/patrickomatic/csv-plus-plus
|
|
183
197
|
homepage_uri: https://github.com/patrickomatic/csv-plus-plus
|
|
184
198
|
source_code_uri: https://github.com/patrickomatic/csv-plus-plus
|
|
185
|
-
changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/CHANGELOG.md
|
|
199
|
+
changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/docs/CHANGELOG.md
|
|
186
200
|
rubygems_mfa_required: 'true'
|
|
187
201
|
post_install_message:
|
|
188
202
|
rdoc_options: []
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative './language/code_section.tab'
|
|
4
|
-
require_relative './language/entities'
|
|
5
|
-
|
|
6
|
-
module CSVPlusPlus
|
|
7
|
-
# A representation of the code section part of a template (the variable and function definitions)
|
|
8
|
-
#
|
|
9
|
-
# @attr variables [Hash<Symbol, Variable>] All defined variables
|
|
10
|
-
# @attr_reader functions [Hash<Symbol, Function>] All defined functions
|
|
11
|
-
class CodeSection
|
|
12
|
-
attr_reader :functions
|
|
13
|
-
attr_accessor :variables
|
|
14
|
-
|
|
15
|
-
# @param variables [Hash<Symbol, Variable>] Initial variables
|
|
16
|
-
# @param functions [Hash<Symbol, Variable>] Initial functions
|
|
17
|
-
def initialize(variables: {}, functions: {})
|
|
18
|
-
@variables = variables
|
|
19
|
-
@functions = functions
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Define a (or re-define an existing) variable
|
|
23
|
-
#
|
|
24
|
-
# @param id [String, Symbol] The identifier for the variable
|
|
25
|
-
# @param entity [Entity] The value (entity) the variable holds
|
|
26
|
-
def def_variable(id, entity)
|
|
27
|
-
@variables[id.to_sym] = entity
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Define (or re-define existing) variables
|
|
31
|
-
#
|
|
32
|
-
# @param variables [Hash<Symbol, Variable>] Variables to define
|
|
33
|
-
def def_variables(variables)
|
|
34
|
-
variables.each { |id, entity| def_variable(id, entity) }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Define a (or re-define an existing) function
|
|
38
|
-
#
|
|
39
|
-
# @param id [String, Symbol] The identifier for the function
|
|
40
|
-
# @param entity [Entities::Function] The defined function
|
|
41
|
-
def def_function(id, entity)
|
|
42
|
-
@functions[id.to_sym] = entity
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Is the variable defined?
|
|
46
|
-
#
|
|
47
|
-
# @param var_id [Symbol, String] The identifier of the variable
|
|
48
|
-
#
|
|
49
|
-
# @return [boolean]
|
|
50
|
-
def defined_variable?(var_id)
|
|
51
|
-
@variables.key?(var_id.to_sym)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Is the function defined?
|
|
55
|
-
#
|
|
56
|
-
# @param fn_id [Symbol, String] The identifier of the function
|
|
57
|
-
#
|
|
58
|
-
# @return [boolean]
|
|
59
|
-
def defined_function?(fn_id)
|
|
60
|
-
@functions.key?(fn_id.to_sym)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# @return [String]
|
|
64
|
-
def to_s
|
|
65
|
-
"CodeSection(functions: #{@functions}, variables: #{@variables})"
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Provide a summary of the functions and variables compiled (to show in verbose mode)
|
|
69
|
-
#
|
|
70
|
-
# @return [String]
|
|
71
|
-
def verbose_summary
|
|
72
|
-
<<~SUMMARY
|
|
73
|
-
# Code Section Summary
|
|
74
|
-
|
|
75
|
-
## Resolved Variables
|
|
76
|
-
|
|
77
|
-
#{variable_summary}
|
|
78
|
-
|
|
79
|
-
## Functions
|
|
80
|
-
|
|
81
|
-
#{function_summary}
|
|
82
|
-
SUMMARY
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
87
|
-
def variable_summary
|
|
88
|
-
return '(no variables defined)' if @variables.empty?
|
|
89
|
-
|
|
90
|
-
@variables.map { |k, v| "#{k} := #{v}" }
|
|
91
|
-
.join("\n")
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def function_summary
|
|
95
|
-
return '(no functions defined)' if @functions.empty?
|
|
96
|
-
|
|
97
|
-
@functions.map { |k, f| "#{k}: #{f}" }
|
|
98
|
-
.join("\n")
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
data/lib/csv_plus_plus/expand.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
Expand =
|
|
5
|
-
::Struct.new(:repetitions) do
|
|
6
|
-
# Does this infinitely expand?
|
|
7
|
-
def infinite?
|
|
8
|
-
repetitions.nil?
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# to_s
|
|
12
|
-
def to_s
|
|
13
|
-
"Expand #{repetitions || 'infinity'}"
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
public_constant :Expand
|
|
18
|
-
end
|
data/lib/csv_plus_plus/graph.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'tsort'
|
|
4
|
-
|
|
5
|
-
module CSVPlusPlus
|
|
6
|
-
# Graph ordering and searching functions
|
|
7
|
-
module Graph
|
|
8
|
-
# Get a list of all variables references in a given +ast+
|
|
9
|
-
# TODO: this is only used in one place - refactor it
|
|
10
|
-
def self.variable_references(ast, runtime, include_runtime_variables: false)
|
|
11
|
-
depth_first_search(ast) do |node|
|
|
12
|
-
next unless node.variable?
|
|
13
|
-
|
|
14
|
-
node.id if !runtime.runtime_variable?(node.id) || include_runtime_variables
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Create a dependency graph of +variables+
|
|
19
|
-
def self.dependency_graph(variables, runtime)
|
|
20
|
-
::CSVPlusPlus::Graph::DependencyGraph[
|
|
21
|
-
variables.map { |var_id, ast| [var_id, variable_references(ast, runtime)] }
|
|
22
|
-
]
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Perform a topological sort on a +DependencyGraph+. A toplogical sort is noteworthy
|
|
26
|
-
# because it will give us the order in which we need to resolve our variable dependencies.
|
|
27
|
-
#
|
|
28
|
-
# Given this dependency graph:
|
|
29
|
-
#
|
|
30
|
-
# { a: [b c], b: [c], c: [d], d: [] }
|
|
31
|
-
#
|
|
32
|
-
# it will return:
|
|
33
|
-
#
|
|
34
|
-
# [d, c, b, a]
|
|
35
|
-
#
|
|
36
|
-
def self.topological_sort(dependencies)
|
|
37
|
-
dependencies.tsort
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Do a DFS on an AST starting at +node+
|
|
41
|
-
def self.depth_first_search(node, accum = [], &)
|
|
42
|
-
ret = yield(node)
|
|
43
|
-
accum << ret unless ret.nil?
|
|
44
|
-
|
|
45
|
-
return accum unless node.function_call?
|
|
46
|
-
|
|
47
|
-
node.arguments.each { |n| depth_first_search(n, accum, &) }
|
|
48
|
-
accum
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# A dependency graph represented as a +Hash+ which will be used by our +topological_sort+ function
|
|
52
|
-
class DependencyGraph < Hash
|
|
53
|
-
include ::TSort
|
|
54
|
-
alias tsort_each_node each_key
|
|
55
|
-
|
|
56
|
-
# sort each child
|
|
57
|
-
def tsort_each_child(node, &)
|
|
58
|
-
fetch(node).each(&)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative './entities'
|
|
4
|
-
|
|
5
|
-
module CSVPlusPlus
|
|
6
|
-
module Language
|
|
7
|
-
# Some helpful functions that can be mixed into a class to help building ASTs
|
|
8
|
-
module ASTBuilder
|
|
9
|
-
# Let the current class have functions which can build a given entity by calling it's type. For example
|
|
10
|
-
# +number(1)+, +variable(:foo)+
|
|
11
|
-
#
|
|
12
|
-
# @param method_name [Symbol] The +method_name+ to respond to
|
|
13
|
-
# @param arguments [] The arguments to create the entity with
|
|
14
|
-
#
|
|
15
|
-
# @return [Entity, #super]
|
|
16
|
-
def method_missing(method_name, *args, **kwargs, &)
|
|
17
|
-
entity_class = ::CSVPlusPlus::Language::TYPES[method_name.to_sym]
|
|
18
|
-
return super unless entity_class
|
|
19
|
-
|
|
20
|
-
entity_class.new(*args, **kwargs, &)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Let the current class have functions which can build a given entity by calling it's type. For example
|
|
24
|
-
# +number(1)+, +variable(:foo)+
|
|
25
|
-
#
|
|
26
|
-
# @param method_name [Symbol] The +method_name+ to respond to
|
|
27
|
-
# @param arguments [] The arguments to create the entity with
|
|
28
|
-
#
|
|
29
|
-
# @return [Boolean, #super]
|
|
30
|
-
def respond_to_missing?(method_name, *_arguments)
|
|
31
|
-
::CSVPlusPlus::Language::TYPES.include?(method_name.to_sym) || super
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Turns index-based/X,Y coordinates into a A1 format
|
|
35
|
-
#
|
|
36
|
-
# @param row_index [Integer]
|
|
37
|
-
# @param cell_index [Integer]
|
|
38
|
-
#
|
|
39
|
-
# @return [String]
|
|
40
|
-
def ref(row_index: nil, cell_index: nil)
|
|
41
|
-
return unless row_index || cell_index
|
|
42
|
-
|
|
43
|
-
rowref = row_index ? (row_index + 1).to_s : ''
|
|
44
|
-
cellref = cell_index ? cell_ref(cell_index) : ''
|
|
45
|
-
cell_reference([cellref, rowref].join)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
ALPHA = ('A'..'Z').to_a.freeze
|
|
51
|
-
private_constant :ALPHA
|
|
52
|
-
|
|
53
|
-
def cell_ref(cell_index)
|
|
54
|
-
c = cell_index.dup
|
|
55
|
-
ref = ''
|
|
56
|
-
|
|
57
|
-
while c >= 0
|
|
58
|
-
# rubocop:disable Lint/ConstantResolution
|
|
59
|
-
ref += ALPHA[c % 26]
|
|
60
|
-
# rubocop:enable Lint/ConstantResolution
|
|
61
|
-
c = (c / 26).floor - 1
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
ref.reverse
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'benchmark'
|
|
4
|
-
|
|
5
|
-
module CSVPlusPlus
|
|
6
|
-
module Language
|
|
7
|
-
# Extend a +Compiler+ class and add benchmark timings
|
|
8
|
-
# @attr_reader timings [Array<Benchmark::Tms>] +Benchmark+ timings that have been accumulated by each step of
|
|
9
|
-
# compilation
|
|
10
|
-
# @attr_reader benchmark [Benchmark] A +Benchmark+ instance
|
|
11
|
-
module BenchmarkedCompiler
|
|
12
|
-
attr_reader :benchmark, :timings
|
|
13
|
-
|
|
14
|
-
# Wrap a +Compiler+ with our instance methods that add benchmarks
|
|
15
|
-
def self.with_benchmarks(compiler, &block)
|
|
16
|
-
::Benchmark.benchmark(::Benchmark::CAPTION, 25, ::Benchmark::FORMAT, '> Total') do |x|
|
|
17
|
-
# compiler = new(options:, runtime:, benchmark: x)
|
|
18
|
-
compiler.extend(self)
|
|
19
|
-
compiler.benchmark = x
|
|
20
|
-
|
|
21
|
-
block.call(compiler)
|
|
22
|
-
|
|
23
|
-
[compiler.timings.reduce(:+)]
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# @param benchmark [Benchmark] A +Benchmark+ instance
|
|
28
|
-
def benchmark=(benchmark)
|
|
29
|
-
@benchmark = benchmark
|
|
30
|
-
@timings = []
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Time the Compiler#outputting! stage
|
|
34
|
-
def outputting!
|
|
35
|
-
time_stage('Writing the spreadsheet') { super }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
protected
|
|
39
|
-
|
|
40
|
-
def parse_code_section!
|
|
41
|
-
time_stage('Parsing code section') { super }
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def parse_csv_section!
|
|
45
|
-
time_stage('Parsing CSV section') { super }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def expanding
|
|
49
|
-
time_stage('Expanding rows') { super }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def resolve_all_cells!(template)
|
|
53
|
-
time_stage('Resolving each cell') { super(template) }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
def time_stage(stage, &block)
|
|
59
|
-
ret = nil
|
|
60
|
-
@timings << @benchmark.report(stage) { ret = block.call }
|
|
61
|
-
ret
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative './ast_builder'
|
|
4
|
-
|
|
5
|
-
module CSVPlusPlus
|
|
6
|
-
module Language
|
|
7
|
-
# Provides ASTs for builtin functions and variables
|
|
8
|
-
module Builtins
|
|
9
|
-
extend ::CSVPlusPlus::Language::ASTBuilder
|
|
10
|
-
|
|
11
|
-
VARIABLES = {
|
|
12
|
-
# The number (integer) of the current cell. Starts at 1
|
|
13
|
-
cellnum: runtime_value(->(runtime) { number(runtime.cell_index + 1) }),
|
|
14
|
-
|
|
15
|
-
# A reference to the current cell
|
|
16
|
-
cellref: runtime_value(->(runtime) { ref(row_index: runtime.row_index, cell_index: runtime.cell_index) }),
|
|
17
|
-
|
|
18
|
-
# A reference to the row above
|
|
19
|
-
rowabove: runtime_value(->(runtime) { ref(row_index: [0, (runtime.row_index - 1)].max) }),
|
|
20
|
-
|
|
21
|
-
# A reference to the row below
|
|
22
|
-
rowbelow: runtime_value(->(runtime) { ref(row_index: runtime.row_index + 1) }),
|
|
23
|
-
|
|
24
|
-
# The number (integer) of the current row. Starts at 1
|
|
25
|
-
rownum: runtime_value(->(runtime) { number(runtime.rownum) }),
|
|
26
|
-
|
|
27
|
-
# A reference to the current row
|
|
28
|
-
rowref: runtime_value(->(runtime) { ref(row_index: runtime.row_index) })
|
|
29
|
-
}.freeze
|
|
30
|
-
public_constant :VARIABLES
|
|
31
|
-
|
|
32
|
-
FUNCTIONS = {
|
|
33
|
-
# TODO: A reference to a cell in a given row?
|
|
34
|
-
# A reference to a cell above the current row
|
|
35
|
-
cellabove: runtime_value(->(runtime, args) { cell_reference([args[0], [1, (runtime.rownum - 1)].max].join) }),
|
|
36
|
-
|
|
37
|
-
# A reference to a cell in the current row
|
|
38
|
-
celladjacent: runtime_value(->(runtime, args) { cell_reference([args[0], runtime.rownum].join) }),
|
|
39
|
-
|
|
40
|
-
# A reference to a cell below the current row
|
|
41
|
-
cellbelow: runtime_value(->(runtime, args) { cell_reference([args[0], runtime.rownum + 1].join) })
|
|
42
|
-
}.freeze
|
|
43
|
-
public_constant :FUNCTIONS
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|