low_type 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d845917e9ed4afc79db302fe7f5a2955a4e299d7bd415e82e2f26af3b14cd25f
4
- data.tar.gz: f9213b5731f3805ebf1e99efa0ccdd741b955464403842aeaa171d0b41fff146
3
+ metadata.gz: 1e76dff27cdb0b8d263e8204299df281bd1e05b2097039b1045aa85f98134568
4
+ data.tar.gz: a6775344f9cd73a4275e0dad7d510bae20a3257922a702d938f0c2506363a1bf
5
5
  SHA512:
6
- metadata.gz: 6066f8c29073720201a83438c58067ef37d2b02b493f108e31bee624069b68a7049e3a64aebe20da851f7b8e13e7d599c02deb1adbb9050ccd271a895933c6c2
7
- data.tar.gz: 16c144045ae7666c1ab42610e641d9b4946b14cc9adf22023239a55dbfcbc5a8da714b53c94972a883249008512bcc56a60b465ce9ba9da1908a0151856afa7c
6
+ metadata.gz: 6a0e1d2c4d89357e1add9051be9be3c0bd972d1aa737c1c5ff6f7ff5ca22fbf4590dc08b52f72f9f6fe252678ce89cbd16a8eee892255f55d4a04218323cd254
7
+ data.tar.gz: 4e9d03cd8588500dfafadeb423f06641e2981532106c342366a90f7fe36a8dcb96ef4191f3231f7f3cb5f21492d7bf61f790d020af31d224bea8d459d902de1b
@@ -1,10 +1,12 @@
1
1
  module LowType
2
- class ProxyInterface
3
- def error_type(value:)
2
+ class ErrorInterface
3
+ attr_reader :file
4
+
5
+ def error_type
4
6
  raise NotImplementedError
5
7
  end
6
8
 
7
- def error_message(value:, line: nil)
9
+ def error_message(value:)
8
10
  raise NotImplementedError
9
11
  end
10
12
  end
data/lib/low_type.rb CHANGED
@@ -34,11 +34,12 @@ module LowType
34
34
  end
35
35
  end
36
36
 
37
- parser = Parser.new(file_path: LowType.file_path(klass:))
37
+ file_path = LowType.file_path(klass:)
38
+ parser = Parser.new(file_path:)
38
39
  private_start_line = parser.private_start_line
39
40
 
40
- klass.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.instance_methods, private_start_line:, klass:)
41
- klass.singleton_class.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.class_methods, private_start_line:, klass:)
41
+ klass.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.instance_methods, klass:, private_start_line:, file_path:)
42
+ klass.singleton_class.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.class_methods, klass:, private_start_line:, file_path:)
42
43
  ensure
43
44
  Array.define_singleton_method('[]', array_class_method)
44
45
  Hash.define_singleton_method('[]', hash_class_method)
@@ -0,0 +1,11 @@
1
+ module LowType
2
+ class FileProxy
3
+ attr_reader :path, :line, :scope
4
+
5
+ def initialize(path:, line:, scope:)
6
+ @path = path
7
+ @line = line
8
+ @scope = scope
9
+ end
10
+ end
11
+ end
@@ -1,21 +1,22 @@
1
- require_relative '../interfaces/proxy_interface'
1
+ require_relative '../interfaces/error_interface'
2
2
  require_relative '../errors'
3
3
 
4
4
  module LowType
5
- class LocalProxy < ProxyInterface
5
+ class LocalProxy < ErrorInterface
6
6
  attr_reader :type_expression, :name
7
7
 
8
- def initialize(type_expression:, name:)
8
+ def initialize(type_expression:, name:, file:)
9
9
  @type_expression = type_expression
10
10
  @name = name
11
+ @file = file
11
12
  end
12
13
 
13
- def error_type(value:)
14
+ def error_type
14
15
  LocalTypeError
15
16
  end
16
17
 
17
- def error_message(value:, line:)
18
- "Invalid variable type #{value.class} in '#{@name.class}' on line #{line}. Valid types: '#{@type_expression.valid_types.join(', ')}'"
18
+ def error_message(value:)
19
+ "Invalid variable type #{value.class} in '#{@name.class}' on line #{@file.line}. Valid types: '#{@type_expression.valid_types}'"
19
20
  end
20
21
  end
21
22
  end
@@ -1,26 +1,24 @@
1
- require_relative '../interfaces/proxy_interface'
1
+ require_relative '../interfaces/error_interface'
2
2
  require_relative '../errors'
3
3
 
4
4
  module LowType
5
- class ParamProxy < ProxyInterface
5
+ class ParamProxy < ErrorInterface
6
6
  attr_reader :type_expression, :name, :type, :position
7
7
 
8
- def initialize(type_expression:, name:, type:, position: nil)
8
+ def initialize(type_expression:, name:, type:, position: nil, file:)
9
9
  @type_expression = type_expression
10
10
  @name = name
11
11
  @type = type
12
12
  @position = position
13
+ @file = file
13
14
  end
14
15
 
15
- def error_type(value:)
16
- return ArgumentError if value.nil?
16
+ def error_type
17
17
  ArgumentTypeError
18
18
  end
19
19
 
20
- def error_message(value:, line: nil)
21
- return "Missing argument for parameter '#{@name}'. Position: #{@position}" if value.nil?
22
-
23
- "Invalid argument type '#{value.class}' for parameter '#{@name}'. Valid types: '#{@type_expression.valid_types.join(', ')}'"
20
+ def error_message(value:)
21
+ "Invalid argument type '#{value.class}' for parameter '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
24
22
  end
25
23
  end
26
24
  end
@@ -1,21 +1,22 @@
1
- require_relative '../interfaces/proxy_interface'
1
+ require_relative '../interfaces/error_interface'
2
2
  require_relative '../errors'
3
3
 
4
4
  module LowType
5
- class ReturnProxy < ProxyInterface
5
+ class ReturnProxy < ErrorInterface
6
6
  attr_reader :type_expression, :name
7
7
 
8
- def initialize(type_expression:, name:)
8
+ def initialize(type_expression:, name:, file:)
9
9
  @type_expression = type_expression
10
10
  @name = name
11
+ @file = file
11
12
  end
12
13
 
13
- def error_type(value:)
14
+ def error_type
14
15
  ReturnTypeError
15
16
  end
16
17
 
17
- def error_message(value:, line: nil)
18
- "Invalid return type '#{value.class}' for method '#{@name}'. Valid types: '#{@type_expression.valid_types.join(', ')}'"
18
+ def error_message(value:)
19
+ "Invalid return type '#{value.class}' for method '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
19
20
  end
20
21
  end
21
22
  end
data/lib/redefiner.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require_relative 'proxies/file_proxy'
1
2
  require_relative 'proxies/method_proxy'
2
3
  require_relative 'proxies/param_proxy'
3
4
  require_relative 'proxies/return_proxy'
@@ -6,13 +7,16 @@ require_relative 'type_expression'
6
7
 
7
8
  module LowType
8
9
  class Redefiner
10
+ FILE_PATH = File.expand_path(__FILE__)
11
+
9
12
  class << self
10
- def redefine_methods(method_nodes:, private_start_line:, klass:)
13
+ def redefine_methods(method_nodes:, klass:, private_start_line:, file_path:)
11
14
  Module.new do
12
15
  method_nodes.each do |method_node|
13
16
  name = method_node.name
14
- params = Redefiner.params_with_type_expressions(method_node:)
15
- return_proxy = Redefiner.return_proxy(method_node:)
17
+ file = FileProxy.new(path: file_path, line: method_node.start_line, scope: "#{klass}##{method_node.name}")
18
+ params = Redefiner.params_with_type_expressions(method_node:, file:)
19
+ return_proxy = Redefiner.return_proxy(method_node:, file:)
16
20
 
17
21
  klass.low_methods[name] = MethodProxy.new(name:, params:, return_proxy:)
18
22
 
@@ -45,7 +49,7 @@ module LowType
45
49
  end
46
50
  end
47
51
 
48
- def params_with_type_expressions(method_node:)
52
+ def params_with_type_expressions(method_node:, file:)
49
53
  return [] if method_node.parameters.nil?
50
54
 
51
55
  params = method_node.parameters.slice
@@ -64,9 +68,9 @@ module LowType
64
68
  expression = binding.local_variable_get(name)
65
69
 
66
70
  if expression.class == TypeExpression
67
- param_proxies << ParamProxy.new(type_expression: expression, name:, type:, position:)
71
+ param_proxies << ParamProxy.new(type_expression: expression, name:, type:, position:, file:)
68
72
  elsif ::LowType.type?(expression)
69
- param_proxies << ParamProxy.new(type_expression: TypeExpression.new(type: expression), name:, type:, position:)
73
+ param_proxies << ParamProxy.new(type_expression: TypeExpression.new(type: expression), name:, type:, position:, file:)
70
74
  end
71
75
  end
72
76
 
@@ -83,14 +87,14 @@ module LowType
83
87
  raise ArgumentError, "Incorrect param syntax: #{e.message}"
84
88
  end
85
89
 
86
- def return_proxy(method_node:)
90
+ def return_proxy(method_node:, file:)
87
91
  return_node = Parser.return_node(method_node:)
88
92
  return nil if return_node.nil?
89
93
 
90
94
  expression = eval(return_node.slice).call
91
95
  expression = TypeExpression.new(type: expression) unless expression.is_a?(TypeExpression)
92
96
 
93
- ReturnProxy.new(type_expression: expression, name: method_node.name)
97
+ ReturnProxy.new(type_expression: expression, name: method_node.name, file:)
94
98
  end
95
99
 
96
100
  private
@@ -1,3 +1,4 @@
1
+ require_relative 'proxies/file_proxy'
1
2
  require_relative 'proxies/local_proxy'
2
3
  require_relative 'type_expression'
3
4
  require_relative 'value_expression'
@@ -12,15 +13,17 @@ module TypeAssignment
12
13
  raise AssignmentError, "Single-instance objects like #{object} are not supported"
13
14
  end
14
15
 
15
- local_proxy = LowType::LocalProxy.new(type_expression:, name: self)
16
+ last_caller = caller_locations(1, 1).first
17
+ file = LowType::FileProxy.new(path: last_caller.path, line: last_caller.lineno, scope: 'local type')
18
+ local_proxy = LowType::LocalProxy.new(type_expression:, name: self, file:)
16
19
  object.instance_variable_set('@local_proxy', local_proxy)
17
20
 
18
- type_expression.validate!(value: object, proxy: local_proxy, line: caller_locations(1, 1).first.lineno)
21
+ type_expression.validate!(value: object, proxy: local_proxy)
19
22
 
20
23
  def object.with_type=(value)
21
24
  local_proxy = self.instance_variable_get('@local_proxy')
22
25
  type_expression = local_proxy.type_expression
23
- type_expression.validate!(value:, proxy: local_proxy, line: caller_locations(1, 1).first.lineno)
26
+ type_expression.validate!(value:, proxy: local_proxy)
24
27
 
25
28
  # We can't reassign self in Ruby so we reassign instance variables instead.
26
29
  value.instance_variables.each do |variable|
@@ -2,6 +2,8 @@ require_relative 'proxies/param_proxy'
2
2
 
3
3
  module LowType
4
4
  class TypeExpression
5
+ FILE_PATH = File.expand_path(__FILE__)
6
+
5
7
  attr_reader :types, :default_value
6
8
 
7
9
  def initialize(type: nil, default_value: :LOW_TYPE_UNDEFINED)
@@ -27,10 +29,10 @@ module LowType
27
29
  @default_value == :LOW_TYPE_UNDEFINED
28
30
  end
29
31
 
30
- def validate!(value:, proxy:, line: nil)
32
+ def validate!(value:, proxy:)
31
33
  if value.nil?
32
34
  return true if @default_value.nil?
33
- raise proxy.error_type(value:), proxy.error_message(value:, line:) if required?
35
+ raise proxy.error_type, proxy.error_message(value:) if required?
34
36
  end
35
37
 
36
38
  @types.each do |type|
@@ -42,13 +44,24 @@ module LowType
42
44
  end
43
45
  end
44
46
 
45
- raise proxy.error_type(value:), proxy.error_message(value:, line:)
47
+ raise proxy.error_type, proxy.error_message(value:)
48
+ rescue proxy.error_type => e
49
+ # Remove LowType file paths from the backtrace.
50
+ internal_file_paths = [FILE_PATH, LowType::Redefiner::FILE_PATH]
51
+ external_backtrace = e.backtrace.reject { |line| internal_file_paths.include?(line.split(':').first) }
52
+
53
+ # Add the proxied file to the backtrace.
54
+ file = proxy.file
55
+ proxy_file_backtrace = "#{file.path}:#{file.line}:in '#{file.scope}'"
56
+
57
+ raise proxy.error_type, e.message, [proxy_file_backtrace, *external_backtrace]
46
58
  end
47
59
 
48
60
  def valid_types
49
61
  types = @types.map { |type| type.inspect.to_s }
50
- return types + ['nil'] if @default_value.nil?
51
- types
62
+ types = types + ['nil'] if @default_value.nil?
63
+
64
+ types.join(' | ')
52
65
  end
53
66
  end
54
67
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LowType
4
- VERSION = '0.7.0'
4
+ VERSION = '0.7.2'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: low_type
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -18,9 +18,10 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - lib/errors.rb
21
- - lib/interfaces/proxy_interface.rb
21
+ - lib/interfaces/error_interface.rb
22
22
  - lib/low_type.rb
23
23
  - lib/parser.rb
24
+ - lib/proxies/file_proxy.rb
24
25
  - lib/proxies/local_proxy.rb
25
26
  - lib/proxies/method_proxy.rb
26
27
  - lib/proxies/param_proxy.rb