shoulda-matchers 2.6.1 → 2.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -0
  4. data/.yardopts +8 -0
  5. data/Appraisals +82 -33
  6. data/Gemfile +18 -2
  7. data/Gemfile.lock +13 -1
  8. data/NEWS.md +27 -2
  9. data/README.md +83 -1329
  10. data/Rakefile +118 -1
  11. data/cucumber.yml +1 -0
  12. data/doc_config/gh-pages/index.html.erb +9 -0
  13. data/doc_config/yard/setup.rb +22 -0
  14. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +298 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  27. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  28. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  29. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  30. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  31. data/doc_config/yard/templates/default/layout/html/setup.rb +40 -0
  32. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  33. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  34. data/docs.watchr +5 -0
  35. data/features/rails_integration.feature +32 -0
  36. data/features/step_definitions/rails_steps.rb +55 -9
  37. data/features/support/env.rb +1 -0
  38. data/gemfiles/3.0.gemfile +13 -1
  39. data/gemfiles/3.0.gemfile.lock +13 -1
  40. data/gemfiles/3.1.gemfile +17 -2
  41. data/gemfiles/3.1.gemfile.lock +31 -2
  42. data/gemfiles/3.1_1.9.2.gemfile +33 -0
  43. data/gemfiles/3.1_1.9.2.gemfile.lock +203 -0
  44. data/gemfiles/3.2.gemfile +18 -2
  45. data/gemfiles/3.2.gemfile.lock +32 -2
  46. data/gemfiles/3.2_1.9.2.gemfile +32 -0
  47. data/gemfiles/3.2_1.9.2.gemfile.lock +200 -0
  48. data/gemfiles/4.0.0.gemfile +20 -1
  49. data/gemfiles/4.0.0.gemfile.lock +46 -2
  50. data/gemfiles/4.0.1.gemfile +20 -1
  51. data/gemfiles/4.0.1.gemfile.lock +46 -2
  52. data/gemfiles/4.1.gemfile +21 -2
  53. data/gemfiles/4.1.gemfile.lock +47 -4
  54. data/lib/shoulda/matchers/action_controller.rb +0 -20
  55. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +119 -28
  56. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +22 -6
  57. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +43 -10
  58. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +40 -13
  59. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +63 -11
  60. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +34 -1
  61. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +84 -15
  62. data/lib/shoulda/matchers/action_controller/route_matcher.rb +84 -28
  63. data/lib/shoulda/matchers/action_controller/route_params.rb +4 -3
  64. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +76 -13
  65. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +147 -13
  66. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +148 -2
  67. data/lib/shoulda/matchers/active_model.rb +0 -25
  68. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +66 -9
  69. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +161 -19
  70. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -5
  71. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +92 -13
  72. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +218 -16
  73. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +198 -32
  74. data/lib/shoulda/matchers/active_model/errors.rb +5 -2
  75. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +1 -1
  76. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +29 -8
  77. data/lib/shoulda/matchers/active_model/helpers.rb +20 -8
  78. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  79. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +4 -6
  80. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +4 -3
  81. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +3 -2
  82. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +4 -3
  83. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +4 -3
  84. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +52 -14
  85. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +51 -13
  86. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +53 -7
  87. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +275 -19
  88. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +84 -14
  89. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +170 -41
  90. data/lib/shoulda/matchers/active_model/validation_matcher.rb +20 -15
  91. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +1 -2
  92. data/lib/shoulda/matchers/active_record.rb +1 -12
  93. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +89 -15
  94. data/lib/shoulda/matchers/active_record/association_matcher.rb +726 -70
  95. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +4 -3
  97. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -3
  98. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +4 -3
  99. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +2 -1
  100. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +4 -3
  101. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +4 -5
  102. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +4 -3
  103. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +4 -3
  104. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +4 -3
  105. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +79 -15
  106. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +64 -15
  107. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +21 -7
  108. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +85 -10
  109. data/lib/shoulda/matchers/assertion_error.rb +7 -1
  110. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  111. data/lib/shoulda/matchers/doublespeak/double.rb +3 -1
  112. data/lib/shoulda/matchers/doublespeak/double_collection.rb +2 -1
  113. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +1 -0
  114. data/lib/shoulda/matchers/doublespeak/object_double.rb +2 -1
  115. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +2 -1
  116. data/lib/shoulda/matchers/doublespeak/structs.rb +2 -0
  117. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +2 -1
  118. data/lib/shoulda/matchers/doublespeak/world.rb +3 -4
  119. data/lib/shoulda/matchers/error.rb +1 -0
  120. data/lib/shoulda/matchers/independent/delegate_matcher.rb +108 -20
  121. data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +4 -3
  122. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +3 -0
  123. data/lib/shoulda/matchers/rails_shim.rb +3 -2
  124. data/lib/shoulda/matchers/version.rb +2 -1
  125. data/lib/shoulda/matchers/warn.rb +1 -0
  126. data/script/SUPPORTED_VERSIONS +1 -0
  127. data/script/install_gems_in_all_appraisals +14 -0
  128. data/script/run_all_tests +14 -0
  129. data/shoulda-matchers.gemspec +0 -10
  130. data/spec/report_warnings.rb +7 -0
  131. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +1 -1
  132. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +9 -0
  133. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +0 -36
  134. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +2 -2
  135. data/spec/shoulda/matchers/doublespeak/double_spec.rb +1 -1
  136. data/spec/shoulda/matchers/doublespeak/world_spec.rb +11 -29
  137. data/spec/shoulda/matchers/doublespeak_spec.rb +3 -3
  138. data/spec/spec_helper.rb +17 -0
  139. data/spec/support/class_builder.rb +4 -0
  140. data/spec/support/test_application.rb +1 -1
  141. data/spec/warnings_spy.rb +64 -0
  142. data/spec/warnings_spy/filesystem.rb +45 -0
  143. data/spec/warnings_spy/partitioner.rb +29 -0
  144. data/spec/warnings_spy/reader.rb +64 -0
  145. data/spec/warnings_spy/reporter.rb +87 -0
  146. metadata +49 -134
@@ -0,0 +1,7 @@
1
+ require File.expand_path('../warnings_spy', __FILE__)
2
+
3
+ # Adapted from <http://myronmars.to/n/dev-blog/2011/08/making-your-gem-warning-free>
4
+
5
+ warnings_spy = WarningsSpy.new('shoulda-matchers')
6
+ warnings_spy.capture_warnings
7
+ warnings_spy.report_warnings_at_exit
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Shoulda::Matchers::ActionController::RouteMatcher, type: :controller do
3
+ describe 'Shoulda::Matchers::ActionController::RouteMatcher', type: :controller do
4
4
  context 'given a controller with a defined glob url' do
5
5
  it 'accepts glob route' do
6
6
  controller = define_controller('Examples').new
@@ -25,6 +25,15 @@ describe Shoulda::Matchers::ActionController do
25
25
 
26
26
  expect(@controller).to permit(:name, :age).for(:create)
27
27
  end
28
+
29
+ it 'can be used more than once in the same test' do
30
+ controller_for_resource_with_strong_parameters(action: :create) do
31
+ params.require(:user).permit(:name)
32
+ end
33
+
34
+ expect(@controller).to permit(:name).for(:create)
35
+ expect(@controller).not_to permit(:admin).for(:create)
36
+ end
28
37
  end
29
38
  end
30
39
 
@@ -383,42 +383,6 @@ describe Shoulda::Matchers::ActiveModel::ValidateUniquenessOfMatcher do
383
383
  end
384
384
  end
385
385
 
386
- context "a model with non-nullable attribute" do
387
- context "of type" do
388
- [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |type|
389
- context type do
390
- it "does not raise an error" do
391
- model = define_model_with_non_nullable(type)
392
- expect { expect(model).to matcher }.not_to raise_error
393
- end
394
- end
395
- end
396
- end
397
-
398
- context "that is a primary key" do
399
- it "does not cause duplicate entry errors by re-using default values for primary keys" do
400
- create_table :examples, id: false do |t|
401
- t.string :attr
402
- t.integer :non_nullable, primary: true
403
- end
404
- model_class = define_model(:example, attr: :string) do
405
- validates_uniqueness_of :attr
406
- end
407
- model_1 = model_class.new
408
- model_2 = model_class.new
409
- expect(model_1).to matcher
410
- expect { expect(model_2).to matcher }.not_to raise_error
411
- end
412
- end
413
-
414
- def define_model_with_non_nullable(type)
415
- define_model(:example, attr: :string, non_nullable: { type: type, options: { null: false } }) do
416
- attr_accessible :attr, :non_nullable
417
- validates_uniqueness_of :attr
418
- end.new
419
- end
420
- end
421
-
422
386
  def case_sensitive_validation_with_existing_value(attr_type)
423
387
  model = define_model(:example, attr: attr_type) do
424
388
  attr_accessible :attr
@@ -67,7 +67,7 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
67
67
 
68
68
  description = finder.messages_description
69
69
 
70
- expected_messages = ['attr is invalid ("xyz")']
70
+ expected_messages = ['is invalid (attribute: "attr", value: "xyz")']
71
71
  expect(description).to eq "errors: #{expected_messages}"
72
72
  end
73
73
 
@@ -87,7 +87,7 @@ describe Shoulda::Matchers::ActiveModel::ValidationMessageFinder do
87
87
  end.new
88
88
  finder = Shoulda::Matchers::ActiveModel::ValidationMessageFinder.new(instance, :attribute)
89
89
 
90
- expected_messages = ['association.association_attribute is invalid']
90
+ expected_messages = ['is invalid (attribute: "association.association_attribute")']
91
91
  expect(finder.messages_description).to eq "errors: #{expected_messages}"
92
92
  end
93
93
 
@@ -103,7 +103,7 @@ module Shoulda::Matchers::Doublespeak
103
103
 
104
104
  describe '#call_original_method' do
105
105
  it 'binds the stored method object to the class and calls it with the given args and block' do
106
- klass = create_class(a_method: nil)
106
+ klass = create_class
107
107
  instance = klass.new
108
108
  actual_args = actual_block = method_called = nil
109
109
  expected_args = [:one, :two, :three]
@@ -2,18 +2,19 @@ require 'spec_helper'
2
2
 
3
3
  module Shoulda::Matchers::Doublespeak
4
4
  describe World do
5
- describe '#register_double_collection' do
6
- it 'calls DoubleCollection.new with the given class' do
7
- DoubleCollection.expects(:new).with(:klass)
5
+ describe '#double_collection_for' do
6
+ it 'calls DoubleCollection.new once with the given class' do
7
+ DoubleCollection.expects(:new).with(:klass).returns(:klass).once
8
8
  world = described_class.new
9
- world.register_double_collection(:klass)
9
+ world.double_collection_for(:klass)
10
+ world.double_collection_for(:klass)
10
11
  end
11
12
 
12
- it 'returns the newly created DoubleCollection' do
13
+ it 'returns the created DoubleCollection' do
13
14
  double_collection = Object.new
14
15
  DoubleCollection.stubs(:new).with(:klass).returns(double_collection)
15
16
  world = described_class.new
16
- expect(world.register_double_collection(:klass)).to be double_collection
17
+ expect(world.double_collection_for(:klass)).to be double_collection
17
18
  end
18
19
  end
19
20
 
@@ -40,9 +41,9 @@ module Shoulda::Matchers::Doublespeak
40
41
  DoubleCollection.stubs(:new).
41
42
  with(:klass3).
42
43
  returns(double_collections[2])
43
- world.register_double_collection(:klass1)
44
- world.register_double_collection(:klass2)
45
- world.register_double_collection(:klass3)
44
+ world.double_collection_for(:klass1)
45
+ world.double_collection_for(:klass2)
46
+ world.double_collection_for(:klass3)
46
47
 
47
48
  world.with_doubles_activated { block_called = true }
48
49
 
@@ -57,32 +58,13 @@ module Shoulda::Matchers::Doublespeak
57
58
  world = described_class.new
58
59
 
59
60
  DoubleCollection.stubs(:new).returns(double_collection)
60
- world.register_double_collection(:klass)
61
+ world.double_collection_for(:klass)
61
62
 
62
63
  begin
63
64
  world.with_doubles_activated { raise 'error' }
64
65
  rescue RuntimeError
65
66
  end
66
67
  end
67
-
68
- it 'does not allow multiple DoubleCollections to be registered that represent the same class' do
69
- double_collections = [stub, stub]
70
- sequence = sequence('with_doubles_activated')
71
- double_collections[0].expects(:activate).never
72
- double_collections[0].expects(:deactivate).never
73
- double_collections[1].expects(:activate).in_sequence(sequence)
74
- double_collections[1].expects(:deactivate).in_sequence(sequence)
75
-
76
- world = described_class.new
77
-
78
- DoubleCollection.stubs(:new).
79
- returns(double_collections[0]).then.
80
- returns(double_collections[1])
81
- world.register_double_collection(:klass1)
82
- world.register_double_collection(:klass1)
83
-
84
- world.with_doubles_activated { }
85
- end
86
68
  end
87
69
  end
88
70
  end
@@ -2,10 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  module Shoulda::Matchers
4
4
  describe Doublespeak do
5
- describe '.register_double_collection' do
5
+ describe '.double_collection_for' do
6
6
  it 'delegates to its world' do
7
- Doublespeak.world.expects(:register_double_collection).with(:klass)
8
- described_class.register_double_collection(:klass)
7
+ Doublespeak.world.expects(:double_collection_for).with(:klass)
8
+ described_class.double_collection_for(:klass)
9
9
  end
10
10
  end
11
11
 
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,24 @@
1
1
  require File.expand_path('../support/test_application', __FILE__)
2
2
 
3
+ def monkey_patch_minitest_to_do_nothing
4
+ # Rails 3.1's test_help file requires Turn, which loads Minitest in autorun
5
+ # mode. This means that Minitest tests will run after these RSpec tests are
6
+ # finished running. This will break on CI since we pass --color to the `rspec`
7
+ # command.
8
+
9
+ if defined?(MiniTest)
10
+ MiniTest::Unit.class_eval do
11
+ def run(*); end
12
+ end
13
+ end
14
+ end
15
+
3
16
  $test_app = TestApplication.new
4
17
  $test_app.create
5
18
  $test_app.load
6
19
 
20
+ monkey_patch_minitest_to_do_nothing
21
+
7
22
  ENV['BUNDLE_GEMFILE'] ||= app.gemfile_path
8
23
  ENV['RAILS_ENV'] = 'test'
9
24
 
@@ -24,3 +39,5 @@ RSpec.configure do |config|
24
39
  config.include Shoulda::Matchers::ActionController,
25
40
  example_group: { file_path: /action_controller/ }
26
41
  end
42
+
43
+ $VERBOSE = true
@@ -10,6 +10,10 @@ module ClassBuilder
10
10
  def define_class(class_name, base = Object, &block)
11
11
  class_name = class_name.to_s.camelize
12
12
 
13
+ if Object.const_defined?(class_name)
14
+ Object.__send__(:remove_const, class_name)
15
+ end
16
+
13
17
  # FIXME: ActionMailer 3.2 calls `name.underscore` immediately upon
14
18
  # subclassing. Class.new.name == nil. So, Class.new(ActionMailer::Base)
15
19
  # errors out since it's trying to do `nil.underscore`. This is very ugly but
@@ -92,7 +92,7 @@ EOT
92
92
  end
93
93
 
94
94
  def install_gems
95
- retrying('bundle install') do |command|
95
+ retrying('bundle install --local') do |command|
96
96
  Bundler.with_clean_env { `#{command}` }
97
97
  end
98
98
  end
@@ -0,0 +1,64 @@
1
+ require 'forwardable'
2
+
3
+ require File.expand_path('../warnings_spy/filesystem', __FILE__)
4
+ require File.expand_path('../warnings_spy/reader', __FILE__)
5
+ require File.expand_path('../warnings_spy/partitioner', __FILE__)
6
+ require File.expand_path('../warnings_spy/reporter', __FILE__)
7
+
8
+ class WarningsSpy
9
+ extend Forwardable
10
+
11
+ def initialize(project_name)
12
+ filesystem = Filesystem.new
13
+ @warnings_file = filesystem.warnings_file
14
+ @reader = Reader.new(filesystem)
15
+ @partitioner = Partitioner.new(reader, filesystem)
16
+ @reporter = Reporter.new(partitioner, filesystem, project_name)
17
+ end
18
+
19
+ def capture_warnings
20
+ $stderr.reopen(warnings_file.path)
21
+ end
22
+
23
+ def report_warnings_at_exit
24
+ at_exit do
25
+ printing_exceptions do
26
+ report_and_exit
27
+ end
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ attr_reader :warnings_file, :reader, :partitioner, :reporter
34
+
35
+ private
36
+
37
+ def_delegators :partitioner, :relevant_warning_groups,
38
+ :irrelevant_warning_groups
39
+
40
+ def report_and_exit
41
+ reader.read
42
+ partitioner.partition
43
+ reporter.report
44
+ #fail_build_if_there_are_any_warnings
45
+ end
46
+
47
+ def fail_build_if_there_are_any_warnings
48
+ if relevant_warning_groups.any?
49
+ exit(1)
50
+ end
51
+ end
52
+
53
+ def printing_exceptions
54
+ begin
55
+ yield
56
+ rescue => error
57
+ puts "\n--- ERROR IN AT_EXIT --------------------------------"
58
+ puts "#{error.class}: #{error.message}"
59
+ puts error.backtrace.join("\n")
60
+ puts "-----------------------------------------------------"
61
+ raise error
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ require 'fileutils'
2
+
3
+ class WarningsSpy
4
+ class Filesystem
5
+ PROJECT_DIR = File.expand_path('../../..', __FILE__)
6
+ TEMP_DIR = File.join(PROJECT_DIR, 'tmp')
7
+
8
+ def initialize
9
+ @files_by_name = Hash.new do |hash, name|
10
+ FileUtils.mkdir_p(TEMP_DIR)
11
+ hash[name] = file_for(name)
12
+ end
13
+ end
14
+
15
+ def warnings_file
16
+ files_by_name['all_warnings']
17
+ end
18
+
19
+ def irrelevant_warnings_file
20
+ files_by_name['irrelevant_warnings']
21
+ end
22
+
23
+ def relevant_warnings_file
24
+ files_by_name['relevant_warnings']
25
+ end
26
+
27
+ def project_dir
28
+ PROJECT_DIR
29
+ end
30
+
31
+ protected
32
+
33
+ attr_reader :files_by_name
34
+
35
+ private
36
+
37
+ def path_for(name)
38
+ File.join(TEMP_DIR, "#{name}.txt")
39
+ end
40
+
41
+ def file_for(name)
42
+ File.open(path_for(name), 'w+')
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ require 'forwardable'
2
+
3
+ class WarningsSpy
4
+ class Partitioner
5
+ extend Forwardable
6
+
7
+ attr_reader :relevant_warning_groups, :irrelevant_warning_groups
8
+
9
+ def initialize(reader, filesystem)
10
+ @reader = reader
11
+ @search_text = filesystem.project_dir
12
+ end
13
+
14
+ def partition
15
+ @relevant_warning_groups, @irrelevant_warning_groups =
16
+ warning_groups.partition do |group|
17
+ group.any? { |line| line.include?(search_text) }
18
+ end
19
+ end
20
+
21
+ protected
22
+
23
+ attr_reader :reader, :search_text
24
+
25
+ private
26
+
27
+ def_delegators :reader, :warning_groups
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ class WarningsSpy
2
+ class Reader
3
+ attr_reader :warning_groups
4
+
5
+ def initialize(filesystem)
6
+ @warnings_file = filesystem.warnings_file
7
+
8
+ @recording = false
9
+ @current_group = []
10
+ @warning_groups = []
11
+ end
12
+
13
+ def read
14
+ warnings_file.rewind
15
+
16
+ warnings_file.each_line do |line|
17
+ process_line(line)
18
+ end
19
+
20
+ add_group(current_group)
21
+ end
22
+
23
+ protected
24
+
25
+ attr_reader :warnings_file, :current_group
26
+
27
+ private
28
+
29
+ def process_line(line)
30
+ if backtrace_line?(line) && recording?
31
+ current_group << line
32
+ else
33
+ unless current_group.empty?
34
+ add_group(current_group)
35
+ current_group.clear
36
+ end
37
+
38
+ current_group << line
39
+
40
+ @recording = true
41
+ end
42
+ end
43
+
44
+ def add_group(group)
45
+ unless group_already_added?(group)
46
+ warning_groups << group
47
+ end
48
+ end
49
+
50
+ def group_already_added?(group_to_be_added)
51
+ warning_groups.any? do |group|
52
+ group == group_to_be_added
53
+ end
54
+ end
55
+
56
+ def backtrace_line?(line)
57
+ line =~ /^\s+/
58
+ end
59
+
60
+ def recording?
61
+ @recording
62
+ end
63
+ end
64
+ end