fast_method_source 0.3.0 → 0.3.1
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/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;
|