low_type 0.7.1 → 0.7.3

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: af6b3684e92cdf1cd8276d6c06b93d7a83667fdc8ebe32590c26a992d64cfb89
4
- data.tar.gz: fb341f9d4ec022a3e2aeda982a30646b44d1a2389ed5d0e473cf8d3c4846fa2b
3
+ metadata.gz: '08c093dff18ac6521c3f61290a28012b565986300d44afabd9161e663ce2a82f'
4
+ data.tar.gz: 4eb9c8282d3e9971fb5bbf0dcc6b9a79f2769b93fe3d72cb62242c93b15ea2e3
5
5
  SHA512:
6
- metadata.gz: 57df3e2a9db8a10f2008c7e7d14ff66cf24562bd80266676ad56c176277eafb76982401db097c3ce98f759fe318d5052095a55366742915c76967449ec22abfc
7
- data.tar.gz: cccd7db020ccabd34684347b4e67182ac40b0425acdc23e31a99bd78369c575f2b80a8deabe6ba0c67ae900f2c775e2fe020b0097ce9147aad47aa04d5c3e858
6
+ metadata.gz: 8d5b73adbff21ff73995856e57681b77048f3e6920ab79d09ab2e60c54a462ee2e0f7a44431466952f2dba7da960be20edecf63a26b0094d4c051bb1e5e5dd5d
7
+ data.tar.gz: 5033b3d43438797757c4fbb927e20459ae207b1619128ec96ff46a1c89dff23fcbc3ef0da999e99cbb9b7abc59bb262d95dd77d4935c3600a001bf89ff8e0003
@@ -0,0 +1,5 @@
1
+ module LowType
2
+ class ArgumentTypeError < TypeError; end;
3
+ class LocalTypeError < TypeError; end;
4
+ class ReturnTypeError < TypeError; end;
5
+ end
@@ -1,10 +1,12 @@
1
1
  module LowType
2
- class ProxyInterface
2
+ class ErrorInterface
3
+ attr_reader :file
4
+
3
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'
2
- require_relative '../errors'
1
+ require_relative '../interfaces/error_interface'
2
+ require_relative '../error_types'
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
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}'"
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,22 +1,23 @@
1
- require_relative '../interfaces/proxy_interface'
2
- require_relative '../errors'
1
+ require_relative '../interfaces/error_interface'
2
+ require_relative '../error_types'
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
16
  def error_type
16
17
  ArgumentTypeError
17
18
  end
18
19
 
19
- def error_message(value:, line: nil)
20
+ def error_message(value:)
20
21
  "Invalid argument type '#{value.class}' for parameter '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
21
22
  end
22
23
  end
@@ -1,20 +1,21 @@
1
- require_relative '../interfaces/proxy_interface'
2
- require_relative '../errors'
1
+ require_relative '../interfaces/error_interface'
2
+ require_relative '../error_types'
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
14
  def error_type
14
15
  ReturnTypeError
15
16
  end
16
17
 
17
- def error_message(value:, line: nil)
18
+ def error_message(value:)
18
19
  "Invalid return type '#{value.class}' for method '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
19
20
  end
20
21
  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, 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,7 +44,21 @@ module LowType
42
44
  end
43
45
  end
44
46
 
45
- raise proxy.error_type, proxy.error_message(value:, line:)
47
+ raise proxy.error_type, proxy.error_message(value:)
48
+ rescue proxy.error_type => e
49
+ file_paths = [FILE_PATH, LowType::Redefiner::FILE_PATH]
50
+ raise proxy.error_type, e.message, backtrace_with_proxy(file_paths:, backtrace: e.backtrace, proxy:)
51
+ end
52
+
53
+ def backtrace_with_proxy(file_paths:, proxy:, backtrace:)
54
+ # Remove LowType file paths from the backtrace.
55
+ filtered_backtrace = backtrace.reject { |line| file_paths.find { |file_path| line.include?(file_path) } }
56
+
57
+ # Add the proxied file to the backtrace.
58
+ proxy_file_backtrace = "#{proxy.file.path}:#{proxy.file.line}:in '#{proxy.file.scope}'"
59
+ proxy_file_backtrace = "from " + proxy_file_backtrace if filtered_backtrace.first.start_with?('from')
60
+
61
+ [proxy_file_backtrace, *filtered_backtrace]
46
62
  end
47
63
 
48
64
  def valid_types
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.1'
4
+ VERSION = '0.7.3'
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.1
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -17,10 +17,11 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - lib/errors.rb
21
- - lib/interfaces/proxy_interface.rb
20
+ - lib/error_types.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
data/lib/errors.rb DELETED
@@ -1,3 +0,0 @@
1
- class ArgumentTypeError < TypeError; end;
2
- class LocalTypeError < TypeError; end;
3
- class ReturnTypeError < TypeError; end;