pippi 0.0.3 → 0.0.4

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: 9f1712f4957c4dc681c64b2031b42668a1965c26
4
- data.tar.gz: 2e7795a1a90750cb9838dcfa37e6a83a5ea9d5d3
3
+ metadata.gz: 95752be642c66d479b293d0887592472cbb7a6d4
4
+ data.tar.gz: 80f13c0e7329c6909e2729161f09f3489d6eb8e9
5
5
  SHA512:
6
- metadata.gz: d8c0198da71b5bc8ae6ce92d432374c74f97249394bfbe75c13862137d47d5864f0c8f7b43ed66084756a4677ac73f0c7dcd660df343455690330eeb5a52b5c1
7
- data.tar.gz: 399fd31a5f4cb6938f2368b586902cfe7ded570ec00975d13c76eacdf90f2400a19c5f1d9afabc1efec1f6c1aa49b798a0cfa94bb874b2ded25d6e044325ab69
6
+ metadata.gz: 3544e1ec0e442f38f8cfb52fe05a46eb6f504af6e9ff4f25665cf1930d1f618660a8adbd5e6bb0c19c750f46b542d2afa39ff42973d67441372a1aa0cc233b50
7
+ data.tar.gz: a56988007f42d5ee982887c5be19a8635fea55c0813193710dec41317f0125801658f87fb09a4a27e319c6f751844219362d8bc100f47d86c909b44ab76cfbc1
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
- tmp/
1
+ tmp/*
2
+ !tmp/baz.rb
2
3
  pippi.log
3
4
  pippi_debug.log
4
5
  pippi*.gem
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ Oct 30, 2014 - 0.0.4:
2
+ Bugfixes around method delegation
3
+
1
4
  Oct 22, 2014 - 0.0.3:
2
5
  Moved AssertWithNil to "buggy" checkset until I can figure out issues.
3
6
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pippi (0.0.3)
4
+ pippi (0.0.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,6 +1,48 @@
1
+ # Pippi
2
+
1
3
  Pippi is a utility for finding suboptimal Ruby class API usage.
2
4
 
3
- <a href="http://thomasleecopeland.com/2014/10/22/finding-suboptimal-api-usage.html">Here's a project overview</a>.
5
+ [Here's a project overview](http://thomasleecopeland.com/2014/10/22/finding-suboptimal-api-usage.html).
6
+
7
+ ## Usage
8
+
9
+ ### Rails with test-unit
10
+
11
+ * Add `gem 'pippi'` to the `test` group in your project's `Gemfile`
12
+ * Add this to `test_helper.rb` just before the `require 'rails/test_help'` line
13
+
14
+ ```ruby
15
+ if ENV['USE_PIPPI'].present?
16
+ Pippi::AutoRunner.new(:checkset => ENV['PIPPI_CHECKSET'] || "basic")
17
+ end
18
+ ```
19
+ * Run it:
20
+
21
+ ```text
22
+ USE_PIPPI=true bundle exec rake test:units && cat log/pippi.log
23
+ ```
24
+
25
+ Here's a [demo Rails application](https://github.com/tcopeland/pippi_demo#pippi-demo).
26
+
27
+ ### Rails with rspec
28
+
29
+ TODO and FIXME
30
+
31
+ ### From the command line:
32
+
33
+ Assuming you're using bundler:
34
+
35
+ ```bash
36
+ # Add this to your project's Gemfile:
37
+ gem 'pippi'
38
+ # Run 'bundle', see some output
39
+ # To run a particular check:
40
+ bundle exec pippi tmp/tmpfile.rb MapFollowedByFlatten Foo.new.bar out.txt
41
+ # Or to run all the basic Pippi checks on your code and exercise it with MyClass.new.exercise_some_code:
42
+ bundle exec ruby -rpippi/auto_runner -e "MyClass.new.exercise_some_code"
43
+ ```
44
+
45
+
4
46
 
5
47
  ## Checksets
6
48
 
@@ -35,6 +77,7 @@ Instead, consider doing this:
35
77
 
36
78
  ```ruby
37
79
  x = nil ; assert_nil(x)
80
+ ```
38
81
 
39
82
  ### MapFollowedByFlatten
40
83
 
@@ -100,26 +143,6 @@ Instead, consider doing this:
100
143
  [1,2,3].count {|x| x > 1 }
101
144
  ```
102
145
 
103
- ## Usage
104
-
105
- ### Inside Rails tests
106
-
107
- See https://github.com/tcopeland/pippi_demo#pippi-demo
108
-
109
- ### From the command line:
110
-
111
- Assuming you're using bundler:
112
-
113
- ```bash
114
- # Add this to your project's Gemfile:
115
- gem 'pippi'
116
- # Run 'bundle', see some output
117
- # To run a particular check:
118
- bundle exec pippi tmp/tmpfile.rb MapFollowedByFlatten Foo.new.bar out.txt
119
- # Or to run all the basic Pippi checks on your code and exercise it with MyClass.new.exercise_some_code:
120
- bundle exec ruby -rpippi/auto_runner -e "MyClass.new.exercise_some_code"
121
- ```
122
-
123
146
  ## Ideas for other problems to detect:
124
147
 
125
148
  ```ruby
@@ -158,20 +181,29 @@ product_path(@product)
158
181
  ````
159
182
 
160
183
  ## Here are some things that Pippi is not well suited for
161
- ### Use self.new vs MyClass.new. This is not a good fit for Pippi because it involves a receiver usage that can be detected with static analysis.
162
- #### wrong
184
+
185
+ Use self.new vs MyClass.new. This is not a good fit for Pippi because it
186
+ involves a receiver usage that can be detected with static analysis.
187
+
188
+ **wrong**:
189
+
190
+ ```
163
191
  class Foo
164
192
  def self.bar
165
193
  Foo.new
166
194
  end
167
195
  end
168
- #### right
196
+ ```
197
+
198
+ **right**:
199
+
200
+ ```
169
201
  class Foo
170
202
  def self.bar
171
203
  self.new
172
204
  end
173
205
  end
174
-
206
+ ```
175
207
 
176
208
  ## TODO
177
209
 
@@ -197,8 +229,20 @@ rm -rf pippi_debug.log pippi.log .bundle/gems/pippi-0.0.1/ .bundle/cache/pippi-0
197
229
 
198
230
  ```
199
231
 
232
+ ## How to do a release
233
+
234
+ * Bump version number
235
+ * Move anything from 'training' to 'buggy' or elsewhere
236
+ * Tie off Changelog notes
237
+ * Regenerate docs with `pippi:generate_docs`, copy and paste that into README
238
+ * Commit, push
239
+ * `bundle exec gem build pippi.gemspec`
240
+ * `gem push pippi-x.gem`
241
+
200
242
  ## Credits
201
243
 
202
- * Thanks to <a href="https://www.livingsocial.com/">LivingSocial</a> for letting me develop and open source this utility.
203
- * Thanks to Evan Phoenix for the idea of watching method invocations at runtime using metaprogramming rather than using `Tracepoint`.
204
- * Thanks to Michael Bernstein (of Code Climate fame) for an inspirational discussion of code anaysis in general.
244
+ * Christopher Schramm bugfixes in fault proc clearing
245
+ * [Evan Phoenix](https://twitter.com/evanphx) for the idea of watching method invocations at runtime using metaprogramming rather than using `Tracepoint`.
246
+ * Igor Kapkov documentation fixes
247
+ * LivingSocial](https://www.livingsocial.com/) for letting me develop and open source this utility.
248
+ * [Michael Bernstein](https://twitter.com/mrb_bk) (of [CodeClimate](https://codeclimate.com/) fame) for an inspirational discussion of code anaysis in general.
@@ -3,9 +3,11 @@ module Pippi
3
3
  class CheckSetMapper
4
4
 
5
5
  attr_reader :raw_check_specifier
6
+ attr_accessor :predefined_sets
6
7
 
7
8
  def initialize(raw_check_specifier)
8
9
  @raw_check_specifier = raw_check_specifier
10
+ define_standard_sets
9
11
  end
10
12
 
11
13
  def check_names
@@ -16,7 +18,8 @@ module Pippi
16
18
 
17
19
  private
18
20
 
19
- def predefined_sets
21
+ def define_standard_sets
22
+ @predefined_sets =
20
23
  {
21
24
  "basic" => [
22
25
  "SelectFollowedByFirst",
@@ -4,11 +4,10 @@ module Pippi::Checks
4
4
 
5
5
  module MyAssertEqual
6
6
  def assert_equal(*args)
7
- result = super
8
7
  if args.size > 1 && args[0].object_id == 8
9
8
  self.class._pippi_check_assert_with_nil.add_problem
10
9
  end
11
- result
10
+ super
12
11
  end
13
12
  end
14
13
 
@@ -17,10 +17,11 @@ module Pippi::Checks
17
17
  ctx.report.add(Pippi::Problem.new(:line_number => problem_location.lineno, :file_path => problem_location.path, :check_class => self.class))
18
18
  end
19
19
 
20
- def clear_fault_proc
21
- Proc.new do
20
+ def clear_fault_proc(clz)
21
+ Proc.new do |*args, &blk|
22
22
  problem_location = caller_locations.detect {|c| c.to_s !~ /byebug|lib\/pippi\/checks/ }
23
- self.class._pippi_check_select_followed_by_size.clear_fault(problem_location.lineno, problem_location.path)
23
+ clz.clear_fault(problem_location.lineno, problem_location.path)
24
+ super(*args, &blk)
24
25
  end
25
26
  end
26
27
 
@@ -29,11 +30,15 @@ module Pippi::Checks
29
30
  end
30
31
 
31
32
  def its_ok_watcher_proc(clazz, method_name)
32
- Proc.new do
33
- singleton_class.ancestors.detect {|x| x == clazz }.instance_eval { remove_method method_name }
34
- super()
33
+ Proc.new do |*args, &blk|
34
+ begin
35
+ singleton_class.ancestors.detect {|x| x == clazz }.instance_eval { remove_method method_name }
36
+ rescue NameError
37
+ return super(*args, &blk)
38
+ else
39
+ return super(*args, &blk)
40
+ end
35
41
  end
36
42
  end
37
-
38
43
  end
39
44
  end
@@ -4,11 +4,14 @@ module Pippi::Checks
4
4
 
5
5
  module MyFlatten
6
6
  def flatten(depth=nil)
7
- result = super(depth)
8
7
  if depth && depth == 1
9
8
  self.class._pippi_check_map_followed_by_flatten.add_problem
10
9
  end
11
- result
10
+ if depth
11
+ super(depth)
12
+ else
13
+ super()
14
+ end
12
15
  end
13
16
  end
14
17
 
@@ -4,9 +4,8 @@ module Pippi::Checks
4
4
 
5
5
  module MyEach
6
6
  def each
7
- result = super()
8
7
  self.class._pippi_check_reverse_followed_by_each.add_problem
9
- result
8
+ super()
10
9
  end
11
10
  end
12
11
 
@@ -4,15 +4,14 @@ module Pippi::Checks
4
4
 
5
5
  module MyFirst
6
6
  def first(elements=nil)
7
- result = if elements
7
+ unless elements
8
+ self.class._pippi_check_select_followed_by_first.add_problem
9
+ end
10
+ if elements
8
11
  super(elements)
9
12
  else
10
13
  super()
11
14
  end
12
- unless elements
13
- self.class._pippi_check_select_followed_by_first.add_problem
14
- end
15
- result
16
15
  end
17
16
  end
18
17
 
@@ -4,12 +4,11 @@ module Pippi::Checks
4
4
 
5
5
  module MySize
6
6
  def size
7
- result = super()
8
7
  self.class._pippi_check_select_followed_by_size.add_problem
9
8
  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|
10
- define_singleton_method(this_means_its_ok_sym, self.class._pippi_check_select_followed_by_size.clear_fault_proc)
9
+ 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))
11
10
  end
12
- result
11
+ super()
13
12
  end
14
13
  end
15
14
 
data/lib/pippi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pippi
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -26,6 +26,19 @@ class AssertWithNilTest < CheckTest
26
26
  # 0004 opt_send_simple <callinfo!mid:x, argc:0, FCALL|VCALL|ARGS_SKIP>
27
27
  # 0006 opt_send_simple <callinfo!mid:foo, argc:1, FCALL|ARGS_SKIP>
28
28
  # 0008 leave
29
+ # also consider
30
+ =begin
31
+ class Bar
32
+ def buz(x)
33
+ end
34
+ def foo
35
+ y = nil
36
+ buz(y)
37
+ RubyVM::InstructionSequence.of(method(__method__)).disasm.split("\n").each {|x| puts x }
38
+ end
39
+ end
40
+ Bar.new.foo
41
+ =end
29
42
  def test_nil_reference_first_arg_doesnt_flag
30
43
  assert_no_problems "x = 42 ; y = nil ; assert_equal(nil, x)", :include_rails_core_extensions => true, :subclass => "ActiveSupport::TestCase"
31
44
  end
@@ -0,0 +1,17 @@
1
+ require "test_helper"
2
+
3
+ class CheckSetMapperTest < Minitest::Test
4
+
5
+ def test_should_find_predefined_sets
6
+ csm = Pippi::CheckSetMapper.new("basic")
7
+ assert csm.check_names.include?("SelectFollowedByFirst")
8
+ end
9
+
10
+ def test_should_allow_comma_separated_checkset_names
11
+ csm = Pippi::CheckSetMapper.new("a,b")
12
+ csm.predefined_sets = {"a" => ["foo"], "b" => ["bar"]}
13
+ assert csm.check_names.include?("foo")
14
+ assert csm.check_names.include?("bar")
15
+ end
16
+
17
+ end
@@ -26,8 +26,22 @@ class SelectFollowedBySizeTest < CheckTest
26
26
  assert_no_problems "tmp = [1,2,3].select {|x| x > 1 } ; tmp.reject! {|x| x } ; tmp.size"
27
27
  end
28
28
 
29
- def test_will_not_flag_if_method_subsequently_invokedzz
29
+ def test_will_not_flag_if_method_subsequently_invoked
30
30
  assert_no_problems "tmp = [1,2,3].select {|x| x > 1 } ; tmp.size ; y = tmp.sort!"
31
31
  end
32
32
 
33
+ def test_clear_fault_proc_should_not_cause_errors_by_failing_to_return_result_of_method_invocations
34
+ str = <<-EOS
35
+ tmp = [1,2,3].select {|x| x > 4 }
36
+ tmp.size
37
+ tmp = tmp.reject{|l| l.nil? }
38
+ tmp.map {|x| 1 }
39
+ EOS
40
+ assert_problems str
41
+ end
42
+
43
+ def test_clear_fault_proc_doesnt_try_to_remove_singleton_method_twice
44
+ assert_no_problems "tmp = [1,2,3].select {|x| x > 1 } ; y = tmp.sort! ; y = tmp.sort!"
45
+ end
46
+
33
47
  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.3
4
+ version: 0.0.4
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-10-23 00:00:00.000000000 Z
11
+ date: 2014-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -93,13 +93,13 @@ files:
93
93
  - test/rails_core_extensions.rb
94
94
  - test/test_helper.rb
95
95
  - test/unit/assert_with_nil_test.rb
96
+ - test/unit/check_set_mapper_test.rb
96
97
  - test/unit/map_followed_by_flatten_test.rb
97
98
  - test/unit/problem_test.rb
98
99
  - test/unit/report_test.rb
99
100
  - test/unit/reverse_followed_by_each_test.rb
100
101
  - test/unit/select_followed_by_first_test.rb
101
102
  - test/unit/select_followed_by_size_test.rb
102
- - tmp/.gitignore
103
103
  - vendor/cache/byebug-2.7.0.gem
104
104
  - vendor/cache/columnize-0.8.9.gem
105
105
  - vendor/cache/debugger-linecache-1.2.0.gem
@@ -134,6 +134,7 @@ test_files:
134
134
  - test/rails_core_extensions.rb
135
135
  - test/test_helper.rb
136
136
  - test/unit/assert_with_nil_test.rb
137
+ - test/unit/check_set_mapper_test.rb
137
138
  - test/unit/map_followed_by_flatten_test.rb
138
139
  - test/unit/problem_test.rb
139
140
  - test/unit/report_test.rb