pippi 0.0.3 → 0.0.4

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