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,179 +1,108 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# @attr borders [Array<Symbol>] The borders that will be set
|
|
8
|
-
# @attr color [Color] The background color of the cell
|
|
9
|
-
# @attr expand [Expand] Whether this row expands into multiple rows
|
|
10
|
-
# @attr fontcolor [Color] The font color of the cell
|
|
11
|
-
# @attr fontfamily [::String] The font family
|
|
12
|
-
# @attr fontsize [Integer] The font size
|
|
13
|
-
# @attr halign [:left, :center, :right] Horizontal alignment
|
|
14
|
-
# @attr note [::String] A note/comment on the cell
|
|
15
|
-
# @attr numberformat [Symbol] A number format to apply to the value in the cell
|
|
16
|
-
# @attr row_level [boolean] Is this a row modifier? If so it's values will apply to all cells in the row
|
|
17
|
-
# (unless overridden by the cell modifier)
|
|
18
|
-
# @attr validation [Object]
|
|
19
|
-
# @attr valign [:top, :center, :bottom] Vertical alignment
|
|
20
|
-
# @attr var [Symbol] The variable bound to this cell
|
|
21
|
-
#
|
|
22
|
-
# @attr_writer borderstyle [:hashed, :dotted, :double, :solid, :solid_medium, :solid_thick]
|
|
23
|
-
# The style of border on the cell
|
|
24
|
-
#
|
|
25
|
-
# @attr_reader borders [Array<Symbol>]
|
|
26
|
-
# @attr_reader formats [Array<Symbol>] Bold/italics/underline/strikethrough formatting
|
|
27
|
-
class Modifier
|
|
28
|
-
attr_accessor :bordercolor,
|
|
29
|
-
:color,
|
|
30
|
-
:expand,
|
|
31
|
-
:fontcolor,
|
|
32
|
-
:fontfamily,
|
|
33
|
-
:fontsize,
|
|
34
|
-
:halign,
|
|
35
|
-
:valign,
|
|
36
|
-
:note,
|
|
37
|
-
:numberformat,
|
|
38
|
-
:row_level,
|
|
39
|
-
:validation,
|
|
40
|
-
:var
|
|
41
|
-
attr_reader :borders, :formats
|
|
42
|
-
attr_writer :borderstyle
|
|
43
|
-
|
|
44
|
-
# When instantiating a new object, extend it with our validation functionality.
|
|
45
|
-
#
|
|
46
|
-
# I'm not sure why I need to do it this way tbh, using +include ValidatedModifier+ at the
|
|
47
|
-
# class level didn't seem to have access to the parent methods
|
|
48
|
-
# def self.new(*args, **kwargs, &)
|
|
49
|
-
# allocate.tap do |i|
|
|
50
|
-
# i.__send__(:initialize, *args, **kwargs, &)
|
|
51
|
-
# i.extend(::CSVPlusPlus::ValidatedModifier)
|
|
52
|
-
# end
|
|
53
|
-
# end
|
|
54
|
-
|
|
55
|
-
# @param row_level [Boolean] Whether or not this modifier applies to the entire row
|
|
56
|
-
def initialize(row_level: false)
|
|
57
|
-
@row_level = row_level
|
|
58
|
-
@freeze = false
|
|
59
|
-
@borders = ::Set.new
|
|
60
|
-
@formats = ::Set.new
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Are there any borders set?
|
|
64
|
-
#
|
|
65
|
-
# @return [Boolean]
|
|
66
|
-
def any_border?
|
|
67
|
-
!@borders.empty?
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Style of border
|
|
71
|
-
#
|
|
72
|
-
# @return [Symbol]
|
|
73
|
-
def borderstyle
|
|
74
|
-
@borderstyle || :solid
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Is this a cell-level modifier?
|
|
78
|
-
#
|
|
79
|
-
# @return [Boolean]
|
|
80
|
-
def cell_level?
|
|
81
|
-
!@row_level
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Assign a border
|
|
85
|
-
#
|
|
86
|
-
# @param side [:top, :left, :bottom, :right, :all]
|
|
87
|
-
def border=(side)
|
|
88
|
-
@borders << side
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Does this have a border along +side+?
|
|
92
|
-
#
|
|
93
|
-
# @param side [:top, :left, :bottom, :right, :all]
|
|
94
|
-
#
|
|
95
|
-
# @return [boolean]
|
|
96
|
-
def border_along?(side)
|
|
97
|
-
@borders.include?(:all) || @borders.include?(side)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Does this have a border along all sides?
|
|
101
|
-
#
|
|
102
|
-
# @return [boolean]
|
|
103
|
-
def border_all?
|
|
104
|
-
@borders.include?(:all) \
|
|
105
|
-
|| (border_along?(:top) && border_along?(:bottom) && border_along?(:left) && border_along?(:right))
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# Set this modifier to expand infinitely
|
|
109
|
-
#
|
|
110
|
-
# @return [::Expand]
|
|
111
|
-
def expand!
|
|
112
|
-
@expand = ::CSVPlusPlus::Expand.new if row_level?
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Set a text format (bolid, italic, underline or strikethrough)
|
|
116
|
-
#
|
|
117
|
-
# @param value [:bold, :italic, :underline, :strikethrough]
|
|
118
|
-
def format=(value)
|
|
119
|
-
@formats << value
|
|
120
|
-
end
|
|
4
|
+
require_relative './modifier/conditional_formatting'
|
|
5
|
+
require_relative './modifier/data_validation'
|
|
6
|
+
require_relative './modifier/expand'
|
|
7
|
+
require_relative './modifier/modifier'
|
|
121
8
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
9
|
+
module CSVPlusPlus
|
|
10
|
+
# All modifier-specific logic is hidden in this module and callers should just call +#new+ on this module.
|
|
11
|
+
module Modifier
|
|
12
|
+
extend ::T::Sig
|
|
13
|
+
|
|
14
|
+
# The sides that a border can be on
|
|
15
|
+
class BorderSide < ::T::Enum
|
|
16
|
+
enums do
|
|
17
|
+
All = new
|
|
18
|
+
Top = new
|
|
19
|
+
Bottom = new
|
|
20
|
+
Left = new
|
|
21
|
+
Right = new
|
|
22
|
+
end
|
|
129
23
|
end
|
|
130
24
|
|
|
131
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
25
|
+
# The various border styles
|
|
26
|
+
class BorderStyle < ::T::Enum
|
|
27
|
+
enums do
|
|
28
|
+
Dashed = new
|
|
29
|
+
Dotted = new
|
|
30
|
+
Double = new
|
|
31
|
+
Solid = new
|
|
32
|
+
SolidMedium = new
|
|
33
|
+
SolidThick = new
|
|
34
|
+
end
|
|
136
35
|
end
|
|
137
36
|
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
37
|
+
# The possible values for a horizontal alignment
|
|
38
|
+
class HorizontalAlign < ::T::Enum
|
|
39
|
+
enums do
|
|
40
|
+
Left = new
|
|
41
|
+
Right = new
|
|
42
|
+
Center = new
|
|
43
|
+
end
|
|
143
44
|
end
|
|
144
45
|
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
46
|
+
# The allowed number formats
|
|
47
|
+
class NumberFormat < ::T::Enum
|
|
48
|
+
enums do
|
|
49
|
+
Currency = new
|
|
50
|
+
Date = new
|
|
51
|
+
DateTime = new
|
|
52
|
+
Number = new
|
|
53
|
+
Percent = new
|
|
54
|
+
Text = new
|
|
55
|
+
Time = new
|
|
56
|
+
Scientific = new
|
|
57
|
+
end
|
|
150
58
|
end
|
|
151
59
|
|
|
152
|
-
#
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
60
|
+
# The types of formats that can be applied to text.
|
|
61
|
+
class TextFormat < ::T::Enum
|
|
62
|
+
enums do
|
|
63
|
+
Bold = new
|
|
64
|
+
Italic = new
|
|
65
|
+
Strikethrough = new
|
|
66
|
+
Underline = new
|
|
67
|
+
end
|
|
157
68
|
end
|
|
158
69
|
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
70
|
+
# The possible values for a horizontal alignment
|
|
71
|
+
class VerticalAlign < ::T::Enum
|
|
72
|
+
enums do
|
|
73
|
+
Top = new
|
|
74
|
+
Bottom = new
|
|
75
|
+
Center = new
|
|
76
|
+
end
|
|
164
77
|
end
|
|
165
78
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
79
|
+
sig do
|
|
80
|
+
params(
|
|
81
|
+
options: ::CSVPlusPlus::Options::Options,
|
|
82
|
+
row_level: ::T::Boolean
|
|
83
|
+
).returns(::CSVPlusPlus::Modifier::Modifier)
|
|
84
|
+
end
|
|
85
|
+
# Return a +Modifier+ with the proper validation and helper functions attached for the given output
|
|
86
|
+
#
|
|
87
|
+
# @param options [boolean] is this a row level modifier? (otherwise cell-level)
|
|
88
|
+
# @param row_level [boolean] is this a row level modifier? (otherwise cell-level)
|
|
89
|
+
#
|
|
90
|
+
# @return [ValidatedModifier]
|
|
91
|
+
def self.new(options, row_level: false)
|
|
92
|
+
output_format = options.output_format
|
|
93
|
+
case output_format
|
|
94
|
+
when ::CSVPlusPlus::Options::OutputFormat::CSV, ::CSVPlusPlus::Options::OutputFormat::OpenDocument
|
|
95
|
+
::CSVPlusPlus::Modifier::Modifier.new(row_level:)
|
|
96
|
+
when ::CSVPlusPlus::Options::OutputFormat::Excel
|
|
97
|
+
::CSVPlusPlus::Modifier::RubyXLModifier.new(row_level:)
|
|
98
|
+
when ::CSVPlusPlus::Options::OutputFormat::GoogleSheets
|
|
99
|
+
::CSVPlusPlus::Modifier::GoogleSheetModifier.new(row_level:)
|
|
100
|
+
else ::T.absurd(output_format)
|
|
176
101
|
end
|
|
177
102
|
end
|
|
178
103
|
end
|
|
179
104
|
end
|
|
105
|
+
|
|
106
|
+
require_relative './modifier/google_sheet_modifier'
|
|
107
|
+
require_relative './modifier/modifier_validator'
|
|
108
|
+
require_relative './modifier/rubyxl_modifier'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module CSVPlusPlus
|
|
5
|
+
module Options
|
|
6
|
+
# The options that are specific for compiling to a file
|
|
7
|
+
#
|
|
8
|
+
# @attr output_filename [Pathname] The file to write our compiled results to
|
|
9
|
+
class FileOptions < ::CSVPlusPlus::Options::Options
|
|
10
|
+
extend ::T::Sig
|
|
11
|
+
extend ::T::Helpers
|
|
12
|
+
|
|
13
|
+
sig { returns(::Pathname) }
|
|
14
|
+
attr_accessor :output_filename
|
|
15
|
+
|
|
16
|
+
sig { params(sheet_name: ::String, output_filename: ::String).void }
|
|
17
|
+
# Initialize an +Options+ object for writing to a file
|
|
18
|
+
def initialize(sheet_name, output_filename)
|
|
19
|
+
super(sheet_name)
|
|
20
|
+
|
|
21
|
+
@output_filename = ::T.let(::Pathname.new(output_filename), ::Pathname)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
sig { override.returns(::CSVPlusPlus::Options::OutputFormat) }
|
|
25
|
+
# Given the options, figure out which type of +OutputFormat+ we'll be writing to
|
|
26
|
+
#
|
|
27
|
+
# @return [Options::OutputFormat]
|
|
28
|
+
def output_format
|
|
29
|
+
case output_filename.extname
|
|
30
|
+
when '.csv' then ::CSVPlusPlus::Options::OutputFormat::CSV
|
|
31
|
+
when '.ods' then ::CSVPlusPlus::Options::OutputFormat::OpenDocument
|
|
32
|
+
when /\.xl(sx|sm|tx|tm)$/ then ::CSVPlusPlus::Options::OutputFormat::Excel
|
|
33
|
+
else raise(::CSVPlusPlus::Error::CLIError, "Unsupported file extension: #{output_filename}")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
sig { override.returns(::String) }
|
|
38
|
+
# Verbose summary for options specific to compiling to a file
|
|
39
|
+
#
|
|
40
|
+
# @return [String]
|
|
41
|
+
def verbose_summary
|
|
42
|
+
shared_summary(
|
|
43
|
+
<<~OUTPUT)
|
|
44
|
+
> Output filename | #{output_filename}
|
|
45
|
+
OUTPUT
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module CSVPlusPlus
|
|
5
|
+
module Options
|
|
6
|
+
# The Google-specific options a user can supply.
|
|
7
|
+
#
|
|
8
|
+
# @attr sheet_id [String] The ID of the Google Sheet to write to.
|
|
9
|
+
class GoogleSheetsOptions < Options
|
|
10
|
+
extend ::T::Sig
|
|
11
|
+
|
|
12
|
+
sig { returns(::String) }
|
|
13
|
+
attr_reader :sheet_id
|
|
14
|
+
|
|
15
|
+
sig { params(sheet_name: ::String, sheet_id: ::String).void }
|
|
16
|
+
# @param sheet_name [String] The name of the sheet
|
|
17
|
+
# @param sheet_id [String] The unique ID Google uses to reference the sheet
|
|
18
|
+
def initialize(sheet_name, sheet_id)
|
|
19
|
+
super(sheet_name)
|
|
20
|
+
|
|
21
|
+
@sheet_id = sheet_id
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
sig { override.returns(::CSVPlusPlus::Options::OutputFormat) }
|
|
25
|
+
# @return [OutputFormat]
|
|
26
|
+
def output_format
|
|
27
|
+
::CSVPlusPlus::Options::OutputFormat::GoogleSheets
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
sig { override.returns(::String) }
|
|
31
|
+
# Format a string with a verbose description of Google-specific options
|
|
32
|
+
#
|
|
33
|
+
# @return [String]
|
|
34
|
+
def verbose_summary
|
|
35
|
+
shared_summary(
|
|
36
|
+
<<~SUMMARY)
|
|
37
|
+
> Sheet ID | #{@sheet_id}
|
|
38
|
+
SUMMARY
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module CSVPlusPlus
|
|
5
|
+
module Options
|
|
6
|
+
# The options a user can supply (via CLI flags)
|
|
7
|
+
#
|
|
8
|
+
# @attr backup [Boolean] Create a backup of the spreadsheet before writing
|
|
9
|
+
# @attr create_if_not_exists [Boolean] Create the spreadsheet if it does not exist?
|
|
10
|
+
# @attr key_values [Hash] Additional variables that can be supplied to the template
|
|
11
|
+
# @attr offset [Array<Integer>] An [x, y] offset (array with two integers)
|
|
12
|
+
# @attr sheet_name [String] The name of the spreadsheet to write to
|
|
13
|
+
# @attr verbose [Boolean] Include extra verbose output?
|
|
14
|
+
class Options
|
|
15
|
+
extend ::T::Sig
|
|
16
|
+
extend ::T::Helpers
|
|
17
|
+
|
|
18
|
+
abstract!
|
|
19
|
+
|
|
20
|
+
sig { returns(::T::Boolean) }
|
|
21
|
+
attr_accessor :backup
|
|
22
|
+
|
|
23
|
+
sig { returns(::T::Boolean) }
|
|
24
|
+
attr_accessor :create_if_not_exists
|
|
25
|
+
|
|
26
|
+
sig { returns(::T::Hash[::Symbol, ::CSVPlusPlus::Entities::Entity]) }
|
|
27
|
+
attr_accessor :key_values
|
|
28
|
+
|
|
29
|
+
sig { returns(::T::Array[::Integer]) }
|
|
30
|
+
attr_accessor :offset
|
|
31
|
+
|
|
32
|
+
sig { returns(::String) }
|
|
33
|
+
attr_accessor :sheet_name
|
|
34
|
+
|
|
35
|
+
sig { returns(::T::Boolean) }
|
|
36
|
+
attr_accessor :verbose
|
|
37
|
+
|
|
38
|
+
sig { params(sheet_name: ::String).void }
|
|
39
|
+
# Initialize a defaul +Options+ object
|
|
40
|
+
def initialize(sheet_name)
|
|
41
|
+
@sheet_name = sheet_name
|
|
42
|
+
@offset = ::T.let([0, 0], ::T::Array[::Integer])
|
|
43
|
+
@create_if_not_exists = ::T.let(false, ::T::Boolean)
|
|
44
|
+
@key_values = ::T.let({}, ::T::Hash[::Symbol, ::CSVPlusPlus::Entities::Entity])
|
|
45
|
+
@verbose = ::T.let(false, ::T::Boolean)
|
|
46
|
+
@backup = ::T.let(false, ::T::Boolean)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
sig { abstract.returns(::CSVPlusPlus::Options::OutputFormat) }
|
|
50
|
+
# Given the options, figure out which type of +OutputFormat+ we'll be writing to
|
|
51
|
+
#
|
|
52
|
+
# @return [Options::OutputFormat]
|
|
53
|
+
def output_format; end
|
|
54
|
+
|
|
55
|
+
sig { abstract.returns(::String) }
|
|
56
|
+
# Return a string with a verbose description of what we're doing with the options
|
|
57
|
+
#
|
|
58
|
+
# @return [String]
|
|
59
|
+
def verbose_summary; end
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
|
|
63
|
+
sig { params(str: ::String).returns(::String) }
|
|
64
|
+
# Return a string with a verbose description of what we're doing with the options
|
|
65
|
+
#
|
|
66
|
+
# @return [String]
|
|
67
|
+
def shared_summary(str)
|
|
68
|
+
<<~SUMMARY
|
|
69
|
+
#{summary_divider}
|
|
70
|
+
|
|
71
|
+
# csv++ Command Options
|
|
72
|
+
|
|
73
|
+
> Sheet name | #{@sheet_name}
|
|
74
|
+
> Create sheet if it does not exist? | #{@create_if_not_exists}
|
|
75
|
+
> Spreadsheet row-offset | #{@offset[0]}
|
|
76
|
+
> Spreadsheet cell-offset | #{@offset[1]}
|
|
77
|
+
> User-supplied key-values | #{@key_values}
|
|
78
|
+
> Verbose | #{@verbose}
|
|
79
|
+
> Backup | #{@backup}
|
|
80
|
+
|
|
81
|
+
## Output Options
|
|
82
|
+
|
|
83
|
+
#{str}
|
|
84
|
+
|
|
85
|
+
#{summary_divider}
|
|
86
|
+
SUMMARY
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
sig { returns(::String) }
|
|
92
|
+
def summary_divider
|
|
93
|
+
'========================================================================='
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -1,88 +1,45 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
require_relative './cli_flag'
|
|
4
|
-
require_relative './google_options'
|
|
5
|
-
|
|
6
4
|
module CSVPlusPlus
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
attr_reader :google
|
|
20
|
-
|
|
21
|
-
# initialize
|
|
22
|
-
def initialize
|
|
23
|
-
@offset = [0, 0]
|
|
24
|
-
@create_if_not_exists = false
|
|
25
|
-
@key_values = {}
|
|
26
|
-
@verbose = false
|
|
27
|
-
@backup = false
|
|
5
|
+
# Options that a user can supply - either specific for compiling to a file (xlsx, csv) or Google Sheets
|
|
6
|
+
module Options
|
|
7
|
+
extend ::T::Sig
|
|
8
|
+
|
|
9
|
+
# The supported output formats. We use this to dispatch flow in several places
|
|
10
|
+
class OutputFormat < ::T::Enum
|
|
11
|
+
enums do
|
|
12
|
+
CSV = new
|
|
13
|
+
Excel = new
|
|
14
|
+
GoogleSheets = new
|
|
15
|
+
OpenDocument = new
|
|
16
|
+
end
|
|
28
17
|
end
|
|
29
18
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# @param sheet_id [String] The identifier used by Google's API to reference the sheet. You can find it in the URL
|
|
33
|
-
# for the sheet
|
|
34
|
-
#
|
|
35
|
-
# @return [String]
|
|
36
|
-
def google_sheet_id=(sheet_id)
|
|
37
|
-
@google = ::CSVPlusPlus::GoogleOptions.new(sheet_id)
|
|
19
|
+
sig do
|
|
20
|
+
params(flags: ::T::Hash[::Symbol, ::String], input_filename: ::Pathname).returns(::CSVPlusPlus::Options::Options)
|
|
38
21
|
end
|
|
39
|
-
|
|
40
|
-
#
|
|
22
|
+
# Use the given +flags+ to determine if we're dealing with either a Google Sheets or file-based
|
|
23
|
+
# compilation and build an +Options+ instance accordingly.
|
|
41
24
|
#
|
|
42
|
-
# @
|
|
43
|
-
|
|
44
|
-
return if @google || @output_filename
|
|
45
|
-
|
|
46
|
-
'You must supply either a Google Sheet ID or an output file'
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Return a string with a verbose description of what we're doing with the options
|
|
25
|
+
# @param flags [Hash<Symbol, String>]
|
|
26
|
+
# @param input_filename [Pathname]
|
|
50
27
|
#
|
|
51
|
-
# @return [
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
> Spreadsheet row-offset | #{@offset[0]}
|
|
62
|
-
> Spreadsheet cell-offset | #{@offset[1]}
|
|
63
|
-
> User-supplied key-values | #{@key_values}
|
|
64
|
-
> Verbose | #{@verbose}
|
|
65
|
-
|
|
66
|
-
## Output Options
|
|
67
|
-
|
|
68
|
-
> Backup | #{@backup}
|
|
69
|
-
> Output filename | #{@output_filename}
|
|
70
|
-
|
|
71
|
-
#{@google&.verbose_summary || ''}
|
|
72
|
-
#{summary_divider}
|
|
73
|
-
SUMMARY
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# @return [String]
|
|
77
|
-
def to_s
|
|
78
|
-
"Options(create_if_not_exists: #{@create_if_not_exists}, google: #{@google}, key_values: #{@key_values}, " \
|
|
79
|
-
"offset: #{@offset}, sheet_name: #{@sheet_name}, verbose: #{@verbose})"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
def summary_divider
|
|
85
|
-
'========================================================================='
|
|
28
|
+
# @return [Options::Options]
|
|
29
|
+
def self.from_cli_flags(flags, input_filename)
|
|
30
|
+
sheet_name = flags[:'sheet-name'] || input_filename.sub_ext('').to_s
|
|
31
|
+
if (google_sheet_id = flags[:'google-sheet-id'])
|
|
32
|
+
::CSVPlusPlus::Options::GoogleSheetsOptions.new(sheet_name, google_sheet_id)
|
|
33
|
+
elsif (output_filename = flags[:output])
|
|
34
|
+
::CSVPlusPlus::Options::FileOptions.new(sheet_name, output_filename)
|
|
35
|
+
else
|
|
36
|
+
raise(::CSVPlusPlus::Error::CLIError, 'You must supply either -o/--output or -g/-google-sheet-id')
|
|
37
|
+
end
|
|
86
38
|
end
|
|
87
39
|
end
|
|
88
40
|
end
|
|
41
|
+
|
|
42
|
+
require_relative './options/options'
|
|
43
|
+
|
|
44
|
+
require_relative './options/file_options'
|
|
45
|
+
require_relative './options/google_sheets_options'
|