csv_plus_plus 0.1.3 → 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.
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