pippi 0.0.9 → 0.0.10
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 +18 -3
- data/doc/docs.md +16 -0
- data/lib/pippi.rb +3 -0
- data/lib/pippi/auto_runner.rb +6 -1
- data/lib/pippi/check_set_mapper.rb +4 -0
- data/lib/pippi/checks/map_followed_by_flatten.rb +2 -0
- data/lib/pippi/checks/method_sequence_checker.rb +80 -0
- data/lib/pippi/checks/method_sequence_finder.rb +84 -0
- data/lib/pippi/checks/reverse_followed_by_each.rb +2 -0
- data/lib/pippi/checks/select_followed_by_any.rb +5 -33
- data/lib/pippi/checks/select_followed_by_empty.rb +5 -33
- data/lib/pippi/checks/select_followed_by_first.rb +2 -0
- data/lib/pippi/checks/select_followed_by_none.rb +28 -0
- data/lib/pippi/checks/select_followed_by_select.rb +5 -26
- data/lib/pippi/checks/select_followed_by_size.rb +5 -31
- data/lib/pippi/context.rb +3 -0
- data/lib/pippi/tasks.rb +1 -1
- data/lib/pippi/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ad992cb9bc5aa2b1e2ea7ee7acbe531cbb2432e
|
4
|
+
data.tar.gz: 564a5feffa9d49e8eb28d878f4635c93ba19921e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e1046f43ec28739b33a224136a3c852ea9a0c91579f5c22bff9f102e0fff483bb0ce9c97a9b93d2cb34d4a1c6fca390bfff9de1ec2020488d96d7ff6d88faec
|
7
|
+
data.tar.gz: 822431d1b25e296483f2031a8ec581788615e6c1d89b02b9fee1fd4474172c72e8b753cbcaaae81f1e51564cc881a6ae38a7dd92ff3dfa5ec9dad96bb15f5879
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -189,6 +189,22 @@ Instead, consider doing this:
|
|
189
189
|
[1,2,3].detect {|x| x > 1 }
|
190
190
|
```
|
191
191
|
|
192
|
+
#### SelectFollowedByNone
|
193
|
+
|
194
|
+
Don't use select followed by none?; use none? with a block instead
|
195
|
+
|
196
|
+
For example, rather than doing this:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
[1,2,3].select {|x| x > 1 }.none?
|
200
|
+
```
|
201
|
+
|
202
|
+
Instead, consider doing this:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
[1,2,3].none? {|x| x > 1 }
|
206
|
+
```
|
207
|
+
|
192
208
|
#### SelectFollowedBySelect
|
193
209
|
|
194
210
|
Don't use consecutive select blocks; use a single select instead
|
@@ -257,8 +273,6 @@ Instead, consider doing this:
|
|
257
273
|
## Ideas for other problems to detect:
|
258
274
|
|
259
275
|
```ruby
|
260
|
-
# Don't use select followed by compact, use select with the nil inside the block
|
261
|
-
|
262
276
|
# unnecessary assignment since String#strip! mutates receiver
|
263
277
|
# wrong
|
264
278
|
x = x.strip!
|
@@ -320,7 +334,8 @@ end
|
|
320
334
|
|
321
335
|
* Clean up this initial hacked out metaprogramming
|
322
336
|
* Do more checks
|
323
|
-
*
|
337
|
+
* Finish refactoring duplicated code into MethodSequenceChecker
|
338
|
+
* Use MethodSequenceFinder to do something with String
|
324
339
|
|
325
340
|
## Developing
|
326
341
|
|
data/doc/docs.md
CHANGED
@@ -64,6 +64,22 @@ Instead, consider doing this:
|
|
64
64
|
[1,2,3].detect {|x| x > 1 }
|
65
65
|
```
|
66
66
|
|
67
|
+
#### SelectFollowedByNone
|
68
|
+
|
69
|
+
Don't use select followed by none?; use none? with a block instead
|
70
|
+
|
71
|
+
For example, rather than doing this:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
[1,2,3].select {|x| x > 1 }.none?
|
75
|
+
```
|
76
|
+
|
77
|
+
Instead, consider doing this:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
[1,2,3].none? {|x| x > 1 }
|
81
|
+
```
|
82
|
+
|
67
83
|
#### SelectFollowedBySelect
|
68
84
|
|
69
85
|
Don't use consecutive select blocks; use a single select instead
|
data/lib/pippi.rb
CHANGED
@@ -14,6 +14,9 @@ require 'pippi/checks/select_followed_by_first'
|
|
14
14
|
require 'pippi/checks/select_followed_by_size'
|
15
15
|
require 'pippi/checks/select_followed_by_empty'
|
16
16
|
require 'pippi/checks/select_followed_by_any'
|
17
|
+
require 'pippi/checks/select_followed_by_none'
|
17
18
|
require 'pippi/checks/select_followed_by_select'
|
19
|
+
require 'pippi/checks/method_sequence_finder'
|
20
|
+
require 'pippi/checks/method_sequence_checker'
|
18
21
|
require 'pippi/checks/assert_with_nil'
|
19
22
|
require 'pippi/checks/debug_check'
|
data/lib/pippi/auto_runner.rb
CHANGED
@@ -5,11 +5,16 @@ module Pippi
|
|
5
5
|
def initialize(opts = {})
|
6
6
|
checkset = opts.fetch(:checkset, 'basic')
|
7
7
|
@ctx = Pippi::Context.new
|
8
|
-
|
8
|
+
|
9
|
+
@ctx.checks = Pippi::CheckLoader.new(@ctx, checkset).checks
|
10
|
+
@ctx.checks.each(&:decorate)
|
9
11
|
at_exit { dump }
|
10
12
|
end
|
11
13
|
|
12
14
|
def dump
|
15
|
+
if @ctx.checks.one? && @ctx.checks.first.kind_of?(Pippi::Checks::MethodSequenceFinder)
|
16
|
+
@ctx.checks.first.dump
|
17
|
+
end
|
13
18
|
File.open('log/pippi.log', 'w') do |outfile|
|
14
19
|
@ctx.report.problems.each do |problem|
|
15
20
|
outfile.syswrite("#{problem.to_text}\n")
|
@@ -23,12 +23,16 @@ module Pippi
|
|
23
23
|
"SelectFollowedByFirst",
|
24
24
|
"SelectFollowedBySize",
|
25
25
|
"SelectFollowedByAny",
|
26
|
+
"SelectFollowedByNone",
|
26
27
|
"SelectFollowedByEmpty",
|
27
28
|
"ReverseFollowedByEach",
|
28
29
|
"SelectFollowedBySelect"
|
29
30
|
],
|
30
31
|
"training" => [
|
31
32
|
],
|
33
|
+
"research" => [
|
34
|
+
"MethodSequenceFinder",
|
35
|
+
],
|
32
36
|
"buggy" => [
|
33
37
|
"AssertWithNil",
|
34
38
|
"MapFollowedByFlatten",
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class MethodSequenceChecker
|
2
|
+
|
3
|
+
ARITY_TYPE_BLOCK_ARG = 1
|
4
|
+
ARITY_TYPE_NONE = 2
|
5
|
+
|
6
|
+
attr_reader :check, :clazz_to_decorate, :method1, :method2, :first_method_arity_type, :second_method_arity_type, :should_check_subsequent_calls
|
7
|
+
|
8
|
+
def initialize(check, clazz_to_decorate, method1, method2, first_method_arity_type, second_method_arity_type, should_check_subsequent_calls)
|
9
|
+
@check = check
|
10
|
+
@clazz_to_decorate = clazz_to_decorate
|
11
|
+
@method1 = method1
|
12
|
+
@method2 = method2
|
13
|
+
@first_method_arity_type = first_method_arity_type
|
14
|
+
@second_method_arity_type = second_method_arity_type
|
15
|
+
@should_check_subsequent_calls = should_check_subsequent_calls
|
16
|
+
end
|
17
|
+
|
18
|
+
def decorate
|
19
|
+
clazz_to_decorate.class_exec(check, self) do |my_check, method_sequence_check_instance|
|
20
|
+
name = "@_pippi_check_#{my_check.class.name.split('::').last.downcase}"
|
21
|
+
self.instance_variable_set(name, my_check)
|
22
|
+
self.class.send(:define_method, name[1..-1]) do
|
23
|
+
instance_variable_get(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
# e.g., "size" in "select followed by size"
|
27
|
+
second_method_decorator = Module.new do
|
28
|
+
define_method(method_sequence_check_instance.method2) do |*args, &blk|
|
29
|
+
self.class.instance_variable_get(name).add_problem
|
30
|
+
if method_sequence_check_instance.should_check_subsequent_calls && method_sequence_check_instance.clazz_to_decorate == Array
|
31
|
+
problem_location = caller_locations.find { |c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
|
32
|
+
self.class.instance_variable_get(name).method_names_that_indicate_this_is_being_used_as_a_collection.each do |this_means_its_ok_sym|
|
33
|
+
define_singleton_method(this_means_its_ok_sym, self.class.instance_variable_get(name).clear_fault_proc(self.class.instance_variable_get(name), problem_location))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if method_sequence_check_instance.second_method_arity_type == ARITY_TYPE_BLOCK_ARG
|
37
|
+
super(&blk)
|
38
|
+
elsif method_sequence_check_instance.second_method_arity_type == ARITY_TYPE_NONE
|
39
|
+
super()
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# e.g., "select" in "select followed ARITY_TYPE_NONEze"
|
45
|
+
first_method_decorator = Module.new do
|
46
|
+
define_method(method_sequence_check_instance.method1) do |*args, &blk|
|
47
|
+
result = if method_sequence_check_instance.first_method_arity_type == ARITY_TYPE_BLOCK_ARG
|
48
|
+
super(&blk)
|
49
|
+
elsif method_sequence_check_instance.first_method_arity_type == ARITY_TYPE_NONE
|
50
|
+
super()
|
51
|
+
end
|
52
|
+
if self.class.instance_variable_get(name)
|
53
|
+
result.extend second_method_decorator
|
54
|
+
self.class.instance_variable_get(name).array_mutator_methods.each do |this_means_its_ok_sym|
|
55
|
+
result.define_singleton_method(this_means_its_ok_sym, self.class.instance_variable_get(name).its_ok_watcher_proc(second_method_decorator, method_sequence_check_instance.method2))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
prepend first_method_decorator
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def array_mutator_methods
|
66
|
+
[:collect!, :compact!, :flatten!, :map!, :reject!, :reverse!, :rotate!, :select!, :shuffle!, :slice!, :sort!, :sort_by!, :uniq!]
|
67
|
+
end
|
68
|
+
|
69
|
+
def its_ok_watcher_proc(clazz, method_name)
|
70
|
+
proc do |*args, &blk|
|
71
|
+
begin
|
72
|
+
singleton_class.ancestors.find { |x| x == clazz }.instance_eval { remove_method method_name }
|
73
|
+
rescue NameError
|
74
|
+
return super(*args, &blk)
|
75
|
+
else
|
76
|
+
return super(*args, &blk)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Pippi::Checks
|
2
|
+
|
3
|
+
module MyModule
|
4
|
+
def split(&blk)
|
5
|
+
result = super
|
6
|
+
if self.class._pippi_method_call_sequences
|
7
|
+
array_methods_to_track.each do |track_this|
|
8
|
+
result.define_singleton_method(track_this, track_it_proc(track_this))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
def track_it_proc(method_name)
|
15
|
+
location = caller_locations.find { |c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
|
16
|
+
proc do |*args, &blk|
|
17
|
+
begin
|
18
|
+
self.class._pippi_method_call_sequences.found_sequence(method_name, location)
|
19
|
+
rescue NameError
|
20
|
+
return super(*args, &blk)
|
21
|
+
else
|
22
|
+
return super(*args, &blk)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def string_methods_to_track
|
28
|
+
[:ascii_only?, :b, :between?, :bytes, :bytesize, :byteslice, :capitalize, :capitalize!, :casecmp, :center, :chars, :chomp, :chomp!, :chop, :chop!, :chr, :clear, :codepoints, :concat, :count, :crypt, :delete, :delete!, :downcase, :downcase!, :dump, :each_byte, :each_char, :each_codepoint, :each_line, :empty?, :encode, :encode!, :encoding, :end_with?, :force_encoding, :getbyte, :gsub, :gsub!, :hex, :index, :insert, :intern, :length, :lines, :ljust, :lstrip, :lstrip!, :match, :next, :next!, :oct, :ord, :partition, :replace, :reverse, :reverse!, :rindex, :rjust, :rpartition, :rstrip, :rstrip!, :scan, :scrub, :scrub!, :setbyte, :size, :slice, :slice!, :split, :squeeze, :squeeze!, :start_with?, :strip, :strip!, :sub, :sub!, :succ, :succ!, :sum, :swapcase, :swapcase!, :to_c, :to_f, :to_i, :to_r, :to_str, :to_sym, :tr, :tr!, :tr_s, :tr_s!, :unpack, :upcase, :upcase!, :upto, :valid_encoding?]
|
29
|
+
end
|
30
|
+
|
31
|
+
def array_methods_to_track
|
32
|
+
[:all?, :any?, :assoc, :at, :bsearch, :chunk, :clear, :collect, :collect!, :collect_concat, :combination, :compact, :compact!, :concat, :count, :cycle, :delete, :delete_at, :delete_if, :detect, :drop, :drop_while, :each, :each_cons, :each_entry, :each_index, :each_slice, :each_with_index, :each_with_object, :empty?, :entries, :fetch, :fill, :find, :find_all, :find_index, :first, :flat_map, :flatten, :flatten!, :grep, :group_by, :histogram, :index, :inject, :insert, :join, :keep_if, :last, :lazy, :length, :map, :map!, :max, :max_by, :member?, :min, :min_by, :minmax, :minmax_by, :none?, :one?, :pack, :partition, :permutation, :pop, :product, :push, :rassoc, :reduce, :reject, :reject!, :repeated_combination, :repeated_permutation, :replace, :reverse, :reverse!, :reverse_each, :rindex, :rotate, :rotate!, :sample, :select, :select!, :shift, :shuffle, :shuffle!, :size, :slice, :slice!, :slice_before, :sort, :sort!, :sort_by, :sort_by!, :take, :take_while, :to_a, :to_ary, :to_h, :transpose, :uniq, :uniq!, :unshift, :values_at, :zip]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class MethodSequenceFinder < Check
|
37
|
+
|
38
|
+
class Record
|
39
|
+
attr_reader :path, :lineno, :meth1, :meth2
|
40
|
+
def initialize(path, lineno, meth1, meth2)
|
41
|
+
@path = path
|
42
|
+
@lineno = lineno
|
43
|
+
@meth1 = meth1
|
44
|
+
@meth2 = meth2
|
45
|
+
end
|
46
|
+
def eql?(other)
|
47
|
+
path == other.path && lineno == other.lineno && meth1 == other.meth1 && meth2 == other.meth2
|
48
|
+
end
|
49
|
+
def hash
|
50
|
+
require 'zlib'
|
51
|
+
Zlib.crc32("#{path}:#{lineno}:#{meth1}:#{meth2}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :sequences, :clazz_to_decorate
|
56
|
+
|
57
|
+
def initialize(ctx)
|
58
|
+
super
|
59
|
+
@clazz_to_decorate = String
|
60
|
+
@sequences = Set.new
|
61
|
+
end
|
62
|
+
|
63
|
+
def dump
|
64
|
+
@sequences.map {|r| "#{r.meth1}:#{r.meth2}" }.inject({}) {|m,i| m[i] ||= 0 ; m[i] += 1 ; m }.to_a.sort_by {|x| x[1] }.reverse.each do |r|
|
65
|
+
puts "#{r[0].split(':')[0]} followed by #{r[0].split(':')[1]} occurred #{r[1]} times\n"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def found_sequence(method_name, location)
|
70
|
+
@sequences << Record.new(location.path, location.lineno, "map", method_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def decorate
|
74
|
+
clazz_to_decorate.class_exec(self) do |my_check|
|
75
|
+
@_pippi_method_call_sequences = my_check
|
76
|
+
class << self
|
77
|
+
attr_reader :_pippi_method_call_sequences
|
78
|
+
end
|
79
|
+
prepend MyModule
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -2,41 +2,13 @@ module Pippi::Checks
|
|
2
2
|
|
3
3
|
class SelectFollowedByAny < Check
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
self.class._pippi_check_select_followed_by_any.add_problem
|
8
|
-
problem_location = caller_locations.find { |c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
|
9
|
-
self.class._pippi_check_select_followed_by_any.method_names_that_indicate_this_is_being_used_as_a_collection.each do |this_means_its_ok_sym|
|
10
|
-
define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_any.clear_fault_proc(self.class._pippi_check_select_followed_by_any, problem_location))
|
11
|
-
end
|
12
|
-
super
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module MySelect
|
17
|
-
def select(&blk)
|
18
|
-
result = super
|
19
|
-
if self.class._pippi_check_select_followed_by_any.nil?
|
20
|
-
# Ignore Array subclasses since select or any may have difference meanings
|
21
|
-
# elsif defined?(ActiveRecord::Relation) && self.class.kind_of?(ActiveRecord::Relation) # maybe also this
|
22
|
-
else
|
23
|
-
result.extend MyAny
|
24
|
-
self.class._pippi_check_select_followed_by_any.array_mutator_methods.each do |this_means_its_ok_sym|
|
25
|
-
result.define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_any.its_ok_watcher_proc(MyAny, :any?))
|
26
|
-
end
|
27
|
-
end
|
28
|
-
result
|
29
|
-
end
|
5
|
+
def decorate
|
6
|
+
@mycheck.decorate
|
30
7
|
end
|
31
8
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
def self._pippi_check_select_followed_by_any
|
36
|
-
@_pippi_check_select_followed_by_any
|
37
|
-
end
|
38
|
-
prepend MySelect
|
39
|
-
end
|
9
|
+
def initialize(ctx)
|
10
|
+
super
|
11
|
+
@mycheck = MethodSequenceChecker.new(self, Array, "select", "any?", MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, MethodSequenceChecker::ARITY_TYPE_NONE, true)
|
40
12
|
end
|
41
13
|
|
42
14
|
class Documentation
|
@@ -2,41 +2,13 @@ module Pippi::Checks
|
|
2
2
|
|
3
3
|
class SelectFollowedByEmpty < Check
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
self.class._pippi_check_select_followed_by_empty.add_problem
|
8
|
-
problem_location = caller_locations.find { |c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
|
9
|
-
self.class._pippi_check_select_followed_by_empty.method_names_that_indicate_this_is_being_used_as_a_collection.each do |this_means_its_ok_sym|
|
10
|
-
define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_empty.clear_fault_proc(self.class._pippi_check_select_followed_by_empty, problem_location))
|
11
|
-
end
|
12
|
-
super
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module MySelect
|
17
|
-
def select(&blk)
|
18
|
-
result = super
|
19
|
-
if self.class._pippi_check_select_followed_by_empty.nil?
|
20
|
-
# Ignore Array subclasses since select or empty may have difference meanings
|
21
|
-
# elsif defined?(ActiveRecord::Relation) && self.class.kind_of?(ActiveRecord::Relation) # maybe also this
|
22
|
-
else
|
23
|
-
result.extend MyEmpty
|
24
|
-
self.class._pippi_check_select_followed_by_empty.array_mutator_methods.each do |this_means_its_ok_sym|
|
25
|
-
result.define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_empty.its_ok_watcher_proc(MyEmpty, :empty?))
|
26
|
-
end
|
27
|
-
end
|
28
|
-
result
|
29
|
-
end
|
5
|
+
def decorate
|
6
|
+
@mycheck.decorate
|
30
7
|
end
|
31
8
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
def self._pippi_check_select_followed_by_empty
|
36
|
-
@_pippi_check_select_followed_by_empty
|
37
|
-
end
|
38
|
-
prepend MySelect
|
39
|
-
end
|
9
|
+
def initialize(ctx)
|
10
|
+
super
|
11
|
+
@mycheck = MethodSequenceChecker.new(self, Array, "select", "empty?", MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, MethodSequenceChecker::ARITY_TYPE_NONE, true)
|
40
12
|
end
|
41
13
|
|
42
14
|
class Documentation
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Pippi::Checks
|
2
|
+
|
3
|
+
class SelectFollowedByNone < Check
|
4
|
+
|
5
|
+
def decorate
|
6
|
+
@mycheck.decorate
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(ctx)
|
10
|
+
super
|
11
|
+
@mycheck = MethodSequenceChecker.new(self, Array, "select", "none?", MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, MethodSequenceChecker::ARITY_TYPE_NONE, true)
|
12
|
+
end
|
13
|
+
|
14
|
+
class Documentation
|
15
|
+
def description
|
16
|
+
"Don't use select followed by none?; use none? with a block instead"
|
17
|
+
end
|
18
|
+
def sample
|
19
|
+
"[1,2,3].select {|x| x > 1 }.none?"
|
20
|
+
end
|
21
|
+
def instead_use
|
22
|
+
"[1,2,3].none? {|x| x > 1 }"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -2,34 +2,13 @@ module Pippi::Checks
|
|
2
2
|
|
3
3
|
class SelectFollowedBySelect < Check
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
self.class._pippi_check_select_followed_by_select.add_problem
|
8
|
-
super
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module MyFirstSelect
|
13
|
-
def select(&blk)
|
14
|
-
result = super
|
15
|
-
if !self.class._pippi_check_select_followed_by_select.nil?
|
16
|
-
result.extend MySecondSelect
|
17
|
-
self.class._pippi_check_select_followed_by_select.array_mutator_methods.each do |this_means_its_ok_sym|
|
18
|
-
result.define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_select.its_ok_watcher_proc(MySecondSelect, :select))
|
19
|
-
end
|
20
|
-
end
|
21
|
-
result
|
22
|
-
end
|
5
|
+
def decorate
|
6
|
+
@mycheck.decorate
|
23
7
|
end
|
24
8
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
def self._pippi_check_select_followed_by_select
|
29
|
-
@_pippi_check_select_followed_by_select
|
30
|
-
end
|
31
|
-
prepend MyFirstSelect
|
32
|
-
end
|
9
|
+
def initialize(ctx)
|
10
|
+
super
|
11
|
+
@mycheck = MethodSequenceChecker.new(self, Array, "select", "select", MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, false)
|
33
12
|
end
|
34
13
|
|
35
14
|
class Documentation
|
@@ -1,39 +1,13 @@
|
|
1
1
|
module Pippi::Checks
|
2
2
|
class SelectFollowedBySize < Check
|
3
|
-
module MySize
|
4
|
-
def size
|
5
|
-
self.class._pippi_check_select_followed_by_size.add_problem
|
6
|
-
problem_location = caller_locations.find { |c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
|
7
|
-
self.class._pippi_check_select_followed_by_size.method_names_that_indicate_this_is_being_used_as_a_collection.each do |this_means_its_ok_sym|
|
8
|
-
define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_size.clear_fault_proc(self.class._pippi_check_select_followed_by_size, problem_location))
|
9
|
-
end
|
10
|
-
super()
|
11
|
-
end
|
12
|
-
end
|
13
3
|
|
14
|
-
|
15
|
-
|
16
|
-
result = super
|
17
|
-
if self.class._pippi_check_select_followed_by_size.nil?
|
18
|
-
# Ignore Array subclasses since select or size may have difference meanings
|
19
|
-
else
|
20
|
-
result.extend MySize
|
21
|
-
self.class._pippi_check_select_followed_by_size.array_mutator_methods.each do |this_means_its_ok_sym|
|
22
|
-
result.define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_size.its_ok_watcher_proc(MySize, :size))
|
23
|
-
end
|
24
|
-
end
|
25
|
-
result
|
26
|
-
end
|
4
|
+
def decorate
|
5
|
+
@mycheck.decorate
|
27
6
|
end
|
28
7
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
class << self
|
33
|
-
attr_reader :_pippi_check_select_followed_by_size
|
34
|
-
end
|
35
|
-
prepend MySelect
|
36
|
-
end
|
8
|
+
def initialize(ctx)
|
9
|
+
super
|
10
|
+
@mycheck = MethodSequenceChecker.new(self, Array, "select", "size", MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, MethodSequenceChecker::ARITY_TYPE_NONE, true)
|
37
11
|
end
|
38
12
|
|
39
13
|
class Documentation
|
data/lib/pippi/context.rb
CHANGED
data/lib/pippi/tasks.rb
CHANGED
@@ -4,7 +4,7 @@ module Pippi
|
|
4
4
|
class Documentation
|
5
5
|
def generate
|
6
6
|
str = ''
|
7
|
-
Pippi::CheckSetMapper.new("").predefined_sets.sort.select {|k,v| v.any? }.each do |checkset_name, checks|
|
7
|
+
Pippi::CheckSetMapper.new("").predefined_sets.sort.select {|k,v| k != "research" && v.any? }.each do |checkset_name, checks|
|
8
8
|
str << "### #{checkset_name}\n"
|
9
9
|
checks.sort.each do |check|
|
10
10
|
obj = Object.const_get("Pippi::Checks::#{check}::Documentation").new
|
data/lib/pippi/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pippi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Copeland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -73,10 +73,13 @@ files:
|
|
73
73
|
- lib/pippi/checks/check.rb
|
74
74
|
- lib/pippi/checks/debug_check.rb
|
75
75
|
- lib/pippi/checks/map_followed_by_flatten.rb
|
76
|
+
- lib/pippi/checks/method_sequence_checker.rb
|
77
|
+
- lib/pippi/checks/method_sequence_finder.rb
|
76
78
|
- lib/pippi/checks/reverse_followed_by_each.rb
|
77
79
|
- lib/pippi/checks/select_followed_by_any.rb
|
78
80
|
- lib/pippi/checks/select_followed_by_empty.rb
|
79
81
|
- lib/pippi/checks/select_followed_by_first.rb
|
82
|
+
- lib/pippi/checks/select_followed_by_none.rb
|
80
83
|
- lib/pippi/checks/select_followed_by_select.rb
|
81
84
|
- lib/pippi/checks/select_followed_by_size.rb
|
82
85
|
- lib/pippi/context.rb
|