csv_plus_plus 0.1.2 → 0.2.0
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 +9 -5
- data/{CHANGELOG.md → docs/CHANGELOG.md} +25 -0
- data/lib/csv_plus_plus/a1_reference.rb +202 -0
- data/lib/csv_plus_plus/benchmarked_compiler.rb +70 -20
- data/lib/csv_plus_plus/cell.rb +29 -41
- data/lib/csv_plus_plus/cli.rb +53 -80
- data/lib/csv_plus_plus/cli_flag.rb +71 -71
- data/lib/csv_plus_plus/color.rb +32 -7
- data/lib/csv_plus_plus/compiler.rb +98 -66
- data/lib/csv_plus_plus/entities/ast_builder.rb +30 -39
- data/lib/csv_plus_plus/entities/boolean.rb +26 -10
- data/lib/csv_plus_plus/entities/builtins.rb +66 -24
- data/lib/csv_plus_plus/entities/date.rb +42 -6
- data/lib/csv_plus_plus/entities/entity.rb +17 -69
- data/lib/csv_plus_plus/entities/entity_with_arguments.rb +44 -0
- data/lib/csv_plus_plus/entities/function.rb +34 -11
- data/lib/csv_plus_plus/entities/function_call.rb +49 -10
- data/lib/csv_plus_plus/entities/has_identifier.rb +19 -0
- data/lib/csv_plus_plus/entities/number.rb +30 -11
- data/lib/csv_plus_plus/entities/reference.rb +77 -0
- data/lib/csv_plus_plus/entities/runtime_value.rb +43 -13
- data/lib/csv_plus_plus/entities/string.rb +23 -7
- data/lib/csv_plus_plus/entities.rb +7 -16
- data/lib/csv_plus_plus/error/cli_error.rb +17 -0
- data/lib/csv_plus_plus/error/compiler_error.rb +17 -0
- data/lib/csv_plus_plus/error/error.rb +25 -2
- data/lib/csv_plus_plus/error/formula_syntax_error.rb +12 -12
- data/lib/csv_plus_plus/error/modifier_syntax_error.rb +34 -12
- data/lib/csv_plus_plus/error/modifier_validation_error.rb +21 -27
- data/lib/csv_plus_plus/error/positional_error.rb +15 -0
- data/lib/csv_plus_plus/error/writer_error.rb +8 -0
- data/lib/csv_plus_plus/error.rb +5 -1
- data/lib/csv_plus_plus/error_formatter.rb +111 -0
- data/lib/csv_plus_plus/google_api_client.rb +25 -10
- data/lib/csv_plus_plus/lexer/racc_lexer.rb +144 -0
- data/lib/csv_plus_plus/lexer/tokenizer.rb +58 -17
- data/lib/csv_plus_plus/lexer.rb +64 -1
- data/lib/csv_plus_plus/modifier/conditional_formatting.rb +1 -0
- data/lib/csv_plus_plus/modifier/data_validation.rb +138 -0
- data/lib/csv_plus_plus/modifier/expand.rb +78 -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 +89 -160
- data/lib/csv_plus_plus/options/file_options.rb +49 -0
- data/lib/csv_plus_plus/options/google_sheets_options.rb +42 -0
- data/lib/csv_plus_plus/options/options.rb +97 -0
- data/lib/csv_plus_plus/options.rb +34 -77
- data/lib/csv_plus_plus/parser/cell_value.tab.rb +66 -67
- data/lib/csv_plus_plus/parser/code_section.tab.rb +86 -83
- data/lib/csv_plus_plus/parser/modifier.tab.rb +57 -53
- data/lib/csv_plus_plus/reader/csv.rb +50 -0
- data/lib/csv_plus_plus/reader/google_sheets.rb +129 -0
- data/lib/csv_plus_plus/reader/reader.rb +27 -0
- data/lib/csv_plus_plus/reader/rubyxl.rb +37 -0
- data/lib/csv_plus_plus/reader.rb +14 -0
- data/lib/csv_plus_plus/row.rb +53 -12
- data/lib/csv_plus_plus/runtime/graph.rb +68 -0
- data/lib/csv_plus_plus/runtime/position.rb +242 -0
- data/lib/csv_plus_plus/runtime/references.rb +115 -0
- data/lib/csv_plus_plus/runtime/runtime.rb +132 -0
- data/lib/csv_plus_plus/runtime/scope.rb +280 -0
- data/lib/csv_plus_plus/runtime.rb +34 -191
- data/lib/csv_plus_plus/source_code.rb +71 -0
- data/lib/csv_plus_plus/template.rb +71 -39
- data/lib/csv_plus_plus/version.rb +2 -1
- data/lib/csv_plus_plus/writer/csv.rb +37 -8
- data/lib/csv_plus_plus/writer/excel.rb +25 -5
- data/lib/csv_plus_plus/writer/file_backer_upper.rb +27 -13
- data/lib/csv_plus_plus/writer/google_sheets.rb +29 -85
- data/lib/csv_plus_plus/writer/google_sheets_builder.rb +179 -0
- data/lib/csv_plus_plus/writer/merger.rb +31 -0
- data/lib/csv_plus_plus/writer/open_document.rb +21 -2
- data/lib/csv_plus_plus/writer/rubyxl_builder.rb +140 -42
- data/lib/csv_plus_plus/writer/writer.rb +42 -0
- data/lib/csv_plus_plus/writer.rb +79 -10
- data/lib/csv_plus_plus.rb +47 -18
- metadata +50 -21
- data/lib/csv_plus_plus/can_define_references.rb +0 -88
- data/lib/csv_plus_plus/can_resolve_references.rb +0 -8
- data/lib/csv_plus_plus/data_validation.rb +0 -138
- data/lib/csv_plus_plus/entities/cell_reference.rb +0 -60
- data/lib/csv_plus_plus/entities/variable.rb +0 -25
- data/lib/csv_plus_plus/error/syntax_error.rb +0 -58
- data/lib/csv_plus_plus/expand.rb +0 -20
- data/lib/csv_plus_plus/google_options.rb +0 -27
- data/lib/csv_plus_plus/graph.rb +0 -62
- data/lib/csv_plus_plus/lexer/lexer.rb +0 -85
- data/lib/csv_plus_plus/references.rb +0 -68
- data/lib/csv_plus_plus/scope.rb +0 -196
- data/lib/csv_plus_plus/validated_modifier.rb +0 -164
- data/lib/csv_plus_plus/writer/base_writer.rb +0 -20
- data/lib/csv_plus_plus/writer/google_sheet_builder.rb +0 -147
- data/lib/csv_plus_plus/writer/google_sheet_modifier.rb +0 -77
- data/lib/csv_plus_plus/writer/rubyxl_modifier.rb +0 -59
data/lib/csv_plus_plus.rb
CHANGED
|
@@ -1,66 +1,95 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
4
|
+
require 'sorbet-runtime'
|
|
5
|
+
|
|
3
6
|
require 'benchmark'
|
|
4
7
|
require 'csv'
|
|
5
8
|
require 'fileutils'
|
|
6
9
|
require 'google/apis/drive_v3'
|
|
7
10
|
require 'google/apis/sheets_v4'
|
|
8
11
|
require 'googleauth'
|
|
12
|
+
require 'optparse'
|
|
9
13
|
require 'pathname'
|
|
10
14
|
require 'rubyXL'
|
|
11
15
|
require 'rubyXL/convenience_methods'
|
|
12
16
|
require 'set'
|
|
17
|
+
require 'strscan'
|
|
13
18
|
require 'tempfile'
|
|
14
19
|
|
|
20
|
+
require_relative 'csv_plus_plus/a1_reference'
|
|
21
|
+
require_relative 'csv_plus_plus/google_api_client'
|
|
22
|
+
require_relative 'csv_plus_plus/options'
|
|
23
|
+
require_relative 'csv_plus_plus/runtime/position'
|
|
24
|
+
require_relative 'csv_plus_plus/source_code'
|
|
25
|
+
|
|
26
|
+
require_relative 'csv_plus_plus/cli_flag'
|
|
15
27
|
require_relative 'csv_plus_plus/entities'
|
|
16
28
|
require_relative 'csv_plus_plus/error'
|
|
29
|
+
require_relative 'csv_plus_plus/error_formatter'
|
|
17
30
|
|
|
18
|
-
require_relative 'csv_plus_plus/cell'
|
|
19
31
|
require_relative 'csv_plus_plus/cli'
|
|
32
|
+
require_relative 'csv_plus_plus/runtime'
|
|
33
|
+
|
|
34
|
+
require_relative 'csv_plus_plus/cell'
|
|
20
35
|
require_relative 'csv_plus_plus/color'
|
|
36
|
+
require_relative 'csv_plus_plus/modifier'
|
|
37
|
+
|
|
38
|
+
require_relative 'csv_plus_plus/parser/cell_value.tab'
|
|
39
|
+
require_relative 'csv_plus_plus/parser/code_section.tab'
|
|
40
|
+
require_relative 'csv_plus_plus/parser/modifier.tab'
|
|
21
41
|
|
|
22
42
|
require_relative 'csv_plus_plus/compiler'
|
|
23
|
-
require_relative 'csv_plus_plus/runtime'
|
|
24
43
|
|
|
25
44
|
require_relative 'csv_plus_plus/lexer'
|
|
26
|
-
require_relative 'csv_plus_plus/
|
|
27
|
-
require_relative 'csv_plus_plus/modifier'
|
|
28
|
-
require_relative 'csv_plus_plus/options'
|
|
29
|
-
require_relative 'csv_plus_plus/parser/modifier.tab'
|
|
45
|
+
require_relative 'csv_plus_plus/reader'
|
|
30
46
|
require_relative 'csv_plus_plus/row'
|
|
31
47
|
require_relative 'csv_plus_plus/template'
|
|
32
|
-
require_relative 'csv_plus_plus/validated_modifier'
|
|
33
48
|
require_relative 'csv_plus_plus/writer'
|
|
34
49
|
|
|
50
|
+
require_relative 'csv_plus_plus/benchmarked_compiler'
|
|
51
|
+
|
|
35
52
|
# A programming language for writing rich CSV files
|
|
36
53
|
module CSVPlusPlus
|
|
54
|
+
extend ::T::Sig
|
|
55
|
+
|
|
56
|
+
sig { params(source_code: ::CSVPlusPlus::SourceCode, options: ::CSVPlusPlus::Options::Options).void }
|
|
37
57
|
# Parse the input into a +Template+ and write it to the desired format
|
|
38
58
|
#
|
|
39
|
-
# @param
|
|
40
|
-
# @param filename [String, nil] The filename the input was read from. +nil+ if it is read from stdin.
|
|
59
|
+
# @param source_code [SourceCode] The source code being compiled
|
|
41
60
|
# @param options [Options] The various options to compile with
|
|
42
|
-
def self.
|
|
43
|
-
|
|
61
|
+
def self.cli_compile(source_code, options)
|
|
62
|
+
runtime = ::CSVPlusPlus::Runtime.new(source_code:)
|
|
44
63
|
|
|
45
|
-
|
|
64
|
+
warn(options.verbose_summary) if options.verbose
|
|
46
65
|
|
|
47
66
|
::CSVPlusPlus::Compiler.with_compiler(options:, runtime:) do |compiler|
|
|
48
67
|
template = compiler.compile_template
|
|
49
|
-
|
|
50
68
|
warn(template.verbose_summary) if options.verbose
|
|
51
69
|
|
|
52
|
-
write_template(template
|
|
70
|
+
write_template(template:, compiler:, options:)
|
|
53
71
|
end
|
|
72
|
+
rescue ::StandardError => e
|
|
73
|
+
::CSVPlusPlus::ErrorFormatter.new(runtime: ::T.must(runtime), options:).handle_error(e)
|
|
74
|
+
# the caller will exit(1)
|
|
75
|
+
raise(e)
|
|
54
76
|
end
|
|
55
77
|
|
|
78
|
+
sig do
|
|
79
|
+
params(
|
|
80
|
+
compiler: ::CSVPlusPlus::Compiler,
|
|
81
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
82
|
+
template: ::CSVPlusPlus::Template
|
|
83
|
+
).void
|
|
84
|
+
end
|
|
56
85
|
# Write the results (and possibly make a backup) of a compiled +template+
|
|
57
86
|
#
|
|
58
|
-
# @param template [Template] The compiled template
|
|
59
87
|
# @param compiler [Compiler] The compiler currently in use
|
|
60
88
|
# @param options [Options] The options we're running with
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
89
|
+
# @param template [Template] The compiled template
|
|
90
|
+
def self.write_template(compiler:, options:, template:)
|
|
91
|
+
compiler.outputting! do |position|
|
|
92
|
+
output = ::CSVPlusPlus::Writer.writer(options, position)
|
|
64
93
|
output.write_backup if options.backup
|
|
65
94
|
output.write(template)
|
|
66
95
|
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.
|
|
4
|
+
version: 0.2.0
|
|
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-05-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: google-apis-drive_v3
|
|
@@ -66,6 +66,20 @@ dependencies:
|
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '3.4'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: sorbet-runtime
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0.5'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0.5'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: bundler
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -118,71 +132,86 @@ executables:
|
|
|
118
132
|
extensions: []
|
|
119
133
|
extra_rdoc_files: []
|
|
120
134
|
files:
|
|
121
|
-
- CHANGELOG.md
|
|
122
135
|
- README.md
|
|
123
136
|
- bin/csv++
|
|
124
137
|
- bin/csvpp
|
|
138
|
+
- docs/CHANGELOG.md
|
|
125
139
|
- lib/csv_plus_plus.rb
|
|
140
|
+
- lib/csv_plus_plus/a1_reference.rb
|
|
126
141
|
- lib/csv_plus_plus/benchmarked_compiler.rb
|
|
127
|
-
- lib/csv_plus_plus/can_define_references.rb
|
|
128
|
-
- lib/csv_plus_plus/can_resolve_references.rb
|
|
129
142
|
- lib/csv_plus_plus/cell.rb
|
|
130
143
|
- lib/csv_plus_plus/cli.rb
|
|
131
144
|
- lib/csv_plus_plus/cli_flag.rb
|
|
132
145
|
- lib/csv_plus_plus/color.rb
|
|
133
146
|
- lib/csv_plus_plus/compiler.rb
|
|
134
|
-
- lib/csv_plus_plus/data_validation.rb
|
|
135
147
|
- lib/csv_plus_plus/entities.rb
|
|
136
148
|
- lib/csv_plus_plus/entities/ast_builder.rb
|
|
137
149
|
- lib/csv_plus_plus/entities/boolean.rb
|
|
138
150
|
- lib/csv_plus_plus/entities/builtins.rb
|
|
139
|
-
- lib/csv_plus_plus/entities/cell_reference.rb
|
|
140
151
|
- lib/csv_plus_plus/entities/date.rb
|
|
141
152
|
- lib/csv_plus_plus/entities/entity.rb
|
|
153
|
+
- lib/csv_plus_plus/entities/entity_with_arguments.rb
|
|
142
154
|
- lib/csv_plus_plus/entities/function.rb
|
|
143
155
|
- lib/csv_plus_plus/entities/function_call.rb
|
|
156
|
+
- lib/csv_plus_plus/entities/has_identifier.rb
|
|
144
157
|
- lib/csv_plus_plus/entities/number.rb
|
|
158
|
+
- lib/csv_plus_plus/entities/reference.rb
|
|
145
159
|
- lib/csv_plus_plus/entities/runtime_value.rb
|
|
146
160
|
- lib/csv_plus_plus/entities/string.rb
|
|
147
|
-
- lib/csv_plus_plus/entities/variable.rb
|
|
148
161
|
- lib/csv_plus_plus/error.rb
|
|
162
|
+
- lib/csv_plus_plus/error/cli_error.rb
|
|
163
|
+
- lib/csv_plus_plus/error/compiler_error.rb
|
|
149
164
|
- lib/csv_plus_plus/error/error.rb
|
|
150
165
|
- lib/csv_plus_plus/error/formula_syntax_error.rb
|
|
151
166
|
- lib/csv_plus_plus/error/modifier_syntax_error.rb
|
|
152
167
|
- lib/csv_plus_plus/error/modifier_validation_error.rb
|
|
153
|
-
- lib/csv_plus_plus/error/
|
|
168
|
+
- lib/csv_plus_plus/error/positional_error.rb
|
|
154
169
|
- lib/csv_plus_plus/error/writer_error.rb
|
|
155
|
-
- lib/csv_plus_plus/
|
|
170
|
+
- lib/csv_plus_plus/error_formatter.rb
|
|
156
171
|
- lib/csv_plus_plus/google_api_client.rb
|
|
157
|
-
- lib/csv_plus_plus/google_options.rb
|
|
158
|
-
- lib/csv_plus_plus/graph.rb
|
|
159
172
|
- lib/csv_plus_plus/lexer.rb
|
|
160
|
-
- lib/csv_plus_plus/lexer/
|
|
173
|
+
- lib/csv_plus_plus/lexer/racc_lexer.rb
|
|
161
174
|
- lib/csv_plus_plus/lexer/tokenizer.rb
|
|
162
175
|
- lib/csv_plus_plus/modifier.rb
|
|
163
176
|
- lib/csv_plus_plus/modifier/conditional_formatting.rb
|
|
177
|
+
- lib/csv_plus_plus/modifier/data_validation.rb
|
|
178
|
+
- lib/csv_plus_plus/modifier/expand.rb
|
|
179
|
+
- lib/csv_plus_plus/modifier/google_sheet_modifier.rb
|
|
180
|
+
- lib/csv_plus_plus/modifier/modifier.rb
|
|
181
|
+
- lib/csv_plus_plus/modifier/modifier_validator.rb
|
|
182
|
+
- lib/csv_plus_plus/modifier/rubyxl_modifier.rb
|
|
164
183
|
- lib/csv_plus_plus/options.rb
|
|
184
|
+
- lib/csv_plus_plus/options/file_options.rb
|
|
185
|
+
- lib/csv_plus_plus/options/google_sheets_options.rb
|
|
186
|
+
- lib/csv_plus_plus/options/options.rb
|
|
165
187
|
- lib/csv_plus_plus/parser/cell_value.tab.rb
|
|
166
188
|
- lib/csv_plus_plus/parser/code_section.tab.rb
|
|
167
189
|
- lib/csv_plus_plus/parser/modifier.tab.rb
|
|
168
|
-
- lib/csv_plus_plus/
|
|
190
|
+
- lib/csv_plus_plus/reader.rb
|
|
191
|
+
- lib/csv_plus_plus/reader/csv.rb
|
|
192
|
+
- lib/csv_plus_plus/reader/google_sheets.rb
|
|
193
|
+
- lib/csv_plus_plus/reader/reader.rb
|
|
194
|
+
- lib/csv_plus_plus/reader/rubyxl.rb
|
|
169
195
|
- lib/csv_plus_plus/row.rb
|
|
170
196
|
- lib/csv_plus_plus/runtime.rb
|
|
171
|
-
- lib/csv_plus_plus/
|
|
197
|
+
- lib/csv_plus_plus/runtime/graph.rb
|
|
198
|
+
- lib/csv_plus_plus/runtime/position.rb
|
|
199
|
+
- lib/csv_plus_plus/runtime/references.rb
|
|
200
|
+
- lib/csv_plus_plus/runtime/runtime.rb
|
|
201
|
+
- lib/csv_plus_plus/runtime/scope.rb
|
|
202
|
+
- lib/csv_plus_plus/source_code.rb
|
|
172
203
|
- lib/csv_plus_plus/template.rb
|
|
173
|
-
- lib/csv_plus_plus/validated_modifier.rb
|
|
174
204
|
- lib/csv_plus_plus/version.rb
|
|
175
205
|
- lib/csv_plus_plus/writer.rb
|
|
176
|
-
- lib/csv_plus_plus/writer/base_writer.rb
|
|
177
206
|
- lib/csv_plus_plus/writer/csv.rb
|
|
178
207
|
- lib/csv_plus_plus/writer/excel.rb
|
|
179
208
|
- lib/csv_plus_plus/writer/file_backer_upper.rb
|
|
180
|
-
- lib/csv_plus_plus/writer/google_sheet_builder.rb
|
|
181
|
-
- lib/csv_plus_plus/writer/google_sheet_modifier.rb
|
|
182
209
|
- lib/csv_plus_plus/writer/google_sheets.rb
|
|
210
|
+
- lib/csv_plus_plus/writer/google_sheets_builder.rb
|
|
211
|
+
- lib/csv_plus_plus/writer/merger.rb
|
|
183
212
|
- lib/csv_plus_plus/writer/open_document.rb
|
|
184
213
|
- lib/csv_plus_plus/writer/rubyxl_builder.rb
|
|
185
|
-
- lib/csv_plus_plus/writer/
|
|
214
|
+
- lib/csv_plus_plus/writer/writer.rb
|
|
186
215
|
homepage: https://github.com/patrickomatic/csv-plus-plus
|
|
187
216
|
licenses:
|
|
188
217
|
- MIT
|
|
@@ -192,7 +221,7 @@ metadata:
|
|
|
192
221
|
github_repo: git://github.com/patrickomatic/csv-plus-plus
|
|
193
222
|
homepage_uri: https://github.com/patrickomatic/csv-plus-plus
|
|
194
223
|
source_code_uri: https://github.com/patrickomatic/csv-plus-plus
|
|
195
|
-
changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/CHANGELOG.md
|
|
224
|
+
changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/docs/CHANGELOG.md
|
|
196
225
|
rubygems_mfa_required: 'true'
|
|
197
226
|
post_install_message:
|
|
198
227
|
rdoc_options: []
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
# Methods for classes that need to manage +@variables+ and +@functions+
|
|
5
|
-
module CanDefineReferences
|
|
6
|
-
# Define a (or re-define an existing) variable
|
|
7
|
-
#
|
|
8
|
-
# @param id [String, Symbol] The identifier for the variable
|
|
9
|
-
# @param entity [Entity] The value (entity) the variable holds
|
|
10
|
-
def def_variable(id, entity)
|
|
11
|
-
variables[id.to_sym] = entity
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Define (or re-define existing) variables
|
|
15
|
-
#
|
|
16
|
-
# @param variables [Hash<Symbol, Variable>] Variables to define
|
|
17
|
-
def def_variables(vars)
|
|
18
|
-
vars.each { |id, entity| def_variable(id, entity) }
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Define a (or re-define an existing) function
|
|
22
|
-
#
|
|
23
|
-
# @param id [String, Symbol] The identifier for the function
|
|
24
|
-
# @param entity [Entities::Function] The defined function
|
|
25
|
-
def def_function(id, entity)
|
|
26
|
-
functions[id.to_sym] = entity
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Is the variable defined?
|
|
30
|
-
#
|
|
31
|
-
# @param var_id [Symbol, String] The identifier of the variable
|
|
32
|
-
#
|
|
33
|
-
# @return [boolean]
|
|
34
|
-
def defined_variable?(var_id)
|
|
35
|
-
variables.key?(var_id.to_sym)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Is the function defined?
|
|
39
|
-
#
|
|
40
|
-
# @param fn_id [Symbol, String] The identifier of the function
|
|
41
|
-
#
|
|
42
|
-
# @return [boolean]
|
|
43
|
-
def defined_function?(fn_id)
|
|
44
|
-
functions.key?(fn_id.to_sym)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Provide a summary of the functions and variables compiled (to show in verbose mode)
|
|
48
|
-
#
|
|
49
|
-
# @return [String]
|
|
50
|
-
def verbose_summary
|
|
51
|
-
<<~SUMMARY
|
|
52
|
-
# Code Section Summary
|
|
53
|
-
|
|
54
|
-
## Resolved Variables
|
|
55
|
-
|
|
56
|
-
#{variable_summary}
|
|
57
|
-
|
|
58
|
-
## Functions
|
|
59
|
-
|
|
60
|
-
#{function_summary}
|
|
61
|
-
SUMMARY
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
private
|
|
65
|
-
|
|
66
|
-
def variables
|
|
67
|
-
@variables ||= {}
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def functions
|
|
71
|
-
@functions ||= {}
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def variable_summary
|
|
75
|
-
return '(no variables defined)' if variables.empty?
|
|
76
|
-
|
|
77
|
-
variables.map { |k, v| "#{k} := #{v}" }
|
|
78
|
-
.join("\n")
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def function_summary
|
|
82
|
-
return '(no functions defined)' if functions.empty?
|
|
83
|
-
|
|
84
|
-
functions.map { |k, f| "#{k}: #{f}" }
|
|
85
|
-
.join("\n")
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
# A validation on a cell value. Used to support the `validate=` modifier directive. This is mostly based on the
|
|
5
|
-
# Google Sheets API spec which can be seen here:
|
|
6
|
-
#
|
|
7
|
-
# {https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ConditionType}
|
|
8
|
-
#
|
|
9
|
-
# @attr_reader arguments [Array<::String>] The parsed arguments as required by the condition.
|
|
10
|
-
# @attr_reader condition [Symbol] The condition (:blank, :text_eq, :date_before, etc.)
|
|
11
|
-
# @attr_reader invalid_reason [::String, nil] If set, the reason why this modifier is not valid.
|
|
12
|
-
class DataValidation
|
|
13
|
-
attr_reader :arguments, :condition, :invalid_reason
|
|
14
|
-
|
|
15
|
-
# @param value [::String] The value to parse as a data validation
|
|
16
|
-
def initialize(value)
|
|
17
|
-
condition, args = unquote(value).split(/\s*:\s*/)
|
|
18
|
-
@arguments = unquote(args || '').split(/\s+/)
|
|
19
|
-
@condition = condition.to_sym
|
|
20
|
-
|
|
21
|
-
validate!
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Each data validation represented by (+condition+) has their own require
|
|
25
|
-
# @return [boolean]
|
|
26
|
-
def valid?
|
|
27
|
-
@invalid_reason.nil?
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
protected
|
|
31
|
-
|
|
32
|
-
def unquote(str)
|
|
33
|
-
# TODO: I'm pretty sure this isn't sufficient and we need to deal with the backslashes
|
|
34
|
-
str.gsub(/^['\s]*|['\s]*$/, '')
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def invalid!(reason)
|
|
38
|
-
@invalid_reason = reason
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def a_number(arg)
|
|
42
|
-
Float(arg)
|
|
43
|
-
rescue ::ArgumentError
|
|
44
|
-
invalid!("Requires a number but given: #{arg}")
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def a1_notation(arg)
|
|
48
|
-
return arg if ::CSVPlusPlus::Entities::CellReference.valid_cell_reference?(arg)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def a_date(arg, allow_relative_date: false)
|
|
52
|
-
return arg if ::CSVPlusPlus::Entities::Date.valid_date?(arg)
|
|
53
|
-
|
|
54
|
-
if allow_relative_date
|
|
55
|
-
a_relative_date(arg)
|
|
56
|
-
else
|
|
57
|
-
invalid!("Requires a date but given: #{arg}")
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def a_relative_date(arg)
|
|
62
|
-
return arg if %w[past_month past_week past_year yesterday today tomorrow].include?(arg.downcase)
|
|
63
|
-
|
|
64
|
-
invalid!('Requires a relative date: past_month, past_week, past_year, yesterday, today or tomorrow')
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def no_args
|
|
68
|
-
return if @arguments.empty?
|
|
69
|
-
|
|
70
|
-
invalid!("Requires no arguments but #{@arguments.length} given: #{@arguments}")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def one_arg
|
|
74
|
-
return @arguments[0] if @arguments.length == 1
|
|
75
|
-
|
|
76
|
-
invalid!("Requires only one argument but #{@arguments.length} given: #{@arguments}")
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def one_arg_or_more
|
|
80
|
-
return @arguments if @arguments.length.positive?
|
|
81
|
-
|
|
82
|
-
invalid!("Requires at least one argument but #{@arguments.length} given: #{@arguments}")
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def two_dates
|
|
86
|
-
return @arguments if @arguments.length == 2 && a_date(@arguments[0]) && a_date(@arguments[1])
|
|
87
|
-
|
|
88
|
-
invalid!("Requires exactly two dates but given: #{@arguments}")
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def two_numbers
|
|
92
|
-
return @arguments if @arguments.length == 2 && a_number(@arguments[0]) && a_number(@arguments[1])
|
|
93
|
-
|
|
94
|
-
invalid!("Requires exactly two numbers but given: #{@arguments}")
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# validate_boolean is a weird one because it can have 0, 1 or 2 @arguments - all of them must be (true | false)
|
|
98
|
-
def validate_boolean
|
|
99
|
-
return @arguments if @arguments.empty?
|
|
100
|
-
|
|
101
|
-
converted_args = @arguments.map(&:strip).map(&:downcase)
|
|
102
|
-
return @arguments if [1, 2].include?(@arguments.length) && converted_args.all? do |arg|
|
|
103
|
-
%w[true false].include?(arg)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
invalid!("Requires 0, 1 or 2 arguments and they all must be either 'true' or 'false'. Received: #{arguments}")
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
110
|
-
def validate!
|
|
111
|
-
case condition.to_sym
|
|
112
|
-
when :blank, :date_is_valid, :not_blank, :text_is_email, :text_is_url
|
|
113
|
-
no_args
|
|
114
|
-
when :text_contains, :text_ends_with, :text_eq, :text_not_contains, :text_starts_with
|
|
115
|
-
one_arg
|
|
116
|
-
when :date_after, :date_before, :date_on_or_after, :date_on_or_before
|
|
117
|
-
a_date(one_arg, allow_relative_date: true)
|
|
118
|
-
when :date_eq, :date_not_eq
|
|
119
|
-
a_date(one_arg)
|
|
120
|
-
when :date_between, :date_not_between
|
|
121
|
-
two_dates
|
|
122
|
-
when :one_of_range
|
|
123
|
-
a1_notation(one_arg)
|
|
124
|
-
when :custom_formula, :one_of_list, :text_not_eq
|
|
125
|
-
one_arg_or_more
|
|
126
|
-
when :number_eq, :number_greater, :number_greater_than_eq, :number_less, :number_less_than_eq, :number_not_eq
|
|
127
|
-
a_number(one_arg)
|
|
128
|
-
when :number_between, :number_not_between
|
|
129
|
-
two_numbers
|
|
130
|
-
when :boolean
|
|
131
|
-
validate_boolean
|
|
132
|
-
else
|
|
133
|
-
invalid!('Not a recognized data validation directive')
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
137
|
-
end
|
|
138
|
-
end
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative './ast_builder'
|
|
4
|
-
require_relative './entity'
|
|
5
|
-
|
|
6
|
-
module CSVPlusPlus
|
|
7
|
-
module Entities
|
|
8
|
-
# A reference to a cell
|
|
9
|
-
#
|
|
10
|
-
# @attr_reader cell_reference [String] The cell reference in A1 format
|
|
11
|
-
class CellReference < Entity
|
|
12
|
-
attr_reader :cell_reference
|
|
13
|
-
|
|
14
|
-
A1_NOTATION_REGEXP = /(['\w]+!)?\w+:\w+/
|
|
15
|
-
public_constant :A1_NOTATION_REGEXP
|
|
16
|
-
|
|
17
|
-
# Create a +CellReference+ to the given indexes
|
|
18
|
-
#
|
|
19
|
-
# @param cell_index [Integer] The current cell index
|
|
20
|
-
# @param row_index [Integer] The current row index
|
|
21
|
-
#
|
|
22
|
-
# @return [CellReference]
|
|
23
|
-
def self.from_index(cell_index:, row_index:)
|
|
24
|
-
return unless row_index || cell_index
|
|
25
|
-
|
|
26
|
-
# I can't just extend this class due to circular references :(
|
|
27
|
-
::Class.new.extend(::CSVPlusPlus::Entities::ASTBuilder).ref(cell_index:, row_index:)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Does the given +cell_reference_string+ conform to a valid cell reference?
|
|
31
|
-
#
|
|
32
|
-
# {https://developers.google.com/sheets/api/guides/concepts}
|
|
33
|
-
#
|
|
34
|
-
# @param cell_reference_string [::String] The string to check if it is a valid cell reference (we assume it's in
|
|
35
|
-
# A1 notation but maybe can support R1C1)
|
|
36
|
-
#
|
|
37
|
-
# @return [boolean]
|
|
38
|
-
def self.valid_cell_reference?(cell_reference_string)
|
|
39
|
-
!(cell_reference_string =~ ::CSVPlusPlus::Entities::CellReference::A1_NOTATION_REGEXP).nil?
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# @param cell_reference [String] The cell reference in A1 format
|
|
43
|
-
def initialize(cell_reference)
|
|
44
|
-
super(:cell_reference)
|
|
45
|
-
|
|
46
|
-
@cell_reference = cell_reference
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# @return [::String]
|
|
50
|
-
def to_s
|
|
51
|
-
@cell_reference
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# @return [Boolean]
|
|
55
|
-
def ==(other)
|
|
56
|
-
super && @cell_reference == other.cell_reference
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
module Entities
|
|
5
|
-
# TODO: get rid of this I think - everything will just be References
|
|
6
|
-
#
|
|
7
|
-
# A reference to a variable
|
|
8
|
-
class Variable < Entity
|
|
9
|
-
# @param id [Symbol] The identifier of the variable
|
|
10
|
-
def initialize(id)
|
|
11
|
-
super(:variable, id:)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# @return [String]
|
|
15
|
-
def to_s
|
|
16
|
-
"$$#{@id}"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# @return [boolean]
|
|
20
|
-
def ==(other)
|
|
21
|
-
super && id == other.id
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
module Error
|
|
5
|
-
# An error that can be thrown for various syntax errors
|
|
6
|
-
class SyntaxError < ::CSVPlusPlus::Error::Error
|
|
7
|
-
# @param runtime [Runtime] The current runtime
|
|
8
|
-
# @param wrapped_error [StandardError] The underlying error that caused the syntax error. For example a
|
|
9
|
-
# Racc::ParseError that was thrown
|
|
10
|
-
def initialize(runtime, wrapped_error: nil)
|
|
11
|
-
@runtime = runtime
|
|
12
|
-
@wrapped_error = wrapped_error
|
|
13
|
-
|
|
14
|
-
super()
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# @return [String]
|
|
18
|
-
def to_s
|
|
19
|
-
to_trace
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Output a verbose user-helpful string that references the current runtime
|
|
23
|
-
def to_verbose_trace
|
|
24
|
-
warn(@wrapped_error.full_message) if @wrapped_error
|
|
25
|
-
warn(@wrapped_error.backtrace) if @wrapped_error
|
|
26
|
-
to_trace
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Output a user-helpful string that references the runtime state
|
|
30
|
-
#
|
|
31
|
-
# @return [String]
|
|
32
|
-
def to_trace
|
|
33
|
-
"#{message_prefix}#{cell_index} #{error_message}"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def cell_index
|
|
39
|
-
row_index = @runtime.row_index
|
|
40
|
-
if @runtime.cell_index
|
|
41
|
-
"[#{row_index},#{@runtime.cell_index}]"
|
|
42
|
-
elsif row_index
|
|
43
|
-
"[#{row_index}]"
|
|
44
|
-
else
|
|
45
|
-
''
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def message_prefix
|
|
50
|
-
line_number = @runtime.line_number
|
|
51
|
-
filename = @runtime.filename
|
|
52
|
-
|
|
53
|
-
line_str = line_number ? ":#{line_number}" : ''
|
|
54
|
-
"#{filename}#{line_str}"
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
data/lib/csv_plus_plus/expand.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
Expand =
|
|
5
|
-
::Struct.new(:repetitions) do
|
|
6
|
-
# Does this infinitely expand?
|
|
7
|
-
#
|
|
8
|
-
# @return [boolean]
|
|
9
|
-
def infinite?
|
|
10
|
-
repetitions.nil?
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# @return [::String]
|
|
14
|
-
def to_s
|
|
15
|
-
"Expand #{repetitions || 'infinity'}"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
public_constant :Expand
|
|
20
|
-
end
|