ffast 0.1.5 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97309977be2dabc51b9113ee555aa7fe94d21a52426bb7386bf1133696fc4b81
4
- data.tar.gz: 5851dd6da013f0561803b73d7c44a96b35960a8323399d012718eb712cf42b43
3
+ metadata.gz: 3942d57d80b4c4a1cd1c8ff40f18cc56508a51f4b6cae53480536f7c36a60b05
4
+ data.tar.gz: b60976ea570cf722ae6face8541881c6a1231b2d645727f25231a05c9f33f7ee
5
5
  SHA512:
6
- metadata.gz: 192e53811678fac65eb03d87145be85971079b832f0675c80d0644e1686765995aa591e955adcb7fad31f28b0a8a2cdea0cfeaee7db9fee9067f19a36f65fd5b
7
- data.tar.gz: 024c2b9a6db910e16516bf54b71f9857af40edec50c180488c312e82b177968f13e9b11d795036ffdc0541e2413b55e2efd016f0a383b06265fc7d28f99dc01f
6
+ metadata.gz: c4df11570f2b2cc164dbd43815a37443541c98c955d6c84ea0b24564fd03b8534cf73479844393ecd72c794231ad40baf678784f9863a8f90c157ac8477f3c9d
7
+ data.tar.gz: d9481952776fc77d251a3c9f518f41e20d672298e9ff01b53b8673a0c0bc38f4919e4dd7234365e8044f5cef8e0738823d847900bea790f9796e6d8554342a06
@@ -8,11 +8,114 @@ AllCops:
8
8
  Exclude:
9
9
  - 'tmp/**/*'
10
10
  - 'examples/*'
11
- TargetRubyVersion: 2.3
11
+ TargetRubyVersion: 2.6
12
12
 
13
- Metrics/LineLength:
13
+ Layout/LineLength:
14
14
  Enabled: false
15
15
 
16
+ Layout/EmptyLinesAroundAttributeAccessor:
17
+ Enabled: false
18
+
19
+ Layout/SpaceAroundMethodCallOperator:
20
+ Enabled: false
21
+
22
+ Lint/BinaryOperatorWithIdenticalOperands:
23
+ Enabled: true
24
+
25
+ Lint/DuplicateElsifCondition:
26
+ Enabled: false
27
+
28
+ Lint/DuplicateRescueException:
29
+ Enabled: false
30
+
31
+ Lint/EmptyConditionalBody:
32
+ Enabled: false
33
+
34
+ Lint/FloatComparison:
35
+ Enabled: false
36
+
37
+ Lint/MissingSuper:
38
+ Enabled: false
39
+
40
+ Lint/OutOfRangeRegexpRef:
41
+ Enabled: false
42
+
43
+ Lint/SelfAssignment:
44
+ Enabled: false
45
+
46
+ Lint/TopLevelReturnWithArgument:
47
+ Enabled: false
48
+
49
+ Lint/UnreachableLoop:
50
+ Enabled: false
51
+
52
+
53
+ Lint/DeprecatedOpenSSLConstant:
54
+ Enabled: false
55
+
56
+ Lint/MixedRegexpCaptureTypes:
57
+ Enabled: false
58
+
59
+ Lint/RaiseException:
60
+ Enabled: true
61
+
62
+ Lint/StructNewOverride:
63
+ Enabled: true
64
+
65
+ Style/AccessorGrouping:
66
+ Enabled: false
67
+
68
+ Style/ArrayCoercion:
69
+ Enabled: false
70
+
71
+ Style/BisectedAttrAccessor:
72
+ Enabled: true
73
+
74
+ Style/CaseLikeIf:
75
+ Enabled: true
76
+
77
+ Style/ExplicitBlockArgument:
78
+ Enabled: false
79
+
80
+ Style/ExponentialNotation:
81
+ Enabled: true
82
+
83
+ Style/GlobalStdStream:
84
+ Enabled: false
85
+
86
+ Style/HashAsLastArrayItem:
87
+ Enabled: false
88
+
89
+ Style/HashLikeCase:
90
+ Enabled: true
91
+
92
+ Style/OptionalBooleanParameter:
93
+ Enabled: true
94
+
95
+ Style/RedundantAssignment:
96
+ Enabled: true
97
+
98
+ Style/RedundantFetchBlock:
99
+ Enabled: true
100
+
101
+ Style/RedundantFileExtensionInRequire:
102
+ Enabled: true
103
+
104
+ Style/SingleArgumentDig:
105
+ Enabled: true
106
+
107
+ Style/StringConcatenation:
108
+ Enabled: true
109
+
110
+ Style/RedundantRegexpCharacterClass:
111
+ Enabled: false
112
+
113
+ Style/RedundantRegexpEscape:
114
+ Enabled: false
115
+
116
+ Style/SlicingWithRange:
117
+ Enabled: true
118
+
16
119
  Metrics/BlockLength:
17
120
  Exclude:
18
121
  - 'spec/**/*'
@@ -46,3 +149,12 @@ RSpec/DescribedClass:
46
149
 
47
150
  RSpec/ImplicitSubject:
48
151
  Enabled: false
152
+
153
+ Style/HashEachMethods:
154
+ Enabled: true
155
+
156
+ Style/HashTransformKeys:
157
+ Enabled: true
158
+
159
+ Style/HashTransformValues:
160
+ Enabled: true
@@ -0,0 +1,2 @@
1
+ pull_requests:
2
+ comments: false
@@ -6,7 +6,7 @@ env:
6
6
  rvm:
7
7
  - 2.6.3
8
8
  before_install:
9
- gem install bundler -v 1.16.1
9
+ gem install bundler -v 2.1.4
10
10
  before_script:
11
11
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
12
12
  - chmod +x ./cc-test-reporter
@@ -14,5 +14,5 @@ before_script:
14
14
  after_script:
15
15
  - ./cc-test-reporter after-build -t simplecov --exit-code $TRAVIS_TEST_RESULT
16
16
  script:
17
- - bundle exec rubocop
17
+ - bundle exec rubocop --fail-level warning --display-only-fail-level-offenses
18
18
  - bundle exec rspec
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
@@ -32,7 +32,7 @@ The current version of Fast covers the following token elements:
32
32
  to build custom rules.
33
33
  - `.<method-name>` - will call `<method-name>` from the `node`
34
34
 
35
- The syntax is inspired by the [RuboCop Node Pattern](https://github.com/bbatsov/rubocop/blob/master/lib/rubocop/node_pattern.rb).
35
+ The syntax is inspired by the [RuboCop Node Pattern](https://github.com/rubocop-hq/rubocop-ast/blob/master/lib/rubocop/ast/node_pattern.rb).
36
36
 
37
37
  ## Installation
38
38
 
@@ -253,25 +253,29 @@ This can be represented as the following AST:
253
253
 
254
254
  We can create a query that searches for such a method:
255
255
 
256
- Fast.match?(ast,'(def $_ ... (send (send nil _) \1))') # => [:name]
256
+ Fast.match?('(def $_ ... (send (send nil _) \1))', ast) # => [:name]
257
257
 
258
258
  ## Fast.search
259
259
 
260
260
  Search allows you to go search the entire AST, collecting nodes that matches given
261
261
  expression. Any matching node is then returned:
262
262
 
263
- Fast.search(Fast.ast('a = 1'), '(int _)') # => s(:int, 1)
263
+ Fast.search('(int _)', Fast.ast('a = 1')) # => s(:int, 1)
264
264
 
265
265
  If you use captures along with a search, both the matching nodes and the
266
266
  captures will be returned:
267
267
 
268
- Fast.search(Fast.ast('a = 1'), '(int $_)') # => [s(:int, 1), 1]
268
+ Fast.search('(int $_)', Fast.ast('a = 1')) # => [s(:int, 1), 1]
269
+
270
+ You can also bind external parameters from the search:
271
+
272
+ Fast.search('(int %1)', Fast.ast('a = 1'), 1) # => [s(:int, 1)]
269
273
 
270
274
  ## Fast.capture
271
275
 
272
276
  To only pick captures and ignore the nodes, use `Fast.capture`:
273
277
 
274
- Fast.capture(Fast.ast('a = 1'), '(int $_)') # => 1
278
+ Fast.capture('(int $_)', Fast.ast('a = 1')) # => 1
275
279
 
276
280
  ## Fast.replace
277
281
 
@@ -421,6 +425,7 @@ The CLI tool takes the following flags
421
425
  - Use `--pry` to jump debugging the first result with pry
422
426
  - Use `-c` to search from code example
423
427
  - Use `-s` to search similar code
428
+ - Use `-p` or `--parallel` to parallelize the search
424
429
 
425
430
  ### Define your `Fastfile`
426
431
 
@@ -11,6 +11,7 @@ $ fast '(def match?)' lib/fast.rb
11
11
  - Use `--pry` to jump debugging the first result with pry
12
12
  - Use `-c` to search from code example
13
13
  - Use `-s` to search similar code
14
+ - Use `-p` to or `--parallel` to use multi core search
14
15
 
15
16
  ## `--pry`
16
17
 
@@ -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).
@@ -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
+ ```
@@ -269,6 +269,11 @@ If you use captures, it returns the node and the captures respectively:
269
269
  Fast.search('(int $_)', Fast.ast('a = 1')) # => [s(:int, 1), 1]
270
270
  ```
271
271
 
272
+ You can also bind external parameters in the search using extra arguments:
273
+ ```ruby
274
+ Fast.search('(int %1)', Fast.ast('a = 1'), 1) # => [s(:int, 1)]
275
+ ```
276
+
272
277
  ## capture
273
278
 
274
279
  To pick just the captures and ignore the nodes, use `Fast.capture`:
@@ -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.