typeprof 0.20.1 → 0.21.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -6
- data/lib/typeprof/analyzer.rb +53 -13
- data/lib/typeprof/block.rb +2 -1
- data/lib/typeprof/container-type.rb +3 -2
- data/lib/typeprof/export.rb +39 -4
- data/lib/typeprof/import.rb +33 -4
- data/lib/typeprof/insns-def.rb +2 -0
- data/lib/typeprof/iseq.rb +2 -2
- data/lib/typeprof/method.rb +25 -4
- data/lib/typeprof/type.rb +4 -4
- data/lib/typeprof/version.rb +1 -1
- data/typeprof.gemspec +2 -2
- data/vscode/package-lock.json +1069 -31
- data/vscode/package.json +3 -3
- data/vscode/src/extension.ts +31 -14
- metadata +4 -12
- data/doc/demo.md +0 -398
- data/doc/doc.ja.md +0 -424
- data/doc/doc.md +0 -437
- data/doc/ide.md +0 -81
- data/doc/ppl2019.pdf +0 -0
- data/doc/todo.md +0 -133
- data/doc/typeprof-for-ide-log.png +0 -0
- data/doc/typeprof-for-ide.png +0 -0
data/vscode/package.json
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
{
|
2
2
|
"name": "ruby-typeprof",
|
3
3
|
"displayName": "Ruby TypeProf",
|
4
|
-
"version": "0.20.
|
4
|
+
"version": "0.20.1",
|
5
5
|
"publisher": "mame",
|
6
6
|
"author": {
|
7
7
|
"name": "Yusuke Endoh"
|
8
8
|
},
|
9
9
|
"repository": {
|
10
10
|
"type": "git",
|
11
|
-
"url": "https://github.com/
|
11
|
+
"url": "https://github.com/ruby/typeprof/tree/master/vscode"
|
12
12
|
},
|
13
13
|
"license": "MIT",
|
14
14
|
"categories": [
|
@@ -62,7 +62,7 @@
|
|
62
62
|
"devDependencies": {
|
63
63
|
"@types/node": "^14.14.37",
|
64
64
|
"typescript": "^4.2.3",
|
65
|
-
"vsce": "^1.
|
65
|
+
"vsce": "^1.103.1",
|
66
66
|
"vscode": "^1.1.37"
|
67
67
|
},
|
68
68
|
"dependencies": {
|
data/vscode/src/extension.ts
CHANGED
@@ -88,6 +88,9 @@ function executeTypeProf(folder: vscode.WorkspaceFolder, arg: String): child_pro
|
|
88
88
|
if (shell && (shell.endsWith("bash") || shell.endsWith("zsh") || shell.endsWith("fish"))) {
|
89
89
|
typeprof = child_process.spawn(shell, ["-c", "-l", cmd], { cwd });
|
90
90
|
}
|
91
|
+
else if (process.platform === "win32") {
|
92
|
+
typeprof = child_process.spawn("C:\\Windows\\System32\\cmd.exe", ["/c", cmd], { cwd });
|
93
|
+
}
|
91
94
|
else {
|
92
95
|
typeprof = child_process.spawn(cmd, { cwd });
|
93
96
|
}
|
@@ -95,20 +98,30 @@ function executeTypeProf(folder: vscode.WorkspaceFolder, arg: String): child_pro
|
|
95
98
|
return typeprof;
|
96
99
|
}
|
97
100
|
|
98
|
-
function getTypeProfVersion(folder: vscode.WorkspaceFolder, callback: (version: string) => void): child_process.ChildProcessWithoutNullStreams {
|
101
|
+
function getTypeProfVersion(folder: vscode.WorkspaceFolder, outputChannel: vscode.OutputChannel, callback: (version: string) => void): child_process.ChildProcessWithoutNullStreams {
|
99
102
|
const typeprof = executeTypeProf(folder, "--version");
|
100
103
|
let output = "";
|
101
104
|
|
105
|
+
const log = (msg: string) => {
|
106
|
+
outputChannel.appendLine("[vscode] " + msg);
|
107
|
+
console.info(msg);
|
108
|
+
};
|
109
|
+
|
102
110
|
typeprof.stdout?.on("data", out => { output += out; });
|
103
|
-
typeprof.stderr?.on("data", out => {
|
111
|
+
typeprof.stderr?.on("data", (out: Buffer) => {
|
112
|
+
const str = ("" + out).trim();
|
113
|
+
for (const line of str.split("\n")) {
|
114
|
+
log("stderr: " + line);
|
115
|
+
}
|
116
|
+
});
|
104
117
|
typeprof.on("error", e => {
|
105
|
-
|
106
|
-
|
118
|
+
log(`typeprof is not supported for this folder: ${folder}`);
|
119
|
+
log(`because: ${e}`);
|
107
120
|
});
|
108
121
|
typeprof.on("exit", (code) => {
|
109
122
|
if (code == 0) {
|
110
|
-
console.info(`typeprof version: ${output}`)
|
111
123
|
const str = output.trim();
|
124
|
+
log(`typeprof version: ${str}`)
|
112
125
|
const version = /^typeprof (\d+).(\d+).(\d+)$/.exec(str);
|
113
126
|
if (version) {
|
114
127
|
const major = Number(version[1]);
|
@@ -118,15 +131,15 @@ function getTypeProfVersion(folder: vscode.WorkspaceFolder, callback: (version:
|
|
118
131
|
callback(str);
|
119
132
|
}
|
120
133
|
else {
|
121
|
-
|
134
|
+
log(`typeprof version ${str} is too old; please use 0.20.0 or later for IDE feature`);
|
122
135
|
}
|
123
136
|
}
|
124
137
|
else {
|
125
|
-
|
138
|
+
log(`typeprof --version showed unknown message`);
|
126
139
|
}
|
127
140
|
}
|
128
141
|
else {
|
129
|
-
|
142
|
+
log(`failed to invoke typeprof: error code ${code}`);
|
130
143
|
}
|
131
144
|
typeprof.kill()
|
132
145
|
});
|
@@ -164,7 +177,7 @@ function getTypeProfStream(folder: vscode.WorkspaceFolder, error: (msg: string)
|
|
164
177
|
});
|
165
178
|
}
|
166
179
|
|
167
|
-
function invokeTypeProf(folder: vscode.WorkspaceFolder): LanguageClient {
|
180
|
+
function invokeTypeProf(folder: vscode.WorkspaceFolder, outputChannel: vscode.OutputChannel): LanguageClient {
|
168
181
|
let client: LanguageClient;
|
169
182
|
|
170
183
|
const reportError = (msg: string) => client.info(msg);
|
@@ -185,6 +198,7 @@ function invokeTypeProf(folder: vscode.WorkspaceFolder): LanguageClient {
|
|
185
198
|
{ scheme: "file", language: "ruby" },
|
186
199
|
{ scheme: "file", language: "rbs" },
|
187
200
|
],
|
201
|
+
outputChannel,
|
188
202
|
synchronize: {
|
189
203
|
fileEvents:
|
190
204
|
vscode.workspace.createFileSystemWatcher("{**/*.rb,**/*.rbs}"),
|
@@ -199,17 +213,21 @@ function invokeTypeProf(folder: vscode.WorkspaceFolder): LanguageClient {
|
|
199
213
|
const clientSessions: Map<vscode.WorkspaceFolder, State> = new Map();
|
200
214
|
|
201
215
|
function startTypeProf(folder: vscode.WorkspaceFolder) {
|
202
|
-
const
|
203
|
-
|
216
|
+
const outputChannel = vscode.window.createOutputChannel("Ruby TypeProf");
|
217
|
+
const showStatus = (msg: string) => {
|
218
|
+
outputChannel.appendLine("[vscode] " + msg);
|
219
|
+
vscode.window.setStatusBarMessage(msg, 3000);
|
220
|
+
}
|
221
|
+
outputChannel.appendLine("[vscode] Try to start TypeProf for IDE");
|
204
222
|
|
205
|
-
const typeprof = getTypeProfVersion(folder, (version) => {
|
223
|
+
const typeprof = getTypeProfVersion(folder, outputChannel, (version) => {
|
206
224
|
if (!version) {
|
207
225
|
showStatus(`Ruby TypeProf is not configured; Try to add "gem 'typeprof'" to Gemfile`);
|
208
226
|
clientSessions.delete(folder);
|
209
227
|
return;
|
210
228
|
}
|
211
229
|
showStatus(`Starting Ruby TypeProf (${version})...`);
|
212
|
-
const client = invokeTypeProf(folder);
|
230
|
+
const client = invokeTypeProf(folder, outputChannel);
|
213
231
|
client.onReady()
|
214
232
|
.then(() => {
|
215
233
|
showStatus("Ruby TypeProf is running");
|
@@ -225,7 +243,6 @@ function startTypeProf(folder: vscode.WorkspaceFolder) {
|
|
225
243
|
}
|
226
244
|
|
227
245
|
function stopTypeProf(state: State) {
|
228
|
-
console.log(`stop: ${state.workspaceFolder}`);
|
229
246
|
switch (state.kind) {
|
230
247
|
case "invoking":
|
231
248
|
state.process.kill();
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typeprof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yusuke Endoh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.8.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.8.1
|
27
27
|
description: |
|
28
28
|
TypeProf performs a type analysis of non-annotated Ruby code.
|
29
29
|
|
@@ -44,14 +44,6 @@ files:
|
|
44
44
|
- LICENSE
|
45
45
|
- README.md
|
46
46
|
- Rakefile
|
47
|
-
- doc/demo.md
|
48
|
-
- doc/doc.ja.md
|
49
|
-
- doc/doc.md
|
50
|
-
- doc/ide.md
|
51
|
-
- doc/ppl2019.pdf
|
52
|
-
- doc/todo.md
|
53
|
-
- doc/typeprof-for-ide-log.png
|
54
|
-
- doc/typeprof-for-ide.png
|
55
47
|
- exe/typeprof
|
56
48
|
- lib/typeprof.rb
|
57
49
|
- lib/typeprof/analyzer.rb
|
data/doc/demo.md
DELETED
@@ -1,398 +0,0 @@
|
|
1
|
-
# TypeProf demo cases
|
2
|
-
|
3
|
-
## A simple demo with a "User" class
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
def hello_message(user)
|
7
|
-
"The name is " + user.name
|
8
|
-
end
|
9
|
-
|
10
|
-
def type_error_demo(user)
|
11
|
-
"The age is " + user.age
|
12
|
-
end
|
13
|
-
|
14
|
-
user = User.new(name: "John", age: 20)
|
15
|
-
|
16
|
-
hello_message(user)
|
17
|
-
type_error_demo(user)
|
18
|
-
```
|
19
|
-
|
20
|
-
```ruby
|
21
|
-
class User
|
22
|
-
attr_reader name: String
|
23
|
-
attr_reader age: Integer
|
24
|
-
|
25
|
-
def initialize: (name: String, age: Integer) -> void
|
26
|
-
end
|
27
|
-
```
|
28
|
-
|
29
|
-
Result:
|
30
|
-
```
|
31
|
-
$ typeprof test.rb test.rbs
|
32
|
-
# Errors
|
33
|
-
test.rb:6: [error] failed to resolve overload: String#+
|
34
|
-
|
35
|
-
# Classes
|
36
|
-
class Object
|
37
|
-
def hello_message : (User) -> String
|
38
|
-
def type_error_demo : (User) -> untyped
|
39
|
-
end
|
40
|
-
```
|
41
|
-
|
42
|
-
You can [try this analysis online](https://mame.github.io/typeprof-playground/#rb=def+hello_message%28user%29%0A++%22The+name+is+%22+%2B+user.name%0Aend%0A%0Adef+type_error_demo%28user%29%0A++%22The+age+is+%22+%2B+user.age%0Aend%0A%0Auser+%3D+User.new%28name%3A+%22John%22%2C+age%3A+20%29%0A%0Ahello_message%28user%29%0Atype_error_demo%28user%29&rbs=class+User%0A++attr_reader+name%3A+String%0A++attr_reader+age%3A+Integer%0A%0A++def+initialize%3A+%28name%3A+String%2C+age%3A+Integer%29+-%3E+void%0Aend).
|
43
|
-
|
44
|
-
## A simple demo to generate the signature prototype of "User" class
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
class User
|
48
|
-
def initialize(name:, age:)
|
49
|
-
@name, @age = name, age
|
50
|
-
end
|
51
|
-
attr_reader :name, :age
|
52
|
-
end
|
53
|
-
|
54
|
-
# A test case to tell TypeProf what types are expected by the class and methods
|
55
|
-
User.new(name: "John", age: 20)
|
56
|
-
```
|
57
|
-
|
58
|
-
Result:
|
59
|
-
```
|
60
|
-
$ typeprof -v test.rb
|
61
|
-
# Classes
|
62
|
-
class User
|
63
|
-
attr_reader name : String
|
64
|
-
attr_reader age : Integer
|
65
|
-
def initialize : (name: String, age: Integer) -> [String, Integer]
|
66
|
-
end
|
67
|
-
```
|
68
|
-
|
69
|
-
## Type inspection by `p` (`Kernel#p`)
|
70
|
-
|
71
|
-
```ruby
|
72
|
-
p 42 #=> Integer
|
73
|
-
p "str" #=> String
|
74
|
-
p "str".chars #=> Array[String]
|
75
|
-
```
|
76
|
-
|
77
|
-
Result:
|
78
|
-
```
|
79
|
-
$ typeprof test.rb
|
80
|
-
# Revealed types
|
81
|
-
# test.rb:1 #=> Integer
|
82
|
-
# test.rb:2 #=> String
|
83
|
-
# test.rb:3 #=> Array[String]
|
84
|
-
```
|
85
|
-
|
86
|
-
## Block with builtin methods
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
# TypeProf runs this block only once
|
90
|
-
10000000000000.times do |n|
|
91
|
-
p n #=> Integer
|
92
|
-
end
|
93
|
-
|
94
|
-
# "each" with Heterogeneous array yields a union type
|
95
|
-
[1, 1.0, "str"].each do |e|
|
96
|
-
p e #=> Float | Integer | String
|
97
|
-
end
|
98
|
-
|
99
|
-
# You can use the idiom `&:method_name` too
|
100
|
-
p [1, 1.0, "str"].map(&:to_s) #=> Array[String]
|
101
|
-
```
|
102
|
-
|
103
|
-
## User-defined blocks
|
104
|
-
|
105
|
-
```ruby
|
106
|
-
def foo(n)
|
107
|
-
yield n.to_s
|
108
|
-
end
|
109
|
-
|
110
|
-
foo(42) do |n|
|
111
|
-
p n #=> String
|
112
|
-
nil
|
113
|
-
end
|
114
|
-
```
|
115
|
-
|
116
|
-
Result:
|
117
|
-
```
|
118
|
-
$ typeprof test.rb
|
119
|
-
# Revealed types
|
120
|
-
# test.rb:6 #=> String
|
121
|
-
|
122
|
-
# Classes
|
123
|
-
class Object
|
124
|
-
def foo : (Integer) { (String) -> nil } -> nil
|
125
|
-
end
|
126
|
-
```
|
127
|
-
|
128
|
-
## Arrays
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
# A fixed-length array literal generates a "tuple" array
|
132
|
-
ary = [1, 1.0]
|
133
|
-
|
134
|
-
# A tuple array keeps its length, and the association between indexes and elements
|
135
|
-
p ary #=> [Integer, Float]
|
136
|
-
p ary[0] #=> Integer
|
137
|
-
p ary[1] #=> Float
|
138
|
-
|
139
|
-
# Destructive operation is well handled (in method-local analysis)
|
140
|
-
ary[0] = "str"
|
141
|
-
p ary #=> [String, Float]
|
142
|
-
|
143
|
-
# An calculated array generates a "sequence" array
|
144
|
-
ary = [1] + [1.0]
|
145
|
-
|
146
|
-
# A sequence array does not keep length nor association
|
147
|
-
p ary #=> Array[Float | Integer]
|
148
|
-
p ary[0] #=> Float | Integer
|
149
|
-
|
150
|
-
# Destructive operation is still handled (but "weak update" is applied)
|
151
|
-
ary[0] = "str"
|
152
|
-
p ary #=> Array[Float | Integer | String]
|
153
|
-
```
|
154
|
-
|
155
|
-
## Multiple return values by using a tuple array
|
156
|
-
|
157
|
-
```ruby
|
158
|
-
def foo
|
159
|
-
return 42, "str"
|
160
|
-
end
|
161
|
-
|
162
|
-
int, str = foo
|
163
|
-
p int #=> Integer
|
164
|
-
p str #=> String
|
165
|
-
```
|
166
|
-
|
167
|
-
## Delegation by using a tuple array
|
168
|
-
|
169
|
-
```ruby
|
170
|
-
def foo(x, y, z)
|
171
|
-
end
|
172
|
-
|
173
|
-
def proxy(dummy, *args)
|
174
|
-
foo(*args)
|
175
|
-
end
|
176
|
-
|
177
|
-
proxy(:dummy, 1, 1.0, "str")
|
178
|
-
```
|
179
|
-
|
180
|
-
## Symbols
|
181
|
-
|
182
|
-
```ruby
|
183
|
-
# Symbols are handled as concrete values instead of abstract ones
|
184
|
-
p [:a, :b, :c] #=> [:a, :b, :c]
|
185
|
-
```
|
186
|
-
|
187
|
-
## Hashes
|
188
|
-
|
189
|
-
```ruby
|
190
|
-
# A Hash is a "type-to-type" map
|
191
|
-
h = { "int" => 1, "float" => 1.0 }
|
192
|
-
p h #=> {String=>Float | Integer}
|
193
|
-
p h["int"] #=> Float | Integer
|
194
|
-
|
195
|
-
# Symbol-key hashes (a.k.a. records) can have distinct types for each key as Symbols are concrete
|
196
|
-
h = { int: 1, float: 1.0 }
|
197
|
-
|
198
|
-
p h #=> {:int=>Integer, :float=>Float}
|
199
|
-
p h[:int] #=> Integer
|
200
|
-
p h[:float] #=> Float
|
201
|
-
|
202
|
-
# Symbol-key hash can be appropriately passed to a keyword method
|
203
|
-
def foo(int:, float:)
|
204
|
-
p [int, float] #=> [Integer, Float]
|
205
|
-
end
|
206
|
-
|
207
|
-
foo(**h)
|
208
|
-
```
|
209
|
-
|
210
|
-
## Structs
|
211
|
-
|
212
|
-
```ruby
|
213
|
-
FooBar = Struct.new(:foo, :bar)
|
214
|
-
|
215
|
-
obj = FooBar.new(42)
|
216
|
-
obj.foo = :dummy
|
217
|
-
obj.bar = "str"
|
218
|
-
```
|
219
|
-
|
220
|
-
Result:
|
221
|
-
```
|
222
|
-
$ typeprof test.rb
|
223
|
-
# Classes
|
224
|
-
class FooBar < Struct
|
225
|
-
attr_accessor foo() : :dummy | Integer
|
226
|
-
attr_accessor bar() : String?
|
227
|
-
end
|
228
|
-
```
|
229
|
-
|
230
|
-
## Exceptions
|
231
|
-
|
232
|
-
```ruby
|
233
|
-
# TypeProf assumes that any exception may be raised anywhere
|
234
|
-
def foo
|
235
|
-
x = 1
|
236
|
-
x = "str"
|
237
|
-
x = :sym
|
238
|
-
ensure
|
239
|
-
p(x) #=> :sym | Integer | String
|
240
|
-
end
|
241
|
-
```
|
242
|
-
|
243
|
-
Result:
|
244
|
-
```
|
245
|
-
$ typeprof test.rb
|
246
|
-
# Revealed types
|
247
|
-
# test.rb:6 #=> :sym | Integer | String
|
248
|
-
|
249
|
-
# Classes
|
250
|
-
class Object
|
251
|
-
def foo : -> :sym
|
252
|
-
end
|
253
|
-
```
|
254
|
-
|
255
|
-
## RBS overloaded methods
|
256
|
-
|
257
|
-
```ruby
|
258
|
-
# TypeProf selects all overloaded method declarations that matches actual arguments
|
259
|
-
p foo(42) #=> Integer
|
260
|
-
p foo("str") #=> String
|
261
|
-
p foo(1.0) #=> failed to resolve overload: Object#foo
|
262
|
-
```
|
263
|
-
|
264
|
-
```
|
265
|
-
class Object
|
266
|
-
def foo: (Integer) -> Integer
|
267
|
-
| (String) -> String
|
268
|
-
end
|
269
|
-
```
|
270
|
-
|
271
|
-
## Flow-sensitive analysis demo: case/when with class constants
|
272
|
-
|
273
|
-
```ruby
|
274
|
-
def foo(n)
|
275
|
-
case n
|
276
|
-
when Integer
|
277
|
-
p n #=> Integer
|
278
|
-
when String
|
279
|
-
p n #=> String
|
280
|
-
else
|
281
|
-
p n #=> Float
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
foo(42)
|
286
|
-
foo(1.0)
|
287
|
-
foo("str")
|
288
|
-
```
|
289
|
-
|
290
|
-
Result:
|
291
|
-
```
|
292
|
-
$ typeprof test.rb
|
293
|
-
# Revealed types
|
294
|
-
# test.rb:4 #=> Integer
|
295
|
-
# test.rb:8 #=> Float
|
296
|
-
# test.rb:6 #=> String
|
297
|
-
|
298
|
-
# Classes
|
299
|
-
class Object
|
300
|
-
def foo : (Float | Integer | String) -> (Float | Integer | String)
|
301
|
-
end
|
302
|
-
```
|
303
|
-
|
304
|
-
## Flow-sensitive analysis demo: `is_a?` and `respond_to?`
|
305
|
-
|
306
|
-
```ruby
|
307
|
-
def foo(n)
|
308
|
-
if n.is_a?(Integer)
|
309
|
-
p n #=> Integer
|
310
|
-
else
|
311
|
-
p n #=> Float | String
|
312
|
-
end
|
313
|
-
|
314
|
-
if n.respond_to?(:times)
|
315
|
-
p n #=> Integer
|
316
|
-
else
|
317
|
-
p n #=> Float | String
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
foo(42)
|
322
|
-
foo(1.0)
|
323
|
-
foo("str")
|
324
|
-
```
|
325
|
-
|
326
|
-
## Flow-sensitive analysis demo: `x || y`
|
327
|
-
|
328
|
-
```ruby
|
329
|
-
# ENV["FOO"] returns String? (which means String | nil)
|
330
|
-
p ENV["FOO"] #=> String?
|
331
|
-
|
332
|
-
# Using "|| (default value)" can force it to be non-nil
|
333
|
-
p ENV["FOO"] || "default" #=> String
|
334
|
-
```
|
335
|
-
|
336
|
-
## Recursion
|
337
|
-
|
338
|
-
```ruby
|
339
|
-
def fib(x)
|
340
|
-
if x <= 1
|
341
|
-
x
|
342
|
-
else
|
343
|
-
fib(x - 1) + fib(x - 2)
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
fib(40000)
|
348
|
-
```
|
349
|
-
|
350
|
-
Result:
|
351
|
-
```
|
352
|
-
$ typeprof test.rb
|
353
|
-
# Classes
|
354
|
-
class Object
|
355
|
-
def fib : (Integer) -> Integer
|
356
|
-
end
|
357
|
-
```
|
358
|
-
|
359
|
-
## "Stub-execution" that invokes methods without tests
|
360
|
-
|
361
|
-
```ruby
|
362
|
-
def foo(n)
|
363
|
-
# bar is invoked with Integer arguments
|
364
|
-
bar(42)
|
365
|
-
n
|
366
|
-
end
|
367
|
-
|
368
|
-
def bar(n)
|
369
|
-
n
|
370
|
-
end
|
371
|
-
|
372
|
-
# As there is no test code to call methods foo and bar,
|
373
|
-
# TypeProf tries to invoke them with "untyped" arguments
|
374
|
-
```
|
375
|
-
|
376
|
-
Result:
|
377
|
-
```
|
378
|
-
$ typeprof test.rb
|
379
|
-
# Classes
|
380
|
-
class Object
|
381
|
-
def foo : (untyped) -> untyped
|
382
|
-
def bar : (Integer) -> Integer
|
383
|
-
end
|
384
|
-
```
|
385
|
-
|
386
|
-
## Library demo
|
387
|
-
|
388
|
-
```ruby
|
389
|
-
require "pathname"
|
390
|
-
|
391
|
-
p Pathname("foo") #=> Pathname
|
392
|
-
p Pathname("foo").dirname #=> Pathname
|
393
|
-
p Pathname("foo").ctime #=> Time
|
394
|
-
```
|
395
|
-
|
396
|
-
## More
|
397
|
-
|
398
|
-
See ruby/typeprof's [smoke](https://github.com/ruby/typeprof/tree/master/smoke) directory.
|