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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -3
  3. data/docs/CHANGELOG.md +16 -0
  4. data/lib/csv_plus_plus/a1_reference.rb +202 -0
  5. data/lib/csv_plus_plus/benchmarked_compiler.rb +3 -3
  6. data/lib/csv_plus_plus/cell.rb +1 -35
  7. data/lib/csv_plus_plus/cli.rb +43 -80
  8. data/lib/csv_plus_plus/cli_flag.rb +71 -70
  9. data/lib/csv_plus_plus/color.rb +1 -1
  10. data/lib/csv_plus_plus/compiler.rb +31 -21
  11. data/lib/csv_plus_plus/entities/ast_builder.rb +11 -4
  12. data/lib/csv_plus_plus/entities/boolean.rb +16 -9
  13. data/lib/csv_plus_plus/entities/builtins.rb +68 -40
  14. data/lib/csv_plus_plus/entities/date.rb +14 -11
  15. data/lib/csv_plus_plus/entities/entity.rb +11 -29
  16. data/lib/csv_plus_plus/entities/entity_with_arguments.rb +18 -31
  17. data/lib/csv_plus_plus/entities/function.rb +22 -11
  18. data/lib/csv_plus_plus/entities/function_call.rb +35 -11
  19. data/lib/csv_plus_plus/entities/has_identifier.rb +19 -0
  20. data/lib/csv_plus_plus/entities/number.rb +15 -10
  21. data/lib/csv_plus_plus/entities/reference.rb +77 -0
  22. data/lib/csv_plus_plus/entities/runtime_value.rb +36 -23
  23. data/lib/csv_plus_plus/entities/string.rb +13 -10
  24. data/lib/csv_plus_plus/entities.rb +2 -18
  25. data/lib/csv_plus_plus/error/cli_error.rb +17 -0
  26. data/lib/csv_plus_plus/error/compiler_error.rb +17 -0
  27. data/lib/csv_plus_plus/error/error.rb +18 -5
  28. data/lib/csv_plus_plus/error/formula_syntax_error.rb +12 -13
  29. data/lib/csv_plus_plus/error/modifier_syntax_error.rb +10 -36
  30. data/lib/csv_plus_plus/error/modifier_validation_error.rb +6 -32
  31. data/lib/csv_plus_plus/error/positional_error.rb +15 -0
  32. data/lib/csv_plus_plus/error/writer_error.rb +1 -1
  33. data/lib/csv_plus_plus/error.rb +4 -1
  34. data/lib/csv_plus_plus/error_formatter.rb +111 -0
  35. data/lib/csv_plus_plus/google_api_client.rb +18 -8
  36. data/lib/csv_plus_plus/lexer/racc_lexer.rb +144 -0
  37. data/lib/csv_plus_plus/lexer/tokenizer.rb +53 -17
  38. data/lib/csv_plus_plus/lexer.rb +40 -1
  39. data/lib/csv_plus_plus/modifier/data_validation.rb +1 -1
  40. data/lib/csv_plus_plus/modifier/expand.rb +17 -0
  41. data/lib/csv_plus_plus/modifier.rb +6 -1
  42. data/lib/csv_plus_plus/options/file_options.rb +49 -0
  43. data/lib/csv_plus_plus/options/google_sheets_options.rb +42 -0
  44. data/lib/csv_plus_plus/options/options.rb +97 -0
  45. data/lib/csv_plus_plus/options.rb +22 -110
  46. data/lib/csv_plus_plus/parser/cell_value.tab.rb +65 -66
  47. data/lib/csv_plus_plus/parser/code_section.tab.rb +92 -84
  48. data/lib/csv_plus_plus/parser/modifier.tab.rb +40 -30
  49. data/lib/csv_plus_plus/reader/csv.rb +50 -0
  50. data/lib/csv_plus_plus/reader/google_sheets.rb +129 -0
  51. data/lib/csv_plus_plus/reader/reader.rb +27 -0
  52. data/lib/csv_plus_plus/reader/rubyxl.rb +37 -0
  53. data/lib/csv_plus_plus/reader.rb +14 -0
  54. data/lib/csv_plus_plus/runtime/graph.rb +6 -6
  55. data/lib/csv_plus_plus/runtime/{position_tracker.rb → position.rb} +16 -5
  56. data/lib/csv_plus_plus/runtime/references.rb +32 -27
  57. data/lib/csv_plus_plus/runtime/runtime.rb +73 -67
  58. data/lib/csv_plus_plus/runtime/scope.rb +280 -0
  59. data/lib/csv_plus_plus/runtime.rb +9 -9
  60. data/lib/csv_plus_plus/source_code.rb +14 -9
  61. data/lib/csv_plus_plus/template.rb +17 -12
  62. data/lib/csv_plus_plus/version.rb +1 -1
  63. data/lib/csv_plus_plus/writer/csv.rb +32 -5
  64. data/lib/csv_plus_plus/writer/excel.rb +19 -6
  65. data/lib/csv_plus_plus/writer/file_backer_upper.rb +27 -14
  66. data/lib/csv_plus_plus/writer/google_sheets.rb +23 -129
  67. data/lib/csv_plus_plus/writer/{google_sheet_builder.rb → google_sheets_builder.rb} +39 -55
  68. data/lib/csv_plus_plus/writer/merger.rb +31 -0
  69. data/lib/csv_plus_plus/writer/open_document.rb +16 -2
  70. data/lib/csv_plus_plus/writer/rubyxl_builder.rb +68 -43
  71. data/lib/csv_plus_plus/writer/writer.rb +42 -0
  72. data/lib/csv_plus_plus/writer.rb +58 -19
  73. data/lib/csv_plus_plus.rb +26 -14
  74. metadata +37 -12
  75. data/lib/csv_plus_plus/entities/cell_reference.rb +0 -231
  76. data/lib/csv_plus_plus/entities/variable.rb +0 -37
  77. data/lib/csv_plus_plus/error/syntax_error.rb +0 -71
  78. data/lib/csv_plus_plus/google_options.rb +0 -32
  79. data/lib/csv_plus_plus/lexer/lexer.rb +0 -89
  80. data/lib/csv_plus_plus/runtime/can_define_references.rb +0 -87
  81. data/lib/csv_plus_plus/runtime/can_resolve_references.rb +0 -209
  82. 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 { params(id: ::Symbol, arguments: ::T::Array[::CSVPlusPlus::Entities::Entity], infix: ::T::Boolean).void }
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(::CSVPlusPlus::Entities::Type::FunctionCall, id:, arguments:)
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(runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
26
- # @param runtime [Runtime]
39
+ sig { override.params(position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
40
+ # @param position [Position]
27
41
  #
28
42
  # @return [::String]
29
- def evaluate(runtime)
30
- evaluated_arguments = evaluate_arguments(runtime)
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: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
40
- # @param other [Entity]
53
+ sig { override.params(other: ::BasicObject).returns(::T::Boolean) }
54
+ # @param other [BasicObject]
41
55
  #
42
- # @return [boolean]
56
+ # @return [Boolean]
43
57
  def ==(other)
44
- return false unless super
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
- other.is_a?(self.class) && @id == other.id && @infix == other.infix
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(::CSVPlusPlus::Entities::Type::Number)
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(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
30
- # @param _runtime [Runtime]
31
+ sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
32
+ # @param _position [Position]
31
33
  #
32
34
  # @return [::String]
33
- def evaluate(_runtime)
35
+ def evaluate(_position)
34
36
  @value.to_s
35
37
  end
36
38
 
37
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
38
- # @param other [Entity]
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
- return false unless super
43
-
44
- other.is_a?(self.class) && @value == other.value
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
- # which takes an ExecutionContext as a param
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
- sig { returns(::T::Array[::T.untyped]) }
14
- attr_reader :arguments
15
-
16
- sig { returns(::T.proc.params(arg0: ::CSVPlusPlus::Runtime::Runtime).returns(::CSVPlusPlus::Entities::Entity)) }
17
- attr_reader :resolve_fn
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
- # @param arguments [Any] Arguments to the runtime value call
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(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
35
- # @param _runtime [Runtime]
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 [String]
38
- def evaluate(_runtime)
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(::CSVPlusPlus::Entities::Type::String)
18
+ super()
19
19
 
20
20
  @value = ::T.let(value.gsub(/^"|"$/, ''), ::String)
21
21
  end
22
22
 
23
- sig { override.params(_runtime: ::CSVPlusPlus::Runtime::Runtime).returns(::String) }
24
- # @param _runtime [Runtime]
23
+ sig { override.params(_position: ::CSVPlusPlus::Runtime::Position).returns(::String) }
24
+ # @param _position [Position]
25
25
  #
26
26
  # @return [::String]
27
- def evaluate(_runtime)
27
+ def evaluate(_position)
28
28
  "\"#{@value}\""
29
29
  end
30
30
 
31
- sig { override.params(other: ::CSVPlusPlus::Entities::Entity).returns(::T::Boolean) }
32
- # @param other [Entity]
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
- return false unless super
37
-
38
- other.is_a?(self.class) && @value == other.value
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
- sig { returns(::String) }
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: true
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::SyntaxError
13
- attr_reader :message, :bad_input
10
+ class FormulaSyntaxError < ::CSVPlusPlus::Error::Error
11
+ extend ::T::Sig
12
+ include ::CSVPlusPlus::Error::PositionalError
14
13
 
15
- # You must supply either a +choices+ or +message+
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, runtime, wrapped_error: nil)
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
- "#{@message}: \"#{@bad_input}\""
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
- # An Error that wraps a +ModifierValidationError+ with a +Runtime+.
9
- class ModifierSyntaxError < ::CSVPlusPlus::Error::SyntaxError
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 runtime [Runtime] The current runtime
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(runtime, bad_input:, message:, modifier: nil, wrapped_error: nil)
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::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
- @bad_input = bad_input
44
- @choices = choices
45
- @modifier = modifier
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
@@ -10,7 +10,7 @@ module CSVPlusPlus
10
10
  sig { override.returns(::String) }
11
11
  # @return [::String]
12
12
  def error_message
13
- "Error writing template: #{message}"
13
+ "Error writing csvpp template: #{message}"
14
14
  end
15
15
  end
16
16
  end