rdl 2.0.0.rc3 → 2.0.0.rc4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +5 -1
- data/README.md +25 -1
- data/lib/rdl.rb +5 -127
- data/lib/rdl/boot.rb +129 -0
- data/lib/rdl/boot_rails.rb +13 -0
- data/lib/rdl/typecheck.rb +15 -11
- data/lib/rdl/types/method.rb +2 -2
- data/lib/rdl/wrap.rb +1 -0
- data/lib/rdl_disable.rb +1 -3
- data/lib/types/rails-5.x/_helpers.rb +32 -0
- data/lib/types/rails-5.x/action_controller/mime_responds.rb +11 -0
- data/lib/types/rails-5.x/action_controller/strong_parameters.rb +22 -0
- data/lib/types/rails-5.x/action_dispatch/routing.rb +10 -0
- data/lib/types/rails-5.x/active_record/model_schema.rb +42 -0
- data/lib/types/rails-5.x/fixnum.rb +3 -0
- data/rdl.gemspec +2 -2
- data/test/test_le.rb +1 -1
- data/test/test_lib_types.rb +1 -1
- data/test/test_type_contract.rb +27 -0
- data/test/test_typecheck.rb +1 -1
- metadata +10 -3
- data/lib/rdl_types.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 036f7f5447f5a5405a0624b7f346101e19012c19
|
4
|
+
data.tar.gz: 3004e573e29f44e4adea3c2b1cdc314134fa4f4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0355d89a993299da187c096dd85b27209205a0155c80780944c88118a775e2b82f6f9746536465f8f096a8197ebfd1084f64c613f90a1319e2a31b88f5b1645a
|
7
|
+
data.tar.gz: db84c871660e4e4e6458d31f11bef1ed5a68056d3ac5dd8fd293e85b5b189cc9431c359c28a1db41fc3dd27244835f854aa8aa287a5873786bb0f4b7a72b72b9
|
data/CHANGES.md
CHANGED
@@ -10,9 +10,13 @@
|
|
10
10
|
|
11
11
|
### Changed
|
12
12
|
- Modified `self` type to be any instance of the self's class
|
13
|
-
- Library types now use new aliases %integer and %numeric instead of the Integer and Numeric classes
|
13
|
+
- Library types now use new aliases %integer and %numeric instead of the Integer and Numeric classes
|
14
|
+
- Instead of requiring `rdl_types.rb`, require `types/core`
|
15
|
+
|
16
|
+
### Fixed
|
14
17
|
- Fix issue #14 - allow type/pre/post to coexist, improve docs on dependent types
|
15
18
|
- Fix typos in README, pull req #13
|
19
|
+
- Fix bug where calling method overloaded sometimes with block and sometimes without would always report type error
|
16
20
|
|
17
21
|
## [1.1.1] - 2016-05-21
|
18
22
|
### Fixed
|
data/README.md
CHANGED
@@ -148,7 +148,29 @@ For performance reasons you probably don't want to use RDL in production code. T
|
|
148
148
|
|
149
149
|
## Rails
|
150
150
|
|
151
|
-
To
|
151
|
+
To add types to a Ruby on Rails application, add
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
gem 'rdl'
|
155
|
+
```
|
156
|
+
|
157
|
+
to your `Gemfile` to get the latest stable version, or
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
gem 'rdl', git: 'https://github.com/plum-umd/rdl'
|
161
|
+
```
|
162
|
+
|
163
|
+
to get the head version from github.
|
164
|
+
|
165
|
+
In development and test mode, you will now have access to `rdl`, `types/core` from RDL, and extra type annotations for Rails and some related gems. In production mode, RDL will be disabled (by loading `rdl_disable`).
|
166
|
+
|
167
|
+
Currently, rdl has types for the following versions of Rails:
|
168
|
+
|
169
|
+
* Rails 5.x support - limited to the following:
|
170
|
+
* Automatically generates
|
171
|
+
* Models
|
172
|
+
* Type annotations for model column getters and setters
|
173
|
+
* `find_by` and `find_by!`
|
152
174
|
|
153
175
|
## Preconditions and Postconditions
|
154
176
|
|
@@ -688,6 +710,8 @@ RDL uses the same approach for hashes: hash literals are treated as finite hashe
|
|
688
710
|
|
689
711
|
* *Caching.* If `typecheck: :call` is specified on a method, Ruby will type check the method every time it is called. In the future, RDL will cache these checks.
|
690
712
|
|
713
|
+
* *Dependent Types.* RDL ignores refinements in checking code with dependent types. E.g., given a `Fixnum x {{ x > 0 }}`, RDL will simply treat `x` as a `Fixnum` and ignore the requirement that it be positive.
|
714
|
+
|
691
715
|
* *Unsupported Features.* There are several features of Ruby that are currently not handled by RDL. Here is a non-exhaustive list:
|
692
716
|
* `super` is not supported.
|
693
717
|
* `lambda` has special semantics for `return`; this is not supported.
|
data/lib/rdl.rb
CHANGED
@@ -1,129 +1,7 @@
|
|
1
|
-
|
2
|
-
require 'digest'
|
3
|
-
require 'set'
|
4
|
-
require 'parser/current'
|
1
|
+
# This wrapper file allows us to completely disable RDL in certain modes.
|
5
2
|
|
6
|
-
|
3
|
+
if defined?(Rails)
|
4
|
+
require 'rdl/boot_rails'
|
5
|
+
else
|
6
|
+
require 'rdl/boot'
|
7
7
|
end
|
8
|
-
|
9
|
-
require 'rdl/config.rb'
|
10
|
-
def RDL.config
|
11
|
-
yield(RDL::Config.instance)
|
12
|
-
end
|
13
|
-
require 'rdl/info.rb'
|
14
|
-
|
15
|
-
# Method/variable info table with kinds:
|
16
|
-
# For methods
|
17
|
-
# :pre to array of precondition contracts
|
18
|
-
# :post to array of postcondition contracts
|
19
|
-
# :type to array of types
|
20
|
-
# :source_location to [filename, linenumber] location of most recent definition
|
21
|
-
# :typecheck - boolean that is true if method should be statically type checked
|
22
|
-
# :otype to set of types that were observed at run time, where a type is a finite hash {:args => Array<Class>, :ret => Class, :block => %bool}
|
23
|
-
# :context_types to array of [klass, meth, Type] - method types that exist only within this method. An icky hack to deal with Rails `params`.
|
24
|
-
# For variables
|
25
|
-
# :type to type
|
26
|
-
$__rdl_info = RDL::Info.new
|
27
|
-
|
28
|
-
# Map from full_method_name to number of times called when wrapped
|
29
|
-
$__rdl_wrapped_calls = Hash.new 0
|
30
|
-
|
31
|
-
# Hash from class name to array of symbols that are the class's type parameters
|
32
|
-
$__rdl_type_params = Hash.new
|
33
|
-
|
34
|
-
# Hash from class name to method name to its alias method name
|
35
|
-
# class names are strings
|
36
|
-
# method names are symbols
|
37
|
-
$__rdl_aliases = Hash.new
|
38
|
-
|
39
|
-
# Set of [class, method] pairs to wrap.
|
40
|
-
# class is a string
|
41
|
-
# method is a symbol
|
42
|
-
$__rdl_to_wrap = Set.new
|
43
|
-
|
44
|
-
# Map from symbols to set of [class, method] pairs to type check when those symbols are rdl_do_typecheck'd
|
45
|
-
# (or the methods are defined, for the symbol :now)
|
46
|
-
$__rdl_to_typecheck = Hash.new
|
47
|
-
$__rdl_to_typecheck[:now] = Set.new
|
48
|
-
|
49
|
-
# List of contracts that should be applied to the next method definition
|
50
|
-
$__rdl_deferred = []
|
51
|
-
|
52
|
-
# Create switches to control whether wrapping happens and whether
|
53
|
-
# contracts are checked. These need to be created before rdl/wrap.rb
|
54
|
-
# is loaded.
|
55
|
-
require 'rdl/switch.rb'
|
56
|
-
$__rdl_wrap_switch = RDL::Switch.new
|
57
|
-
$__rdl_contract_switch = RDL::Switch.new
|
58
|
-
|
59
|
-
require 'rdl/types/type.rb'
|
60
|
-
require 'rdl/types/annotated_arg.rb'
|
61
|
-
require 'rdl/types/bot.rb'
|
62
|
-
require 'rdl/types/dependent_arg.rb'
|
63
|
-
require 'rdl/types/dots_query.rb'
|
64
|
-
require 'rdl/types/finite_hash.rb'
|
65
|
-
require 'rdl/types/generic.rb'
|
66
|
-
require 'rdl/types/intersection.rb'
|
67
|
-
require 'rdl/types/lexer.rex.rb'
|
68
|
-
require 'rdl/types/method.rb'
|
69
|
-
require 'rdl/types/singleton.rb'
|
70
|
-
require 'rdl/types/nominal.rb'
|
71
|
-
require 'rdl/types/non_null.rb'
|
72
|
-
require 'rdl/types/optional.rb'
|
73
|
-
require 'rdl/types/parser.tab.rb'
|
74
|
-
require 'rdl/types/structural.rb'
|
75
|
-
require 'rdl/types/top.rb'
|
76
|
-
require 'rdl/types/tuple.rb'
|
77
|
-
require 'rdl/types/type_query.rb'
|
78
|
-
require 'rdl/types/union.rb'
|
79
|
-
require 'rdl/types/var.rb'
|
80
|
-
require 'rdl/types/vararg.rb'
|
81
|
-
require 'rdl/types/wild_query.rb'
|
82
|
-
|
83
|
-
require 'rdl/contracts/contract.rb'
|
84
|
-
require 'rdl/contracts/and.rb'
|
85
|
-
require 'rdl/contracts/flat.rb'
|
86
|
-
require 'rdl/contracts/or.rb'
|
87
|
-
require 'rdl/contracts/proc.rb'
|
88
|
-
|
89
|
-
require 'rdl/util.rb'
|
90
|
-
require 'rdl/wrap.rb'
|
91
|
-
require 'rdl/query.rb'
|
92
|
-
require 'rdl/typecheck.rb'
|
93
|
-
#require_relative 'rdl/stats.rb'
|
94
|
-
|
95
|
-
$__rdl_parser = RDL::Type::Parser.new
|
96
|
-
|
97
|
-
# Map from file names to [digest, cache] where 2nd elt maps
|
98
|
-
# :ast to the AST
|
99
|
-
# :line_defs maps linenumber to AST for def at that line
|
100
|
-
$__rdl_ruby_parser_cache = Hash.new
|
101
|
-
|
102
|
-
# Some generally useful types; not really a big deal to do this since
|
103
|
-
# NominalTypes are cached, but these names are shorter to type
|
104
|
-
$__rdl_nil_type = RDL::Type::NominalType.new NilClass # actually creates singleton type
|
105
|
-
$__rdl_top_type = RDL::Type::TopType.new
|
106
|
-
$__rdl_bot_type = RDL::Type::BotType.new
|
107
|
-
$__rdl_object_type = RDL::Type::NominalType.new Object
|
108
|
-
$__rdl_true_type = RDL::Type::NominalType.new TrueClass # actually creates singleton type
|
109
|
-
$__rdl_false_type = RDL::Type::NominalType.new FalseClass # also singleton type
|
110
|
-
$__rdl_bool_type = RDL::Type::UnionType.new($__rdl_true_type, $__rdl_false_type)
|
111
|
-
$__rdl_fixnum_type = RDL::Type::NominalType.new Fixnum
|
112
|
-
$__rdl_bignum_type = RDL::Type::NominalType.new Bignum
|
113
|
-
$__rdl_float_type = RDL::Type::NominalType.new Float
|
114
|
-
$__rdl_complex_type = RDL::Type::NominalType.new Complex
|
115
|
-
$__rdl_rational_type = RDL::Type::NominalType.new Rational
|
116
|
-
$__rdl_integer_type = RDL::Type::UnionType.new($__rdl_fixnum_type, $__rdl_bignum_type)
|
117
|
-
$__rdl_numeric_type = RDL::Type::NominalType.new Numeric
|
118
|
-
$__rdl_string_type = RDL::Type::NominalType.new String
|
119
|
-
$__rdl_array_type = RDL::Type::NominalType.new Array
|
120
|
-
$__rdl_hash_type = RDL::Type::NominalType.new Hash
|
121
|
-
$__rdl_symbol_type = RDL::Type::NominalType.new Symbol
|
122
|
-
$__rdl_range_type = RDL::Type::NominalType.new Range
|
123
|
-
$__rdl_regexp_type = RDL::Type::NominalType.new Regexp
|
124
|
-
$__rdl_standard_error_type = RDL::Type::NominalType.new StandardError
|
125
|
-
|
126
|
-
# Hash from special type names to their values
|
127
|
-
$__rdl_special_types = {'%any' => $__rdl_top_type,
|
128
|
-
'%bot' => $__rdl_bot_type,
|
129
|
-
'%bool' => $__rdl_bool_type}
|
data/lib/rdl/boot.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'digest'
|
3
|
+
require 'set'
|
4
|
+
require 'parser/current'
|
5
|
+
|
6
|
+
module RDL
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rdl/config.rb'
|
10
|
+
def RDL.config
|
11
|
+
yield(RDL::Config.instance)
|
12
|
+
end
|
13
|
+
require 'rdl/info.rb'
|
14
|
+
|
15
|
+
# Method/variable info table with kinds:
|
16
|
+
# For methods
|
17
|
+
# :pre to array of precondition contracts
|
18
|
+
# :post to array of postcondition contracts
|
19
|
+
# :type to array of types
|
20
|
+
# :source_location to [filename, linenumber] location of most recent definition
|
21
|
+
# :typecheck - boolean that is true if method should be statically type checked
|
22
|
+
# :otype to set of types that were observed at run time, where a type is a finite hash {:args => Array<Class>, :ret => Class, :block => %bool}
|
23
|
+
# :context_types to array of [klass, meth, Type] - method types that exist only within this method. An icky hack to deal with Rails `params`.
|
24
|
+
# For variables
|
25
|
+
# :type to type
|
26
|
+
$__rdl_info = RDL::Info.new
|
27
|
+
|
28
|
+
# Map from full_method_name to number of times called when wrapped
|
29
|
+
$__rdl_wrapped_calls = Hash.new 0
|
30
|
+
|
31
|
+
# Hash from class name to array of symbols that are the class's type parameters
|
32
|
+
$__rdl_type_params = Hash.new
|
33
|
+
|
34
|
+
# Hash from class name to method name to its alias method name
|
35
|
+
# class names are strings
|
36
|
+
# method names are symbols
|
37
|
+
$__rdl_aliases = Hash.new
|
38
|
+
|
39
|
+
# Set of [class, method] pairs to wrap.
|
40
|
+
# class is a string
|
41
|
+
# method is a symbol
|
42
|
+
$__rdl_to_wrap = Set.new
|
43
|
+
|
44
|
+
# Map from symbols to set of [class, method] pairs to type check when those symbols are rdl_do_typecheck'd
|
45
|
+
# (or the methods are defined, for the symbol :now)
|
46
|
+
$__rdl_to_typecheck = Hash.new
|
47
|
+
$__rdl_to_typecheck[:now] = Set.new
|
48
|
+
|
49
|
+
# List of contracts that should be applied to the next method definition
|
50
|
+
$__rdl_deferred = []
|
51
|
+
|
52
|
+
# Create switches to control whether wrapping happens and whether
|
53
|
+
# contracts are checked. These need to be created before rdl/wrap.rb
|
54
|
+
# is loaded.
|
55
|
+
require 'rdl/switch.rb'
|
56
|
+
$__rdl_wrap_switch = RDL::Switch.new
|
57
|
+
$__rdl_contract_switch = RDL::Switch.new
|
58
|
+
|
59
|
+
require 'rdl/types/type.rb'
|
60
|
+
require 'rdl/types/annotated_arg.rb'
|
61
|
+
require 'rdl/types/bot.rb'
|
62
|
+
require 'rdl/types/dependent_arg.rb'
|
63
|
+
require 'rdl/types/dots_query.rb'
|
64
|
+
require 'rdl/types/finite_hash.rb'
|
65
|
+
require 'rdl/types/generic.rb'
|
66
|
+
require 'rdl/types/intersection.rb'
|
67
|
+
require 'rdl/types/lexer.rex.rb'
|
68
|
+
require 'rdl/types/method.rb'
|
69
|
+
require 'rdl/types/singleton.rb'
|
70
|
+
require 'rdl/types/nominal.rb'
|
71
|
+
require 'rdl/types/non_null.rb'
|
72
|
+
require 'rdl/types/optional.rb'
|
73
|
+
require 'rdl/types/parser.tab.rb'
|
74
|
+
require 'rdl/types/structural.rb'
|
75
|
+
require 'rdl/types/top.rb'
|
76
|
+
require 'rdl/types/tuple.rb'
|
77
|
+
require 'rdl/types/type_query.rb'
|
78
|
+
require 'rdl/types/union.rb'
|
79
|
+
require 'rdl/types/var.rb'
|
80
|
+
require 'rdl/types/vararg.rb'
|
81
|
+
require 'rdl/types/wild_query.rb'
|
82
|
+
|
83
|
+
require 'rdl/contracts/contract.rb'
|
84
|
+
require 'rdl/contracts/and.rb'
|
85
|
+
require 'rdl/contracts/flat.rb'
|
86
|
+
require 'rdl/contracts/or.rb'
|
87
|
+
require 'rdl/contracts/proc.rb'
|
88
|
+
|
89
|
+
require 'rdl/util.rb'
|
90
|
+
require 'rdl/wrap.rb'
|
91
|
+
require 'rdl/query.rb'
|
92
|
+
require 'rdl/typecheck.rb'
|
93
|
+
#require_relative 'rdl/stats.rb'
|
94
|
+
|
95
|
+
$__rdl_parser = RDL::Type::Parser.new
|
96
|
+
|
97
|
+
# Map from file names to [digest, cache] where 2nd elt maps
|
98
|
+
# :ast to the AST
|
99
|
+
# :line_defs maps linenumber to AST for def at that line
|
100
|
+
$__rdl_ruby_parser_cache = Hash.new
|
101
|
+
|
102
|
+
# Some generally useful types; not really a big deal to do this since
|
103
|
+
# NominalTypes are cached, but these names are shorter to type
|
104
|
+
$__rdl_nil_type = RDL::Type::NominalType.new NilClass # actually creates singleton type
|
105
|
+
$__rdl_top_type = RDL::Type::TopType.new
|
106
|
+
$__rdl_bot_type = RDL::Type::BotType.new
|
107
|
+
$__rdl_object_type = RDL::Type::NominalType.new Object
|
108
|
+
$__rdl_true_type = RDL::Type::NominalType.new TrueClass # actually creates singleton type
|
109
|
+
$__rdl_false_type = RDL::Type::NominalType.new FalseClass # also singleton type
|
110
|
+
$__rdl_bool_type = RDL::Type::UnionType.new($__rdl_true_type, $__rdl_false_type)
|
111
|
+
$__rdl_fixnum_type = RDL::Type::NominalType.new Fixnum
|
112
|
+
$__rdl_bignum_type = RDL::Type::NominalType.new Bignum
|
113
|
+
$__rdl_float_type = RDL::Type::NominalType.new Float
|
114
|
+
$__rdl_complex_type = RDL::Type::NominalType.new Complex
|
115
|
+
$__rdl_rational_type = RDL::Type::NominalType.new Rational
|
116
|
+
$__rdl_integer_type = RDL::Type::UnionType.new($__rdl_fixnum_type, $__rdl_bignum_type)
|
117
|
+
$__rdl_numeric_type = RDL::Type::NominalType.new Numeric
|
118
|
+
$__rdl_string_type = RDL::Type::NominalType.new String
|
119
|
+
$__rdl_array_type = RDL::Type::NominalType.new Array
|
120
|
+
$__rdl_hash_type = RDL::Type::NominalType.new Hash
|
121
|
+
$__rdl_symbol_type = RDL::Type::NominalType.new Symbol
|
122
|
+
$__rdl_range_type = RDL::Type::NominalType.new Range
|
123
|
+
$__rdl_regexp_type = RDL::Type::NominalType.new Regexp
|
124
|
+
$__rdl_standard_error_type = RDL::Type::NominalType.new StandardError
|
125
|
+
|
126
|
+
# Hash from special type names to their values
|
127
|
+
$__rdl_special_types = {'%any' => $__rdl_top_type,
|
128
|
+
'%bot' => $__rdl_bot_type,
|
129
|
+
'%bool' => $__rdl_bool_type}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
if Rails.env.development? || Rails.env.test?
|
2
|
+
require 'rdl/boot'
|
3
|
+
require 'types/core'
|
4
|
+
|
5
|
+
dir = Rails::VERSION::STRING.split('.')[0] + ".x"
|
6
|
+
require_relative "../types/rails-#{dir}/_helpers.rb" # load type aliases first
|
7
|
+
Dir[File.dirname(__FILE__) + "/../types/rails-#{dir}/**/*.rb"].each { |f| require f }
|
8
|
+
elsif Rails.env.production?
|
9
|
+
require 'rdl_disable'
|
10
|
+
def (ActionController::Base).params_type(typs); end
|
11
|
+
else
|
12
|
+
raise RuntimeError, "Don't know what to do in Rails environment #{Rails.env}"
|
13
|
+
end
|
data/lib/rdl/typecheck.rb
CHANGED
@@ -805,9 +805,6 @@ RUBY
|
|
805
805
|
when :lvar # local variable
|
806
806
|
error :undefined_local_or_method, [name], e unless env.has_key? name
|
807
807
|
capture(scope, name, env[name].canonical) if scope[:outer_env] && (scope[:outer_env].has_key? name) && (not (scope[:outer_env].fixed? name))
|
808
|
-
# if scope[:outer_env] && (scope[:outer_env].has_key? name) && (not (scope[:outer_env].fixed? name))
|
809
|
-
# error :nonlocal_access, [name], e
|
810
|
-
# end
|
811
808
|
if scope[:captured] && scope[:captured].has_key?(name) then
|
812
809
|
[env, scope[:captured][name]]
|
813
810
|
else
|
@@ -1114,6 +1111,7 @@ RUBY
|
|
1114
1111
|
# *always* included module's instance methods only
|
1115
1112
|
# if included, those methods are added to instance_methods
|
1116
1113
|
# if extended, those methods are added to singleton_methods
|
1114
|
+
# (except Kernel is special...)
|
1117
1115
|
def self.lookup(scope, klass, name, e)
|
1118
1116
|
if scope[:context_types]
|
1119
1117
|
# return array of all matching types from context_types, if any
|
@@ -1121,7 +1119,11 @@ RUBY
|
|
1121
1119
|
scope[:context_types].each { |ctk, ctm, ctt| ts << ctt if ctk.to_s == klass && ctm == name }
|
1122
1120
|
return ts unless ts.empty?
|
1123
1121
|
end
|
1124
|
-
|
1122
|
+
if scope[:context_types]
|
1123
|
+
scope[:context_types].each { |k, m, t|
|
1124
|
+
return t if k == klass && m = name
|
1125
|
+
}
|
1126
|
+
end
|
1125
1127
|
t = $__rdl_info.get_with_aliases(klass, name, :type)
|
1126
1128
|
return t if t # simplest case, no need to walk inheritance hierarchy
|
1127
1129
|
the_klass = RDL::Util.to_class(klass)
|
@@ -1141,7 +1143,10 @@ RUBY
|
|
1141
1143
|
return tancestor if tancestor
|
1142
1144
|
end
|
1143
1145
|
if ancestor.instance_methods(false).member?(name)
|
1144
|
-
|
1146
|
+
if RDL::Util.has_singleton_marker klass
|
1147
|
+
klass = RDL::Util.remove_singleton_marker klass
|
1148
|
+
klass = '(singleton) ' + klass
|
1149
|
+
end
|
1145
1150
|
error :missing_ancestor_type, [ancestor, klass, name], e
|
1146
1151
|
end
|
1147
1152
|
}
|
@@ -1162,18 +1167,17 @@ type_error_messages = {
|
|
1162
1167
|
inconsistent_var_type: "local variable `%s' has declared type on some paths but not all",
|
1163
1168
|
inconsistent_var_type_type: "local variable `%s' declared with inconsistent types %s",
|
1164
1169
|
no_each_type: "can't find `each' method with signature `() { (t1) -> t2 } -> t3' in class `%s'",
|
1165
|
-
tuple_finite_hash_promote: "can't promote
|
1170
|
+
tuple_finite_hash_promote: "can't promote `%s' to `%s'",
|
1166
1171
|
masgn_bad_rhs: "multiple assignment has right-hand side of type `%s' where tuple or array expected",
|
1167
1172
|
masgn_num: "can't multiple-assign %d values to %d variables",
|
1168
1173
|
masgn_bad_lhs: "no corresponding right-hand side elemnt for left-hand side assignee",
|
1169
|
-
kw_not_allowed: "can't use
|
1170
|
-
kw_arg_not_allowed: "argument to
|
1171
|
-
arg_count_mismatch: "
|
1172
|
-
nonlocal_access: "variable %s from outer scope must have type declared with var_type",
|
1174
|
+
kw_not_allowed: "can't use `%s' in current scope",
|
1175
|
+
kw_arg_not_allowed: "argument to `%s' not allowed in current scope",
|
1176
|
+
arg_count_mismatch: "`%s' signature expects %d arguments, actual `%s' has %d arguments",
|
1173
1177
|
no_block: "attempt to call yield in method not declared to take a block argument",
|
1174
1178
|
block_block: "can't call yield on a block expecting another block argument",
|
1175
1179
|
block_type_error: "argument type error for block\n%s",
|
1176
|
-
missing_ancestor_type: "ancestor
|
1180
|
+
missing_ancestor_type: "ancestor `%s' of `%s' has method `%s' but no type for it",
|
1177
1181
|
type_cast_format: "type_cast must be called as `type_cast type-string' or `type_cast type-string, force: expr'",
|
1178
1182
|
var_type_format: "var_type must be called as `var_type :var-name, type-string'",
|
1179
1183
|
puts_type_format: "puts_type must be called as `puts_type e'",
|
data/lib/rdl/types/method.rb
CHANGED
@@ -61,10 +61,10 @@ module RDL::Type
|
|
61
61
|
check_arg_preds(bind, preds) if preds.size > 0
|
62
62
|
@args.each_with_index {|a,i| args[i] = block_wrap(slf, inst, a, bind, &args[i]) if a.is_a? MethodType }
|
63
63
|
if @block then
|
64
|
-
|
64
|
+
next unless blk
|
65
65
|
blk = block_wrap(slf, inst, @block, bind, &blk)
|
66
66
|
elsif blk then
|
67
|
-
|
67
|
+
next
|
68
68
|
end
|
69
69
|
return [true, args, blk, bind]
|
70
70
|
end
|
data/lib/rdl/wrap.rb
CHANGED
@@ -537,6 +537,7 @@ class Object
|
|
537
537
|
|
538
538
|
# Type check all methods that had annotation `typecheck: sym' at type call
|
539
539
|
def rdl_do_typecheck(sym)
|
540
|
+
return unless $__rdl_to_typecheck[sym]
|
540
541
|
$__rdl_to_typecheck[sym].each { |klass, meth|
|
541
542
|
RDL::Typecheck.typecheck(klass, meth)
|
542
543
|
}
|
data/lib/rdl_disable.rb
CHANGED
@@ -18,6 +18,7 @@ class Object
|
|
18
18
|
def type_alias(*args); end
|
19
19
|
def rdl_do_typecheck(*args); end
|
20
20
|
def rdl_note_type(*args); end
|
21
|
+
def rdl_remove_type(*args); end
|
21
22
|
|
22
23
|
def attr_accessor_type(*args)
|
23
24
|
args.each_slice(2) { |name, typ| attr_accessor name }
|
@@ -35,7 +36,4 @@ class Object
|
|
35
36
|
args.each_slice(2) { |name, typ| attr_writer name }
|
36
37
|
nil
|
37
38
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
39
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# :integer, :bigint, :float, :decimal, :numeric, :datetime, :time, :date, :binary, :boolean.
|
2
|
+
# null allowed
|
3
|
+
|
4
|
+
module RDL
|
5
|
+
class Rails
|
6
|
+
|
7
|
+
# [+ rails_type +] is a Rails column type (:string, :integer, etc)
|
8
|
+
# returns a String containing an RDL type
|
9
|
+
def self.column_to_rdl(rails_type)
|
10
|
+
case rails_type
|
11
|
+
when :string, :text, :binary
|
12
|
+
return 'String'
|
13
|
+
when :integer
|
14
|
+
return 'Fixnum'
|
15
|
+
when :float
|
16
|
+
return 'Float'
|
17
|
+
when :decimal
|
18
|
+
return 'BigDecimal'
|
19
|
+
when :boolean
|
20
|
+
return '%bool'
|
21
|
+
when :date
|
22
|
+
return 'Date'
|
23
|
+
when :time
|
24
|
+
return 'Time'
|
25
|
+
when :datetime
|
26
|
+
return 'DateTime'
|
27
|
+
else
|
28
|
+
raise RuntimeError, "Unrecoganized column type #{rails_type}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActionController
|
2
|
+
module MimeResponds
|
3
|
+
type :respond_to, '(*(String or Symbol)) { (ActionController::MimeResponds::Collector) -> %any } -> Array<String> or String'
|
4
|
+
|
5
|
+
class Collector
|
6
|
+
Mime::EXTENSION_LOOKUP.each { |mime|
|
7
|
+
type :method_missing, "(#{mime[1].symbol.inspect}) { (ActionController::MimeResponds::Collector::VariantCollector) -> %any } -> %any"
|
8
|
+
}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# TODO: This is all a bit of a hack. Right now, ActionControll::Parameters has its [] method set appropriately during the context
|
2
|
+
# of the next method by params_types. But that doesn't quite match what actually happens in Rails.
|
3
|
+
|
4
|
+
class ActionController::Base
|
5
|
+
|
6
|
+
# [+ typ_hash +] is a Hash<Symbol, String>, where the keys are the parameter names and the Strings are the corresponding types
|
7
|
+
# adds these parameters to the `params` hash in the immediately following controller method
|
8
|
+
def self.params_type(typs)
|
9
|
+
# TODO: Ick, this is ugly. Once it's obvious how to generalize this kind of reasoning to other cases, clean this up!
|
10
|
+
typs.each_pair { |param, param_type|
|
11
|
+
param_type = $__rdl_parser.scan_str "#T #{param_type}"
|
12
|
+
meth_type = $__rdl_parser.scan_str "(#{param.inspect}) -> #{param_type}" # given singleton symbol arg, get param's return type
|
13
|
+
$__rdl_deferred << [self, :context_types, [ActionController::Parameters, :[], meth_type], class_check: self]
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ActionController
|
19
|
+
module StrongParameters
|
20
|
+
type :params, '() -> ActionController::Parameters'
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ModelSchema
|
3
|
+
module ClassMethods
|
4
|
+
post(:load_schema!) { |ret| # load_schema! doesn't return anything interesting
|
5
|
+
find_by_args = []
|
6
|
+
|
7
|
+
columns_hash.each { |name, col|
|
8
|
+
t = RDL::Rails.column_to_rdl(col.type)
|
9
|
+
if col.null
|
10
|
+
# may be null; show nullability in return type
|
11
|
+
type name, "() -> #{t} or nil" # getter
|
12
|
+
type "#{name}=", "(#{t}) -> #{t} or nil" # setter
|
13
|
+
type "write_attribute", "(:#{name}, #{t}) -> %bool"
|
14
|
+
type "update_attribute", "(:#{name}, #{t}) -> %bool"
|
15
|
+
type "update_column", "(:#{name}, #{t}) -> %bool"
|
16
|
+
find_by_args << "#{name}: ?#{t}"
|
17
|
+
else
|
18
|
+
# not null; can't truly check in type system but hint via the name
|
19
|
+
type name, "() -> !#{t}" # getter
|
20
|
+
type "#{name}=", "(!#{t}) -> !#{t}" # setter
|
21
|
+
type "write_attribute", "(:#{name}, !#{t}) -> %bool"
|
22
|
+
type "update_attribute", "(:#{name}, #{t}) -> %bool"
|
23
|
+
type "update_column", "(:#{name}, #{t}) -> %bool"
|
24
|
+
find_by_args << "#{name}: ?!#{t}"
|
25
|
+
end
|
26
|
+
}
|
27
|
+
hash_args = find_by_args.join(',')
|
28
|
+
type 'self.find_by', '(' + hash_args + ") -> #{self} or nil"
|
29
|
+
type 'self.find_by!', '(' + hash_args + ") -> #{self}"
|
30
|
+
type 'update', '(' + hash_args + ') -> %bool'
|
31
|
+
type 'update_columns', '(' + hash_args + ') -> %bool'
|
32
|
+
type 'attributes=', '(' + hash_args + ') -> %bool'
|
33
|
+
|
34
|
+
# If called with String arguments, can't check types as precisely
|
35
|
+
type 'write_attribute', '(String, %any) -> %bool'
|
36
|
+
type 'update_attribute', '(String, %any) -> %bool'
|
37
|
+
type 'update_column', '(String, %any) -> %bool'
|
38
|
+
true
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/rdl.gemspec
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'rdl'
|
7
|
-
s.version = '2.0.0.
|
8
|
-
s.date = '2016-08-
|
7
|
+
s.version = '2.0.0.rc4'
|
8
|
+
s.date = '2016-08-13'
|
9
9
|
s.summary = 'Ruby type and contract system'
|
10
10
|
s.description = <<-EOF
|
11
11
|
RDL is a gem that adds types and contracts to Ruby. RDL includes extensive
|
data/test/test_le.rb
CHANGED
data/test/test_lib_types.rb
CHANGED
data/test/test_type_contract.rb
CHANGED
@@ -264,4 +264,31 @@ class TestTypeContract < Minitest::Test
|
|
264
264
|
assert_raises(TypeError) { p8.call(43, x: "foo", y: "foo") }
|
265
265
|
assert_raises(TypeError) { p8.call(43, x: :foo, y: "foo", z: 44) }
|
266
266
|
end
|
267
|
+
|
268
|
+
type '() { () -> nil } -> nil'
|
269
|
+
def _test_with_block
|
270
|
+
nil
|
271
|
+
end
|
272
|
+
|
273
|
+
type '() -> nil'
|
274
|
+
def _test_without_block
|
275
|
+
nil
|
276
|
+
end
|
277
|
+
|
278
|
+
type '() -> nil'
|
279
|
+
type '() { () -> nil } -> nil'
|
280
|
+
def _test_with_without_block
|
281
|
+
nil
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_block
|
285
|
+
assert_nil(_test_with_block { nil })
|
286
|
+
assert_raises(TypeError) { _test_with_block }
|
287
|
+
|
288
|
+
assert_raises(TypeError) { _test_without_block { nil } }
|
289
|
+
assert_nil(_test_without_block)
|
290
|
+
|
291
|
+
assert_nil(_test_with_without_block)
|
292
|
+
assert_nil(_test_with_without_block { nil })
|
293
|
+
end
|
267
294
|
end
|
data/test/test_typecheck.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeffrey S. Foster
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2016-08-
|
15
|
+
date: 2016-08-13 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: parser
|
@@ -112,6 +112,8 @@ files:
|
|
112
112
|
- extras/type_tests/|.rb
|
113
113
|
- gemfiles/Gemfile.travis
|
114
114
|
- lib/rdl.rb
|
115
|
+
- lib/rdl/boot.rb
|
116
|
+
- lib/rdl/boot_rails.rb
|
115
117
|
- lib/rdl/config.rb
|
116
118
|
- lib/rdl/contracts/and.rb
|
117
119
|
- lib/rdl/contracts/contract.rb
|
@@ -151,7 +153,6 @@ files:
|
|
151
153
|
- lib/rdl/util.rb
|
152
154
|
- lib/rdl/wrap.rb
|
153
155
|
- lib/rdl_disable.rb
|
154
|
-
- lib/rdl_types.rb
|
155
156
|
- lib/types/core-ruby-2.x/_aliases.rb
|
156
157
|
- lib/types/core-ruby-2.x/abbrev.rb
|
157
158
|
- lib/types/core-ruby-2.x/array.rb
|
@@ -201,6 +202,12 @@ files:
|
|
201
202
|
- lib/types/core-ruby-2.x/uri.rb
|
202
203
|
- lib/types/core-ruby-2.x/yaml.rb
|
203
204
|
- lib/types/core.rb
|
205
|
+
- lib/types/rails-5.x/_helpers.rb
|
206
|
+
- lib/types/rails-5.x/action_controller/mime_responds.rb
|
207
|
+
- lib/types/rails-5.x/action_controller/strong_parameters.rb
|
208
|
+
- lib/types/rails-5.x/action_dispatch/routing.rb
|
209
|
+
- lib/types/rails-5.x/active_record/model_schema.rb
|
210
|
+
- lib/types/rails-5.x/fixnum.rb
|
204
211
|
- rdl.gemspec
|
205
212
|
- test/disabled_test_coverage.rb
|
206
213
|
- test/disabled_test_rdoc.rb
|
data/lib/rdl_types.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require_relative "types/core.rb"
|