rdl 2.0.0.rc3 → 2.0.0.rc4
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 +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"
|