typeguard 1.0.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.
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typeguard
4
+ module Validation
5
+ class Wrapper
6
+ include Typeguard::TypeModel::Definitions
7
+
8
+ def initialize(definitions, config)
9
+ @definitions = definitions
10
+ @config = config
11
+ end
12
+
13
+ def wrap!
14
+ @definitions.each { |definition| wrap_definition(definition) }
15
+ end
16
+
17
+ def wrap_definition(definition)
18
+ case definition
19
+ when ModuleDefinition, ClassDefinition
20
+ mod = Object.const_get(definition.name)
21
+ definition.children.each do |child|
22
+ if child.is_a?(MethodDefinition)
23
+ wrap_method(mod, child)
24
+ else
25
+ # Wrap nested modules
26
+ wrap_definition(child)
27
+ end
28
+ end
29
+ when MethodDefinition
30
+ # Method defined in root, as a private instance method of Object
31
+ wrap_method(Object, definition)
32
+ else raise "Unexpected definition for '#{definition}'"
33
+ end
34
+ end
35
+
36
+ def wrap_method(mod, sig)
37
+ return if unsafe_method?(sig)
38
+
39
+ target = sig.scope == :class ? mod.singleton_class : mod
40
+ method_name = sig.name
41
+ original_method = target.instance_method(method_name)
42
+ check_arity(mod, sig, original_method)
43
+ actual_visibility = check_visibility(target, mod, sig, method_name)
44
+ Validator.exhaustive_path(mod, original_method, sig)
45
+ target.send(actual_visibility, method_name)
46
+ end
47
+
48
+ def unsafe_method?(sig)
49
+ # It is unsafe to redefine these methods because
50
+ # the return type is not always the same: assignment
51
+ # vs method call
52
+ sig.name == :initialize || sig.name.to_s =~ /=$/
53
+ end
54
+
55
+ def check_arity(mod, sig, original_method)
56
+ expected_arity = sig.parameters.size
57
+ actual_arity = original_method.parameters.count
58
+ return if expected_arity == actual_arity
59
+
60
+ log = Metrics.report(mod, sig, :unexpected_arity, expected_arity, actual_arity)
61
+ raise Metrics.format_log(log) if @config.raise_on_unexpected_arity
62
+ end
63
+
64
+ def check_visibility(target, mod, sig, method_name)
65
+ expected_visibility = sig.visibility
66
+ actual_visibility =
67
+ if target.public_instance_methods(false).include?(method_name)
68
+ :public
69
+ elsif target.protected_instance_methods(false).include?(method_name)
70
+ :protected
71
+ elsif target.private_instance_methods(false).include?(method_name)
72
+ :private
73
+ else
74
+ :public
75
+ end
76
+
77
+ error = false
78
+ unless expected_visibility.nil? || expected_visibility == actual_visibility
79
+ if expected_visibility == :public && actual_visibility == :private
80
+ if sig.name == :initialize
81
+ # Initialize is private by default, ignore
82
+ elsif mod == Object
83
+ # Methods on Object (root) are private by default, ignore
84
+ else
85
+ error = true
86
+ end
87
+ else
88
+ error = true
89
+ end
90
+ end
91
+
92
+ if error
93
+ log = Metrics.report(mod, sig, :unexpected_visibility, expected_visibility, actual_visibility)
94
+ raise Metrics.format_log(log) if @config.raise_on_unexpected_visibility
95
+ end
96
+
97
+ actual_visibility
98
+ end
99
+ end
100
+ end
101
+ end
data/lib/typeguard.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'typeguard/type_model/definitions'
4
+ require_relative 'typeguard/type_model/builder'
5
+ require_relative 'typeguard/version'
6
+ require_relative 'typeguard/configuration'
7
+ require_relative 'typeguard/resolver'
8
+ require_relative 'typeguard/metrics'
9
+ require_relative 'typeguard/types'
10
+ require_relative 'typeguard/validator'
11
+ require_relative 'typeguard/wrapper'
@@ -0,0 +1,77 @@
1
+ # Custom constant
2
+ class Foo
3
+ end
4
+
5
+ # Nested modules and classes
6
+ module One
7
+ class OneClass
8
+ end
9
+
10
+ module Two
11
+ class TwoClass
12
+ end
13
+
14
+ module Three
15
+ # Nested class
16
+ class ThreeClass
17
+ # _@param_ `one`
18
+ #
19
+ # _@param_ `two`
20
+ def nested_fn: (One::OneClass one, One::Two::TwoClass two) -> [One::OneClass, One::Two::TwoClass, One::Two::Three::ThreeClass]
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ # Yardoc validation example
27
+ class Example
28
+ # _@return_ — a regular type
29
+ def regular0: () -> Object
30
+
31
+ # _@return_ — Ruby literal 'true'
32
+ def literal0: () -> bool
33
+
34
+ # sord duck - #push looks like a duck type, replacing with untyped
35
+ # _@return_ — duck-type: responds to :push
36
+ def duck0: () -> untyped
37
+
38
+ # _@param_ `a` — Integer to double
39
+ #
40
+ # _@return_ — double of a
41
+ def double1: (Integer a) -> Integer
42
+
43
+ # _@param_ `a`
44
+ #
45
+ # _@param_ `b`
46
+ #
47
+ # _@return_ — generic array of numbers
48
+ def generic_array2: (Integer a, Integer b) -> ::Array[(Integer | Float)]
49
+
50
+ # _@param_ `a`
51
+ #
52
+ # _@return_ — fixed array with order Symbol -> Integer
53
+ def fixed_array1: (Integer a) -> [Symbol, Integer]
54
+
55
+ # sord warn - Invalid hash, must have exactly two types: "Hash{Symbol => Integer, Float}".
56
+ # _@param_ `a`
57
+ #
58
+ # _@return_ — special hash syntax with 1 key and 2 value types
59
+ def special_hash1: (Integer a) -> untyped
60
+
61
+ # sord duck - #push looks like a duck type, replacing with untyped
62
+ # sord warn - Invalid hash, must have exactly two types: "Hash{Symbol, String => Boolean, Array<Array(Foo, #push, Set<Integer>)>}".
63
+ # _@param_ `a`
64
+ #
65
+ # _@return_ — complex types
66
+ def complex1: (Integer a) -> untyped
67
+
68
+ # sord warn - Invalid hash, must have exactly two types: "{Symbol => Integer, Symbol}".
69
+ # _@param_ `a`
70
+ #
71
+ # _@return_ — shorthands for collections
72
+ def shorthands1: (Integer a) -> [[Integer, Float], ::Array[Symbol], untyped]
73
+
74
+ def nested_modules0: () -> [One::OneClass, One::Two::TwoClass, One::Two::Three::ThreeClass]
75
+
76
+ end
77
+
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typeguard
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tesorion
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: dry-configurable
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rbs
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: yard
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: zeitwerk
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 2.6.0
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 2.6.0
68
+ email:
69
+ - QmanageDevelopment@tesorion.nl
70
+ executables: []
71
+ extensions: []
72
+ extra_rdoc_files: []
73
+ files:
74
+ - ".editorconfig"
75
+ - ".rubocop.yml"
76
+ - ".rubocop_todo.yml"
77
+ - Gemfile
78
+ - LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - lib/typeguard.rb
82
+ - lib/typeguard/configuration.rb
83
+ - lib/typeguard/metrics.rb
84
+ - lib/typeguard/resolver.rb
85
+ - lib/typeguard/type_model/builder.rb
86
+ - lib/typeguard/type_model/builder/rbs_builder.rb
87
+ - lib/typeguard/type_model/builder/yard_builder.rb
88
+ - lib/typeguard/type_model/definitions.rb
89
+ - lib/typeguard/type_model/mapper/rbs_mapper.rb
90
+ - lib/typeguard/type_model/mapper/yard_mapper.rb
91
+ - lib/typeguard/types.rb
92
+ - lib/typeguard/validator.rb
93
+ - lib/typeguard/version.rb
94
+ - lib/typeguard/wrapper.rb
95
+ - sig/typeguard/bin/example.rbs
96
+ homepage: https://github.com/tesorion/typeguard
97
+ licenses:
98
+ - MIT
99
+ metadata:
100
+ homepage_uri: https://github.com/tesorion/typeguard
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '3.1'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.6.8
116
+ specification_version: 4
117
+ summary: Validate YARD and RBS type signatures
118
+ test_files: []