csv_plus_plus 0.1.3 → 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 +8 -3
- data/docs/CHANGELOG.md +16 -0
- data/lib/csv_plus_plus/a1_reference.rb +202 -0
- data/lib/csv_plus_plus/benchmarked_compiler.rb +3 -3
- data/lib/csv_plus_plus/cell.rb +1 -35
- data/lib/csv_plus_plus/cli.rb +43 -80
- data/lib/csv_plus_plus/cli_flag.rb +71 -70
- data/lib/csv_plus_plus/color.rb +1 -1
- data/lib/csv_plus_plus/compiler.rb +31 -21
- data/lib/csv_plus_plus/entities/ast_builder.rb +11 -4
- data/lib/csv_plus_plus/entities/boolean.rb +16 -9
- data/lib/csv_plus_plus/entities/builtins.rb +68 -40
- data/lib/csv_plus_plus/entities/date.rb +14 -11
- data/lib/csv_plus_plus/entities/entity.rb +11 -29
- data/lib/csv_plus_plus/entities/entity_with_arguments.rb +18 -31
- data/lib/csv_plus_plus/entities/function.rb +22 -11
- data/lib/csv_plus_plus/entities/function_call.rb +35 -11
- data/lib/csv_plus_plus/entities/has_identifier.rb +19 -0
- data/lib/csv_plus_plus/entities/number.rb +15 -10
- data/lib/csv_plus_plus/entities/reference.rb +77 -0
- data/lib/csv_plus_plus/entities/runtime_value.rb +36 -23
- data/lib/csv_plus_plus/entities/string.rb +13 -10
- data/lib/csv_plus_plus/entities.rb +2 -18
- 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 +18 -5
- data/lib/csv_plus_plus/error/formula_syntax_error.rb +12 -13
- data/lib/csv_plus_plus/error/modifier_syntax_error.rb +10 -36
- data/lib/csv_plus_plus/error/modifier_validation_error.rb +6 -32
- data/lib/csv_plus_plus/error/positional_error.rb +15 -0
- data/lib/csv_plus_plus/error/writer_error.rb +1 -1
- data/lib/csv_plus_plus/error.rb +4 -1
- data/lib/csv_plus_plus/error_formatter.rb +111 -0
- data/lib/csv_plus_plus/google_api_client.rb +18 -8
- data/lib/csv_plus_plus/lexer/racc_lexer.rb +144 -0
- data/lib/csv_plus_plus/lexer/tokenizer.rb +53 -17
- data/lib/csv_plus_plus/lexer.rb +40 -1
- data/lib/csv_plus_plus/modifier/data_validation.rb +1 -1
- data/lib/csv_plus_plus/modifier/expand.rb +17 -0
- data/lib/csv_plus_plus/modifier.rb +6 -1
- 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 +22 -110
- data/lib/csv_plus_plus/parser/cell_value.tab.rb +65 -66
- data/lib/csv_plus_plus/parser/code_section.tab.rb +92 -84
- data/lib/csv_plus_plus/parser/modifier.tab.rb +40 -30
- 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/runtime/graph.rb +6 -6
- data/lib/csv_plus_plus/runtime/{position_tracker.rb → position.rb} +16 -5
- data/lib/csv_plus_plus/runtime/references.rb +32 -27
- data/lib/csv_plus_plus/runtime/runtime.rb +73 -67
- data/lib/csv_plus_plus/runtime/scope.rb +280 -0
- data/lib/csv_plus_plus/runtime.rb +9 -9
- data/lib/csv_plus_plus/source_code.rb +14 -9
- data/lib/csv_plus_plus/template.rb +17 -12
- data/lib/csv_plus_plus/version.rb +1 -1
- data/lib/csv_plus_plus/writer/csv.rb +32 -5
- data/lib/csv_plus_plus/writer/excel.rb +19 -6
- data/lib/csv_plus_plus/writer/file_backer_upper.rb +27 -14
- data/lib/csv_plus_plus/writer/google_sheets.rb +23 -129
- data/lib/csv_plus_plus/writer/{google_sheet_builder.rb → google_sheets_builder.rb} +39 -55
- data/lib/csv_plus_plus/writer/merger.rb +31 -0
- data/lib/csv_plus_plus/writer/open_document.rb +16 -2
- data/lib/csv_plus_plus/writer/rubyxl_builder.rb +68 -43
- data/lib/csv_plus_plus/writer/writer.rb +42 -0
- data/lib/csv_plus_plus/writer.rb +58 -19
- data/lib/csv_plus_plus.rb +26 -14
- metadata +37 -12
- data/lib/csv_plus_plus/entities/cell_reference.rb +0 -231
- data/lib/csv_plus_plus/entities/variable.rb +0 -37
- data/lib/csv_plus_plus/error/syntax_error.rb +0 -71
- data/lib/csv_plus_plus/google_options.rb +0 -32
- data/lib/csv_plus_plus/lexer/lexer.rb +0 -89
- data/lib/csv_plus_plus/runtime/can_define_references.rb +0 -87
- data/lib/csv_plus_plus/runtime/can_resolve_references.rb +0 -209
- data/lib/csv_plus_plus/writer/base_writer.rb +0 -45
@@ -8,26 +8,40 @@ module CSVPlusPlus
|
|
8
8
|
# @attr_reader infix [boolean] Whether or not this function call is infix (X * Y, A + B, etc)
|
9
9
|
class FunctionCall < EntityWithArguments
|
10
10
|
extend ::T::Sig
|
11
|
+
include ::CSVPlusPlus::Entities::HasIdentifier
|
12
|
+
|
13
|
+
ArgumentsType = type_member { { fixed: ::CSVPlusPlus::Entities::Entity } }
|
14
|
+
public_constant :ArgumentsType
|
11
15
|
|
12
16
|
sig { returns(::T::Boolean) }
|
13
17
|
attr_reader :infix
|
14
18
|
|
15
|
-
sig {
|
19
|
+
sig { returns(::Symbol) }
|
20
|
+
attr_reader :id
|
21
|
+
|
22
|
+
sig do
|
23
|
+
params(
|
24
|
+
id: ::Symbol,
|
25
|
+
arguments: ::T::Array[::CSVPlusPlus::Entities::FunctionCall::ArgumentsType],
|
26
|
+
infix: ::T::Boolean
|
27
|
+
).void
|
28
|
+
end
|
16
29
|
# @param id [::String] The name of the function
|
17
30
|
# @param arguments [Array<Entity>] The arguments to the function
|
18
31
|
# @param infix [T::Boolean] Whether the function is infix
|
19
32
|
def initialize(id, arguments, infix: false)
|
20
|
-
super(
|
33
|
+
super(arguments:)
|
21
34
|
|
35
|
+
@id = ::T.let(identifier(id), ::Symbol)
|
22
36
|
@infix = infix
|
23
37
|
end
|
24
38
|
|
25
|
-
sig { override.params(
|
26
|
-
# @param
|
39
|
+
sig { override.params(position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
|
40
|
+
# @param position [Position]
|
27
41
|
#
|
28
42
|
# @return [::String]
|
29
|
-
def evaluate(
|
30
|
-
evaluated_arguments = evaluate_arguments(
|
43
|
+
def evaluate(position)
|
44
|
+
evaluated_arguments = evaluate_arguments(position)
|
31
45
|
|
32
46
|
if @infix
|
33
47
|
"(#{evaluated_arguments.join(" #{@id} ")})"
|
@@ -36,14 +50,24 @@ module CSVPlusPlus
|
|
36
50
|
end
|
37
51
|
end
|
38
52
|
|
39
|
-
sig { override.params(other: ::
|
40
|
-
# @param other [
|
53
|
+
sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
|
54
|
+
# @param other [BasicObject]
|
41
55
|
#
|
42
|
-
# @return [
|
56
|
+
# @return [Boolean]
|
43
57
|
def ==(other)
|
44
|
-
|
58
|
+
case other
|
59
|
+
when self.class
|
60
|
+
@id == other.id && @infix == other.infix
|
61
|
+
else
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
45
67
|
|
46
|
-
|
68
|
+
sig { params(position: ::CSVPlusPlus::Runtime::Position).returns(::T::Array[::String]) }
|
69
|
+
def evaluate_arguments(position)
|
70
|
+
@arguments.map { |arg| arg.evaluate(position) }
|
47
71
|
end
|
48
72
|
end
|
49
73
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module CSVPlusPlus
|
5
|
+
module Entities
|
6
|
+
# Can be included on any class that has a comparable id
|
7
|
+
module HasIdentifier
|
8
|
+
extend ::T::Sig
|
9
|
+
|
10
|
+
sig { params(symbol: ::Symbol).returns(::Symbol) }
|
11
|
+
# Variables and functions are case insensitive. I hate it but it's how excel is
|
12
|
+
#
|
13
|
+
# @param symbol [Symbol]
|
14
|
+
def identifier(symbol)
|
15
|
+
symbol.downcase
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -6,14 +6,16 @@ module CSVPlusPlus
|
|
6
6
|
# A number value
|
7
7
|
#
|
8
8
|
# @attr_reader value [Numeric] The parsed number value
|
9
|
-
class Number < Entity
|
9
|
+
class Number < ::CSVPlusPlus::Entities::Entity
|
10
|
+
extend ::T::Sig
|
11
|
+
|
10
12
|
sig { returns(::Numeric) }
|
11
13
|
attr_reader :value
|
12
14
|
|
13
15
|
sig { params(value: ::T.any(::String, ::Numeric)).void }
|
14
16
|
# @param value [String, Numeric] Either a +String+ that looks like a number, or an already parsed Numeric
|
15
17
|
def initialize(value)
|
16
|
-
super(
|
18
|
+
super()
|
17
19
|
|
18
20
|
@value =
|
19
21
|
::T.let(
|
@@ -26,22 +28,25 @@ module CSVPlusPlus
|
|
26
28
|
)
|
27
29
|
end
|
28
30
|
|
29
|
-
sig { override.params(
|
30
|
-
# @param
|
31
|
+
sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
|
32
|
+
# @param _position [Position]
|
31
33
|
#
|
32
34
|
# @return [::String]
|
33
|
-
def evaluate(
|
35
|
+
def evaluate(_position)
|
34
36
|
@value.to_s
|
35
37
|
end
|
36
38
|
|
37
|
-
sig { override.params(other: ::
|
38
|
-
# @param other [
|
39
|
+
sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
|
40
|
+
# @param other [BasicObject]
|
39
41
|
#
|
40
42
|
# @return [::T::Boolean]
|
41
43
|
def ==(other)
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
case other
|
45
|
+
when self.class
|
46
|
+
@value == other.value
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
45
50
|
end
|
46
51
|
end
|
47
52
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module CSVPlusPlus
|
5
|
+
module Entities
|
6
|
+
# A reference to something - this is typically either a cell reference (handled by +A1Reference+) or a reference
|
7
|
+
# to a variable.
|
8
|
+
#
|
9
|
+
# One sticking point with the design of this class is that we don't know if a reference is a variable reference
|
10
|
+
# unless we look at currently defined variables and see if there is one by that name. Since all cell references
|
11
|
+
# can be a valid variable name, we can't be sure which is which. So we delegate that decision as late as possible
|
12
|
+
# - in #evaluate
|
13
|
+
#
|
14
|
+
# @attr_reader scoped_to_expand [Expand, nil] If set, the expand in which this variable is scoped to. It cannot be
|
15
|
+
# resolved outside of the given expand.
|
16
|
+
class Reference < ::CSVPlusPlus::Entities::Entity
|
17
|
+
extend ::T::Sig
|
18
|
+
include ::CSVPlusPlus::Entities::HasIdentifier
|
19
|
+
|
20
|
+
sig { returns(::T.nilable(::String)) }
|
21
|
+
attr_reader :ref
|
22
|
+
|
23
|
+
# sig { returns(::T.nilable(::CSVPlusPlus::A1Reference)) }
|
24
|
+
# attr_reader :a1_ref
|
25
|
+
|
26
|
+
sig { params(ref: ::T.nilable(::String), a1_ref: ::T.nilable(::CSVPlusPlus::A1Reference)).void }
|
27
|
+
# Either +ref+, +cell_index+ or +row_index+ must be specified.
|
28
|
+
#
|
29
|
+
# @param ref [Integer, nil] An A1-style cell reference (that will be parsed into it's row/cell indexes).
|
30
|
+
# @param a1_ref [Integer, nil] An A1-style cell reference (that will be parsed into it's row/cell indexes).
|
31
|
+
def initialize(ref: nil, a1_ref: nil)
|
32
|
+
super()
|
33
|
+
|
34
|
+
raise(::ArgumentError, 'Must specify :ref or :a1_ref') unless ref || a1_ref
|
35
|
+
|
36
|
+
@ref = ref
|
37
|
+
@a1_ref = a1_ref
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
|
41
|
+
# @param other [BasicObject]
|
42
|
+
#
|
43
|
+
# @return [boolean]
|
44
|
+
def ==(other)
|
45
|
+
case other
|
46
|
+
when self.class
|
47
|
+
a1_ref == other.a1_ref
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
sig { returns(::CSVPlusPlus::A1Reference) }
|
54
|
+
# @return [A1Reference]
|
55
|
+
def a1_ref
|
56
|
+
@a1_ref ||= ::CSVPlusPlus::A1Reference.new(ref: ::T.must(ref))
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { override.params(position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
|
60
|
+
# Get the A1-style cell reference
|
61
|
+
#
|
62
|
+
# @param position [Position] The current position
|
63
|
+
#
|
64
|
+
# @return [::String] An A1-style reference
|
65
|
+
def evaluate(position)
|
66
|
+
# TODO: ugh make to_a1_ref not return a nil
|
67
|
+
ref || a1_ref.to_a1_ref(position) || ''
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { returns(::T.nilable(::Symbol)) }
|
71
|
+
# @return [Symbol]
|
72
|
+
def id
|
73
|
+
ref && identifier(::T.must(ref).to_sym)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,41 +1,54 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require_relative './entity'
|
5
|
+
|
4
6
|
module CSVPlusPlus
|
5
7
|
module Entities
|
6
|
-
# A runtime value. These are values which can be materialized at any point via the +resolve_fn+
|
7
|
-
#
|
8
|
-
|
9
|
-
# @attr_reader resolve_fn [lambda] A lambda that is called when the runtime value is resolved
|
10
|
-
class RuntimeValue < Entity
|
8
|
+
# A runtime value. These are values which can be materialized at any point via the +resolve_fn+ which
|
9
|
+
# will provide a value depending on the +Runtime+'s current state.
|
10
|
+
class RuntimeValue < ::CSVPlusPlus::Entities::Entity
|
11
11
|
extend ::T::Sig
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
ResolveFn =
|
14
|
+
::T.type_alias do
|
15
|
+
::T.proc.params(
|
16
|
+
position: ::CSVPlusPlus::Runtime::Position,
|
17
|
+
arguments: ::T::Enumerable[::CSVPlusPlus::Entities::Entity]
|
18
|
+
).returns(::CSVPlusPlus::Entities::Entity)
|
19
|
+
end
|
20
|
+
public_constant :ResolveFn
|
18
21
|
|
19
22
|
sig do
|
20
|
-
params(
|
21
|
-
resolve_fn: ::T.proc.params(arg0: ::CSVPlusPlus::Runtime::Runtime).returns(::CSVPlusPlus::Entities::Entity),
|
22
|
-
arguments: ::T::Array[::T.untyped]
|
23
|
-
).void
|
23
|
+
params(resolve_fn: ::CSVPlusPlus::Entities::RuntimeValue::ResolveFn).void
|
24
24
|
end
|
25
25
|
# @param resolve_fn [lambda] A lambda that is called when the runtime value is resolved
|
26
|
-
|
27
|
-
def initialize(resolve_fn, arguments: [])
|
28
|
-
super(::CSVPlusPlus::Entities::Type::RuntimeValue)
|
29
|
-
|
30
|
-
@arguments = arguments
|
26
|
+
def initialize(resolve_fn)
|
31
27
|
@resolve_fn = resolve_fn
|
28
|
+
super()
|
29
|
+
end
|
30
|
+
|
31
|
+
sig do
|
32
|
+
params(
|
33
|
+
position: ::CSVPlusPlus::Runtime::Position,
|
34
|
+
arguments: ::T::Enumerable[::CSVPlusPlus::Entities::Entity]
|
35
|
+
).returns(::CSVPlusPlus::Entities::Entity)
|
36
|
+
end
|
37
|
+
# Using the +@resolve_fn+, evaluate this runtime value into an +Entity+ that can be later evaluated
|
38
|
+
def call(position, arguments)
|
39
|
+
@resolve_fn.call(position, arguments)
|
32
40
|
end
|
33
41
|
|
34
|
-
sig { override.params(
|
35
|
-
#
|
42
|
+
sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
|
43
|
+
# Given the current runtime, call +@resolve_fn+ to produce a value
|
44
|
+
#
|
45
|
+
# @param _position [Position]
|
36
46
|
#
|
37
|
-
# @return [
|
38
|
-
def evaluate(
|
47
|
+
# @return [Entities::Entity]
|
48
|
+
def evaluate(_position)
|
49
|
+
# TODO: we can do a check on arguments here and make sure that the RuntimeValue is being called
|
50
|
+
# with the number of arguments it requires
|
51
|
+
# @resolve_fn.call(position, ::T.must(arguments)).evaluate(position)
|
39
52
|
'(runtime value)'
|
40
53
|
end
|
41
54
|
end
|
@@ -6,7 +6,7 @@ module CSVPlusPlus
|
|
6
6
|
# A string value
|
7
7
|
#
|
8
8
|
# @attr_reader value [String]
|
9
|
-
class String < Entity
|
9
|
+
class String < ::CSVPlusPlus::Entities::Entity
|
10
10
|
extend ::T::Sig
|
11
11
|
|
12
12
|
sig { returns(::String) }
|
@@ -15,27 +15,30 @@ module CSVPlusPlus
|
|
15
15
|
sig { params(value: ::String).void }
|
16
16
|
# @param value [String] The string that has been parsed out of the template
|
17
17
|
def initialize(value)
|
18
|
-
super(
|
18
|
+
super()
|
19
19
|
|
20
20
|
@value = ::T.let(value.gsub(/^"|"$/, ''), ::String)
|
21
21
|
end
|
22
22
|
|
23
|
-
sig { override.params(
|
24
|
-
# @param
|
23
|
+
sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
|
24
|
+
# @param _position [Position]
|
25
25
|
#
|
26
26
|
# @return [::String]
|
27
|
-
def evaluate(
|
27
|
+
def evaluate(_position)
|
28
28
|
"\"#{@value}\""
|
29
29
|
end
|
30
30
|
|
31
|
-
sig { override.params(other: ::
|
32
|
-
# @param other [
|
31
|
+
sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
|
32
|
+
# @param other [BasicObject]
|
33
33
|
#
|
34
34
|
# @return [T::Boolean]
|
35
35
|
def ==(other)
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
case other
|
37
|
+
when self.class
|
38
|
+
@value == other.value
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
@@ -3,36 +3,20 @@
|
|
3
3
|
|
4
4
|
require_relative 'entities/entity'
|
5
5
|
require_relative 'entities/entity_with_arguments'
|
6
|
+
require_relative 'entities/has_identifier'
|
6
7
|
|
7
8
|
require_relative 'entities/boolean'
|
8
|
-
require_relative 'entities/cell_reference'
|
9
9
|
require_relative 'entities/date'
|
10
10
|
require_relative 'entities/function'
|
11
11
|
require_relative 'entities/function_call'
|
12
12
|
require_relative 'entities/number'
|
13
|
+
require_relative 'entities/reference'
|
13
14
|
require_relative 'entities/runtime_value'
|
14
15
|
require_relative 'entities/string'
|
15
|
-
require_relative 'entities/variable'
|
16
16
|
|
17
17
|
module CSVPlusPlus
|
18
18
|
# The entities that form abstract syntax trees which make up the language
|
19
19
|
module Entities
|
20
|
-
extend ::T::Sig
|
21
|
-
|
22
|
-
# A primitive type. These all correspond to an implementation of the same name in the CSVPlusPlus::Entities module.
|
23
|
-
class Type < ::T::Enum
|
24
|
-
enums do
|
25
|
-
Boolean = new
|
26
|
-
CellReference = new
|
27
|
-
Date = new
|
28
|
-
Function = new
|
29
|
-
FunctionCall = new
|
30
|
-
Number = new
|
31
|
-
RuntimeValue = new
|
32
|
-
String = new
|
33
|
-
Variable = new
|
34
|
-
end
|
35
|
-
end
|
36
20
|
end
|
37
21
|
end
|
38
22
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module CSVPlusPlus
|
5
|
+
module Error
|
6
|
+
# An error that represents an invalid CLI option or state
|
7
|
+
class CLIError < ::CSVPlusPlus::Error::Error
|
8
|
+
extend ::T::Sig
|
9
|
+
|
10
|
+
sig { override.returns(::String) }
|
11
|
+
# @return [String]
|
12
|
+
def error_message
|
13
|
+
message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module CSVPlusPlus
|
5
|
+
module Error
|
6
|
+
# An error that represents an invalid state during compilation.
|
7
|
+
class CompilerError < ::CSVPlusPlus::Error::Error
|
8
|
+
extend ::T::Sig
|
9
|
+
|
10
|
+
sig { override.returns(::String) }
|
11
|
+
# @return [String]
|
12
|
+
def error_message
|
13
|
+
message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,17 +4,30 @@
|
|
4
4
|
module CSVPlusPlus
|
5
5
|
module Error
|
6
6
|
# An error thrown by our code (generally to be handled at the top level bin/ command)
|
7
|
-
class Error < StandardError
|
7
|
+
class Error < ::StandardError
|
8
8
|
extend ::T::Sig
|
9
9
|
extend ::T::Helpers
|
10
10
|
|
11
|
-
|
11
|
+
abstract!
|
12
|
+
|
13
|
+
sig { returns(::T.nilable(::StandardError)) }
|
14
|
+
attr_reader :wrapped_error
|
15
|
+
|
16
|
+
sig { params(message: ::String, wrapped_error: ::T.nilable(::StandardError)).void }
|
17
|
+
# @param wrapped_error [StandardError] The underlying error that caused the syntax error. For example a
|
18
|
+
# Racc::ParseError that was thrown
|
19
|
+
def initialize(message, wrapped_error: nil)
|
20
|
+
super(message)
|
21
|
+
|
22
|
+
@message = message
|
23
|
+
@wrapped_error = wrapped_error
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { abstract.returns(::String) }
|
12
27
|
# Return an error message for display to a command-line user.
|
13
28
|
#
|
14
29
|
# @return [::String]
|
15
|
-
def error_message
|
16
|
-
message
|
17
|
-
end
|
30
|
+
def error_message; end
|
18
31
|
end
|
19
32
|
end
|
20
33
|
end
|
@@ -1,36 +1,35 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative './syntax_error'
|
5
|
-
|
6
4
|
module CSVPlusPlus
|
7
5
|
module Error
|
8
6
|
# An error that can be thrown when there is an error parsing a modifier
|
9
7
|
#
|
10
8
|
# @attr_reader message [::String] A helpful error message
|
11
9
|
# @attr_reader bad_input [String] The offending input that caused the error to be thrown
|
12
|
-
class FormulaSyntaxError < ::CSVPlusPlus::Error::
|
13
|
-
|
10
|
+
class FormulaSyntaxError < ::CSVPlusPlus::Error::Error
|
11
|
+
extend ::T::Sig
|
12
|
+
include ::CSVPlusPlus::Error::PositionalError
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
sig { returns(::String) }
|
15
|
+
attr_reader :bad_input
|
16
|
+
|
17
|
+
sig { params(message: ::String, bad_input: ::String, wrapped_error: ::T.nilable(::StandardError)).void }
|
17
18
|
# @param message [String] A relevant message to show
|
18
19
|
# @param bad_input [String] The offending input that caused the error to be thrown
|
19
|
-
# @param runtime [Runtime] The current runtime
|
20
20
|
# @param wrapped_error [StandardError] The underlying error that caused the syntax error. For example a
|
21
21
|
# Racc::ParseError that was thrown
|
22
|
-
def initialize(message, bad_input
|
22
|
+
def initialize(message, bad_input:, wrapped_error: nil)
|
23
|
+
super(message, wrapped_error:)
|
23
24
|
@bad_input = bad_input
|
24
|
-
@message = message
|
25
|
-
|
26
|
-
super(runtime, wrapped_error:)
|
27
25
|
end
|
28
26
|
|
27
|
+
sig { override.returns(::String) }
|
29
28
|
# Create a relevant error message given +@bad_input+ and +@message+.
|
30
29
|
#
|
31
30
|
# @return [::String]
|
32
31
|
def error_message
|
33
|
-
"#{
|
32
|
+
"#{message}: \"#{bad_input}\""
|
34
33
|
end
|
35
34
|
end
|
36
35
|
end
|
@@ -1,62 +1,36 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require_relative './syntax_error'
|
5
|
-
|
6
4
|
module CSVPlusPlus
|
7
5
|
module Error
|
8
|
-
#
|
9
|
-
class ModifierSyntaxError < ::CSVPlusPlus::Error::
|
6
|
+
# A syntax error encountered when parsing a modifier definition
|
7
|
+
class ModifierSyntaxError < ::CSVPlusPlus::Error::Error
|
10
8
|
extend ::T::Sig
|
9
|
+
include ::CSVPlusPlus::Error::PositionalError
|
11
10
|
|
12
11
|
sig { returns(::String) }
|
13
12
|
attr_reader :bad_input
|
14
13
|
|
15
|
-
sig { returns(::String) }
|
16
|
-
attr_reader :message
|
17
|
-
|
18
14
|
sig { returns(::T.nilable(::Symbol)) }
|
19
15
|
attr_reader :modifier
|
20
16
|
|
21
17
|
sig do
|
22
18
|
params(
|
23
|
-
runtime: ::CSVPlusPlus::Runtime::Runtime,
|
24
|
-
modifier_validation_error: ::CSVPlusPlus::Error::ModifierValidationError
|
25
|
-
).returns(::CSVPlusPlus::Error::ModifierSyntaxError)
|
26
|
-
end
|
27
|
-
# Create a +ModifierSyntaxError+ given a +runtime+ and +ModifierValidationError+.
|
28
|
-
#
|
29
|
-
# @param runtime [Runtime]
|
30
|
-
# @param modifier_validation_error [ModifierValidationError]
|
31
|
-
#
|
32
|
-
# @return [ModifierSyntaxError]
|
33
|
-
def self.from_validation_error(runtime, modifier_validation_error)
|
34
|
-
new(
|
35
|
-
runtime,
|
36
|
-
modifier: modifier_validation_error.modifier,
|
37
|
-
bad_input: modifier_validation_error.bad_input,
|
38
|
-
message: modifier_validation_error.message,
|
39
|
-
wrapped_error: modifier_validation_error
|
40
|
-
)
|
41
|
-
end
|
42
|
-
|
43
|
-
sig do
|
44
|
-
params(
|
45
|
-
runtime: ::CSVPlusPlus::Runtime::Runtime,
|
46
|
-
bad_input: ::String,
|
47
19
|
message: ::String,
|
20
|
+
bad_input: ::String,
|
48
21
|
modifier: ::T.nilable(::Symbol),
|
49
22
|
wrapped_error: ::T.nilable(::StandardError)
|
50
23
|
).void
|
51
24
|
end
|
52
|
-
# @param
|
25
|
+
# @param message [String] The error message
|
26
|
+
# @param bad_input [String] The offending input
|
27
|
+
# @param modifier [Symbol] The modifier being parsed
|
53
28
|
# @param wrapped_error [ModifierValidationError] The validtion error that this is wrapping
|
54
|
-
def initialize(
|
29
|
+
def initialize(message, bad_input:, modifier: nil, wrapped_error: nil)
|
30
|
+
super(message, wrapped_error:)
|
31
|
+
|
55
32
|
@bad_input = bad_input
|
56
33
|
@modifier = modifier
|
57
|
-
@message = message
|
58
|
-
|
59
|
-
super(runtime, wrapped_error:)
|
60
34
|
end
|
61
35
|
|
62
36
|
sig { override.returns(::String) }
|
@@ -9,20 +9,9 @@ module CSVPlusPlus
|
|
9
9
|
# @attr_reader bad_input [String] The offending input that caused the error to be thrown
|
10
10
|
# @attr_reader choices [Array<Symbol>, nil] The choices that +value+ must be one of (but violated)
|
11
11
|
# @attr_reader message [String, nil] A relevant message to show
|
12
|
-
class ModifierValidationError < ::CSVPlusPlus::Error::
|
12
|
+
class ModifierValidationError < ::CSVPlusPlus::Error::ModifierSyntaxError
|
13
13
|
extend ::T::Sig
|
14
|
-
|
15
|
-
sig { returns(::String) }
|
16
|
-
attr_reader :bad_input
|
17
|
-
|
18
|
-
sig { returns(::T.nilable(::T.class_of(::T::Enum))) }
|
19
|
-
attr_reader :choices
|
20
|
-
|
21
|
-
sig { returns(::String) }
|
22
|
-
attr_reader :message
|
23
|
-
|
24
|
-
sig { returns(::Symbol) }
|
25
|
-
attr_reader :modifier
|
14
|
+
include ::CSVPlusPlus::Error::PositionalError
|
26
15
|
|
27
16
|
sig do
|
28
17
|
params(
|
@@ -38,31 +27,16 @@ module CSVPlusPlus
|
|
38
27
|
# @param bad_input [String] The offending input that caused the error to be thrown
|
39
28
|
# @param choices [Array<Symbol>, nil] The choices that +value+ must be one of (but violated)
|
40
29
|
# @param message [String, nil] A relevant message to show
|
41
|
-
# rubocop:disable Metrics/MethodLength
|
42
30
|
def initialize(modifier, bad_input:, choices: nil, message: nil)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@message = ::T.let(
|
48
|
-
if @choices
|
49
|
-
"must be one of (#{@choices.values.map(&:serialize).join(', ')})"
|
31
|
+
message = ::T.let(
|
32
|
+
if choices
|
33
|
+
"must be one of (#{choices.values.map(&:serialize).join(', ')})"
|
50
34
|
else
|
51
35
|
::T.must(message)
|
52
36
|
end,
|
53
37
|
::String
|
54
38
|
)
|
55
|
-
|
56
|
-
super(@message)
|
57
|
-
end
|
58
|
-
# rubocop:enable Metrics/MethodLength
|
59
|
-
|
60
|
-
sig { returns(::String) }
|
61
|
-
# A user-facing error message
|
62
|
-
#
|
63
|
-
# @return [::String]
|
64
|
-
def error_message
|
65
|
-
@message
|
39
|
+
super(message, bad_input:, modifier:)
|
66
40
|
end
|
67
41
|
end
|
68
42
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module CSVPlusPlus
|
5
|
+
module Error
|
6
|
+
# Methods that can be included into a class to denote that it's result it dependent on the current
|
7
|
+
# +Runtime::Position+
|
8
|
+
module PositionalError
|
9
|
+
extend ::T::Sig
|
10
|
+
extend ::T::Helpers
|
11
|
+
|
12
|
+
interface!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|