csv_plus_plus 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|