fast_method_source 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +102 -70
- data/VERSION +1 -1
- data/ext/fast_method_source/fast_method_source.c +29 -16
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d73c77ef828261b4ad145f88bd1d78682133b215
|
4
|
+
data.tar.gz: 3fa8f4dc7471bd3e2b78f6c479bc795d38972f13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d3ab1de1d9a55e1c681e684c85cbc92f349e77927cbfb0999ce59419c35a6120d588286133399e0484ff60258fb4313f02145de33a0f71419db504b98f24054
|
7
|
+
data.tar.gz: 4426e0c403f8de0b80bed5264cd91495a06d5468ba73912b5b5a4511ef0a4942915c7d1b19f7a64bb67d2e65d055922a6c1a6d4f298b53fff8ab3ca5f094c871
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,33 @@
|
|
1
|
+
<a name="Back_to_top">
|
1
2
|
# Fast Method Source
|
2
3
|
|
3
4
|
* Repository: [https://github.com/kyrylo/fast_method_source/][repo]
|
4
5
|
|
6
|
+
Table of Contents
|
7
|
+
-----------------
|
8
|
+
|
9
|
+
* <a href="#description">Description</a>
|
10
|
+
* <a href="#installation">Installation</a>
|
11
|
+
* <a href="#synopsis">Synopsis</a>
|
12
|
+
* <a href="#speed-improvements">Speed Improvements</a>
|
13
|
+
* <a href="#source">#source</a>
|
14
|
+
* <a href="#comment">#comment</a>
|
15
|
+
* <a href="#source-and-comment">#source_and_comment</a>
|
16
|
+
* <a href="#correctness-of-output">Correctness Of Output</a>
|
17
|
+
* <a href="#ram-consumption">RAM Consumption</a>
|
18
|
+
* <a href="#api">API</a>
|
19
|
+
* <a href="#method-information">Method Information</a>
|
20
|
+
* <a href="#fastmethodsourcesource_formethod">FastMethodSource#source_for(method)</a>
|
21
|
+
* <a href="#fastmethodsourcecomment_formethod">FastMethodSource#comment_for(method)</a>
|
22
|
+
* <a href="#fastmethodsourcecomment_and_source_formethod">FastMethodSource#comment_and_source_for(method)</a>
|
23
|
+
* <a href="#limitations">Limitations</a>
|
24
|
+
* <a href="#rubies">Rubies</a>
|
25
|
+
* <a href="#operation-systems">Operation Systems</a>
|
26
|
+
* <a href="#roadmap">Roadmap</a>
|
27
|
+
* <a href="#further-speed-improvements">Further Speed Improvements</a>
|
28
|
+
* <a href="#optional-memoization">Optional Memoization</a>
|
29
|
+
* <a href="#licence">Licence</a>
|
30
|
+
|
5
31
|
Description
|
6
32
|
-----------
|
7
33
|
|
@@ -10,7 +36,7 @@ their source code and comments.
|
|
10
36
|
|
11
37
|
```ruby
|
12
38
|
require 'fast_method_source'
|
13
|
-
require 'fast_method_source/core_ext'
|
39
|
+
require 'fast_method_source/core_ext' # Adds #source to UnboundMethod
|
14
40
|
require 'set'
|
15
41
|
|
16
42
|
puts Set.instance_method(:merge).source
|
@@ -40,73 +66,78 @@ All you need is to install the gem.
|
|
40
66
|
Synopsis
|
41
67
|
--------
|
42
68
|
|
43
|
-
Fast Method Source provides similar
|
44
|
-
|
45
|
-
|
46
|
-
|
69
|
+
Fast Method Source provides functionality similar to [method_source][ms], which
|
70
|
+
powers [Pry](https://github.com/pry/pry)'s `show-source`, `show-comment` and
|
71
|
+
`find-method` commands, but with a number of key differences that are listed
|
72
|
+
below.
|
47
73
|
|
48
|
-
|
49
|
-
library is much faster than method_source. What's acceptable for Pry, when you
|
50
|
-
query only one method, is not acceptable for other use cases such as querying
|
51
|
-
all the methods defined in your Ruby process. The benchmark showed that Fast
|
52
|
-
Method Source is about 5-10x faster than its competitor.
|
74
|
+
### Speed Improvements
|
53
75
|
|
54
|
-
|
55
|
-
|
76
|
+
The main goal of Fast Method Source is to retrieve information as fast as
|
77
|
+
possible. In result, the library is extremely fast and is capable of quering
|
78
|
+
thousands of methods in a couple of seconds. The benchmarks included in this
|
79
|
+
repository show that Fast Method Source outpaces method_source in every aspect
|
80
|
+
by far. The results from those benchmarks below show the comparison of these
|
81
|
+
libraries.
|
56
82
|
|
57
|
-
#### #
|
83
|
+
#### #source
|
58
84
|
##### ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
|
59
85
|
|
60
|
-
|
86
|
+
The speed boost of method_source after the rehearsal that can be observed in
|
87
|
+
this benchmark comes from the fact that it uses memoization. Fast Method Source
|
88
|
+
does not support it at the moment.
|
61
89
|
|
62
90
|
```
|
63
91
|
Processor: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
|
64
92
|
Platform: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
|
65
93
|
Counting the number of sample methods...
|
66
|
-
Sample methods:
|
67
|
-
|
68
|
-
FastMethodSource#
|
94
|
+
Sample methods: 18970
|
95
|
+
Rehearsal -----------------------------------------------------------
|
96
|
+
FastMethodSource#source 6.340000 0.460000 6.800000 ( 7.616361)
|
97
|
+
MethodSource#source 86.030000 0.500000 86.530000 (104.094356)
|
98
|
+
------------------------------------------------- total: 93.330000sec
|
99
|
+
|
100
|
+
user system total real
|
101
|
+
FastMethodSource#source 6.830000 0.590000 7.420000 ( 8.258469)
|
102
|
+
MethodSource#source 80.470000 0.310000 80.780000 ( 89.864366)
|
69
103
|
```
|
70
104
|
|
71
|
-
#### #
|
105
|
+
#### #comment
|
72
106
|
##### ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
|
73
107
|
|
74
108
|
```
|
75
109
|
Processor: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
|
76
110
|
Platform: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
|
77
111
|
Counting the number of sample methods...
|
78
|
-
Sample methods:
|
79
|
-
Rehearsal
|
80
|
-
FastMethodSource#
|
81
|
-
MethodSource#
|
82
|
-
|
112
|
+
Sample methods: 19596
|
113
|
+
Rehearsal ------------------------------------------------------------
|
114
|
+
FastMethodSource#comment 1.820000 0.240000 2.060000 ( 2.300117)
|
115
|
+
MethodSource#comment 77.020000 0.360000 77.380000 ( 94.672830)
|
116
|
+
-------------------------------------------------- total: 79.440000sec
|
83
117
|
|
84
|
-
|
85
|
-
FastMethodSource#
|
86
|
-
MethodSource#
|
118
|
+
user system total real
|
119
|
+
FastMethodSource#comment 1.570000 0.230000 1.800000 ( 1.997811)
|
120
|
+
MethodSource#comment 71.410000 0.160000 71.570000 ( 79.657388)
|
87
121
|
```
|
88
122
|
|
89
|
-
#### #
|
123
|
+
#### #comment_and_source
|
90
124
|
##### ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
|
91
125
|
|
126
|
+
This is a convenience method, and method_source doesn't have it.
|
127
|
+
|
92
128
|
```
|
129
|
+
Processor: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
|
93
130
|
Platform: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
|
94
131
|
Counting the number of sample methods...
|
95
|
-
Sample methods:
|
96
|
-
|
97
|
-
FastMethodSource#
|
98
|
-
MethodSource#comment 85.020000 0.370000 85.390000 (103.061652)
|
99
|
-
-------------------------------------------------- total: 87.390000sec
|
100
|
-
|
101
|
-
user system total real
|
102
|
-
FastMethodSource#comment 1.620000 0.250000 1.870000 ( 2.072023)
|
103
|
-
MethodSource#comment 84.560000 0.320000 84.880000 ( 94.465574)
|
132
|
+
Sample methods: 18970
|
133
|
+
user system total real
|
134
|
+
FastMethodSource#comment_and_source_for 8.240000 0.750000 8.990000 ( 10.036892)
|
104
135
|
```
|
105
136
|
|
106
|
-
### Correctness
|
137
|
+
### Correctness Of Output
|
107
138
|
|
108
139
|
Fast Method Source is capable of displaying source code even for dynamically
|
109
|
-
defined methods
|
140
|
+
defined methods.
|
110
141
|
|
111
142
|
```ruby
|
112
143
|
require 'fast_method_source'
|
@@ -126,38 +157,39 @@ Output.
|
|
126
157
|
end
|
127
158
|
```
|
128
159
|
|
129
|
-
|
160
|
+
That said, you need to be cautious, because sometimes it's not working as
|
161
|
+
expected. Feel free to file issues.
|
162
|
+
|
163
|
+
### RAM Consumption
|
130
164
|
|
131
165
|
The [`comment_and_source`](/benchmarks/comment_and_source_for.rb) benchmark
|
132
|
-
shows that
|
166
|
+
shows that the library uses about 80-140 MB of RES RAM for computing information
|
167
|
+
for 19K methods.
|
133
168
|
|
134
169
|
API
|
135
170
|
---
|
136
171
|
|
137
|
-
### General description
|
138
|
-
|
139
172
|
The library provides the following methods: `#comment`, `#source` and
|
140
|
-
`#comment_and_source`. There are two ways to use Fast Method Source.
|
141
|
-
|
173
|
+
`#comment_and_source`. There are two ways to use Fast Method Source.
|
174
|
+
|
175
|
+
One way is to monkey-patch relevant core Ruby classes and use the methods
|
176
|
+
directly.
|
142
177
|
|
143
178
|
```ruby
|
144
179
|
require 'fast_method_source'
|
145
|
-
require 'fast_method_source/core_ext'
|
180
|
+
require 'fast_method_source/core_ext' # <= monkey-patches
|
146
181
|
|
147
|
-
#
|
148
|
-
Set.instance_method(:merge).source
|
149
|
-
#=> " def merge(enum)\n..."
|
182
|
+
# Monkey-patch of UnboundMethod
|
183
|
+
Set.instance_method(:merge).source #=> " def merge(enum)\n..."
|
150
184
|
|
151
|
-
#
|
152
|
-
Set.method(:[]).source
|
153
|
-
#=> " def self.[](*ary)\n..."
|
185
|
+
# Monkey-patch of Method
|
186
|
+
Set.method(:[]).source #=> " def self.[](*ary)\n..."
|
154
187
|
|
155
|
-
#
|
188
|
+
# Monkey-patch of Proc (or lambda)
|
156
189
|
myproc = proc { |arg|
|
157
190
|
arg + 1
|
158
191
|
}
|
159
|
-
myproc.source
|
160
|
-
#=> "myproc = proc { |arg|\n..."
|
192
|
+
myproc.source #=> "myproc = proc { |arg|\n..."
|
161
193
|
```
|
162
194
|
|
163
195
|
The other way is by using these methods defined on the library's class directly.
|
@@ -166,22 +198,19 @@ The other way is by using these methods defined on the library's class directly.
|
|
166
198
|
require 'fast_method_source'
|
167
199
|
|
168
200
|
# With UnboundMethod
|
169
|
-
FastMethodSource.source_for(Set.instance_method(:merge))
|
170
|
-
#=> " def merge(enum)\n..."
|
201
|
+
FastMethodSource.source_for(Set.instance_method(:merge)) #=> " def merge(enum)\n..."
|
171
202
|
|
172
203
|
# With Method
|
173
|
-
FastMethodSource.source_for(Set.method(:[]))
|
174
|
-
#=> " def self.[](*ary)\n..."
|
204
|
+
FastMethodSource.source_for(Set.method(:[])) #=> " def self.[](*ary)\n..."
|
175
205
|
|
176
206
|
# With Proc (or lambda)
|
177
207
|
myproc = proc { |arg|
|
178
208
|
arg + 1
|
179
209
|
}
|
180
|
-
FastMethodSource.source_for(myproc)
|
181
|
-
#=> "myproc = proc { |arg|\n..."
|
210
|
+
FastMethodSource.source_for(myproc) #=> "myproc = proc { |arg|\n..."
|
182
211
|
```
|
183
212
|
|
184
|
-
###
|
213
|
+
### Method Information
|
185
214
|
|
186
215
|
#### FastMethodSource#source_for(method)
|
187
216
|
|
@@ -224,7 +253,7 @@ Limitations
|
|
224
253
|
Rubies below 2.2.2 were not tested, so in theory if it quacks like Ruby 2, it
|
225
254
|
may work.
|
226
255
|
|
227
|
-
###
|
256
|
+
### Operation Systems
|
228
257
|
|
229
258
|
* GNU/Linux
|
230
259
|
* Mac OS (hopefully)
|
@@ -232,19 +261,22 @@ may work.
|
|
232
261
|
Roadmap
|
233
262
|
-------
|
234
263
|
|
235
|
-
### Further
|
264
|
+
### Further Speed Improvements
|
236
265
|
|
237
266
|
Although Fast Method Source is faster than any of its competitors, it's still
|
238
|
-
very slow. On average, a mature Rails 4 application has at least 45K
|
239
|
-
|
240
|
-
|
267
|
+
very slow. On average, a mature Rails 4 application has at least 45K
|
268
|
+
methods. The goal of the project is to be able to query 50K methods in less than
|
269
|
+
15 seconds.
|
241
270
|
|
242
|
-
|
243
|
-
seconds. Whether it's possible or not is to be determined.
|
271
|
+
### Optional Memoization
|
244
272
|
|
245
|
-
|
273
|
+
I'm not sure about this, if it's really needed, but it will speed up further
|
274
|
+
queries greatly (at the cost of RAM). At this moment I think if I add it, it
|
275
|
+
should be optional and configurable like this:
|
246
276
|
|
247
|
-
|
277
|
+
```ruby
|
278
|
+
FastMethodSource.memoization = true # or `false`
|
279
|
+
```
|
248
280
|
|
249
281
|
Licence
|
250
282
|
-------
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
@@ -42,6 +42,7 @@ static VALUE find_method_source(struct method_data *data);
|
|
42
42
|
static NODE *parse_expr(VALUE rb_str);
|
43
43
|
static NODE *parse_with_silenced_stderr(VALUE rb_str);
|
44
44
|
static void filter_interp(char *line);
|
45
|
+
static int contains_skippables(const char *line);
|
45
46
|
static int contains_end_kw(const char *line);
|
46
47
|
static int is_comment(const char *line, const size_t line_len);
|
47
48
|
static int is_static_definition(const char *line);
|
@@ -121,7 +122,8 @@ read_lines(finder finder, struct method_data *data)
|
|
121
122
|
}
|
122
123
|
strncat(expression, current_line, cl_len);
|
123
124
|
|
124
|
-
if (current_line[0] == '\n'
|
125
|
+
if (current_line[0] == '\n' ||
|
126
|
+
is_comment(current_line, cl_len))
|
125
127
|
continue;
|
126
128
|
|
127
129
|
if (line_count == data->method_location) {
|
@@ -130,9 +132,6 @@ read_lines(finder finder, struct method_data *data)
|
|
130
132
|
}
|
131
133
|
}
|
132
134
|
|
133
|
-
if (is_comment(current_line, cl_len))
|
134
|
-
continue;
|
135
|
-
|
136
135
|
if (is_dangling_literal_end(current_line)) {
|
137
136
|
dangling_literal = 0;
|
138
137
|
} else if (is_dangling_literal_begin(current_line)) {
|
@@ -149,6 +148,9 @@ read_lines(finder finder, struct method_data *data)
|
|
149
148
|
}
|
150
149
|
strncat(parse_expression, current_line, cl_len);
|
151
150
|
|
151
|
+
if (contains_skippables(current_line))
|
152
|
+
continue;
|
153
|
+
|
152
154
|
if (should_parse || contains_end_kw(current_line)) {
|
153
155
|
if (parse_expr(rb_str_new2(parse_expression)) != NULL) {
|
154
156
|
found_expression = 1;
|
@@ -209,7 +211,6 @@ parse_with_silenced_stderr(VALUE rb_str)
|
|
209
211
|
|
210
212
|
volatile VALUE vparser = rb_parser_new();
|
211
213
|
NODE *node = rb_parser_compile_string(vparser, "-", rb_str, 1);
|
212
|
-
rb_str_free(rb_str);
|
213
214
|
rb_set_errinfo(last_exception);
|
214
215
|
|
215
216
|
fflush(stderr);
|
@@ -255,6 +256,28 @@ filter_interp(char *line)
|
|
255
256
|
}
|
256
257
|
}
|
257
258
|
|
259
|
+
static int
|
260
|
+
contains_skippables(const char *line)
|
261
|
+
{
|
262
|
+
|
263
|
+
static unsigned short len = 57;
|
264
|
+
static const char *skippables[57] = {
|
265
|
+
" if ", " else ", " then ", " case ", " for ", " in ", " loop ",
|
266
|
+
" unless ", "||", "||=", "&&", " and ", " or ", " do ", " not ",
|
267
|
+
" while ", " = ", " == ", " === ", " > ", " < ", " >= ", " <= ",
|
268
|
+
" << ", " += ", "\"", "'", ":", ",", ".", " % ", "!", "?",
|
269
|
+
" until ", "(&", "|", "(", ")", "~", " * ", " - ", " + ", " / ",
|
270
|
+
" {", " raise ", " fail ", " begin ", " rescue ", " ensure ",
|
271
|
+
".new", "@", " lambda", " proc", " ->", "[", "]", "$"};
|
272
|
+
|
273
|
+
for (unsigned short i = 0; i < len; i++) {
|
274
|
+
if (strstr(line, skippables[i]) != NULL)
|
275
|
+
return 1;
|
276
|
+
}
|
277
|
+
|
278
|
+
return 0;
|
279
|
+
}
|
280
|
+
|
258
281
|
static int
|
259
282
|
contains_end_kw(const char *line)
|
260
283
|
{
|
@@ -283,17 +306,7 @@ is_comment(const char *line, const size_t line_len)
|
|
283
306
|
for (size_t i = 0; i < line_len; i++) {
|
284
307
|
if (line[i] == ' ')
|
285
308
|
continue;
|
286
|
-
|
287
|
-
if (line[i] == '#' && line[i + 1] != '{') {
|
288
|
-
for (size_t j = i - 1; j != 0; j--) {
|
289
|
-
if (line[j] != ' ')
|
290
|
-
return 0;
|
291
|
-
}
|
292
|
-
|
293
|
-
return 1;
|
294
|
-
} else {
|
295
|
-
return 0;
|
296
|
-
}
|
309
|
+
return line[i] == '#' && line[i + 1] != '{';
|
297
310
|
}
|
298
311
|
|
299
312
|
return 0;
|