pippi 0.0.10 → 0.0.11

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
  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