csv_plus_plus 0.1.1 → 0.1.2
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/CHANGELOG.md +8 -0
- data/README.md +18 -62
- data/lib/csv_plus_plus/benchmarked_compiler.rb +62 -0
- data/lib/csv_plus_plus/{code_section.rb → can_define_references.rb} +22 -35
- data/lib/csv_plus_plus/can_resolve_references.rb +8 -0
- data/lib/csv_plus_plus/cell.rb +3 -3
- data/lib/csv_plus_plus/cli.rb +24 -7
- data/lib/csv_plus_plus/color.rb +12 -6
- data/lib/csv_plus_plus/compiler.rb +156 -0
- data/lib/csv_plus_plus/data_validation.rb +138 -0
- data/lib/csv_plus_plus/{language → entities}/ast_builder.rb +3 -5
- data/lib/csv_plus_plus/entities/boolean.rb +31 -0
- data/lib/csv_plus_plus/{language → entities}/builtins.rb +2 -4
- data/lib/csv_plus_plus/entities/cell_reference.rb +60 -0
- data/lib/csv_plus_plus/entities/date.rb +30 -0
- data/lib/csv_plus_plus/entities/entity.rb +84 -0
- data/lib/csv_plus_plus/entities/function.rb +33 -0
- data/lib/csv_plus_plus/entities/function_call.rb +35 -0
- data/lib/csv_plus_plus/entities/number.rb +34 -0
- data/lib/csv_plus_plus/entities/runtime_value.rb +26 -0
- data/lib/csv_plus_plus/entities/string.rb +29 -0
- data/lib/csv_plus_plus/entities/variable.rb +25 -0
- data/lib/csv_plus_plus/entities.rb +33 -0
- data/lib/csv_plus_plus/error/error.rb +10 -0
- data/lib/csv_plus_plus/error/formula_syntax_error.rb +36 -0
- data/lib/csv_plus_plus/error/modifier_syntax_error.rb +27 -0
- data/lib/csv_plus_plus/error/modifier_validation_error.rb +49 -0
- data/lib/csv_plus_plus/{language → error}/syntax_error.rb +6 -14
- data/lib/csv_plus_plus/error/writer_error.rb +9 -0
- data/lib/csv_plus_plus/error.rb +9 -2
- data/lib/csv_plus_plus/expand.rb +3 -1
- data/lib/csv_plus_plus/google_api_client.rb +4 -0
- data/lib/csv_plus_plus/lexer/lexer.rb +13 -6
- data/lib/csv_plus_plus/modifier/conditional_formatting.rb +17 -0
- data/lib/csv_plus_plus/modifier.rb +73 -65
- data/lib/csv_plus_plus/{language → parser}/cell_value.tab.rb +20 -20
- data/lib/csv_plus_plus/{language → parser}/code_section.tab.rb +83 -87
- data/lib/csv_plus_plus/parser/modifier.tab.rb +484 -0
- data/lib/csv_plus_plus/references.rb +68 -0
- data/lib/csv_plus_plus/row.rb +0 -3
- data/lib/csv_plus_plus/runtime.rb +199 -0
- data/lib/csv_plus_plus/scope.rb +196 -0
- data/lib/csv_plus_plus/template.rb +10 -10
- data/lib/csv_plus_plus/validated_modifier.rb +164 -0
- data/lib/csv_plus_plus/version.rb +1 -1
- data/lib/csv_plus_plus/writer/file_backer_upper.rb +6 -4
- data/lib/csv_plus_plus/writer/google_sheet_builder.rb +24 -29
- data/lib/csv_plus_plus/writer/google_sheet_modifier.rb +33 -12
- data/lib/csv_plus_plus/writer/rubyxl_builder.rb +3 -6
- data/lib/csv_plus_plus.rb +19 -10
- metadata +34 -24
- data/lib/csv_plus_plus/language/benchmarked_compiler.rb +0 -65
- 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/modifier.tab.rb +0 -907
@@ -25,12 +25,6 @@ module CSVPlusPlus
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
def sheets_ns
|
29
|
-
::Google::Apis::SheetsV4
|
30
|
-
end
|
31
|
-
|
32
|
-
def sheets_color(color); end
|
33
|
-
|
34
28
|
def set_extended_value_type!(extended_value, value)
|
35
29
|
v = value || ''
|
36
30
|
if v.start_with?('=')
|
@@ -45,7 +39,7 @@ module CSVPlusPlus
|
|
45
39
|
end
|
46
40
|
|
47
41
|
def build_cell_format(mod)
|
48
|
-
|
42
|
+
::Google::Apis::SheetsV4::CellFormat.new.tap do |cf|
|
49
43
|
cf.text_format = mod.text_format
|
50
44
|
|
51
45
|
cf.horizontal_alignment = mod.halign
|
@@ -56,7 +50,7 @@ module CSVPlusPlus
|
|
56
50
|
end
|
57
51
|
|
58
52
|
def grid_range_for_cell(cell)
|
59
|
-
|
53
|
+
::Google::Apis::SheetsV4::GridRange.new(
|
60
54
|
sheet_id: @sheet_id,
|
61
55
|
start_column_index: cell.index,
|
62
56
|
end_column_index: cell.index + 1,
|
@@ -72,7 +66,7 @@ module CSVPlusPlus
|
|
72
66
|
end
|
73
67
|
|
74
68
|
def build_cell_value(cell)
|
75
|
-
|
69
|
+
::Google::Apis::SheetsV4::ExtendedValue.new.tap do |xv|
|
76
70
|
value =
|
77
71
|
if cell.value.nil?
|
78
72
|
current_value(cell.row_index, cell.index)
|
@@ -87,7 +81,7 @@ module CSVPlusPlus
|
|
87
81
|
def build_cell_data(cell)
|
88
82
|
mod = ::CSVPlusPlus::Writer::GoogleSheetModifier.new(cell.modifier)
|
89
83
|
|
90
|
-
|
84
|
+
::Google::Apis::SheetsV4::CellData.new.tap do |cd|
|
91
85
|
cd.user_entered_format = build_cell_format(mod)
|
92
86
|
cd.note = mod.note if mod.note
|
93
87
|
|
@@ -97,13 +91,13 @@ module CSVPlusPlus
|
|
97
91
|
end
|
98
92
|
|
99
93
|
def build_row_data(row)
|
100
|
-
|
94
|
+
::Google::Apis::SheetsV4::RowData.new(values: row.cells.map { |cell| build_cell_data(cell) })
|
101
95
|
end
|
102
96
|
|
103
97
|
def build_update_cells_request(rows)
|
104
|
-
|
98
|
+
::Google::Apis::SheetsV4::UpdateCellsRequest.new(
|
105
99
|
fields: '*',
|
106
|
-
start:
|
100
|
+
start: ::Google::Apis::SheetsV4::GridCoordinate.new(
|
107
101
|
sheet_id: @sheet_id,
|
108
102
|
column_index: @column_index,
|
109
103
|
row_index: @row_index
|
@@ -113,29 +107,31 @@ module CSVPlusPlus
|
|
113
107
|
end
|
114
108
|
|
115
109
|
def build_border(cell)
|
116
|
-
mod = cell.modifier
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
top: mod.border_along?(
|
121
|
-
right: mod.border_along?(
|
122
|
-
left: mod.border_along?(
|
123
|
-
bottom: mod.border_along?(
|
110
|
+
mod = ::CSVPlusPlus::Writer::GoogleSheetModifier.new(cell.modifier)
|
111
|
+
border = mod.border
|
112
|
+
|
113
|
+
::Google::Apis::SheetsV4::UpdateBordersRequest.new(
|
114
|
+
top: mod.border_along?(:top) ? border : nil,
|
115
|
+
right: mod.border_along?(:right) ? border : nil,
|
116
|
+
left: mod.border_along?(:left) ? border : nil,
|
117
|
+
bottom: mod.border_along?(:bottom) ? border : nil,
|
124
118
|
range: grid_range_for_cell(cell)
|
125
119
|
)
|
126
120
|
end
|
127
121
|
|
128
122
|
def build_update_borders_request(cell)
|
129
|
-
|
123
|
+
::Google::Apis::SheetsV4::Request.new(update_borders: build_border(cell))
|
124
|
+
end
|
125
|
+
|
126
|
+
def chunked_requests(rows)
|
127
|
+
rows.each_slice(1000).to_a.map do |chunked_rows|
|
128
|
+
::Google::Apis::SheetsV4::Request.new(update_cells: build_update_cells_request(chunked_rows))
|
129
|
+
end
|
130
130
|
end
|
131
131
|
|
132
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
133
132
|
def build_batch_request(rows)
|
134
|
-
|
135
|
-
bu.requests =
|
136
|
-
rows.each_slice(1000).to_a.map do |chunked_rows|
|
137
|
-
sheets_ns::Request.new(update_cells: build_update_cells_request(chunked_rows))
|
138
|
-
end
|
133
|
+
::Google::Apis::SheetsV4::BatchUpdateSpreadsheetRequest.new.tap do |bu|
|
134
|
+
bu.requests = chunked_requests(rows)
|
139
135
|
|
140
136
|
rows.each do |row|
|
141
137
|
row.cells.filter { |c| c.modifier.any_border? }
|
@@ -145,7 +141,6 @@ module CSVPlusPlus
|
|
145
141
|
end
|
146
142
|
end
|
147
143
|
end
|
148
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
149
144
|
end
|
150
145
|
# rubocop:enable Metrics/ClassLength
|
151
146
|
end
|
@@ -4,44 +4,65 @@ module CSVPlusPlus
|
|
4
4
|
module Writer
|
5
5
|
# Decorate a Modifier so it can be written to the Google Sheets API
|
6
6
|
class GoogleSheetModifier < ::SimpleDelegator
|
7
|
-
# Format the
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
# Format the border for Google Sheets
|
8
|
+
#
|
9
|
+
# @return [Google::Apis::SheetsV4::Border]
|
10
|
+
def border
|
11
|
+
# TODO: allow different border styles per side
|
12
|
+
::Google::Apis::SheetsV4::Border.new(
|
13
|
+
color: bordercolor&.to_s || '#000000',
|
14
|
+
style: borderstyle&.to_s || 'solid'
|
15
|
+
)
|
15
16
|
end
|
16
17
|
|
17
18
|
# Format the color for Google Sheets
|
19
|
+
#
|
20
|
+
# @return [Google::Apis::SheetsV4::Color]
|
18
21
|
def color
|
19
22
|
google_sheets_color(super) if super
|
20
23
|
end
|
21
24
|
|
22
25
|
# Format the fontcolor for Google Sheets
|
26
|
+
#
|
27
|
+
# @return [Google::Apis::SheetsV4::Color]
|
23
28
|
def fontcolor
|
24
29
|
google_sheets_color(super) if super
|
25
30
|
end
|
26
31
|
|
32
|
+
# Format the halign for Google Sheets
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
def halign
|
36
|
+
super&.to_s&.upcase
|
37
|
+
end
|
38
|
+
|
27
39
|
# Format the numberformat for Google Sheets
|
40
|
+
#
|
41
|
+
# @return [::Google::Apis::SheetsV4::NumberFormat]
|
28
42
|
def numberformat
|
29
43
|
::Google::Apis::SheetsV4::NumberFormat.new(type: super) if super
|
30
44
|
end
|
31
45
|
|
32
46
|
# Builds a SheetsV4::TextFormat with the underlying Modifier
|
47
|
+
#
|
48
|
+
# @return [::Google::Apis::SheetsV4::TextFormat]
|
33
49
|
def text_format
|
34
50
|
::Google::Apis::SheetsV4::TextFormat.new(
|
35
|
-
bold: formatted?(
|
36
|
-
italic: formatted?(
|
37
|
-
strikethrough: formatted?(
|
38
|
-
underline: formatted?(
|
51
|
+
bold: formatted?(:bold) || nil,
|
52
|
+
italic: formatted?(:italic) || nil,
|
53
|
+
strikethrough: formatted?(:strikethrough) || nil,
|
54
|
+
underline: formatted?(:underline) || nil,
|
39
55
|
font_family: fontfamily,
|
40
56
|
font_size: fontsize,
|
41
57
|
foreground_color: fontcolor
|
42
58
|
)
|
43
59
|
end
|
44
60
|
|
61
|
+
# Format the valign for Google Sheets
|
62
|
+
def valign
|
63
|
+
super&.to_s&.upcase
|
64
|
+
end
|
65
|
+
|
45
66
|
private
|
46
67
|
|
47
68
|
def google_sheets_color(color)
|
@@ -24,10 +24,7 @@ module CSVPlusPlus
|
|
24
24
|
#
|
25
25
|
# @return [RubyXL::Workbook]
|
26
26
|
def build_workbook
|
27
|
-
open_workbook.tap
|
28
|
-
@worksheet = workbook[@sheet_name]
|
29
|
-
build_workbook!
|
30
|
-
end
|
27
|
+
open_workbook.tap { build_workbook! }
|
31
28
|
end
|
32
29
|
|
33
30
|
private
|
@@ -107,11 +104,11 @@ module CSVPlusPlus
|
|
107
104
|
def open_workbook
|
108
105
|
if ::File.exist?(@input_filename)
|
109
106
|
::RubyXL::Parser.parse(@input_filename).tap do |workbook|
|
110
|
-
workbook
|
107
|
+
@worksheet = workbook[@sheet_name] || workbook.add_worksheet(@sheet_name)
|
111
108
|
end
|
112
109
|
else
|
113
110
|
::RubyXL::Workbook.new.tap do |workbook|
|
114
|
-
workbook.worksheets[0].sheet_name = @sheet_name
|
111
|
+
@worksheet = workbook.worksheets[0].tap { |w| w.sheet_name = @sheet_name }
|
115
112
|
end
|
116
113
|
end
|
117
114
|
end
|
data/lib/csv_plus_plus.rb
CHANGED
@@ -1,26 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'benchmark'
|
4
|
+
require 'csv'
|
5
|
+
require 'fileutils'
|
3
6
|
require 'google/apis/drive_v3'
|
4
7
|
require 'google/apis/sheets_v4'
|
5
8
|
require 'googleauth'
|
9
|
+
require 'pathname'
|
6
10
|
require 'rubyXL'
|
7
11
|
require 'rubyXL/convenience_methods'
|
8
12
|
require 'set'
|
13
|
+
require 'tempfile'
|
14
|
+
|
15
|
+
require_relative 'csv_plus_plus/entities'
|
16
|
+
require_relative 'csv_plus_plus/error'
|
9
17
|
|
10
18
|
require_relative 'csv_plus_plus/cell'
|
11
19
|
require_relative 'csv_plus_plus/cli'
|
12
|
-
require_relative 'csv_plus_plus/code_section'
|
13
20
|
require_relative 'csv_plus_plus/color'
|
14
|
-
|
15
|
-
require_relative 'csv_plus_plus/
|
16
|
-
require_relative 'csv_plus_plus/
|
17
|
-
|
18
|
-
require_relative 'csv_plus_plus/
|
21
|
+
|
22
|
+
require_relative 'csv_plus_plus/compiler'
|
23
|
+
require_relative 'csv_plus_plus/runtime'
|
24
|
+
|
25
|
+
require_relative 'csv_plus_plus/lexer'
|
26
|
+
require_relative 'csv_plus_plus/lexer/tokenizer'
|
19
27
|
require_relative 'csv_plus_plus/modifier'
|
20
|
-
require_relative 'csv_plus_plus/modifier.tab'
|
21
28
|
require_relative 'csv_plus_plus/options'
|
29
|
+
require_relative 'csv_plus_plus/parser/modifier.tab'
|
22
30
|
require_relative 'csv_plus_plus/row'
|
23
31
|
require_relative 'csv_plus_plus/template'
|
32
|
+
require_relative 'csv_plus_plus/validated_modifier'
|
24
33
|
require_relative 'csv_plus_plus/writer'
|
25
34
|
|
26
35
|
# A programming language for writing rich CSV files
|
@@ -33,9 +42,9 @@ module CSVPlusPlus
|
|
33
42
|
def self.apply_template_to_sheet!(input, filename, options)
|
34
43
|
warn(options.verbose_summary) if options.verbose
|
35
44
|
|
36
|
-
runtime = ::CSVPlusPlus::
|
45
|
+
runtime = ::CSVPlusPlus::Runtime.new(input:, filename:)
|
37
46
|
|
38
|
-
::CSVPlusPlus::
|
47
|
+
::CSVPlusPlus::Compiler.with_compiler(options:, runtime:) do |compiler|
|
39
48
|
template = compiler.compile_template
|
40
49
|
|
41
50
|
warn(template.verbose_summary) if options.verbose
|
@@ -50,8 +59,8 @@ module CSVPlusPlus
|
|
50
59
|
# @param compiler [Compiler] The compiler currently in use
|
51
60
|
# @param options [Options] The options we're running with
|
52
61
|
def self.write_template(template, compiler, options)
|
53
|
-
output = ::CSVPlusPlus::Writer.writer(options)
|
54
62
|
compiler.outputting! do
|
63
|
+
output = ::CSVPlusPlus::Writer.writer(options)
|
55
64
|
output.write_backup if options.backup
|
56
65
|
output.write(template)
|
57
66
|
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.2
|
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-03-
|
11
|
+
date: 2023-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-apis-drive_v3
|
@@ -123,44 +123,54 @@ files:
|
|
123
123
|
- bin/csv++
|
124
124
|
- bin/csvpp
|
125
125
|
- lib/csv_plus_plus.rb
|
126
|
+
- 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
|
126
129
|
- lib/csv_plus_plus/cell.rb
|
127
130
|
- lib/csv_plus_plus/cli.rb
|
128
131
|
- lib/csv_plus_plus/cli_flag.rb
|
129
|
-
- lib/csv_plus_plus/code_section.rb
|
130
132
|
- lib/csv_plus_plus/color.rb
|
133
|
+
- lib/csv_plus_plus/compiler.rb
|
134
|
+
- lib/csv_plus_plus/data_validation.rb
|
135
|
+
- lib/csv_plus_plus/entities.rb
|
136
|
+
- lib/csv_plus_plus/entities/ast_builder.rb
|
137
|
+
- lib/csv_plus_plus/entities/boolean.rb
|
138
|
+
- lib/csv_plus_plus/entities/builtins.rb
|
139
|
+
- lib/csv_plus_plus/entities/cell_reference.rb
|
140
|
+
- lib/csv_plus_plus/entities/date.rb
|
141
|
+
- lib/csv_plus_plus/entities/entity.rb
|
142
|
+
- lib/csv_plus_plus/entities/function.rb
|
143
|
+
- lib/csv_plus_plus/entities/function_call.rb
|
144
|
+
- lib/csv_plus_plus/entities/number.rb
|
145
|
+
- lib/csv_plus_plus/entities/runtime_value.rb
|
146
|
+
- lib/csv_plus_plus/entities/string.rb
|
147
|
+
- lib/csv_plus_plus/entities/variable.rb
|
131
148
|
- lib/csv_plus_plus/error.rb
|
149
|
+
- lib/csv_plus_plus/error/error.rb
|
150
|
+
- lib/csv_plus_plus/error/formula_syntax_error.rb
|
151
|
+
- lib/csv_plus_plus/error/modifier_syntax_error.rb
|
152
|
+
- lib/csv_plus_plus/error/modifier_validation_error.rb
|
153
|
+
- lib/csv_plus_plus/error/syntax_error.rb
|
154
|
+
- lib/csv_plus_plus/error/writer_error.rb
|
132
155
|
- lib/csv_plus_plus/expand.rb
|
133
156
|
- lib/csv_plus_plus/google_api_client.rb
|
134
157
|
- lib/csv_plus_plus/google_options.rb
|
135
158
|
- 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
159
|
- lib/csv_plus_plus/lexer.rb
|
157
160
|
- lib/csv_plus_plus/lexer/lexer.rb
|
158
161
|
- lib/csv_plus_plus/lexer/tokenizer.rb
|
159
162
|
- lib/csv_plus_plus/modifier.rb
|
160
|
-
- lib/csv_plus_plus/modifier.
|
163
|
+
- lib/csv_plus_plus/modifier/conditional_formatting.rb
|
161
164
|
- lib/csv_plus_plus/options.rb
|
165
|
+
- lib/csv_plus_plus/parser/cell_value.tab.rb
|
166
|
+
- lib/csv_plus_plus/parser/code_section.tab.rb
|
167
|
+
- lib/csv_plus_plus/parser/modifier.tab.rb
|
168
|
+
- lib/csv_plus_plus/references.rb
|
162
169
|
- lib/csv_plus_plus/row.rb
|
170
|
+
- lib/csv_plus_plus/runtime.rb
|
171
|
+
- lib/csv_plus_plus/scope.rb
|
163
172
|
- lib/csv_plus_plus/template.rb
|
173
|
+
- lib/csv_plus_plus/validated_modifier.rb
|
164
174
|
- lib/csv_plus_plus/version.rb
|
165
175
|
- lib/csv_plus_plus/writer.rb
|
166
176
|
- lib/csv_plus_plus/writer/base_writer.rb
|
@@ -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,152 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'csv'
|
4
|
-
|
5
|
-
require_relative 'benchmarked_compiler'
|
6
|
-
require_relative 'code_section.tab'
|
7
|
-
require_relative 'entities'
|
8
|
-
require_relative 'runtime'
|
9
|
-
require_relative 'scope'
|
10
|
-
|
11
|
-
module CSVPlusPlus
|
12
|
-
module Language
|
13
|
-
# Encapsulates the parsing and building of objects (+Template+ -> +Row+ -> +Cell+). Variable resolution is delegated
|
14
|
-
# to the +Scope+
|
15
|
-
#
|
16
|
-
# @attr_reader options [Options] The +Options+ to compile with
|
17
|
-
# @attr_reader runtime [Runtime] The runtime execution
|
18
|
-
# @attr_reader scope [Scope] +Scope+ for variable resolution
|
19
|
-
class Compiler
|
20
|
-
attr_reader :timings, :benchmark, :options, :runtime, :scope
|
21
|
-
|
22
|
-
# Create a compiler and make sure it gets cleaned up
|
23
|
-
#
|
24
|
-
# @param runtime [Runtime] The initial +Runtime+ for the compiler
|
25
|
-
# @param options [Options]
|
26
|
-
def self.with_compiler(runtime:, options:, &block)
|
27
|
-
compiler = new(options:, runtime:)
|
28
|
-
if options.verbose
|
29
|
-
::CSVPlusPlus::Language::BenchmarkedCompiler.with_benchmarks(compiler) do |c|
|
30
|
-
block.call(c)
|
31
|
-
end
|
32
|
-
else
|
33
|
-
yield(compiler)
|
34
|
-
end
|
35
|
-
ensure
|
36
|
-
runtime.cleanup!
|
37
|
-
end
|
38
|
-
|
39
|
-
# @param runtime [Runtime]
|
40
|
-
# @param options [Options]
|
41
|
-
# @param scope [Scope, nil]
|
42
|
-
def initialize(runtime:, options:, scope: nil)
|
43
|
-
@options = options
|
44
|
-
@runtime = runtime
|
45
|
-
@scope = scope || ::CSVPlusPlus::Language::Scope.new(runtime:)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Write the compiled results
|
49
|
-
def outputting!
|
50
|
-
@runtime.start_at_csv!
|
51
|
-
yield
|
52
|
-
end
|
53
|
-
|
54
|
-
# Compile a template and return a +::CSVPlusPlus::Template+ instance ready to be written with a +Writer+
|
55
|
-
#
|
56
|
-
# @return [Template]
|
57
|
-
def compile_template
|
58
|
-
parse_code_section!
|
59
|
-
rows = parse_csv_section!
|
60
|
-
|
61
|
-
::CSVPlusPlus::Template.new(rows:, code_section: scope.code_section).tap do |t|
|
62
|
-
t.validate_infinite_expands(@runtime)
|
63
|
-
expanding { t.expand_rows! }
|
64
|
-
resolve_all_cells!(t)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# @return [String]
|
69
|
-
def to_s
|
70
|
-
"Compiler(options: #{@options}, runtime: #{@runtime}, scope: #{@scope})"
|
71
|
-
end
|
72
|
-
|
73
|
-
protected
|
74
|
-
|
75
|
-
# Parses the input file and returns a +CodeSection+
|
76
|
-
#
|
77
|
-
# @return [CodeSection]
|
78
|
-
def parse_code_section!
|
79
|
-
@runtime.start!
|
80
|
-
parsing_code_section do |input|
|
81
|
-
code_section, csv_section = ::CSVPlusPlus::Language::CodeSectionParser.new.parse(input, @runtime)
|
82
|
-
# TODO: infer a type
|
83
|
-
# allow user-supplied key/values to override anything global or from the code section
|
84
|
-
code_section.def_variables(
|
85
|
-
options.key_values.transform_values { |v| ::CSVPlusPlus::Language::Entities::String.new(v.to_s) }
|
86
|
-
)
|
87
|
-
@scope.code_section = code_section
|
88
|
-
|
89
|
-
# return the csv_section to the caller because they're gonna re-write input with it
|
90
|
-
next csv_section
|
91
|
-
end
|
92
|
-
@scope.code_section
|
93
|
-
end
|
94
|
-
|
95
|
-
# Parse the CSV section and return an array of +Row+s
|
96
|
-
#
|
97
|
-
# @return [Array<Row>]
|
98
|
-
def parse_csv_section!
|
99
|
-
@runtime.start_at_csv!
|
100
|
-
@runtime.map_rows(::CSV.new(runtime.input)) do |csv_row|
|
101
|
-
parse_row(csv_row)
|
102
|
-
end
|
103
|
-
ensure
|
104
|
-
# we're done with the file and everything is in memory
|
105
|
-
@runtime.cleanup!
|
106
|
-
end
|
107
|
-
|
108
|
-
# Iterates through each cell of each row and resolves it's variable and function references.
|
109
|
-
#
|
110
|
-
# @param template [Template]
|
111
|
-
# @return [Array<Entity>]
|
112
|
-
def resolve_all_cells!(template)
|
113
|
-
@runtime.start_at_csv!
|
114
|
-
@runtime.map_rows(template.rows, cells_too: true) do |cell|
|
115
|
-
cell.ast = @scope.resolve_cell_value if cell.ast
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# Expanding rows
|
120
|
-
def expanding
|
121
|
-
@runtime.start_at_csv!
|
122
|
-
yield
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
def parsing_code_section
|
128
|
-
csv_section = yield(@runtime.input.read)
|
129
|
-
@runtime.rewrite_input!(csv_section)
|
130
|
-
end
|
131
|
-
|
132
|
-
# Using the current +@runtime+ and the given +csv_row+ parse it into a +Row+ of +Cell+s
|
133
|
-
# +csv_row+ should have already been run through a CSV parser and is an array of strings
|
134
|
-
#
|
135
|
-
# @param csv_row [Array<Array<String>>]
|
136
|
-
# @return [Row]
|
137
|
-
def parse_row(csv_row)
|
138
|
-
row_modifier = ::CSVPlusPlus::Modifier.new(row_level: true)
|
139
|
-
|
140
|
-
cells =
|
141
|
-
@runtime.map_row(csv_row) do |value, _cell_index|
|
142
|
-
cell_modifier = ::CSVPlusPlus::Modifier.new
|
143
|
-
parsed_value = ::CSVPlusPlus::ModifierParser.new(row_modifier:, cell_modifier:).parse(value, @runtime)
|
144
|
-
|
145
|
-
::CSVPlusPlus::Cell.parse(parsed_value, runtime:, modifier: cell_modifier)
|
146
|
-
end
|
147
|
-
|
148
|
-
::CSVPlusPlus::Row.new(@runtime.row_index, cells, row_modifier)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative './entity'
|
4
|
-
|
5
|
-
module CSVPlusPlus
|
6
|
-
module Language
|
7
|
-
module Entities
|
8
|
-
# A boolean value
|
9
|
-
#
|
10
|
-
# @attr_reader value [true, false]
|
11
|
-
class Boolean < Entity
|
12
|
-
attr_reader :value
|
13
|
-
|
14
|
-
# @param value [String, Boolean]
|
15
|
-
def initialize(value)
|
16
|
-
super(:boolean)
|
17
|
-
# TODO: probably can do a lot better in general on type validation
|
18
|
-
@value = value.is_a?(::String) ? (value.downcase == 'true') : value
|
19
|
-
end
|
20
|
-
|
21
|
-
# @return [String]
|
22
|
-
def to_s
|
23
|
-
@value.to_s.upcase
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [boolean]
|
27
|
-
def ==(other)
|
28
|
-
super && value == other.value
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative './entity'
|
4
|
-
|
5
|
-
module CSVPlusPlus
|
6
|
-
module Language
|
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
|
-
# @param cell_reference [String] The cell reference in A1 format
|
15
|
-
def initialize(cell_reference)
|
16
|
-
super(:cell_reference)
|
17
|
-
|
18
|
-
@cell_reference = cell_reference
|
19
|
-
end
|
20
|
-
|
21
|
-
# @return [String]
|
22
|
-
def to_s
|
23
|
-
@cell_reference
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [Boolean]
|
27
|
-
def ==(other)
|
28
|
-
super && @cell_reference == other.cell_reference
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|