csv_plus_plus 0.1.3 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +13 -3
- data/docs/CHANGELOG.md +18 -0
- data/lib/csv_plus_plus/a1_reference.rb +202 -0
- data/lib/csv_plus_plus/benchmarked_compiler.rb +3 -3
- data/lib/csv_plus_plus/cell.rb +1 -35
- data/lib/csv_plus_plus/cli.rb +43 -80
- data/lib/csv_plus_plus/cli_flag.rb +77 -70
- data/lib/csv_plus_plus/color.rb +1 -1
- data/lib/csv_plus_plus/compiler.rb +31 -21
- data/lib/csv_plus_plus/entities/ast_builder.rb +11 -4
- data/lib/csv_plus_plus/entities/boolean.rb +16 -9
- data/lib/csv_plus_plus/entities/builtins.rb +68 -40
- data/lib/csv_plus_plus/entities/date.rb +14 -11
- data/lib/csv_plus_plus/entities/entity.rb +11 -29
- data/lib/csv_plus_plus/entities/entity_with_arguments.rb +18 -31
- data/lib/csv_plus_plus/entities/function.rb +22 -11
- data/lib/csv_plus_plus/entities/function_call.rb +35 -11
- data/lib/csv_plus_plus/entities/has_identifier.rb +19 -0
- data/lib/csv_plus_plus/entities/number.rb +15 -10
- data/lib/csv_plus_plus/entities/reference.rb +77 -0
- data/lib/csv_plus_plus/entities/runtime_value.rb +36 -23
- data/lib/csv_plus_plus/entities/string.rb +13 -10
- data/lib/csv_plus_plus/entities.rb +2 -18
- 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 +18 -5
- data/lib/csv_plus_plus/error/formula_syntax_error.rb +12 -13
- data/lib/csv_plus_plus/error/modifier_syntax_error.rb +10 -36
- data/lib/csv_plus_plus/error/modifier_validation_error.rb +6 -32
- data/lib/csv_plus_plus/error/positional_error.rb +15 -0
- data/lib/csv_plus_plus/error/writer_error.rb +1 -1
- data/lib/csv_plus_plus/error.rb +4 -1
- data/lib/csv_plus_plus/error_formatter.rb +111 -0
- data/lib/csv_plus_plus/google_api_client.rb +18 -8
- data/lib/csv_plus_plus/lexer/racc_lexer.rb +144 -0
- data/lib/csv_plus_plus/lexer/tokenizer.rb +53 -17
- data/lib/csv_plus_plus/lexer.rb +40 -1
- data/lib/csv_plus_plus/modifier/data_validation.rb +1 -1
- data/lib/csv_plus_plus/modifier/expand.rb +17 -0
- data/lib/csv_plus_plus/modifier.rb +6 -1
- 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 +102 -0
- data/lib/csv_plus_plus/options.rb +22 -110
- data/lib/csv_plus_plus/parser/cell_value.tab.rb +65 -66
- data/lib/csv_plus_plus/parser/code_section.tab.rb +92 -84
- data/lib/csv_plus_plus/parser/modifier.tab.rb +40 -30
- 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/runtime/graph.rb +6 -6
- data/lib/csv_plus_plus/runtime/{position_tracker.rb → position.rb} +16 -5
- data/lib/csv_plus_plus/runtime/references.rb +32 -27
- data/lib/csv_plus_plus/runtime/runtime.rb +73 -67
- data/lib/csv_plus_plus/runtime/scope.rb +280 -0
- data/lib/csv_plus_plus/runtime.rb +9 -9
- data/lib/csv_plus_plus/source_code.rb +14 -9
- data/lib/csv_plus_plus/template.rb +17 -12
- data/lib/csv_plus_plus/version.rb +1 -1
- data/lib/csv_plus_plus/writer/csv.rb +32 -5
- data/lib/csv_plus_plus/writer/excel.rb +19 -6
- data/lib/csv_plus_plus/writer/file_backer_upper.rb +27 -14
- data/lib/csv_plus_plus/writer/google_sheets.rb +23 -129
- data/lib/csv_plus_plus/writer/{google_sheet_builder.rb → google_sheets_builder.rb} +39 -55
- data/lib/csv_plus_plus/writer/merger.rb +56 -0
- data/lib/csv_plus_plus/writer/open_document.rb +16 -2
- data/lib/csv_plus_plus/writer/rubyxl_builder.rb +68 -43
- data/lib/csv_plus_plus/writer/writer.rb +42 -0
- data/lib/csv_plus_plus/writer.rb +58 -19
- data/lib/csv_plus_plus.rb +26 -14
- metadata +43 -18
- data/lib/csv_plus_plus/entities/cell_reference.rb +0 -231
- data/lib/csv_plus_plus/entities/variable.rb +0 -37
- data/lib/csv_plus_plus/error/syntax_error.rb +0 -71
- data/lib/csv_plus_plus/google_options.rb +0 -32
- data/lib/csv_plus_plus/lexer/lexer.rb +0 -89
- data/lib/csv_plus_plus/runtime/can_define_references.rb +0 -87
- data/lib/csv_plus_plus/runtime/can_resolve_references.rb +0 -209
- data/lib/csv_plus_plus/writer/base_writer.rb +0 -45
data/lib/csv_plus_plus/writer.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require_relative './writer/
|
|
4
|
+
require_relative './writer/merger'
|
|
5
|
+
require_relative './writer/writer'
|
|
6
|
+
|
|
5
7
|
require_relative './writer/csv'
|
|
6
8
|
require_relative './writer/excel'
|
|
7
9
|
require_relative './writer/google_sheets'
|
|
10
|
+
require_relative './writer/google_sheets_builder'
|
|
8
11
|
require_relative './writer/open_document'
|
|
12
|
+
require_relative './writer/rubyxl_builder'
|
|
9
13
|
|
|
10
14
|
module CSVPlusPlus
|
|
11
15
|
# Various strategies for writing to various formats (excel, google sheets, CSV & OpenDocument (not yet implemented))
|
|
@@ -14,8 +18,8 @@ module CSVPlusPlus
|
|
|
14
18
|
|
|
15
19
|
sig do
|
|
16
20
|
params(
|
|
17
|
-
options: ::CSVPlusPlus::Options,
|
|
18
|
-
|
|
21
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
22
|
+
position: ::CSVPlusPlus::Runtime::Position
|
|
19
23
|
).returns(
|
|
20
24
|
::T.any(
|
|
21
25
|
::CSVPlusPlus::Writer::CSV,
|
|
@@ -28,27 +32,62 @@ module CSVPlusPlus
|
|
|
28
32
|
# Return an instance of a writer depending on the given +options+
|
|
29
33
|
#
|
|
30
34
|
# @param options [Options] The supplied options.
|
|
31
|
-
# @param
|
|
35
|
+
# @param position [Position] The current position.
|
|
32
36
|
#
|
|
33
37
|
# @return [Writer::CSV | Writer::Excel | Writer::GoogleSheets | Writer::OpenDocument]
|
|
34
|
-
|
|
35
|
-
def self.writer(options, runtime)
|
|
38
|
+
def self.writer(options, position)
|
|
36
39
|
output_format = options.output_format
|
|
37
40
|
case output_format
|
|
38
|
-
when ::CSVPlusPlus::Options::OutputFormat::CSV then
|
|
39
|
-
when ::CSVPlusPlus::Options::OutputFormat::Excel then
|
|
40
|
-
when ::CSVPlusPlus::Options::OutputFormat::GoogleSheets then
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
44
|
-
when ::CSVPlusPlus::Options::OutputFormat::OpenDocument then ::CSVPlusPlus::Writer::OpenDocument.new(
|
|
45
|
-
options,
|
|
46
|
-
runtime
|
|
47
|
-
)
|
|
48
|
-
else
|
|
49
|
-
::T.absurd(output_format)
|
|
41
|
+
when ::CSVPlusPlus::Options::OutputFormat::CSV then csv(options, position)
|
|
42
|
+
when ::CSVPlusPlus::Options::OutputFormat::Excel then excel(options, position)
|
|
43
|
+
when ::CSVPlusPlus::Options::OutputFormat::GoogleSheets then google_sheets(options, position)
|
|
44
|
+
when ::CSVPlusPlus::Options::OutputFormat::OpenDocument then open_document(options, position)
|
|
45
|
+
else ::T.absurd(output_format)
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
|
-
|
|
48
|
+
|
|
49
|
+
sig do
|
|
50
|
+
params(
|
|
51
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
52
|
+
position: ::CSVPlusPlus::Runtime::Position
|
|
53
|
+
).returns(::CSVPlusPlus::Writer::CSV)
|
|
54
|
+
end
|
|
55
|
+
# Instantiate a +CSV+ writer
|
|
56
|
+
def self.csv(options, position)
|
|
57
|
+
::CSVPlusPlus::Writer::CSV.new(::T.cast(options, ::CSVPlusPlus::Options::FileOptions), position)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
sig do
|
|
61
|
+
params(
|
|
62
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
63
|
+
position: ::CSVPlusPlus::Runtime::Position
|
|
64
|
+
).returns(::CSVPlusPlus::Writer::Excel)
|
|
65
|
+
end
|
|
66
|
+
# Instantiate a +Excel+ writer
|
|
67
|
+
def self.excel(options, position)
|
|
68
|
+
::CSVPlusPlus::Writer::Excel.new(::T.cast(options, ::CSVPlusPlus::Options::FileOptions), position)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
sig do
|
|
72
|
+
params(
|
|
73
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
74
|
+
position: ::CSVPlusPlus::Runtime::Position
|
|
75
|
+
).returns(::CSVPlusPlus::Writer::GoogleSheets)
|
|
76
|
+
end
|
|
77
|
+
# Instantiate a +GoogleSheets+ writer
|
|
78
|
+
def self.google_sheets(options, position)
|
|
79
|
+
::CSVPlusPlus::Writer::GoogleSheets.new(::T.cast(options, ::CSVPlusPlus::Options::GoogleSheetsOptions), position)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
sig do
|
|
83
|
+
params(
|
|
84
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
85
|
+
position: ::CSVPlusPlus::Runtime::Position
|
|
86
|
+
).returns(::CSVPlusPlus::Writer::OpenDocument)
|
|
87
|
+
end
|
|
88
|
+
# Instantiate an +OpenDocument+ writer
|
|
89
|
+
def self.open_document(options, position)
|
|
90
|
+
::CSVPlusPlus::Writer::OpenDocument.new(::T.cast(options, ::CSVPlusPlus::Options::FileOptions), position)
|
|
91
|
+
end
|
|
53
92
|
end
|
|
54
93
|
end
|
data/lib/csv_plus_plus.rb
CHANGED
|
@@ -14,18 +14,24 @@ require 'pathname'
|
|
|
14
14
|
require 'rubyXL'
|
|
15
15
|
require 'rubyXL/convenience_methods'
|
|
16
16
|
require 'set'
|
|
17
|
+
require 'strscan'
|
|
17
18
|
require 'tempfile'
|
|
18
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'
|
|
19
24
|
require_relative 'csv_plus_plus/source_code'
|
|
20
25
|
|
|
21
|
-
require_relative 'csv_plus_plus/runtime'
|
|
22
|
-
|
|
23
26
|
require_relative 'csv_plus_plus/cli_flag'
|
|
24
27
|
require_relative 'csv_plus_plus/entities'
|
|
25
28
|
require_relative 'csv_plus_plus/error'
|
|
29
|
+
require_relative 'csv_plus_plus/error_formatter'
|
|
26
30
|
|
|
27
|
-
require_relative 'csv_plus_plus/cell'
|
|
28
31
|
require_relative 'csv_plus_plus/cli'
|
|
32
|
+
require_relative 'csv_plus_plus/runtime'
|
|
33
|
+
|
|
34
|
+
require_relative 'csv_plus_plus/cell'
|
|
29
35
|
require_relative 'csv_plus_plus/color'
|
|
30
36
|
require_relative 'csv_plus_plus/modifier'
|
|
31
37
|
|
|
@@ -35,9 +41,8 @@ require_relative 'csv_plus_plus/parser/modifier.tab'
|
|
|
35
41
|
|
|
36
42
|
require_relative 'csv_plus_plus/compiler'
|
|
37
43
|
|
|
38
|
-
require_relative 'csv_plus_plus/google_options'
|
|
39
44
|
require_relative 'csv_plus_plus/lexer'
|
|
40
|
-
require_relative 'csv_plus_plus/
|
|
45
|
+
require_relative 'csv_plus_plus/reader'
|
|
41
46
|
require_relative 'csv_plus_plus/row'
|
|
42
47
|
require_relative 'csv_plus_plus/template'
|
|
43
48
|
require_relative 'csv_plus_plus/writer'
|
|
@@ -48,16 +53,15 @@ require_relative 'csv_plus_plus/benchmarked_compiler'
|
|
|
48
53
|
module CSVPlusPlus
|
|
49
54
|
extend ::T::Sig
|
|
50
55
|
|
|
51
|
-
sig { params(
|
|
56
|
+
sig { params(source_code: ::CSVPlusPlus::SourceCode, options: ::CSVPlusPlus::Options::Options).void }
|
|
52
57
|
# Parse the input into a +Template+ and write it to the desired format
|
|
53
58
|
#
|
|
54
|
-
# @param
|
|
55
|
-
# @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
|
|
56
60
|
# @param options [Options] The various options to compile with
|
|
57
|
-
def self.
|
|
58
|
-
|
|
61
|
+
def self.cli_compile(source_code, options)
|
|
62
|
+
runtime = ::CSVPlusPlus::Runtime.new(source_code:)
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
warn(options.verbose_summary) if options.verbose
|
|
61
65
|
|
|
62
66
|
::CSVPlusPlus::Compiler.with_compiler(options:, runtime:) do |compiler|
|
|
63
67
|
template = compiler.compile_template
|
|
@@ -65,10 +69,18 @@ module CSVPlusPlus
|
|
|
65
69
|
|
|
66
70
|
write_template(template:, compiler:, options:)
|
|
67
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)
|
|
68
76
|
end
|
|
69
77
|
|
|
70
78
|
sig do
|
|
71
|
-
params(
|
|
79
|
+
params(
|
|
80
|
+
compiler: ::CSVPlusPlus::Compiler,
|
|
81
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
82
|
+
template: ::CSVPlusPlus::Template
|
|
83
|
+
).void
|
|
72
84
|
end
|
|
73
85
|
# Write the results (and possibly make a backup) of a compiled +template+
|
|
74
86
|
#
|
|
@@ -76,8 +88,8 @@ module CSVPlusPlus
|
|
|
76
88
|
# @param options [Options] The options we're running with
|
|
77
89
|
# @param template [Template] The compiled template
|
|
78
90
|
def self.write_template(compiler:, options:, template:)
|
|
79
|
-
compiler.outputting! do |
|
|
80
|
-
output = ::CSVPlusPlus::Writer.writer(options,
|
|
91
|
+
compiler.outputting! do |position|
|
|
92
|
+
output = ::CSVPlusPlus::Writer.writer(options, position)
|
|
81
93
|
output.write_backup if options.backup
|
|
82
94
|
output.write(template)
|
|
83
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.1
|
|
4
|
+
version: 0.2.1
|
|
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-09-09 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
|
|
@@ -123,6 +137,7 @@ files:
|
|
|
123
137
|
- bin/csvpp
|
|
124
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
142
|
- lib/csv_plus_plus/cell.rb
|
|
128
143
|
- lib/csv_plus_plus/cli.rb
|
|
@@ -133,27 +148,29 @@ files:
|
|
|
133
148
|
- lib/csv_plus_plus/entities/ast_builder.rb
|
|
134
149
|
- lib/csv_plus_plus/entities/boolean.rb
|
|
135
150
|
- lib/csv_plus_plus/entities/builtins.rb
|
|
136
|
-
- lib/csv_plus_plus/entities/cell_reference.rb
|
|
137
151
|
- lib/csv_plus_plus/entities/date.rb
|
|
138
152
|
- lib/csv_plus_plus/entities/entity.rb
|
|
139
153
|
- lib/csv_plus_plus/entities/entity_with_arguments.rb
|
|
140
154
|
- lib/csv_plus_plus/entities/function.rb
|
|
141
155
|
- lib/csv_plus_plus/entities/function_call.rb
|
|
156
|
+
- lib/csv_plus_plus/entities/has_identifier.rb
|
|
142
157
|
- lib/csv_plus_plus/entities/number.rb
|
|
158
|
+
- lib/csv_plus_plus/entities/reference.rb
|
|
143
159
|
- lib/csv_plus_plus/entities/runtime_value.rb
|
|
144
160
|
- lib/csv_plus_plus/entities/string.rb
|
|
145
|
-
- lib/csv_plus_plus/entities/variable.rb
|
|
146
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
|
|
147
164
|
- lib/csv_plus_plus/error/error.rb
|
|
148
165
|
- lib/csv_plus_plus/error/formula_syntax_error.rb
|
|
149
166
|
- lib/csv_plus_plus/error/modifier_syntax_error.rb
|
|
150
167
|
- lib/csv_plus_plus/error/modifier_validation_error.rb
|
|
151
|
-
- lib/csv_plus_plus/error/
|
|
168
|
+
- lib/csv_plus_plus/error/positional_error.rb
|
|
152
169
|
- lib/csv_plus_plus/error/writer_error.rb
|
|
170
|
+
- lib/csv_plus_plus/error_formatter.rb
|
|
153
171
|
- lib/csv_plus_plus/google_api_client.rb
|
|
154
|
-
- lib/csv_plus_plus/google_options.rb
|
|
155
172
|
- lib/csv_plus_plus/lexer.rb
|
|
156
|
-
- lib/csv_plus_plus/lexer/
|
|
173
|
+
- lib/csv_plus_plus/lexer/racc_lexer.rb
|
|
157
174
|
- lib/csv_plus_plus/lexer/tokenizer.rb
|
|
158
175
|
- lib/csv_plus_plus/modifier.rb
|
|
159
176
|
- lib/csv_plus_plus/modifier/conditional_formatting.rb
|
|
@@ -164,39 +181,47 @@ files:
|
|
|
164
181
|
- lib/csv_plus_plus/modifier/modifier_validator.rb
|
|
165
182
|
- lib/csv_plus_plus/modifier/rubyxl_modifier.rb
|
|
166
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
|
|
167
187
|
- lib/csv_plus_plus/parser/cell_value.tab.rb
|
|
168
188
|
- lib/csv_plus_plus/parser/code_section.tab.rb
|
|
169
189
|
- lib/csv_plus_plus/parser/modifier.tab.rb
|
|
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
|
|
170
195
|
- lib/csv_plus_plus/row.rb
|
|
171
196
|
- 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
197
|
- lib/csv_plus_plus/runtime/graph.rb
|
|
175
|
-
- lib/csv_plus_plus/runtime/
|
|
198
|
+
- lib/csv_plus_plus/runtime/position.rb
|
|
176
199
|
- lib/csv_plus_plus/runtime/references.rb
|
|
177
200
|
- lib/csv_plus_plus/runtime/runtime.rb
|
|
201
|
+
- lib/csv_plus_plus/runtime/scope.rb
|
|
178
202
|
- lib/csv_plus_plus/source_code.rb
|
|
179
203
|
- lib/csv_plus_plus/template.rb
|
|
180
204
|
- lib/csv_plus_plus/version.rb
|
|
181
205
|
- lib/csv_plus_plus/writer.rb
|
|
182
|
-
- lib/csv_plus_plus/writer/base_writer.rb
|
|
183
206
|
- lib/csv_plus_plus/writer/csv.rb
|
|
184
207
|
- lib/csv_plus_plus/writer/excel.rb
|
|
185
208
|
- lib/csv_plus_plus/writer/file_backer_upper.rb
|
|
186
|
-
- lib/csv_plus_plus/writer/google_sheet_builder.rb
|
|
187
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
|
|
188
212
|
- lib/csv_plus_plus/writer/open_document.rb
|
|
189
213
|
- lib/csv_plus_plus/writer/rubyxl_builder.rb
|
|
190
|
-
|
|
214
|
+
- lib/csv_plus_plus/writer/writer.rb
|
|
215
|
+
homepage: https://github.com/patrickomatic/csv-plus-plus-ruby
|
|
191
216
|
licenses:
|
|
192
217
|
- MIT
|
|
193
218
|
metadata:
|
|
194
|
-
bug_tracker_uri: https://github.com/patrickomatic/csv-plus-plus/issues
|
|
219
|
+
bug_tracker_uri: https://github.com/patrickomatic/csv-plus-plus-ruby/issues
|
|
195
220
|
documentation_uri: https://www.rubydoc.info/gems/csv_plus_plus/
|
|
196
|
-
github_repo: git://github.com/patrickomatic/csv-plus-plus
|
|
197
|
-
homepage_uri: https://github.com/patrickomatic/csv-plus-plus
|
|
198
|
-
source_code_uri: https://github.com/patrickomatic/csv-plus-plus
|
|
199
|
-
changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/docs/CHANGELOG.md
|
|
221
|
+
github_repo: git://github.com/patrickomatic/csv-plus-plus-ruby
|
|
222
|
+
homepage_uri: https://github.com/patrickomatic/csv-plus-plus-ruby
|
|
223
|
+
source_code_uri: https://github.com/patrickomatic/csv-plus-plus-ruby
|
|
224
|
+
changelog_uri: https://github.com/patrickomatic/csv-plus-plus-ruby/blob/main/docs/CHANGELOG.md
|
|
200
225
|
rubygems_mfa_required: 'true'
|
|
201
226
|
post_install_message:
|
|
202
227
|
rdoc_options: []
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
# typed: strict
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module CSVPlusPlus
|
|
5
|
-
module Entities
|
|
6
|
-
# A reference to a cell. Internally it is represented by a simple +cell_index+ and +row_index+ but there are
|
|
7
|
-
# functions for converting to and from A1-style formats. Supported formats are:
|
|
8
|
-
#
|
|
9
|
-
# * `1` - A reference to the entire first row
|
|
10
|
-
# * `A` - A reference to the entire first column
|
|
11
|
-
# * `A1` - A reference to the first cell (top left)
|
|
12
|
-
# * `A1:D10` - The range defined between A1 and D10
|
|
13
|
-
# * `Sheet1!B2` - Cell B2 on the sheet "Sheet1"
|
|
14
|
-
#
|
|
15
|
-
# @attr sheet_name [String, nil] The name of the sheet reference
|
|
16
|
-
# @attr_reader cell_index [Integer, nil] The cell index of the cell being referenced
|
|
17
|
-
# @attr_reader row_index [Integer, nil] The row index of the cell being referenced
|
|
18
|
-
# @attr_reader scoped_to_expand [Expand, nil] If set, the expand in which this variable is scoped to. It cannot be
|
|
19
|
-
# resolved outside of the given expand.
|
|
20
|
-
# @attr_reader upper_cell_index [Integer, nil] If set, the cell reference is a range and this is the upper cell
|
|
21
|
-
# index of it
|
|
22
|
-
# @attr_reader upper_row_index [Integer, nil] If set, the cell reference is a range and this is the upper row index
|
|
23
|
-
# of it
|
|
24
|
-
# rubocop:disable Metrics/ClassLength
|
|
25
|
-
class CellReference < Entity
|
|
26
|
-
extend ::T::Sig
|
|
27
|
-
|
|
28
|
-
sig { returns(::T.nilable(::String)) }
|
|
29
|
-
attr_accessor :sheet_name
|
|
30
|
-
|
|
31
|
-
sig { returns(::T.nilable(::Integer)) }
|
|
32
|
-
attr_reader :cell_index
|
|
33
|
-
|
|
34
|
-
sig { returns(::T.nilable(::Integer)) }
|
|
35
|
-
attr_reader :row_index
|
|
36
|
-
|
|
37
|
-
sig { returns(::T.nilable(::CSVPlusPlus::Modifier::Expand)) }
|
|
38
|
-
attr_reader :scoped_to_expand
|
|
39
|
-
|
|
40
|
-
sig { returns(::T.nilable(::Integer)) }
|
|
41
|
-
attr_reader :upper_cell_index
|
|
42
|
-
|
|
43
|
-
sig { returns(::T.nilable(::Integer)) }
|
|
44
|
-
attr_reader :upper_row_index
|
|
45
|
-
|
|
46
|
-
# TODO: this is getting gross, maybe define an actual parser
|
|
47
|
-
A1_NOTATION_REGEXP = /
|
|
48
|
-
^
|
|
49
|
-
(?:
|
|
50
|
-
(?:
|
|
51
|
-
(?:'([^'\\]|\\.)*') # allow for a single-quoted sheet name
|
|
52
|
-
|
|
|
53
|
-
(\w+) # or if it's not quoted, just allow \w+
|
|
54
|
-
)
|
|
55
|
-
! # if a sheet name is specified, it's always followed by a !
|
|
56
|
-
)?
|
|
57
|
-
([a-zA-Z0-9]+) # the only part required - something alphanumeric
|
|
58
|
-
(?: :([a-zA-Z0-9]+))? # and they might make it a range
|
|
59
|
-
$
|
|
60
|
-
/x
|
|
61
|
-
public_constant :A1_NOTATION_REGEXP
|
|
62
|
-
|
|
63
|
-
ALPHA = ::T.let(('A'..'Z').to_a.freeze, ::T::Array[::String])
|
|
64
|
-
private_constant :ALPHA
|
|
65
|
-
|
|
66
|
-
sig { params(cell_reference_string: ::String).returns(::T::Boolean) }
|
|
67
|
-
# Does the given +cell_reference_string+ conform to a valid cell reference?
|
|
68
|
-
#
|
|
69
|
-
# {https://developers.google.com/sheets/api/guides/concepts}
|
|
70
|
-
#
|
|
71
|
-
# @param cell_reference_string [::String] The string to check if it is a valid cell reference (we assume it's in
|
|
72
|
-
# A1 notation but maybe can support R1C1)
|
|
73
|
-
#
|
|
74
|
-
# @return [::T::Boolean]
|
|
75
|
-
def self.valid_cell_reference?(cell_reference_string)
|
|
76
|
-
!(cell_reference_string =~ ::CSVPlusPlus::Entities::CellReference::A1_NOTATION_REGEXP).nil?
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
sig do
|
|
80
|
-
params(
|
|
81
|
-
cell_index: ::T.nilable(::Integer),
|
|
82
|
-
ref: ::T.nilable(::String),
|
|
83
|
-
row_index: ::T.nilable(::Integer),
|
|
84
|
-
scoped_to_expand: ::T.nilable(::CSVPlusPlus::Modifier::Expand)
|
|
85
|
-
).void
|
|
86
|
-
end
|
|
87
|
-
# Either +ref+, +cell_index+ or +row_index+ must be specified.
|
|
88
|
-
#
|
|
89
|
-
# @param cell_index [Integer, nil] The index of the cell being referenced.
|
|
90
|
-
# @param ref [Integer, nil] An A1-style cell reference (that will be parsed into it's row/cell indexes).
|
|
91
|
-
# @param row_index [Integer, nil] The index of the row being referenced.
|
|
92
|
-
# @param scoped_to_expand [Expand] The [[expand]] that this cell reference will be scoped to. In other words, it
|
|
93
|
-
# will only be able to be resolved if the runtime is within the bounds of the expand (it can't be referenced
|
|
94
|
-
# outside of the expand.)
|
|
95
|
-
# rubocop:disable Metrics/MethodLength
|
|
96
|
-
def initialize(cell_index: nil, ref: nil, row_index: nil, scoped_to_expand: nil)
|
|
97
|
-
raise(::ArgumentError, 'Must specify :ref, :cell_index or :row_index') unless ref || cell_index || row_index
|
|
98
|
-
|
|
99
|
-
super(::CSVPlusPlus::Entities::Type::CellReference)
|
|
100
|
-
|
|
101
|
-
if ref
|
|
102
|
-
from_a1_ref!(ref)
|
|
103
|
-
else
|
|
104
|
-
@cell_index = ::T.let(cell_index, ::T.nilable(::Integer))
|
|
105
|
-
@row_index = ::T.let(row_index, ::T.nilable(::Integer))
|
|
106
|
-
|
|
107
|
-
@upper_cell_index = ::T.let(nil, ::T.nilable(::Integer))
|
|
108
|
-
@upper_row_index = ::T.let(nil, ::T.nilable(::Integer))
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
@scoped_to_expand = scoped_to_expand
|
|
112
|
-
end
|
|
113
|
-
# rubocop:enable Metrics/MethodLength
|
|
114
|
-
|
|
115
|
-
sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
|
|
116
|
-
# @param other [Entity]
|
|
117
|
-
#
|
|
118
|
-
# @return [boolean]
|
|
119
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
120
|
-
def ==(other)
|
|
121
|
-
return false unless super
|
|
122
|
-
|
|
123
|
-
other.is_a?(self.class) && @cell_index == other.cell_index && @row_index == other.row_index \
|
|
124
|
-
&& @sheet_name == other.sheet_name && @scoped_to_expand == other.scoped_to_expand \
|
|
125
|
-
&& @upper_cell_index == other.upper_cell_index && @upper_row_index == other.upper_row_index
|
|
126
|
-
end
|
|
127
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
128
|
-
|
|
129
|
-
sig { override.params(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
|
|
130
|
-
# Get the A1-style cell reference
|
|
131
|
-
#
|
|
132
|
-
# @param runtime [Runtime] The current runtime
|
|
133
|
-
#
|
|
134
|
-
# @return [::String] An A1-style reference
|
|
135
|
-
def evaluate(runtime)
|
|
136
|
-
# unless in_scope?(runtime)
|
|
137
|
-
# runtime.raise_modifier_syntax_error(message: 'Reference is out of scope', bad_input: runtime.cell.value)
|
|
138
|
-
# end
|
|
139
|
-
|
|
140
|
-
to_a1_ref(runtime) || ''
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
sig { returns(::T::Boolean) }
|
|
144
|
-
# Is the cell_reference a range? - something like A1:D10
|
|
145
|
-
#
|
|
146
|
-
# @return [boolean]
|
|
147
|
-
def range?
|
|
148
|
-
!upper_row_index.nil? || !upper_cell_index.nil?
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
private
|
|
152
|
-
|
|
153
|
-
sig { params(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::T.nilable(::String)) }
|
|
154
|
-
# Turns index-based/X,Y coordinates into a A1 format
|
|
155
|
-
#
|
|
156
|
-
# @param runtime [Runtime]
|
|
157
|
-
#
|
|
158
|
-
# @return [::String, nil]
|
|
159
|
-
def to_a1_ref(runtime)
|
|
160
|
-
row_index = runtime_row_index(runtime)
|
|
161
|
-
return unless row_index || @cell_index
|
|
162
|
-
|
|
163
|
-
rowref = row_index ? (row_index + 1).to_s : ''
|
|
164
|
-
cellref = @cell_index ? to_a1_cell_ref : ''
|
|
165
|
-
[cellref, rowref].join
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
sig { params(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::T.nilable(::Integer)) }
|
|
169
|
-
def runtime_row_index(runtime)
|
|
170
|
-
@scoped_to_expand ? runtime.row_index : @row_index
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
sig { returns(::String) }
|
|
174
|
-
# Turns a cell index into an A1 reference (just the "A" part - for example 0 == 'A', 1 == 'B', 2 == 'C', etc.)
|
|
175
|
-
#
|
|
176
|
-
# @return [::String]
|
|
177
|
-
def to_a1_cell_ref
|
|
178
|
-
c = @cell_index.dup
|
|
179
|
-
ref = ''
|
|
180
|
-
|
|
181
|
-
while c >= 0
|
|
182
|
-
# rubocop:disable Lint/ConstantResolution
|
|
183
|
-
ref += ::T.must(ALPHA[c % 26])
|
|
184
|
-
# rubocop:enable Lint/ConstantResolution
|
|
185
|
-
c = (c / 26).floor - 1
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
ref.reverse
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
sig { params(ref: ::String).void }
|
|
192
|
-
def from_a1_ref!(ref)
|
|
193
|
-
quoted_sheet_name, unquoted_sheet_name, lower_range, upper_range = ::T.must(
|
|
194
|
-
ref.strip.match(
|
|
195
|
-
::CSVPlusPlus::Entities::CellReference::A1_NOTATION_REGEXP
|
|
196
|
-
)
|
|
197
|
-
).captures
|
|
198
|
-
|
|
199
|
-
@sheet_name = quoted_sheet_name || unquoted_sheet_name
|
|
200
|
-
|
|
201
|
-
parse_lower_range!(lower_range) if lower_range
|
|
202
|
-
parse_upper_range!(upper_range) if upper_range
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
sig { params(lower_range: ::String).void }
|
|
206
|
-
def parse_lower_range!(lower_range)
|
|
207
|
-
cell_ref, row_ref = ::T.must(lower_range.match(/^([a-zA-Z]+)?(\d+)?$/)).captures
|
|
208
|
-
@cell_index = from_a1_cell_ref!(cell_ref) if cell_ref
|
|
209
|
-
@row_index = Integer(row_ref, 10) - 1 if row_ref
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
sig { params(upper_range: ::String).void }
|
|
213
|
-
# TODO: make this less redundant with the above function
|
|
214
|
-
def parse_upper_range!(upper_range)
|
|
215
|
-
cell_ref, row_ref = ::T.must(upper_range.match(/^([a-zA-Z]+)?(\d+)?$/)).captures
|
|
216
|
-
@upper_cell_index = from_a1_cell_ref!(cell_ref) if cell_ref
|
|
217
|
-
@upper_row_index = Integer(row_ref, 10) - 1 if row_ref
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
sig { params(cell_ref: ::String).returns(::Integer) }
|
|
221
|
-
def from_a1_cell_ref!(cell_ref)
|
|
222
|
-
(cell_ref.upcase.chars.reduce(0) do |cell_index, letter|
|
|
223
|
-
# rubocop:disable Lint/ConstantResolution
|
|
224
|
-
(cell_index * 26) + ::T.must(ALPHA.find_index(letter)) + 1
|
|
225
|
-
# rubocop:enable Lint/ConstantResolution
|
|
226
|
-
end) - 1
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
# rubocop:enable Metrics/ClassLength
|
|
230
|
-
end
|
|
231
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# typed: strict
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module CSVPlusPlus
|
|
5
|
-
module Entities
|
|
6
|
-
# TODO: get rid of this I think - everything will just be References
|
|
7
|
-
#
|
|
8
|
-
# A reference to a variable
|
|
9
|
-
class Variable < Entity
|
|
10
|
-
extend ::T::Sig
|
|
11
|
-
|
|
12
|
-
sig { params(id: ::Symbol).void }
|
|
13
|
-
# @param id [Symbol] The identifier of the variable
|
|
14
|
-
def initialize(id)
|
|
15
|
-
super(::CSVPlusPlus::Entities::Type::Variable, id:)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
sig { override.params(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
|
|
19
|
-
# @param _runtime [Runtime]
|
|
20
|
-
#
|
|
21
|
-
# @return [::String]
|
|
22
|
-
def evaluate(_runtime)
|
|
23
|
-
"$$#{@id}"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
|
|
27
|
-
# @param other [Entity]
|
|
28
|
-
#
|
|
29
|
-
# @return [boolean]
|
|
30
|
-
def ==(other)
|
|
31
|
-
return false unless super
|
|
32
|
-
|
|
33
|
-
other.is_a?(self.class) && @id == other.id
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# typed: strict
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module CSVPlusPlus
|
|
5
|
-
module Error
|
|
6
|
-
# An error that can be thrown for various syntax errors
|
|
7
|
-
class SyntaxError < ::CSVPlusPlus::Error::Error
|
|
8
|
-
extend ::T::Sig
|
|
9
|
-
|
|
10
|
-
sig { params(runtime: ::CSVPlusPlus::Runtime::Runtime, wrapped_error: ::T.nilable(::StandardError)).void }
|
|
11
|
-
# @param runtime [Runtime] The current runtime
|
|
12
|
-
# @param wrapped_error [StandardError] The underlying error that caused the syntax error. For example a
|
|
13
|
-
# Racc::ParseError that was thrown
|
|
14
|
-
def initialize(runtime, wrapped_error: nil)
|
|
15
|
-
@runtime = runtime
|
|
16
|
-
@wrapped_error = wrapped_error
|
|
17
|
-
|
|
18
|
-
super()
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
sig { returns(::String) }
|
|
22
|
-
# @return [::String]
|
|
23
|
-
def to_s
|
|
24
|
-
to_trace
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# TODO: clean up all these different string-formatting error classes
|
|
28
|
-
sig { override.returns(::String) }
|
|
29
|
-
# @return [::String]
|
|
30
|
-
def error_message
|
|
31
|
-
''
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
sig { returns(::String) }
|
|
35
|
-
# Output a verbose user-helpful string that references the current runtime
|
|
36
|
-
def to_verbose_trace
|
|
37
|
-
warn(@wrapped_error.full_message) if @wrapped_error
|
|
38
|
-
warn((@wrapped_error.backtrace || []).join("\n")) if @wrapped_error&.backtrace
|
|
39
|
-
to_trace
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
sig { returns(::String) }
|
|
43
|
-
# Output a user-helpful string that references the runtime state
|
|
44
|
-
#
|
|
45
|
-
# @return [String]
|
|
46
|
-
def to_trace
|
|
47
|
-
"#{message_prefix}#{cell_index} #{error_message}"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
sig { returns(::String) }
|
|
53
|
-
def cell_index
|
|
54
|
-
if @runtime.parsing_csv_section?
|
|
55
|
-
"[#{@runtime.row_index},#{@runtime.cell_index}]"
|
|
56
|
-
else
|
|
57
|
-
''
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
sig { returns(::String) }
|
|
62
|
-
def message_prefix
|
|
63
|
-
line_number = @runtime.line_number
|
|
64
|
-
filename = @runtime.source_code.filename
|
|
65
|
-
|
|
66
|
-
line_str = ":#{line_number}"
|
|
67
|
-
"#{filename}#{line_str}"
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|