ffast 0.1.8 → 0.1.9
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/docs/ideas.md +80 -0
- data/docs/research.md +93 -0
- data/docs/shortcuts.md +64 -29
- data/fast.gemspec +1 -1
- data/lib/fast.rb +3 -2
- data/lib/fast/version.rb +1 -1
- data/mkdocs.yml +2 -0
- metadata +10 -9
- data/.github/FUNDING.yml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18d062e72ef849cb0b6533af8c6dc37a6612036faead3c53e1d0427a001e8f24
|
4
|
+
data.tar.gz: 55b4dfdd79ee4b789fa7652760fb3516a49f68b7503d827042b78c5101fecee6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 813ca8cbe0bad2ce3f6dce1477820b68c00ac06021a3fd4263df9ea5634a6510ae0cac6cd178ffc8342b31bf7e956522a482d809dbcbe3500a488b6bc609a78a
|
7
|
+
data.tar.gz: 7fb04918062ca0f972622fe69e8d6bb77631b1e7df9ba9aa5b1e37385c0cdbcd802324d6e46801a89e53d4f30b7fe92edf51ad3eba0252cf6fce5183c76f60de
|
data/docs/ideas.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Ideas I want to build with Fast
|
2
|
+
|
3
|
+
I don't have all the time I need to develop all the ideas I have to build
|
4
|
+
around this tool, so here is a dump of a few brainstormings:
|
5
|
+
|
6
|
+
## Inline target code
|
7
|
+
|
8
|
+
I started [fast-inline](https://github.com/jonatas/fast-inline) that can be
|
9
|
+
useful to try to see how much every library is used in a project.
|
10
|
+
|
11
|
+
My idea is try to inline some specific method call to understand if it makes
|
12
|
+
sense to have an entire library in the stock.
|
13
|
+
|
14
|
+
Understanding dependencies and how the code works can be a first step to get an
|
15
|
+
"algorithm as a service". Instead of loading everything from the library, it
|
16
|
+
would facilitate the cherry pick of only the proper dependencies necessaries to
|
17
|
+
run the code you have and not the code that is overloading the project.
|
18
|
+
|
19
|
+
## Neo4J adapter
|
20
|
+
|
21
|
+
Easy pipe fast results to Neo4J. It would facilitate to explore more complex
|
22
|
+
scenarios and combine data from other sources.
|
23
|
+
|
24
|
+
## Git adapter
|
25
|
+
|
26
|
+
Add extra tags to nodes with information from Git.
|
27
|
+
|
28
|
+
* Revision
|
29
|
+
* Author
|
30
|
+
* Date
|
31
|
+
|
32
|
+
Tag every node with the proper author.
|
33
|
+
|
34
|
+
## Ast Diff
|
35
|
+
|
36
|
+
Allow to compare and return a summary of differences between two trees.
|
37
|
+
|
38
|
+
It would be useful to identify renamings or other small changes, like only
|
39
|
+
changes in comments that does not affect the file and possibly be ignored for
|
40
|
+
some operations like run or not run tests.
|
41
|
+
|
42
|
+
## Transition synapses
|
43
|
+
|
44
|
+
Following the previous idea, it would be great if we can understand the
|
45
|
+
transition synapses and make it easily available to catch up with previous
|
46
|
+
learnings.
|
47
|
+
|
48
|
+
https://github.com/jonatas/chewy-diff/blob/master/lib/chewy/diff.rb
|
49
|
+
|
50
|
+
This example, shows adds and removals from specific node targets between two
|
51
|
+
different files.
|
52
|
+
|
53
|
+
If we start tracking AST transition synapses and associating with "Fixes" or
|
54
|
+
"Reverts" we can predict introduction of new bugs by inpecting if the
|
55
|
+
introduction of new patterns that can be possibly reverted or improved.
|
56
|
+
|
57
|
+
## Fast Rewriter with pure strings
|
58
|
+
|
59
|
+
As the AST rewriter adopts a custom block that needs to implement ruby code,
|
60
|
+
we can expand the a query language for rewriting files without need to take the
|
61
|
+
custom Ruby block.
|
62
|
+
|
63
|
+
Example:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
Fast.gsub_expression('remove(@expression)') # (node) => { remove(node.location.expression) }
|
67
|
+
```
|
68
|
+
|
69
|
+
And later we can bind it in the command line to allow implement custom
|
70
|
+
replacements without need to write a ruby file.
|
71
|
+
|
72
|
+
```
|
73
|
+
fast (def my_target_method) lib spec --rewrite "remove(@expression)"
|
74
|
+
```
|
75
|
+
|
76
|
+
or
|
77
|
+
|
78
|
+
```
|
79
|
+
fast (def my_target_method) lib spec --rewrite "replace(@name, 'renamed_method')"
|
80
|
+
```
|
data/docs/research.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
# Research
|
3
|
+
|
4
|
+
I love to research about codebase as data and prototyping ideas several times
|
5
|
+
doesn't fit in simple [shortcuts](/shortcuts).
|
6
|
+
|
7
|
+
Here is my first research that worth sharing:
|
8
|
+
|
9
|
+
## Combining Runtime metadata with AST complex searches
|
10
|
+
|
11
|
+
This example covers how to find RSpec `allow` combined with `and_return` missing
|
12
|
+
the `with` clause specifying the nested parameters.
|
13
|
+
|
14
|
+
Here is the [gist](https://gist.github.com/jonatas/c1e580dcb74e20d4f2df4632ceb084ef)
|
15
|
+
if you want to go straight and run it.
|
16
|
+
|
17
|
+
Scenario for simple example:
|
18
|
+
|
19
|
+
Given I have the following class:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
class Account
|
23
|
+
def withdraw(value)
|
24
|
+
if @total >= value
|
25
|
+
@total -= value
|
26
|
+
:ok
|
27
|
+
else
|
28
|
+
:not_allowed
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
And I'm testing it with `allow` and some possibilities:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# bad
|
38
|
+
allow(Account).to receive(:withdraw).and_return(:ok)
|
39
|
+
# good
|
40
|
+
allow(Account).to receive(:withdraw).with(100).and_return(:ok)
|
41
|
+
```
|
42
|
+
|
43
|
+
**Objective:** find all bad cases of **any** class that does not respect the method
|
44
|
+
parameters signature.
|
45
|
+
|
46
|
+
First, let's understand the method signature of a method:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
Account.instance_method(:withdraw).parameters
|
50
|
+
# => [[:req, :value]]
|
51
|
+
```
|
52
|
+
|
53
|
+
Now, we can build a small script to use the node pattern to match the proper
|
54
|
+
specs that are using such pattern and later visit their method signatures.
|
55
|
+
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
Fast.class_eval do
|
59
|
+
# Captures class and method name when find syntax like:
|
60
|
+
# `allow(...).to receive(...)` that does not end with `.with(...)`
|
61
|
+
pattern_with_captures = <<~FAST
|
62
|
+
(send (send nil allow (const nil $_)) to
|
63
|
+
(send (send nil receive (sym $_)) !with))
|
64
|
+
FAST
|
65
|
+
|
66
|
+
pattern = expression(pattern_with_captures.tr('$',''))
|
67
|
+
|
68
|
+
ruby_files_from('spec').each do |file|
|
69
|
+
results = search_file(pattern, file) || [] rescue next
|
70
|
+
results.each do |n|
|
71
|
+
clazz, method = capture(n, pattern_with_captures)
|
72
|
+
if klazz = Object.const_get(clazz.to_s) rescue nil
|
73
|
+
if klazz.respond_to?(method)
|
74
|
+
params = klazz.method(method).parameters
|
75
|
+
if params.any?{|e|e.first == :req}
|
76
|
+
code = n.loc.expression
|
77
|
+
range = [code.first_line, code.last_line].uniq.join(",")
|
78
|
+
boom_message = "BOOM! #{clazz}.#{method} does not include the REQUIRED parameters!"
|
79
|
+
puts boom_message, "#{file}:#{range}", code.source
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
!!! hint "Preload your environment **before** run the script"
|
89
|
+
|
90
|
+
Keep in mind that you should run it with your environment preloaded otherwise it
|
91
|
+
will skip the classes.
|
92
|
+
You can add elses for `const_get` and `respond_to` and report weird cases if
|
93
|
+
your environment is not preloading properly.
|
data/docs/shortcuts.md
CHANGED
@@ -11,6 +11,70 @@ first param is not a shortcut. It should start with `.`.
|
|
11
11
|
I'm building several researches and I'll make the examples open here to show
|
12
12
|
several interesting cases in action.
|
13
13
|
|
14
|
+
## List your fast shortcuts
|
15
|
+
|
16
|
+
As the interface is very rudimentar, let's build a shortcut to print what
|
17
|
+
shortcuts are available. This is a good one to your `$HOME/Fastfile`:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# List all shortcut with comments
|
21
|
+
Fast.shortcut :shortcuts do
|
22
|
+
fast_files.each do |file|
|
23
|
+
lines = File.readlines(file).map{|line|line.chomp.gsub(/\s*#/,'').strip}
|
24
|
+
result = capture_file('(send ... shortcut $(sym _', file)
|
25
|
+
result = [result] unless result.is_a?Array
|
26
|
+
result.each do |capture|
|
27
|
+
target = capture.loc.expression
|
28
|
+
puts "fast .#{target.source[1..-1].ljust(30)} # #{lines[target.line-2]}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
And using it on `fast` project that loads both `~/Fastfile` and the Fastfile from the project:
|
35
|
+
|
36
|
+
```
|
37
|
+
fast .version # Let's say you'd like to show the version that is over the version file
|
38
|
+
fast .parser # Simple shortcut that I used often to show how the expression parser works
|
39
|
+
fast .bump_version # Use `fast .bump_version` to rewrite the version file
|
40
|
+
fast .shortcuts # List all shortcut with comments
|
41
|
+
```
|
42
|
+
|
43
|
+
## Search for references
|
44
|
+
|
45
|
+
I always miss bringing something simple as `grep keyword` where I can leave a simple string and it can
|
46
|
+
search in all types of nodes and report interesting things about it.
|
47
|
+
|
48
|
+
Let's consider a very flexible search that can target any code related to some
|
49
|
+
keyword. Considering that we're talking about code indentifiers:
|
50
|
+
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# Search all references about some keyword or regular expression
|
54
|
+
Fast.shortcut(:ref) do
|
55
|
+
require 'fast/cli'
|
56
|
+
Kernel.class_eval do
|
57
|
+
def matches_args? identifier
|
58
|
+
search = ARGV.last
|
59
|
+
regex = Regexp.new(search, Regexp::IGNORECASE)
|
60
|
+
case identifier
|
61
|
+
when Symbol, String
|
62
|
+
regex.match?(identifier) || identifier.to_s.include?(search)
|
63
|
+
when Astrolabe::Node
|
64
|
+
regex.match?(identifier.to_sexp)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
pattern = <<~FAST
|
69
|
+
{
|
70
|
+
({class def sym str} #matches_args?)'
|
71
|
+
({const send} nil #matches_args?)'
|
72
|
+
}
|
73
|
+
FAST
|
74
|
+
Fast::Cli.run!([pattern, '.', '--parallel'])
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
14
78
|
## Rails: Show validations from models
|
15
79
|
|
16
80
|
If the shortcut does not define a block, it works as a holder for arguments from
|
@@ -73,35 +137,6 @@ module Fast
|
|
73
137
|
end
|
74
138
|
```
|
75
139
|
|
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
140
|
## RSpec: Find unused shared contexts
|
106
141
|
|
107
142
|
If you build shared contexts often, probably you can forget some left overs.
|
data/fast.gemspec
CHANGED
@@ -28,12 +28,12 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_dependency 'coderay'
|
29
29
|
spec.add_dependency 'parallel'
|
30
30
|
spec.add_dependency 'parser'
|
31
|
-
spec.add_dependency 'pry'
|
32
31
|
|
33
32
|
spec.add_development_dependency 'bundler'
|
34
33
|
spec.add_development_dependency 'guard'
|
35
34
|
spec.add_development_dependency 'guard-livereload'
|
36
35
|
spec.add_development_dependency 'guard-rspec'
|
36
|
+
spec.add_development_dependency 'pry'
|
37
37
|
spec.add_development_dependency 'rake'
|
38
38
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
39
39
|
spec.add_development_dependency 'rspec-its', '~> 1.2'
|
data/lib/fast.rb
CHANGED
@@ -226,14 +226,15 @@ module Fast
|
|
226
226
|
# @param files can be file paths or directories.
|
227
227
|
# When the argument is a folder, it recursively fetches all `.rb` files from it.
|
228
228
|
def ruby_files_from(*files)
|
229
|
-
|
229
|
+
dir_filter = File.method(:directory?)
|
230
|
+
directories = files.select(&dir_filter)
|
230
231
|
|
231
232
|
if directories.any?
|
232
233
|
files -= directories
|
233
234
|
files |= directories.flat_map { |dir| Dir["#{dir}/**/*.rb"] }
|
234
235
|
files.uniq!
|
235
236
|
end
|
236
|
-
files
|
237
|
+
files.reject(&dir_filter)
|
237
238
|
end
|
238
239
|
|
239
240
|
# Extracts a node pattern expression from a given node supressing identifiers and primitive types.
|
data/lib/fast/version.rb
CHANGED
data/mkdocs.yml
CHANGED
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.9
|
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: 2020-
|
11
|
+
date: 2020-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: astrolabe
|
@@ -67,13 +67,13 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
|
-
type: :
|
76
|
+
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: guard
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name: guard
|
98
|
+
name: guard-livereload
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name: guard-
|
112
|
+
name: guard-rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: pry
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
@@ -243,7 +243,6 @@ executables:
|
|
243
243
|
extensions: []
|
244
244
|
extra_rdoc_files: []
|
245
245
|
files:
|
246
|
-
- ".github/FUNDING.yml"
|
247
246
|
- ".gitignore"
|
248
247
|
- ".projections.json"
|
249
248
|
- ".rspec"
|
@@ -264,8 +263,10 @@ files:
|
|
264
263
|
- docs/command_line.md
|
265
264
|
- docs/editors-integration.md
|
266
265
|
- docs/experiments.md
|
266
|
+
- docs/ideas.md
|
267
267
|
- docs/index.md
|
268
268
|
- docs/pry-integration.md
|
269
|
+
- docs/research.md
|
269
270
|
- docs/shortcuts.md
|
270
271
|
- docs/similarity_tutorial.md
|
271
272
|
- docs/syntax.md
|
data/.github/FUNDING.yml
DELETED