ffast 0.1.6 → 0.1.7
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/Fastfile +3 -0
- data/README.md +1 -0
- data/docs/command_line.md +1 -0
- data/docs/editors-integration.md +46 -0
- data/docs/shortcuts.md +288 -0
- data/docs/videos.md +12 -0
- data/fast.gemspec +1 -0
- data/lib/fast.rb +44 -22
- data/lib/fast/cli.rb +35 -16
- data/lib/fast/shortcut.rb +1 -1
- data/lib/fast/version.rb +1 -1
- data/mkdocs.yml +3 -0
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1ae41b9a66311eb3308fd3ca3f69f5a06943a337f9907d502f1a2ed27342a46
|
4
|
+
data.tar.gz: 80e545ae2769ab27ba39d8338b57c60626ca3f79ec5e73139c12f3cb01dfd5fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbcb874fb1c2916d0fa89d687fd9e320f248c8cc64c5193244b8d007b39cffb86b23db2ff7c3134c4d43baba1d4d99b6526831a20b3c630867691d5076ae33bc
|
7
|
+
data.tar.gz: de6c3a1e706f6a3e39791a413584dc227af3ee8810628145b0844d9b4d2ac1f9d7f631c9db859a7cb6d8c7f56313b3f0aff2be4b9868627c31ece3924e79379c
|
data/Fastfile
CHANGED
@@ -8,6 +8,9 @@
|
|
8
8
|
# Let's say you'd like to show the version that is over the version file
|
9
9
|
Fast.shortcut(:version, '(casgn nil VERSION (str _))', 'lib/fast/version.rb')
|
10
10
|
|
11
|
+
# Show all classes that inherits Fast::Find
|
12
|
+
Fast.shortcut(:finders, '(class ... (const nil Find)', 'lib')
|
13
|
+
|
11
14
|
# You can run shortcuts appending a dot to the shortcut.
|
12
15
|
# $ fast .version
|
13
16
|
# # lib/fast/version.rb:4
|
data/README.md
CHANGED
@@ -421,6 +421,7 @@ The CLI tool takes the following flags
|
|
421
421
|
- Use `--pry` to jump debugging the first result with pry
|
422
422
|
- Use `-c` to search from code example
|
423
423
|
- Use `-s` to search similar code
|
424
|
+
- Use `-p` or `--parallel` to parallelize the search
|
424
425
|
|
425
426
|
### Define your `Fastfile`
|
426
427
|
|
data/docs/command_line.md
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Editors' integration
|
2
|
+
|
3
|
+
We don't have any proper integration or official plugins for editors yet.
|
4
|
+
|
5
|
+
Here are a few ideas you can use to make your own flow.
|
6
|
+
|
7
|
+
## Vim
|
8
|
+
|
9
|
+
Split terminal vertically and open fast focused on build the expression.
|
10
|
+
|
11
|
+
```vim
|
12
|
+
nnoremap <Leader>ff :vsplit \| terminal fast "()" % <Left><Left><Left><Left><Left>
|
13
|
+
```
|
14
|
+
|
15
|
+
Or you can build a function:
|
16
|
+
|
17
|
+
```vim
|
18
|
+
function! s:Fast(args)
|
19
|
+
let cmd = ''
|
20
|
+
if !empty(b:ruby_project_root)
|
21
|
+
let cmd .= 'cd ' . b:ruby_project_root . ' && '
|
22
|
+
endif
|
23
|
+
|
24
|
+
let cmd .= 'fast --no-color ' . a:args
|
25
|
+
|
26
|
+
let custom_maker = neomake#utils#MakerFromCommand(cmd)
|
27
|
+
let custom_maker.name = cmd
|
28
|
+
let custom_maker.cwd = b:ruby_project_root
|
29
|
+
let custom_maker.remove_invalid_entries = 0
|
30
|
+
" e.g.:
|
31
|
+
" # path/to/file.rb:1141
|
32
|
+
" my_method(
|
33
|
+
" :boom,
|
34
|
+
" arg1: 1,
|
35
|
+
" )
|
36
|
+
" %W# %f:%l -> start a multiline warning when the line matches '# path/file.rb:1234'
|
37
|
+
" %-Z# end multiline warning on the next line that starts with '#'
|
38
|
+
" %C%m continued multiline warning message
|
39
|
+
let custom_maker.errorformat = '%W# %f:%l, %-Z#, %C%m'
|
40
|
+
let enabled_makers = [custom_maker]
|
41
|
+
update | call neomake#Make(0, enabled_makers) | echom "running: " . cmd
|
42
|
+
endfunction
|
43
|
+
command! -complete=file -nargs=1 Fast call s:Fast(<q-args>)
|
44
|
+
```
|
45
|
+
|
46
|
+
Check the conversation about vim integration [here](https://github.com/jonatas/fast/pull/16#issuecomment-555115606).
|
data/docs/shortcuts.md
ADDED
@@ -0,0 +1,288 @@
|
|
1
|
+
# Shortcuts
|
2
|
+
|
3
|
+
Shortcuts are defined on a `Fastfile` inside any ruby project.
|
4
|
+
|
5
|
+
!!!info "Use `~/Fastfile`"
|
6
|
+
You can also add one extra in your `$HOME` if you want to have something loaded always.
|
7
|
+
|
8
|
+
By default, the command line interface does not load any `Fastfile` if the
|
9
|
+
first param is not a shortcut. It should start with `.`.
|
10
|
+
|
11
|
+
I'm building several researches and I'll make the examples open here to show
|
12
|
+
several interesting cases in action.
|
13
|
+
|
14
|
+
## Rails: Show validations from models
|
15
|
+
|
16
|
+
If the shortcut does not define a block, it works as a holder for arguments from
|
17
|
+
the command line.
|
18
|
+
|
19
|
+
Let's say you always use `fast "(send nil {validate validates})" app/models` to
|
20
|
+
check validations in the models. You can define a shortcut to hold the args and
|
21
|
+
avoid retyping long lines:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# Show validations from app/models
|
25
|
+
Fast.shortcut(:validations, "(send nil {validate validates})", "app/models")
|
26
|
+
```
|
27
|
+
And you can reuse the search with the shortcut starting with a `.`:
|
28
|
+
|
29
|
+
```
|
30
|
+
fast .validations
|
31
|
+
```
|
32
|
+
And it will also accept params if you want to filter a specific file:
|
33
|
+
|
34
|
+
```
|
35
|
+
fast .validations app/models/user.rb
|
36
|
+
```
|
37
|
+
|
38
|
+
!!! info "Note that you can also use flags in the command line shortcuts"
|
39
|
+
|
40
|
+
Let's say you also want to use `fast --headless` you can add it to the params:
|
41
|
+
|
42
|
+
> Fast.shortcut(:validations, "(send nil {validate validates})", "app/models", "--headless")
|
43
|
+
|
44
|
+
## Automated Refactor: Bump version
|
45
|
+
|
46
|
+
Let's start with a [real usage](https://github.com/jonatas/fast/blob/master/Fastfile#L20-L34)
|
47
|
+
to bump a new version of the gem.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
Fast.shortcut :bump_version do
|
51
|
+
rewrite_file('(casgn nil VERSION (str _)', 'lib/fast/version.rb') do |node|
|
52
|
+
target = node.children.last.loc.expression
|
53
|
+
pieces = target.source.split('.').map(&:to_i)
|
54
|
+
pieces.reverse.each_with_index do |fragment, i|
|
55
|
+
if fragment < 9
|
56
|
+
pieces[-(i + 1)] = fragment + 1
|
57
|
+
break
|
58
|
+
else
|
59
|
+
pieces[-(i + 1)] = 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
replace(target, "'#{pieces.join('.')}'")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
And then the change is done in the `lib/fast/version.rb`:
|
68
|
+
|
69
|
+
```diff
|
70
|
+
module Fast
|
71
|
+
- VERSION = '0.1.6'
|
72
|
+
+ VERSION = '0.1.7'
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
## List Shortcuts
|
77
|
+
|
78
|
+
As the interface is very rudimentar, let's build a shortcut to print what
|
79
|
+
shortcuts are available. This is a good one to your `$HOME/Fastfile`:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# List all shortcut with comments
|
83
|
+
Fast.shortcut :shortcuts do
|
84
|
+
fast_files.each do |file|
|
85
|
+
lines = File.readlines(file).map{|line|line.chomp.gsub(/\s*#/,'').strip}
|
86
|
+
result = capture_file('(send ... shortcut $(sym _', file)
|
87
|
+
result = [result] unless result.is_a?Array
|
88
|
+
result.each do |capture|
|
89
|
+
target = capture.loc.expression
|
90
|
+
puts "fast .#{target.source[1..-1].ljust(30)} # #{lines[target.line-2]}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
And using it on `fast` project that loads both `~/Fastfile` and the Fastfile from the project:
|
97
|
+
|
98
|
+
```
|
99
|
+
fast .version # Let's say you'd like to show the version that is over the version file
|
100
|
+
fast .parser # Simple shortcut that I used often to show how the expression parser works
|
101
|
+
fast .bump_version # Use `fast .bump_version` to rewrite the version file
|
102
|
+
fast .shortcuts # List all shortcut with comments
|
103
|
+
```
|
104
|
+
|
105
|
+
## RSpec: Find unused shared contexts
|
106
|
+
|
107
|
+
If you build shared contexts often, probably you can forget some left overs.
|
108
|
+
|
109
|
+
The objective of the shortcut is find leftovers from shared contexts.
|
110
|
+
|
111
|
+
First, the objective is capture all names of the `RSpec.shared_context` or
|
112
|
+
`shared_context` declared in the `spec/support` folder.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
Fast.capture_all('(block (send {nil,_} shared_context (str $_)))', Fast.ruby_files_from('spec/support'))
|
116
|
+
```
|
117
|
+
|
118
|
+
Then, we need to check all the specs and search for `include_context` usages to
|
119
|
+
confirm if all defined contexts are being used:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
specs = Fast.ruby_files_from('spec').select{|f|f !~ %r{spec/support/}}
|
123
|
+
Fast.search_all("(send nil include_context (str #register_usage)", specs)
|
124
|
+
```
|
125
|
+
|
126
|
+
Note that we created a new reference to `#register_usage` and we need to define the method too:
|
127
|
+
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
@used = []
|
131
|
+
def register_usage context_name
|
132
|
+
@used << context_name
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
Wrapping up everything in a shortcut:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
# Show unused shared contexts
|
140
|
+
Fast.shortcut(:unused_shared_contexts) do
|
141
|
+
puts "Checking shared contexts"
|
142
|
+
Kernel.class_eval do
|
143
|
+
@used = []
|
144
|
+
def register_usage context_name
|
145
|
+
@used << context_name
|
146
|
+
end
|
147
|
+
def show_report! defined_contexts
|
148
|
+
unused = defined_contexts.values.flatten - @used
|
149
|
+
if unused.any?
|
150
|
+
puts "Unused shared contexts", unused
|
151
|
+
else
|
152
|
+
puts "Good job! all the #{defined_contexts.size} contexts are used!"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
specs = ruby_files_from('spec/').select{|f|f !~ %r{spec/support/}}
|
157
|
+
search_all("(send nil include_context (str #register_usage)", specs)
|
158
|
+
defined_contexts = capture_all('(block (send {nil,_} shared_context (str $_)))', ruby_files_from('spec'))
|
159
|
+
Kernel.public_send(:show_report!, defined_contexts)
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
!!! faq "Why `#register_usage` is defined on the `Kernel`?"
|
164
|
+
Yes! note that the `#register_usage` was forced to be inside `Kernel`
|
165
|
+
because of the `shortcut` block that takes the `Fast` context to be easy
|
166
|
+
to access in the default functions. As I can define multiple shortcuts
|
167
|
+
I don't want to polute my Kernel module with other methods that are not useful.
|
168
|
+
|
169
|
+
|
170
|
+
## RSpec: Remove unused let
|
171
|
+
|
172
|
+
!!! hint "First shortcut with experiments"
|
173
|
+
If you're not familiar with automated experiments, you can read about it [here](/experiments).
|
174
|
+
|
175
|
+
The current scenario is similar in terms of search with the previous one, but more advanced
|
176
|
+
because we're going to introduce automated refactoring.
|
177
|
+
|
178
|
+
The idea is simple, if it finds a `let` in a RSpec scenario that is not referenced, it tries to experimentally remove the `let` and run the tests:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
# Experimental remove `let` that are not referenced in the spec
|
182
|
+
Fast.shortcut(:exp_remove_let) do
|
183
|
+
require 'fast/experiment'
|
184
|
+
Kernel.class_eval do
|
185
|
+
file = ARGV.last
|
186
|
+
|
187
|
+
defined_lets = Fast.capture_file('(block (send nil let (sym $_)))', file).uniq
|
188
|
+
@unreferenced= defined_lets.select do |identifier|
|
189
|
+
Fast.search_file("(send nil #{identifier})", file).empty?
|
190
|
+
end
|
191
|
+
|
192
|
+
def unreferenced_let?(identifier)
|
193
|
+
@unreferenced.include? identifier
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
experiment('RSpec/RemoveUnreferencedLet') do
|
198
|
+
lookup ARGV.last
|
199
|
+
search '(block (send nil let (sym #unreferenced_let?)))'
|
200
|
+
edit { |node| remove(node.loc.expression) }
|
201
|
+
policy { |new_file| system("bundle exec rspec --fail-fast #{new_file}") }
|
202
|
+
end.run
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
206
|
+
And it will run with a single file from command line:
|
207
|
+
|
208
|
+
```
|
209
|
+
fast .exp_remove_let spec/my_file_spec.rb
|
210
|
+
```
|
211
|
+
|
212
|
+
## FactoryBot: Replace `create` with `build_stubbed`
|
213
|
+
|
214
|
+
For performance reasons, if we can avoid touching the database the test will
|
215
|
+
always be faster.
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# Experimental switch from `create` to `build_stubbed`
|
219
|
+
Fast.shortcut(:exp_build_stubbed) do
|
220
|
+
require 'fast/experiment'
|
221
|
+
Fast.experiment('FactoryBot/UseBuildStubbed') do
|
222
|
+
lookup ARGV.last
|
223
|
+
search '(send nil create)'
|
224
|
+
edit { |node| replace(node.loc.selector, 'build_stubbed') }
|
225
|
+
policy { |new_file| system("bundle exec rspec --fail-fast #{new_file}") }
|
226
|
+
end.run
|
227
|
+
end
|
228
|
+
```
|
229
|
+
## RSpec: Use `let_it_be` instead of `let`
|
230
|
+
|
231
|
+
The `let_it_be` is a simple helper from
|
232
|
+
[TestProf](https://test-prof.evilmartians.io/#/let_it_be) gem that can speed up
|
233
|
+
the specs by caching some factories using like a `before_all` approach.
|
234
|
+
|
235
|
+
This experiment hunts for `let(...) { create(...) }` and switch the `let` to
|
236
|
+
`let_it_be`:
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
# Experimental replace `let(_)` with `let_it_be` case it calls `create` inside the block
|
240
|
+
Fast.shortcut(:exp_let_it_be) do
|
241
|
+
require 'fast/experiment'
|
242
|
+
Fast.experiment('FactoryBot/LetItBe') do
|
243
|
+
lookup ARGV.last
|
244
|
+
search '(block (send nil let (sym _)) (args) (send nil create))'
|
245
|
+
edit { |node| replace(node.children.first.loc.selector, 'let_it_be') }
|
246
|
+
policy { |new_file| system("bin/spring rspec --fail-fast #{new_file}") }
|
247
|
+
end.run
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
## RSpec: Remove `before` or `after` blocks
|
252
|
+
|
253
|
+
From time to time, we forget some left overs like `before` or `after` blocks
|
254
|
+
that even removing from the code, the tests still passes. This experiment
|
255
|
+
removes the before/after blocks and check if the test passes.
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
# Experimental remove `before` or `after` blocks.
|
259
|
+
Fast.shortcut(:exp_remove_before_after) do
|
260
|
+
require 'fast/experiment'
|
261
|
+
Fast.experiment('RSpec/RemoveBeforeAfter') do
|
262
|
+
lookup ARGV.last
|
263
|
+
search '(block (send nil {before after}))'
|
264
|
+
edit { |node| remove(node.loc.expression) }
|
265
|
+
policy { |new_file| system("bin/spring rspec --fail-fast #{new_file}") }
|
266
|
+
end.run
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
## RSpec: Show message chains
|
271
|
+
|
272
|
+
I often forget the syntax and need to search for message chains on specs, so I
|
273
|
+
created an shortcut for it.
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
# Show RSpec message chains
|
277
|
+
Fast.shortcut(:message_chains, '^^(send nil receive_message_chain)', 'spec')
|
278
|
+
```
|
279
|
+
|
280
|
+
## RSpec: Show nested assertions
|
281
|
+
|
282
|
+
I love to use nested assertions and I often need examples to refer to them:
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
# Show RSpec nested assertions with .and
|
286
|
+
Fast.shortcut(:nested_assertions, '^^(send ... and)', 'spec')
|
287
|
+
```
|
288
|
+
|
data/docs/videos.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Videos
|
2
|
+
|
3
|
+
- Grepping Ruby code like a boss: [RubyConf Brazil 2019 (Portuguese)](https://www.eventials.com/locaweb/jonatas-paganini-live-coding-grepping-ruby-code-like-a-boss/#_=_)
|
4
|
+
|
5
|
+
- Introduction to [inline code](https://www.youtube.com/watch?v=KQXglNLUv7o).
|
6
|
+
<iframe width="560" height="315" src="https://www.youtube.com/embed/KQXglNLUv7o" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
7
|
+
|
8
|
+
- [Making local variables inline](https://www.youtube.com/watch?v=JD44nhegCRs)
|
9
|
+
<iframe width="560" height="315" src="https://www.youtube.com/embed/YN0s9kV1A2A" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
10
|
+
|
11
|
+
- [Making methods inline](https://www.youtube.com/watch?v=JD44nhegCRs)
|
12
|
+
<iframe width="560" height="315" src="https://www.youtube.com/embed/YN0s9kV1A2A" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
data/fast.gemspec
CHANGED
data/lib/fast.rb
CHANGED
@@ -108,25 +108,50 @@ module Fast
|
|
108
108
|
# @param [String] pattern
|
109
109
|
# @param [Array<String>] *locations where to search. Default is '.'
|
110
110
|
# @return [Hash<String,Array<Astrolabe::Node>>] with files and results
|
111
|
-
def search_all(pattern, locations = ['.'])
|
112
|
-
|
113
|
-
|
111
|
+
def search_all(pattern, locations = ['.'], parallel: true, on_result: nil)
|
112
|
+
group_results(build_grouped_search(:search_file, pattern, on_result),
|
113
|
+
locations, parallel: parallel)
|
114
114
|
end
|
115
115
|
|
116
116
|
# Capture with pattern on a directory or multiple files
|
117
117
|
# @param [String] pattern
|
118
118
|
# @param [Array<String>] locations where to search. Default is '.'
|
119
119
|
# @return [Hash<String,Object>] with files and captures
|
120
|
-
def capture_all(pattern, locations = ['.'])
|
121
|
-
|
122
|
-
|
120
|
+
def capture_all(pattern, locations = ['.'], parallel: true, on_result: nil)
|
121
|
+
group_results(build_grouped_search(:capture_file, pattern, on_result),
|
122
|
+
locations, parallel: parallel)
|
123
|
+
end
|
124
|
+
|
125
|
+
# @return [Proc] binding `pattern` argument from a given `method_name`.
|
126
|
+
# @param [Symbol] method_name with `:capture_file` or `:search_file`
|
127
|
+
# @param [String] pattern to match in a search to any file
|
128
|
+
# @param [Proc] on_result is a callback that can be notified soon it matches
|
129
|
+
def build_grouped_search(method_name, pattern, on_result)
|
130
|
+
search_pattern = method(method_name).curry.call(pattern)
|
131
|
+
proc do |file|
|
132
|
+
results = search_pattern.call(file)
|
133
|
+
next if results.nil? || results.empty?
|
134
|
+
|
135
|
+
on_result&.(file, results)
|
136
|
+
{ file => results }
|
137
|
+
end
|
123
138
|
end
|
124
139
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
140
|
+
# Compact grouped results by file allowing parallel processing.
|
141
|
+
# @param [Proc] group_files allows to define a search that can be executed
|
142
|
+
# parallel or not.
|
143
|
+
# @param [Proc] on_result allows to define a callback for fast feedback
|
144
|
+
# while it process several locations in parallel.
|
145
|
+
# @param [Boolean] parallel runs the `group_files` in parallel
|
146
|
+
# @return [Hash[String, Array]] with files and results
|
147
|
+
def group_results(group_files, locations, parallel: true)
|
148
|
+
files = ruby_files_from(*locations)
|
149
|
+
if parallel
|
150
|
+
require 'parallel' unless defined?(Parallel)
|
151
|
+
Parallel.map(files, &group_files)
|
152
|
+
else
|
153
|
+
files.map(&group_files)
|
154
|
+
end.compact.inject(&:merge!)
|
130
155
|
end
|
131
156
|
|
132
157
|
# Capture elements from searches in files. Keep in mind you need to use `$`
|
@@ -154,19 +179,16 @@ module Fast
|
|
154
179
|
end
|
155
180
|
end
|
156
181
|
|
157
|
-
#
|
182
|
+
# Only captures from a search
|
158
183
|
# @return [Array<Object>] with all captured elements.
|
159
|
-
# @return [Object] with single element when single capture.
|
160
184
|
def capture(pattern, node)
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
res = [res] unless res.is_a?(Array)
|
169
|
-
res.one? ? res.first : res
|
185
|
+
if (match = match?(pattern, node))
|
186
|
+
match == true ? node : match
|
187
|
+
else
|
188
|
+
node.each_child_node
|
189
|
+
.flat_map { |child| capture(pattern, child) }
|
190
|
+
.compact.flatten
|
191
|
+
end
|
170
192
|
end
|
171
193
|
|
172
194
|
def expression(string)
|
data/lib/fast/cli.rb
CHANGED
@@ -69,6 +69,10 @@ module Fast
|
|
69
69
|
@show_sexp = true
|
70
70
|
end
|
71
71
|
|
72
|
+
opts.on('-p', '--parallel', 'Paralelize search') do
|
73
|
+
@parallel = true
|
74
|
+
end
|
75
|
+
|
72
76
|
opts.on('--captures', 'Print only captures of the patterns and skip node results') do
|
73
77
|
@captures = true
|
74
78
|
end
|
@@ -129,6 +133,8 @@ module Fast
|
|
129
133
|
|
130
134
|
# Show help or search for node patterns
|
131
135
|
def run!
|
136
|
+
raise 'pry and parallel options are incompatible :(' if @parallel && @pry
|
137
|
+
|
132
138
|
if @help || @files.empty? && @pattern.nil?
|
133
139
|
puts option_parser.help
|
134
140
|
else
|
@@ -137,6 +143,7 @@ module Fast
|
|
137
143
|
end
|
138
144
|
|
139
145
|
# Create fast expression from node pattern using the command line
|
146
|
+
# @return [Array<Fast::Find>] with the expression from string.
|
140
147
|
def expression
|
141
148
|
Fast.expression(@pattern)
|
142
149
|
end
|
@@ -146,24 +153,29 @@ module Fast
|
|
146
153
|
# If capture option is enabled it will only print the captures, otherwise it
|
147
154
|
# prints all the results.
|
148
155
|
def search
|
149
|
-
if debug_mode?
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
report(result, file)
|
156
|
-
end
|
156
|
+
return Fast.debug(&method(:execute_search)) if debug_mode?
|
157
|
+
|
158
|
+
execute_search do |file, results|
|
159
|
+
results.each do |result|
|
160
|
+
binding.pry if @pry # rubocop:disable Lint/Debugger
|
161
|
+
report(file, result)
|
157
162
|
end
|
158
163
|
end
|
159
164
|
end
|
160
165
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
166
|
+
# Executes search for all files yielding the results
|
167
|
+
# @yieldparam [String, Array] with file and respective search results
|
168
|
+
def execute_search(&on_result)
|
169
|
+
Fast.public_send(search_method_name,
|
170
|
+
expression,
|
171
|
+
@files,
|
172
|
+
parallel: parallel?,
|
173
|
+
on_result: on_result)
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Symbol] with `:capture_all` or `:search_all` depending the command line options
|
177
|
+
def search_method_name
|
178
|
+
@captures ? :capture_all : :search_all
|
167
179
|
end
|
168
180
|
|
169
181
|
# @return [Boolean] true when "-d" or "--debug" option is passed
|
@@ -176,9 +188,13 @@ module Fast
|
|
176
188
|
puts(info) if debug_mode?
|
177
189
|
end
|
178
190
|
|
191
|
+
def parallel?
|
192
|
+
@parallel == true
|
193
|
+
end
|
194
|
+
|
179
195
|
# Report results using the actual options binded from command line.
|
180
196
|
# @see Fast.report
|
181
|
-
def report(
|
197
|
+
def report(file, result)
|
182
198
|
Fast.report(result, file: file, show_sexp: @show_sexp, headless: @headless, colorize: @colorize)
|
183
199
|
end
|
184
200
|
|
@@ -198,7 +214,10 @@ module Fast
|
|
198
214
|
# Prints available shortcuts as extra help and exit with code 1.
|
199
215
|
def exit_shortcut_not_found(name)
|
200
216
|
puts "Shortcut \033[1m#{name}\033[0m not found :("
|
201
|
-
|
217
|
+
if Fast.shortcuts.any?
|
218
|
+
puts "Available shortcuts are: #{Fast.shortcuts.keys.join(', ')}."
|
219
|
+
Fast.load_fast_files!
|
220
|
+
end
|
202
221
|
exit 1
|
203
222
|
end
|
204
223
|
end
|
data/lib/fast/shortcut.rb
CHANGED
@@ -66,7 +66,7 @@ module Fast
|
|
66
66
|
# the options from previous alias and replacing the files with the
|
67
67
|
# @param [Array] extra_args
|
68
68
|
def merge_args(extra_args)
|
69
|
-
[params[0], *options, *extra_args]
|
69
|
+
[params[0], *options, *extra_args.select(&File.method(:exists?))]
|
70
70
|
end
|
71
71
|
|
72
72
|
# If the shortcut was defined with a single block and no extra arguments, it
|
data/lib/fast/version.rb
CHANGED
data/mkdocs.yml
CHANGED
@@ -18,5 +18,8 @@ nav:
|
|
18
18
|
- Syntax: syntax.md
|
19
19
|
- Command Line: command_line.md
|
20
20
|
- Experiments: experiments.md
|
21
|
+
- Shortcuts: shortcuts.md
|
21
22
|
- Code Similarity: similarity_tutorial.md
|
22
23
|
- Pry Integration: pry-integration.md
|
24
|
+
- Editors' Integration: editors-integration.md
|
25
|
+
- Videos: videos.md
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jônatas Davi Paganini
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: astrolabe
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: parallel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: parser
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -247,11 +261,14 @@ files:
|
|
247
261
|
- bin/fast-experiment
|
248
262
|
- bin/setup
|
249
263
|
- docs/command_line.md
|
264
|
+
- docs/editors-integration.md
|
250
265
|
- docs/experiments.md
|
251
266
|
- docs/index.md
|
252
267
|
- docs/pry-integration.md
|
268
|
+
- docs/shortcuts.md
|
253
269
|
- docs/similarity_tutorial.md
|
254
270
|
- docs/syntax.md
|
271
|
+
- docs/videos.md
|
255
272
|
- examples/build_stubbed_and_let_it_be_experiment.rb
|
256
273
|
- examples/experimental_replacement.rb
|
257
274
|
- examples/find_usage.rb
|
@@ -291,7 +308,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
291
308
|
- !ruby/object:Gem::Version
|
292
309
|
version: '0'
|
293
310
|
requirements: []
|
294
|
-
|
311
|
+
rubyforge_project:
|
312
|
+
rubygems_version: 2.7.6.2
|
295
313
|
signing_key:
|
296
314
|
specification_version: 4
|
297
315
|
summary: 'FAST: Find by AST.'
|