pippi 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ad992cb9bc5aa2b1e2ea7ee7acbe531cbb2432e
4
- data.tar.gz: 564a5feffa9d49e8eb28d878f4635c93ba19921e
3
+ metadata.gz: c05baba246fbeb0947f998387800ef5e59bea9d0
4
+ data.tar.gz: 88364a935624811ace53ee739bf5f7bde545ad0e
5
5
  SHA512:
6
- metadata.gz: 9e1046f43ec28739b33a224136a3c852ea9a0c91579f5c22bff9f102e0fff483bb0ce9c97a9b93d2cb34d4a1c6fca390bfff9de1ec2020488d96d7ff6d88faec
7
- data.tar.gz: 822431d1b25e296483f2031a8ec581788615e6c1d89b02b9fee1fd4474172c72e8b753cbcaaae81f1e51564cc881a6ae38a7dd92ff3dfa5ec9dad96bb15f5879
6
+ metadata.gz: 8d7e3c193f1d5c74835b4eaf2e94cb5c4038a2a202ce7b89febeab9f7529ee8db5a6f49acd89f77578e16772846321898fb777502104064a72596232cbf5bbda
7
+ data.tar.gz: 4fa3c78158aa1469e4354e97826ccf4cba4cd41d560dfd7ca24bc00783d174d78417bd236161f1e0573eee081b798b8022ee0981ffbf967aa58592f3142d7c50
@@ -1,3 +1,7 @@
1
+ ## 0.0.11 (2014-12-19)
2
+
3
+ * [NEW] More logging options
4
+
1
5
  ## 0.0.10 (2014-12-09)
2
6
 
3
7
  * [NEW] Added SelectFollowedByNone
data/README.md CHANGED
@@ -49,7 +49,7 @@ Here's how pippi stacks up using the [Aaron Quint](https://twitter.com/aq) [Ruby
49
49
  * Realtimedness - finds stuff right away
50
50
  * Special Abilities - ?
51
51
 
52
- Finally, why "pippi"? Because Pippi Longstocking was a Thing-Finder, and pippi finds things.
52
+ Finally, why "pippi"? Because Pippi Longstocking was a <a href="http://www.laredoisd.org/cdbooks/NOVELS/Pippi%20Longstocking/CH02.txt">Thing-Finder</a>, and pippi finds things.
53
53
 
54
54
  ## Usage
55
55
 
@@ -61,6 +61,8 @@ Finally, why "pippi"? Because Pippi Longstocking was a Thing-Finder, and pippi f
61
61
  ```ruby
62
62
  if ENV['USE_PIPPI'].present?
63
63
  Pippi::AutoRunner.new(:checkset => ENV['PIPPI_CHECKSET'] || "basic")
64
+ # you can also pass in an IO:
65
+ # Pippi::AutoRunner.new(:checkset => "basic", :io => $stdout)
64
66
  end
65
67
  ```
66
68
  * Run it:
@@ -373,6 +375,7 @@ rm -rf pippi_debug.log pippi.log .bundle/gems/pippi-0.0.1/ .bundle/cache/pippi-0
373
375
  * [Evan Phoenix](https://twitter.com/evanphx)([@evanphx](https://github.com/evanphx)) for the idea of watching method invocations at runtime using metaprogramming rather than using `Tracepoint`.
374
376
  * Hubert Dąbrowski: Ruby 2.0.0 fixes
375
377
  * [Igor Kapkov](https://twitter.com/igasgeek)([@igas](https://github.com/igas)) documentation fixes
378
+ * [Josh Bodah](https://github.com/jbodah): Better logging support
376
379
  * [LivingSocial](https://www.livingsocial.com/) for letting me develop and open source this utility.
377
380
  * [Michael Bernstein](https://twitter.com/mrb_bk)([@mrb](https://github.com/mrb)) (of [CodeClimate](https://codeclimate.com/) fame) for an inspirational discussion of code anaysis in general.
378
381
  * [Olle Jonsson](https://twitter.com/olleolleolle)([@olleolleolle](https://github.com/olleolleolle)) rubocop fixes
@@ -4,6 +4,7 @@ module Pippi
4
4
 
5
5
  def initialize(opts = {})
6
6
  checkset = opts.fetch(:checkset, 'basic')
7
+ @io = opts.fetch(:io, File.open('log/pippi.log', 'w'))
7
8
  @ctx = Pippi::Context.new
8
9
 
9
10
  @ctx.checks = Pippi::CheckLoader.new(@ctx, checkset).checks
@@ -15,10 +16,8 @@ module Pippi
15
16
  if @ctx.checks.one? && @ctx.checks.first.kind_of?(Pippi::Checks::MethodSequenceFinder)
16
17
  @ctx.checks.first.dump
17
18
  end
18
- File.open('log/pippi.log', 'w') do |outfile|
19
- @ctx.report.problems.each do |problem|
20
- outfile.syswrite("#{problem.to_text}\n")
21
- end
19
+ @ctx.report.problems.each do |problem|
20
+ @io.puts(problem.to_text)
22
21
  end
23
22
  end
24
23
  end
@@ -24,24 +24,31 @@ class MethodSequenceChecker
24
24
  end
25
25
 
26
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))
27
+ second_method_decorator = if method_sequence_check_instance.second_method_arity_type.kind_of?(Module)
28
+ method_sequence_check_instance.second_method_arity_type
29
+ else
30
+ Module.new do
31
+ define_method(method_sequence_check_instance.method2) do |*args, &blk|
32
+ # Using "self.class" implies that the first method invocation returns the same type as the receiver
33
+ # e.g., Array#select returns an Array. Would need to further parameterize this to get
34
+ # different behavior.
35
+ self.class.instance_variable_get(name).add_problem
36
+ if method_sequence_check_instance.should_check_subsequent_calls && method_sequence_check_instance.clazz_to_decorate == Array
37
+ problem_location = caller_locations.find { |c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
38
+ self.class.instance_variable_get(name).method_names_that_indicate_this_is_being_used_as_a_collection.each do |this_means_its_ok_sym|
39
+ 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))
40
+ end
41
+ end
42
+ if method_sequence_check_instance.second_method_arity_type == ARITY_TYPE_BLOCK_ARG
43
+ super(&blk)
44
+ elsif method_sequence_check_instance.second_method_arity_type == ARITY_TYPE_NONE
45
+ super()
34
46
  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
47
  end
41
48
  end
42
49
  end
43
50
 
44
- # e.g., "select" in "select followed ARITY_TYPE_NONEze"
51
+ # e.g., "select" in "select followed by size"
45
52
  first_method_decorator = Module.new do
46
53
  define_method(method_sequence_check_instance.method1) do |*args, &blk|
47
54
  result = if method_sequence_check_instance.first_method_arity_type == ARITY_TYPE_BLOCK_ARG
@@ -1,10 +1,10 @@
1
1
  module Pippi::Checks
2
2
 
3
3
  module MyModule
4
- def split(&blk)
4
+ def strip(*args, &blk)
5
5
  result = super
6
6
  if self.class._pippi_method_call_sequences
7
- array_methods_to_track.each do |track_this|
7
+ self.class._pippi_method_call_sequences.methods_to_track.each do |track_this|
8
8
  result.define_singleton_method(track_this, track_it_proc(track_this))
9
9
  end
10
10
  end
@@ -23,18 +23,15 @@ module Pippi::Checks
23
23
  end
24
24
  end
25
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
26
 
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
27
  end
35
28
 
36
29
  class MethodSequenceFinder < Check
37
30
 
31
+ STRING_METHODS_TO_TRACK = [: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?]
32
+
33
+ ARRAY_METHODS_TO_TRACK = [: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]
34
+
38
35
  class Record
39
36
  attr_reader :path, :lineno, :meth1, :meth2
40
37
  def initialize(path, lineno, meth1, meth2)
@@ -52,22 +49,43 @@ module Pippi::Checks
52
49
  end
53
50
  end
54
51
 
55
- attr_reader :sequences, :clazz_to_decorate
52
+ attr_reader :sequences, :clazz_to_decorate, :starting_method
53
+
54
+ =begin
55
+ To add a new sequence finder where the first method is on String, change the starting_method below
56
+ and also change the method name up in MyModule. To change it to a different class you must also
57
+ change :clazz_to_decorate
56
58
 
59
+ =end
57
60
  def initialize(ctx)
58
61
  super
59
62
  @clazz_to_decorate = String
63
+ @starting_method = "strip"
64
+
60
65
  @sequences = Set.new
61
66
  end
62
67
 
68
+ def methods_to_track
69
+ if clazz_to_decorate == String
70
+ STRING_METHODS_TO_TRACK
71
+ elsif clazz_to_decorate == Array
72
+ ARRAY_METHODS_TO_TRACK
73
+ else
74
+ raise "Unhandled class #{clazz_to_decorate}"
75
+ end
76
+ end
77
+
63
78
  def dump
64
79
  @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
80
  puts "#{r[0].split(':')[0]} followed by #{r[0].split(':')[1]} occurred #{r[1]} times\n"
81
+ @sequences.select {|s| (s.meth1 == r[0].split(':')[0]) && (s.meth2 == r[0].split(':')[1].to_sym) }.each do |s|
82
+ puts "#{s.path}: #{s.lineno}"
83
+ end
66
84
  end
67
85
  end
68
86
 
69
87
  def found_sequence(method_name, location)
70
- @sequences << Record.new(location.path, location.lineno, "map", method_name)
88
+ @sequences << Record.new(location.path, location.lineno, starting_method, method_name)
71
89
  end
72
90
 
73
91
  def decorate
@@ -1,11 +1,10 @@
1
1
  module Pippi::Checks
2
2
  class SelectFollowedByFirst < Check
3
3
 
4
- # TODO make this use MethodSequenceChecker
5
- module MyFirst
4
+ module MyModule
6
5
  def first(elements = nil)
7
6
  unless elements
8
- self.class._pippi_check_select_followed_by_first.add_problem
7
+ self.class._pippi_check_selectfollowedbyfirst.add_problem
9
8
  end
10
9
  if elements
11
10
  super(elements)
@@ -15,29 +14,13 @@ module Pippi::Checks
15
14
  end
16
15
  end
17
16
 
18
- module MySelect
19
- def select(&blk)
20
- result = super
21
- if self.class._pippi_check_select_followed_by_first.nil?
22
- # Ignore Array subclasses since select or first may have difference meanings
23
- else
24
- result.extend MyFirst
25
- self.class._pippi_check_select_followed_by_first.array_mutator_methods.each do |this_means_its_ok_sym|
26
- result.define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_first.its_ok_watcher_proc(MyFirst, :first))
27
- end
28
- end
29
- result
30
- end
17
+ def decorate
18
+ @mycheck.decorate
31
19
  end
32
20
 
33
- def decorate
34
- Array.class_exec(self) do |my_check|
35
- @_pippi_check_select_followed_by_first = my_check
36
- class << self
37
- attr_reader :_pippi_check_select_followed_by_first
38
- end
39
- prepend MySelect
40
- end
21
+ def initialize(ctx)
22
+ super
23
+ @mycheck = MethodSequenceChecker.new(self, Array, "select", "first", MethodSequenceChecker::ARITY_TYPE_BLOCK_ARG, MyModule, true)
41
24
  end
42
25
 
43
26
  class Documentation
@@ -1,3 +1,3 @@
1
1
  module Pippi
2
- VERSION = '0.0.10'
2
+ VERSION = '0.0.11'
3
3
  end
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.10
4
+ version: 0.0.11
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-09 00:00:00.000000000 Z
11
+ date: 2014-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake