csv_plus_plus 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +18 -62
  4. data/lib/csv_plus_plus/benchmarked_compiler.rb +62 -0
  5. data/lib/csv_plus_plus/{code_section.rb → can_define_references.rb} +22 -35
  6. data/lib/csv_plus_plus/can_resolve_references.rb +8 -0
  7. data/lib/csv_plus_plus/cell.rb +3 -3
  8. data/lib/csv_plus_plus/cli.rb +24 -7
  9. data/lib/csv_plus_plus/color.rb +12 -6
  10. data/lib/csv_plus_plus/compiler.rb +156 -0
  11. data/lib/csv_plus_plus/data_validation.rb +138 -0
  12. data/lib/csv_plus_plus/{language → entities}/ast_builder.rb +3 -5
  13. data/lib/csv_plus_plus/entities/boolean.rb +31 -0
  14. data/lib/csv_plus_plus/{language → entities}/builtins.rb +2 -4
  15. data/lib/csv_plus_plus/entities/cell_reference.rb +60 -0
  16. data/lib/csv_plus_plus/entities/date.rb +30 -0
  17. data/lib/csv_plus_plus/entities/entity.rb +84 -0
  18. data/lib/csv_plus_plus/entities/function.rb +33 -0
  19. data/lib/csv_plus_plus/entities/function_call.rb +35 -0
  20. data/lib/csv_plus_plus/entities/number.rb +34 -0
  21. data/lib/csv_plus_plus/entities/runtime_value.rb +26 -0
  22. data/lib/csv_plus_plus/entities/string.rb +29 -0
  23. data/lib/csv_plus_plus/entities/variable.rb +25 -0
  24. data/lib/csv_plus_plus/entities.rb +33 -0
  25. data/lib/csv_plus_plus/error/error.rb +10 -0
  26. data/lib/csv_plus_plus/error/formula_syntax_error.rb +36 -0
  27. data/lib/csv_plus_plus/error/modifier_syntax_error.rb +27 -0
  28. data/lib/csv_plus_plus/error/modifier_validation_error.rb +49 -0
  29. data/lib/csv_plus_plus/{language → error}/syntax_error.rb +6 -14
  30. data/lib/csv_plus_plus/error/writer_error.rb +9 -0
  31. data/lib/csv_plus_plus/error.rb +9 -2
  32. data/lib/csv_plus_plus/expand.rb +3 -1
  33. data/lib/csv_plus_plus/google_api_client.rb +4 -0
  34. data/lib/csv_plus_plus/lexer/lexer.rb +13 -6
  35. data/lib/csv_plus_plus/modifier/conditional_formatting.rb +17 -0
  36. data/lib/csv_plus_plus/modifier.rb +73 -65
  37. data/lib/csv_plus_plus/{language → parser}/cell_value.tab.rb +20 -20
  38. data/lib/csv_plus_plus/{language → parser}/code_section.tab.rb +83 -87
  39. data/lib/csv_plus_plus/parser/modifier.tab.rb +484 -0
  40. data/lib/csv_plus_plus/references.rb +68 -0
  41. data/lib/csv_plus_plus/row.rb +0 -3
  42. data/lib/csv_plus_plus/runtime.rb +199 -0
  43. data/lib/csv_plus_plus/scope.rb +196 -0
  44. data/lib/csv_plus_plus/template.rb +10 -10
  45. data/lib/csv_plus_plus/validated_modifier.rb +164 -0
  46. data/lib/csv_plus_plus/version.rb +1 -1
  47. data/lib/csv_plus_plus/writer/file_backer_upper.rb +6 -4
  48. data/lib/csv_plus_plus/writer/google_sheet_builder.rb +24 -29
  49. data/lib/csv_plus_plus/writer/google_sheet_modifier.rb +33 -12
  50. data/lib/csv_plus_plus/writer/rubyxl_builder.rb +3 -6
  51. data/lib/csv_plus_plus.rb +19 -10
  52. metadata +34 -24
  53. data/lib/csv_plus_plus/language/benchmarked_compiler.rb +0 -65
  54. data/lib/csv_plus_plus/language/compiler.rb +0 -152
  55. data/lib/csv_plus_plus/language/entities/boolean.rb +0 -33
  56. data/lib/csv_plus_plus/language/entities/cell_reference.rb +0 -33
  57. data/lib/csv_plus_plus/language/entities/entity.rb +0 -86
  58. data/lib/csv_plus_plus/language/entities/function.rb +0 -35
  59. data/lib/csv_plus_plus/language/entities/function_call.rb +0 -37
  60. data/lib/csv_plus_plus/language/entities/number.rb +0 -36
  61. data/lib/csv_plus_plus/language/entities/runtime_value.rb +0 -28
  62. data/lib/csv_plus_plus/language/entities/string.rb +0 -31
  63. data/lib/csv_plus_plus/language/entities/variable.rb +0 -25
  64. data/lib/csv_plus_plus/language/entities.rb +0 -28
  65. data/lib/csv_plus_plus/language/references.rb +0 -70
  66. data/lib/csv_plus_plus/language/runtime.rb +0 -205
  67. data/lib/csv_plus_plus/language/scope.rb +0 -192
  68. 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
- sheets_ns::CellFormat.new.tap do |cf|
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
- sheets_ns::GridRange.new(
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
- sheets_ns::ExtendedValue.new.tap do |xv|
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
- sheets_ns::CellData.new.tap do |cd|
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
- sheets_ns::RowData.new(values: row.cells.map { |cell| build_cell_data(cell) })
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
- sheets_ns::UpdateCellsRequest.new(
98
+ ::Google::Apis::SheetsV4::UpdateCellsRequest.new(
105
99
  fields: '*',
106
- start: sheets_ns::GridCoordinate.new(
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
- # TODO: allow different border styles per side
118
- border = sheets_ns::Border.new(color: mod.bordercolor || '#000000', style: mod.borderstyle || 'solid')
119
- sheets_ns::UpdateBordersRequest.new(
120
- top: mod.border_along?('top') ? border : nil,
121
- right: mod.border_along?('right') ? border : nil,
122
- left: mod.border_along?('left') ? border : nil,
123
- bottom: mod.border_along?('bottom') ? border : nil,
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
- sheets_ns::Request.new(update_borders: build_border(cell))
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
- sheets_ns::BatchUpdateSpreadsheetRequest.new.tap do |bu|
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 halign for Google Sheets
8
- def halign
9
- super&.upcase
10
- end
11
-
12
- # Format the valign for Google Sheets
13
- def valign
14
- super&.upcase
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?('bold') || nil,
36
- italic: formatted?('italic') || nil,
37
- strikethrough: formatted?('strikethrough') || nil,
38
- underline: formatted?('underline') || nil,
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 do |workbook|
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.add_worksheet(@sheet_name) unless workbook[@sheet_name]
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
- 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'
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::Language::Runtime.new(input:, filename:)
45
+ runtime = ::CSVPlusPlus::Runtime.new(input:, filename:)
37
46
 
38
- ::CSVPlusPlus::Language::Compiler.with_compiler(options:, runtime:) do |compiler|
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.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 00:00:00.000000000 Z
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.tab.rb
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