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
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative './google_sheet_modifier'
|
|
4
|
-
|
|
5
|
-
module CSVPlusPlus
|
|
6
|
-
module Writer
|
|
7
|
-
# Given +rows+ from a +Template+, build requests compatible with Google Sheets Ruby API
|
|
8
|
-
# rubocop:disable Metrics/ClassLength
|
|
9
|
-
class GoogleSheetBuilder
|
|
10
|
-
# @param current_sheet_values
|
|
11
|
-
def initialize(current_sheet_values:, sheet_id:, rows:, column_index: 0, row_index: 0)
|
|
12
|
-
@current_sheet_values = current_sheet_values
|
|
13
|
-
@sheet_id = sheet_id
|
|
14
|
-
@rows = rows
|
|
15
|
-
@column_index = column_index
|
|
16
|
-
@row_index = row_index
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Build a Google::Apis::SheetsV4::BatchUpdateSpreadsheetRequest
|
|
20
|
-
#
|
|
21
|
-
# @return [Google::Apis::SheetsV4::BatchUpdateSpreadsheetRequest]
|
|
22
|
-
def batch_update_spreadsheet_request
|
|
23
|
-
build_batch_request(@rows)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
private
|
|
27
|
-
|
|
28
|
-
def set_extended_value_type!(extended_value, value)
|
|
29
|
-
v = value || ''
|
|
30
|
-
if v.start_with?('=')
|
|
31
|
-
extended_value.formula_value = value
|
|
32
|
-
elsif v.match(/^-?[\d.]+$/)
|
|
33
|
-
extended_value.number_value = value
|
|
34
|
-
elsif v.downcase == 'true' || v.downcase == 'false'
|
|
35
|
-
extended_value.boolean_value = value
|
|
36
|
-
else
|
|
37
|
-
extended_value.string_value = value
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def build_cell_format(mod)
|
|
42
|
-
::Google::Apis::SheetsV4::CellFormat.new.tap do |cf|
|
|
43
|
-
cf.text_format = mod.text_format
|
|
44
|
-
|
|
45
|
-
cf.horizontal_alignment = mod.halign
|
|
46
|
-
cf.vertical_alignment = mod.valign
|
|
47
|
-
cf.background_color = mod.color
|
|
48
|
-
cf.number_format = mod.numberformat
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def grid_range_for_cell(cell)
|
|
53
|
-
::Google::Apis::SheetsV4::GridRange.new(
|
|
54
|
-
sheet_id: @sheet_id,
|
|
55
|
-
start_column_index: cell.index,
|
|
56
|
-
end_column_index: cell.index + 1,
|
|
57
|
-
start_row_index: cell.row_index,
|
|
58
|
-
end_row_index: cell.row_index + 1
|
|
59
|
-
)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def current_value(row_index, cell_index)
|
|
63
|
-
@current_sheet_values[row_index][cell_index]
|
|
64
|
-
rescue ::StandardError
|
|
65
|
-
nil
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def build_cell_value(cell)
|
|
69
|
-
::Google::Apis::SheetsV4::ExtendedValue.new.tap do |xv|
|
|
70
|
-
value =
|
|
71
|
-
if cell.value.nil?
|
|
72
|
-
current_value(cell.row_index, cell.index)
|
|
73
|
-
else
|
|
74
|
-
cell.to_csv
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
set_extended_value_type!(xv, value)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def build_cell_data(cell)
|
|
82
|
-
mod = ::CSVPlusPlus::Writer::GoogleSheetModifier.new(cell.modifier)
|
|
83
|
-
|
|
84
|
-
::Google::Apis::SheetsV4::CellData.new.tap do |cd|
|
|
85
|
-
cd.user_entered_format = build_cell_format(mod)
|
|
86
|
-
cd.note = mod.note if mod.note
|
|
87
|
-
|
|
88
|
-
# XXX apply data validation
|
|
89
|
-
cd.user_entered_value = build_cell_value(cell)
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def build_row_data(row)
|
|
94
|
-
::Google::Apis::SheetsV4::RowData.new(values: row.cells.map { |cell| build_cell_data(cell) })
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def build_update_cells_request(rows)
|
|
98
|
-
::Google::Apis::SheetsV4::UpdateCellsRequest.new(
|
|
99
|
-
fields: '*',
|
|
100
|
-
start: ::Google::Apis::SheetsV4::GridCoordinate.new(
|
|
101
|
-
sheet_id: @sheet_id,
|
|
102
|
-
column_index: @column_index,
|
|
103
|
-
row_index: @row_index
|
|
104
|
-
),
|
|
105
|
-
rows: rows.map { |row| build_row_data(row) }
|
|
106
|
-
)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def build_border(cell)
|
|
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,
|
|
118
|
-
range: grid_range_for_cell(cell)
|
|
119
|
-
)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def build_update_borders_request(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
|
-
end
|
|
131
|
-
|
|
132
|
-
def build_batch_request(rows)
|
|
133
|
-
::Google::Apis::SheetsV4::BatchUpdateSpreadsheetRequest.new.tap do |bu|
|
|
134
|
-
bu.requests = chunked_requests(rows)
|
|
135
|
-
|
|
136
|
-
rows.each do |row|
|
|
137
|
-
row.cells.filter { |c| c.modifier.any_border? }
|
|
138
|
-
.each do |cell|
|
|
139
|
-
bu.requests << build_update_borders_request(cell)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
# rubocop:enable Metrics/ClassLength
|
|
146
|
-
end
|
|
147
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
module Writer
|
|
5
|
-
# Decorate a Modifier so it can be written to the Google Sheets API
|
|
6
|
-
class GoogleSheetModifier < ::SimpleDelegator
|
|
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
|
-
)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Format the color for Google Sheets
|
|
19
|
-
#
|
|
20
|
-
# @return [Google::Apis::SheetsV4::Color]
|
|
21
|
-
def color
|
|
22
|
-
google_sheets_color(super) if super
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Format the fontcolor for Google Sheets
|
|
26
|
-
#
|
|
27
|
-
# @return [Google::Apis::SheetsV4::Color]
|
|
28
|
-
def fontcolor
|
|
29
|
-
google_sheets_color(super) if super
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Format the halign for Google Sheets
|
|
33
|
-
#
|
|
34
|
-
# @return [String]
|
|
35
|
-
def halign
|
|
36
|
-
super&.to_s&.upcase
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Format the numberformat for Google Sheets
|
|
40
|
-
#
|
|
41
|
-
# @return [::Google::Apis::SheetsV4::NumberFormat]
|
|
42
|
-
def numberformat
|
|
43
|
-
::Google::Apis::SheetsV4::NumberFormat.new(type: super) if super
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Builds a SheetsV4::TextFormat with the underlying Modifier
|
|
47
|
-
#
|
|
48
|
-
# @return [::Google::Apis::SheetsV4::TextFormat]
|
|
49
|
-
def text_format
|
|
50
|
-
::Google::Apis::SheetsV4::TextFormat.new(
|
|
51
|
-
bold: formatted?(:bold) || nil,
|
|
52
|
-
italic: formatted?(:italic) || nil,
|
|
53
|
-
strikethrough: formatted?(:strikethrough) || nil,
|
|
54
|
-
underline: formatted?(:underline) || nil,
|
|
55
|
-
font_family: fontfamily,
|
|
56
|
-
font_size: fontsize,
|
|
57
|
-
foreground_color: fontcolor
|
|
58
|
-
)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Format the valign for Google Sheets
|
|
62
|
-
def valign
|
|
63
|
-
super&.to_s&.upcase
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
private
|
|
67
|
-
|
|
68
|
-
def google_sheets_color(color)
|
|
69
|
-
::Google::Apis::SheetsV4::Color.new(
|
|
70
|
-
red: color.red_percent,
|
|
71
|
-
green: color.green_percent,
|
|
72
|
-
blue: color.blue_percent
|
|
73
|
-
)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CSVPlusPlus
|
|
4
|
-
module Writer
|
|
5
|
-
# Build a RubyXL-decorated Modifier class adds some support for Excel
|
|
6
|
-
class RubyXLModifier < ::SimpleDelegator
|
|
7
|
-
# https://www.rubydoc.info/gems/rubyXL/RubyXL/NumberFormats
|
|
8
|
-
# https://support.microsoft.com/en-us/office/number-format-codes-5026bbd6-04bc-48cd-bf33-80f18b4eae68
|
|
9
|
-
NUM_FMT_IDS = {
|
|
10
|
-
currency: 5,
|
|
11
|
-
date: 14,
|
|
12
|
-
date_time: 22,
|
|
13
|
-
number: 1,
|
|
14
|
-
percent: 9,
|
|
15
|
-
text: 49,
|
|
16
|
-
time: 21,
|
|
17
|
-
scientific: 48
|
|
18
|
-
}.freeze
|
|
19
|
-
private_constant :NUM_FMT_IDS
|
|
20
|
-
|
|
21
|
-
# https://www.rubydoc.info/gems/rubyXL/2.3.0/RubyXL
|
|
22
|
-
# ST_BorderStyle = %w{ none thin medium dashed dotted thick double hair mediumDashed dashDot mediumDashDot
|
|
23
|
-
# dashDotDot slantDashDot }
|
|
24
|
-
BORDER_STYLES = {
|
|
25
|
-
dashed: 'dashed',
|
|
26
|
-
dotted: 'dotted',
|
|
27
|
-
double: 'double',
|
|
28
|
-
solid: 'thin',
|
|
29
|
-
solid_medium: 'medium',
|
|
30
|
-
solid_thick: 'thick'
|
|
31
|
-
}.freeze
|
|
32
|
-
private_constant :BORDER_STYLES
|
|
33
|
-
|
|
34
|
-
# The excel-specific border weight
|
|
35
|
-
#
|
|
36
|
-
# @return [Integer]
|
|
37
|
-
def border_weight
|
|
38
|
-
return unless borderstyle
|
|
39
|
-
|
|
40
|
-
# rubocop:disable Lint/ConstantResolution
|
|
41
|
-
BORDER_STYLES[borderstyle.to_sym]
|
|
42
|
-
# rubocop:enable Lint/ConstantResolution
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# The excel-specific number format code
|
|
46
|
-
#
|
|
47
|
-
# @return [String]
|
|
48
|
-
def number_format_code
|
|
49
|
-
return unless numberformat
|
|
50
|
-
|
|
51
|
-
::RubyXL::NumberFormats::DEFAULT_NUMBER_FORMATS.find_by_format_id(
|
|
52
|
-
# rubocop:disable Lint/ConstantResolution
|
|
53
|
-
NUM_FMT_IDS[numberformat.to_sym]
|
|
54
|
-
# rubocop:enable Lint/ConstantResolution
|
|
55
|
-
).format_code
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|