tphases 0.1.2 → 0.2.0

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.
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ script: bundle exec rspec spec
6
+ notifications:
7
+ email: false
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # TPhases
2
2
 
3
+ [![Build Status](https://travis-ci.org/charleseff/tphases.png)](https://travis-ci.org/charleseff/tphases)
4
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/charleseff/tphases)
5
+
3
6
  TPhases (Transactional Phases) is a support framework that helps you build your Rails request life cycles into read-only, write-only, and no-transaction-allowed phases.
4
7
 
5
8
  The way it accomplishes this is with the methods `TPhases.read_phase`, `TPhases.write_phase` and `TPhases.no_transactions_phase` which take blocks. Here is a simple example inside of a controller action:
@@ -46,23 +49,38 @@ Somewhere in the initialization process of your app, call
46
49
 
47
50
  ## Usage
48
51
 
49
- ### In production:
52
+ ### Environments
53
+
54
+ #### In production:
50
55
  The `read_phase`, `write_phase`, and `no_transaction_phase` methods simply yield to the block given.
51
56
 
52
- ### In development:
57
+ #### In development:
53
58
 
54
- #### `read_phase`
59
+ ##### `read_phase`
55
60
  throws an exception if a database transaction is attempted within its block which is a write. This is known as a "read transactional violation".
56
61
 
57
- #### `write_phase`
62
+ ##### `write_phase`
58
63
  throws an exception if a database transaction is attempted within its block which is a read. This is a write transactional violation.
59
64
 
60
- #### `no_transactions_phase`
65
+ ##### `no_transactions_phase`
61
66
  throws an exception if any database transaction is attempted within its block.
62
67
 
63
- ### In test:
68
+ #### In test:
64
69
  If a transactional violation occurs in a TPhase, the code will continue to run, but the test will fail at the end citing the list of transactional violations that occurred.
65
70
 
71
+ ### Methods
72
+
73
+ #### `ensure_no_transactions_on`
74
+ Call `ensure_no_transactions_on` on controllers to prevent DB transactions within the views of controller actions. e.g.:
75
+
76
+ ```ruby
77
+ class BarsController < ApplicationController
78
+
79
+ ensure_no_transactions_on [:show,:update]
80
+ end
81
+ ```
82
+
83
+
66
84
  ## Contributing
67
85
 
68
86
  1. Fork it
@@ -8,10 +8,16 @@ module TPhases
8
8
  yield config
9
9
  end
10
10
 
11
- private
12
11
  # the config
12
+ # settings options are:
13
+ #
14
+ # - mode
15
+ # - collect_mode_failures_on - defaults to true, but can be turned off temporarily to disable failures on
16
+ # transaction violations
17
+ #
13
18
  # sets default value `mode` value based on presence of Rails and environment type
14
19
  # the default setting is the safest, :pass_through, which means TPhases does nothing.
20
+ #
15
21
  def config
16
22
  @config ||= begin
17
23
 
@@ -32,7 +38,7 @@ module TPhases
32
38
  end
33
39
  end
34
40
 
35
- Struct.new(:mode).new(default_mode)
41
+ Struct.new(:mode, :collect_mode_failures_on).new(default_mode, true)
36
42
  end
37
43
  end
38
44
 
@@ -5,6 +5,12 @@ module TPhases
5
5
  module ClassMethods
6
6
  # initiates TPhases. Any overrides to config mode need to be made prior to running this.
7
7
  def initiate!
8
+ add_mode_methods!
9
+ add_rails_methods! if defined? Rails
10
+ end
11
+
12
+ private
13
+ def add_mode_methods!
8
14
  case config.mode
9
15
  when :pass_through
10
16
  require 'tphases/modes/pass_through_mode'
@@ -18,7 +24,6 @@ module TPhases
18
24
  else
19
25
  raise "TPhases mode must be one of :pass_through, :exceptions, or :collect, but instead is #{config.mode}"
20
26
  end
21
-
22
27
  end
23
28
 
24
29
  end
@@ -1,5 +1,6 @@
1
1
  require 'tphases/transactional_violation'
2
2
  require 'tphases/modes/helpers/transactional_violations_helper'
3
+ require 'tphases/modes/helpers/rails_helper'
3
4
 
4
5
  # the default 'test' mode, Collect Mode collects incidents of
5
6
  # immediately inside of a TPhase block if a transactional violation occurs
@@ -8,9 +9,11 @@ module TPhases
8
9
  module CollectMode
9
10
  extend ActiveSupport::Concern
10
11
  include Helpers::TransactionalViolationsHelper
12
+ include Helpers::RailsHelper if defined? Rails
11
13
 
12
14
  included do
13
15
  add_rspec_after! if defined?(RSpec)
16
+ add_cucumber_after! if defined?(Cucumber)
14
17
  @violations = []
15
18
  end
16
19
 
@@ -34,26 +37,49 @@ module TPhases
34
37
  # adds an after block for all rspec tests that cause them to fail if any transactional violations are present
35
38
  def add_rspec_after!
36
39
  RSpec.configure do |config|
37
- config.after(:each) do
38
- begin
39
- unless TPhases.violations.empty?
40
- #fail "This spec had #{TPhases.violations.count} transactional violations: \n\t#{TPhases.violations.map(&:inspect).join("\n\t")}"
41
- fail <<-FAILURE_MESSAGE
42
- This spec had #{TPhases.violations.count} transactional violations:
43
- #{TPhases.violations.each_with_index.map do |violation,index|
44
- "#{index}: Violation Type: #{violation[:type]},\nSQL: #{violation[:sql]}\nCall Stack:\n\t#{violation[:call_stack].join("\n\t")}"
45
- end.join("\n*********************************************************\n")}
46
- end
47
- FAILURE_MESSAGE
40
+ config.after(:each, &after_test_fail_if_violations_proc)
41
+ end
42
+ end
43
+
44
+ def add_cucumber_after!
45
+ # todo: get me working
46
+ #require 'cucumber/rb_support/rb_dsl'
47
+ #Cucumber::RbSupport::RbDsl.register_rb_hook('after', [], after_test_fail_if_violations_proc)
48
+ end
49
+
50
+ # fails if there were any transactional violations
51
+ def after_test_fail_if_violations_proc
52
+ Proc.new do
53
+ begin
54
+ if TPhases.config.collect_mode_failures_on && !TPhases.violations.empty?
55
+
56
+ fail_message = "This spec had #{TPhases.violations.count} transactional violations:\n"
57
+ TPhases.violations.each_with_index.map do |violation, index|
58
+ fail_message << "*"*50 + "\n"
59
+ fail_message << "Violation ##{index+1}, type: #{violation[:type]}\n"
60
+ fail_message << "SQL: #{violation[:sql]}\n"
61
+ fail_message << "Call Stack: \n\t\t#{TPhases.cleaned_call_stack(violation[:call_stack]).join("\n\t\t")}\n"
48
62
  end
49
- ensure
50
- # reset violations list:
51
- TPhases.violations = []
63
+
64
+ fail fail_message
52
65
  end
66
+ ensure
67
+ TPhases.violations = [] # reset violations list
53
68
  end
54
69
  end
70
+
55
71
  end
56
72
 
73
+ public
74
+ # taken from https://github.com/rails/rails/blob/77977f34a5a4ea899f59e31ad869b582285fa5c1/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L148 :
75
+ # shows a cleaned stack for Rails apps by default
76
+ def cleaned_call_stack(call_stack)
77
+ defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ?
78
+ Rails.backtrace_cleaner.clean(call_stack, :silent) :
79
+ call_stack
80
+ end
81
+
82
+
57
83
  end
58
84
  end
59
85
  end
@@ -1,5 +1,6 @@
1
1
  require 'tphases/transactional_violation'
2
2
  require 'tphases/modes/helpers/transactional_violations_helper'
3
+ require 'tphases/modes/helpers/rails_helper'
3
4
 
4
5
  # the default 'development' mode, Exceptions Mode means that an exception will be raised
5
6
  # immediately inside of a TPhase block if a transactional violation occurs
@@ -8,6 +9,7 @@ module TPhases
8
9
  module ExceptionsMode
9
10
  extend ActiveSupport::Concern
10
11
  include Helpers::TransactionalViolationsHelper
12
+ include Helpers::RailsHelper if defined? Rails
11
13
 
12
14
  module ClassMethods
13
15
  private
@@ -0,0 +1,41 @@
1
+ module TPhases::Modes
2
+ module Helpers
3
+ module RailsHelper
4
+ extend ActiveSupport::Concern
5
+ module ClassMethods
6
+ def add_rails_methods!
7
+ add_render_alias_method_chain!
8
+
9
+ require 'tphases/rails/no_transactions_in_controller'
10
+ ActionController::Base.send :include, TPhases::Rails::NoTransactionsInController
11
+ end
12
+
13
+ private
14
+ def add_render_alias_method_chain!
15
+ unless Gem.loaded_specs.values.map { |value| value.full_gem_path }.any? { |n| n.include? "actionpack-3.0." }
16
+ raise "TPhases currently expects Rails version 3.0.* for patching ActionView template."
17
+ end
18
+
19
+ ActionView::Template.class_eval do
20
+
21
+ def render_with_tphases_no_transactions(view, locals, &block)
22
+ controller_class = view.controller.class
23
+ if controller_class.class_variable_defined?(:@@no_transaction_actions) &&
24
+ controller_class.class_variable_get(:@@no_transaction_actions).include?(view.action_name.to_sym)
25
+ TPhases.no_transactions_phase do
26
+ render_without_tphases_no_transactions(view, locals, &block)
27
+ end
28
+ else
29
+ render_without_tphases_no_transactions(view, locals, &block)
30
+ end
31
+ end
32
+
33
+ alias_method_chain :render, :tphases_no_transactions
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -13,121 +13,75 @@ module TPhases
13
13
 
14
14
  included do
15
15
  define_phase_methods!
16
+
17
+ # used to keep track of nested phases. a nested phase overrides any prior phase.
18
+ @phase_stack = []
16
19
  end
17
20
 
18
- private
19
21
  module ClassMethods
20
22
 
21
- # if version of activesupport is 3.2.1, it has the subscribed method. else, it doesn't
22
23
  def define_phase_methods!
23
- if ActiveSupport::VERSION::MAJOR > 3
24
- define_phase_methods_with_subscribed_method!
25
- elsif ActiveSupport::VERSION::MAJOR == 3
26
- if ActiveSupport::VERSION::MINOR > 2
27
- define_phase_methods_with_subscribed_method!
28
- elsif ActiveSupport::VERSION::MINOR == 2
29
- if ActiveSupport::VERSION::TINY >= 1
30
- define_phase_methods_with_subscribed_method!
31
- else
32
- define_phase_methods_without_subscribed_method!
24
+ %w{read write no_transactions}.each do |phase_type|
25
+ define_singleton_method(:"#{phase_type}_phase") do |&block|
26
+ phase = Phase.new
27
+ @phase_stack << phase
28
+ begin
29
+ subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |name, date, date2, sha, args|
30
+ next unless @phase_stack.last == phase
31
+ if send(:"#{phase_type}_violation?", args[:sql])
32
+ send(:"#{phase_type}_violation_action", args[:sql], caller)
33
+ end
34
+
35
+ end
36
+ block.call
37
+ ensure
38
+ ActiveSupport::Notifications.unsubscribe(subscriber)
39
+ @phase_stack.pop
33
40
  end
34
- else
35
- define_phase_methods_without_subscribed_method!
36
41
  end
37
- else
38
- define_phase_methods_without_subscribed_method!
39
- end
40
- end
41
-
42
- # adds methods using the subscribed method
43
- def define_phase_methods_with_subscribed_method!
44
- define_singleton_method(:read_phase) do |&block|
45
- ActiveSupport::Notifications.subscribed(read_phase_subscription_callback, "sql.active_record", &block)
46
- end
47
-
48
- define_singleton_method(:write_phase) do |&block|
49
- ActiveSupport::Notifications.subscribed(write_phase_subscription_callback, "sql.active_record", &block)
50
- end
51
-
52
- define_singleton_method(:no_transactions_phase) do |&block|
53
- ActiveSupport::Notifications.subscribed(no_transactions_phase_subscription_callback, "sql.active_record", &block)
54
42
  end
55
43
  end
56
44
 
57
- def define_phase_methods_without_subscribed_method!
58
- define_singleton_method(:read_phase) do |&block|
59
- begin
60
- subscriber = ActiveSupport::Notifications.subscribe("sql.active_record", &read_phase_subscription_callback)
61
- block.call
62
- ensure
63
- ActiveSupport::Notifications.unsubscribe(subscriber)
64
- end
65
- end
66
-
67
- define_singleton_method(:write_phase) do |&block|
68
- begin
69
- subscriber = ActiveSupport::Notifications.subscribe("sql.active_record", &write_phase_subscription_callback)
70
- block.call
71
- ensure
72
- ActiveSupport::Notifications.unsubscribe(subscriber)
73
- end
74
- end
45
+ private
46
+ READ_QUERIES = %w{show select describe}
47
+ WRITE_QUERIES = %w{update commit insert delete}
48
+ RAILS_IGNORABLE_QUERIES = %w{describe}
75
49
 
76
- define_singleton_method(:no_transactions_phase) do |&block|
77
- begin
78
- subscriber = ActiveSupport::Notifications.subscribe("sql.active_record", &no_transactions_phase_subscription_callback)
79
- block.call
80
- ensure
81
- ActiveSupport::Notifications.unsubscribe(subscriber)
82
- end
83
- end
50
+ def rails_ignorable_read_queries
51
+ @rails_ignorable_read_queries ||= READ_QUERIES - RAILS_IGNORABLE_QUERIES
84
52
  end
85
53
 
86
- # the set of blocks that run when an ActiveSupport notification is fired on sql.active_record
87
- # each call *_violation_action methods which are defined in the implementing module
88
-
89
- def write_phase_subscription_callback
90
- Proc.new do |name, date, date2, sha, args|
91
- if write_transactional_violation?(args[:sql])
92
- write_violation_action(args[:sql], caller)
93
- end
94
- end
54
+ # determines if this query is a read transactional violation (if it is anything besides a read)
55
+ def read_violation?(sql)
56
+ WRITE_QUERIES.include?(first_word(sql))
95
57
  end
96
58
 
97
- def read_phase_subscription_callback
98
- Proc.new do |name, date, date2, sha, args|
99
- if read_transactional_violation?(args[:sql])
100
- read_violation_action(args[:sql], caller)
101
- end
102
- end
59
+ # determines if this query is a write transactional violation (if it is anything besides a write)
60
+ def write_violation?(sql)
61
+ query_types = (Object.const_defined? :Rails) ? rails_ignorable_read_queries : READ_QUERIES
62
+ query_types.include?(first_word(sql))
103
63
  end
104
64
 
105
- def no_transactions_phase_subscription_callback
106
- Proc.new do |name, date, date2, sha, args|
107
- no_transactions_violation_action(args[:sql], caller)
65
+ # violation unless it's Rails and we are running an ignorable query
66
+ def no_transactions_violation?(sql)
67
+ if Object.const_defined? :Rails
68
+ !RAILS_IGNORABLE_QUERIES.include?(first_word(sql))
69
+ else
70
+ true
108
71
  end
109
72
  end
110
73
 
111
- READ_QUERIES = %w{update commit insert delete}
112
- WRITE_QUERIES = %w{show select}
113
-
114
- # determines if this query is a read transactional violation (if it is anything besides a read)
115
- def read_transactional_violation?(sql)
116
- READ_QUERIES.include?(first_word(sql))
117
- end
118
-
119
- # determines if this query is a write transactional violation (if it is anything besides a write)
120
- def write_transactional_violation?(sql)
121
- WRITE_QUERIES.include?(first_word(sql))
122
- end
123
-
124
74
  def first_word(str)
125
75
  str.split(' ').first.downcase
126
76
  end
127
77
 
128
78
  end
129
79
 
80
+ # simple class to represent a phase on the stack of phases. Used to determine which phase is active
81
+ class Phase;
82
+ end
83
+
130
84
  end
131
85
  end
132
86
  end
133
- end
87
+ end
@@ -16,6 +16,12 @@ module TPhases
16
16
  def no_transactions_phase
17
17
  yield
18
18
  end
19
+
20
+ private
21
+ def add_rails_methods!
22
+ require 'tphases/rails/no_transactions_in_controller_pass_through'
23
+ ActionController::Base.send :include, TPhases::Rails::NoTransactionsInControllerPassThrough
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -0,0 +1,15 @@
1
+ module TPhases
2
+ module Rails
3
+ module NoTransactionsInController
4
+ extend ActiveSupport::Concern
5
+ module ClassMethods
6
+
7
+ def ensure_no_transactions_on(actions)
8
+ class_variable_set(:@@no_transaction_actions, actions)
9
+ end
10
+
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module TPhases
2
+ module Rails
3
+ module NoTransactionsInControllerPassThrough
4
+ extend ActiveSupport::Concern
5
+ module ClassMethods
6
+ def ensure_no_transactions_on(actions)
7
+ # do nothing
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  module Tphases
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
Binary file
@@ -58,4 +58,45 @@ describe TPhases::Modes::ExceptionsMode do
58
58
 
59
59
  end
60
60
  end
61
+
62
+ describe "nested phases" do
63
+ context "read_phase inside of a no_transactions_phase" do
64
+ it "should allow read transactions" do
65
+ expect {
66
+ subject.no_transactions_phase do
67
+ subject.read_phase do
68
+ ActiveRecord::Base.connection.select_all(read_sql)
69
+ end
70
+ end
71
+ }.to_not raise_error
72
+
73
+ end
74
+ end
75
+
76
+ context "no_transactions_phase inside a read_phase" do
77
+ it "should disallow read transactions" do
78
+ expect {
79
+ subject.read_phase do
80
+ subject.no_transactions_phase do
81
+ ActiveRecord::Base.connection.select_all(read_sql)
82
+ end
83
+ end
84
+ }.to raise_error(ActiveRecord::StatementInvalid, "TransactionalViolation: #{read_sql} ran inside of a 'no_transactions_phase' block.: #{read_sql}")
85
+
86
+
87
+ end
88
+ end
89
+
90
+ it "should have the right phase_stack sizes" do
91
+ subject.instance_variable_get("@phase_stack").should be_empty
92
+ subject.read_phase do
93
+ subject.instance_variable_get("@phase_stack").size.should == 1
94
+ subject.no_transactions_phase do
95
+ subject.instance_variable_get("@phase_stack").size.should == 2
96
+ end
97
+ subject.instance_variable_get("@phase_stack").size.should == 1
98
+ end
99
+ subject.instance_variable_get("@phase_stack").should be_empty
100
+ end
101
+ end
61
102
  end
@@ -2,37 +2,67 @@ require 'spec_helper'
2
2
  require 'tphases/modes/helpers/transactional_violations_helper'
3
3
 
4
4
  describe TPhases::Modes::Helpers::TransactionalViolationsHelper do
5
- describe TPhases::Modes::Helpers::TransactionalViolationsHelper do
6
- subject { Module.new { include TPhases::Modes::Helpers::TransactionalViolationsHelper } }
5
+ subject { Module.new { include TPhases::Modes::Helpers::TransactionalViolationsHelper } }
7
6
 
8
- let(:write_queries) {
9
- [
10
- "UPDATE `users` SET `email` = 'woifjwe@owiejf.com' WHERE `users`.`id` = 1",
11
- "INSERT INTO tablename (col1, col2) VALUES('data1', 'data2' )",
12
- "COMMIT",
13
- "DELETE FROM example WHERE age='15'"
14
- ]
15
- }
16
- let(:read_queries) {
17
- [
18
- "select * from foobar",
19
- "show variables like 'version'"
20
- ]
21
- }
7
+ let(:write_queries) {
8
+ [
9
+ "UPDATE `users` SET `email` = 'woifjwe@owiejf.com' WHERE `users`.`id` = 1",
10
+ "INSERT INTO tablename (col1, col2) VALUES('data1', 'data2' )",
11
+ "COMMIT",
12
+ "DELETE FROM example WHERE age='15'"
13
+ ]
14
+ }
15
+ let(:read_queries) {
16
+ [
17
+ "select * from foobar",
18
+ "show variables like 'version'"
19
+ ]
20
+ }
22
21
 
23
- describe "#read_transactional_violation?" do
24
- it "should detect correctly" do
25
- read_queries.each { |read_query| expect(subject.send(:read_transactional_violation?, read_query)).to eq(false) }
26
- write_queries.each { |write_query| expect(subject.send(:read_transactional_violation?, write_query)).to eq(true) }
22
+ describe "#read_transactional_violation?" do
23
+ it "should detect correctly" do
24
+ read_queries.each { |read_query| expect(subject.send(:read_violation?, read_query)).to eq(false) }
25
+ write_queries.each { |write_query| expect(subject.send(:read_violation?, write_query)).to eq(true) }
26
+ end
27
+ end
28
+
29
+ describe "#write_violation?" do
30
+ it "should detect correctly" do
31
+ read_queries.each { |read_query| expect(subject.send(:write_violation?, read_query)).to be_true }
32
+ write_queries.each { |write_query| expect(subject.send(:write_violation?, write_query)).to be_false }
33
+ end
34
+
35
+ context "describe queries" do
36
+ context "when Rails is present" do
37
+ it "should detect correctly" do
38
+ Object.should_receive(:const_defined?).with(:Rails).and_return(true)
39
+ expect(subject.send(:write_violation?, "describe foo")).to be_false
40
+ end
41
+ end
42
+ context "when Rails is not present" do
43
+ it "should detect correctly" do
44
+ Object.should_receive(:const_defined?).with(:Rails).and_return(false)
45
+ expect(subject.send(:write_violation?, "describe foo")).to be_true
46
+ end
27
47
  end
28
48
  end
29
49
 
30
- describe " #write_transactional_violation?" do
50
+ end
51
+
52
+ describe "#no_transactions_violation?" do
53
+ context "when Rails is present" do
31
54
  it "should detect correctly" do
32
- read_queries.each { |read_query| expect(subject.send(:write_transactional_violation?, read_query)).to be_true }
33
- write_queries.each { |write_query| expect(subject.send(:write_transactional_violation?, write_query)).to be_false }
55
+ Object.stub(:const_defined?).with(:Rails).and_return(true)
56
+ expect(subject.send(:no_transactions_violation?, "describe foo")).to be_false
57
+ expect(subject.send(:no_transactions_violation?, "select * from foo")).to be_true
58
+ end
59
+ end
60
+ context "when Rails is not present" do
61
+ it "should detect correctly" do
62
+ Object.stub(:const_defined?).with(:Rails).and_return(false)
63
+ expect(subject.send(:no_transactions_violation?, "describe foo")).to be_true
64
+ expect(subject.send(:no_transactions_violation?, "select * from foo")).to be_true
34
65
  end
35
66
  end
36
-
37
67
  end
38
- end
68
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tphases
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-03 00:00:00.000000000 Z
12
+ date: 2012-11-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -117,6 +117,7 @@ extra_rdoc_files: []
117
117
  files:
118
118
  - .gitignore
119
119
  - .rspec
120
+ - .travis.yml
120
121
  - Gemfile
121
122
  - LICENSE.txt
122
123
  - README.md
@@ -126,8 +127,11 @@ files:
126
127
  - lib/tphases/initialization.rb
127
128
  - lib/tphases/modes/collect_mode.rb
128
129
  - lib/tphases/modes/exceptions_mode.rb
130
+ - lib/tphases/modes/helpers/rails_helper.rb
129
131
  - lib/tphases/modes/helpers/transactional_violations_helper.rb
130
132
  - lib/tphases/modes/pass_through_mode.rb
133
+ - lib/tphases/rails/no_transactions_in_controller.rb
134
+ - lib/tphases/rails/no_transactions_in_controller_pass_through.rb
131
135
  - lib/tphases/transactional_violation.rb
132
136
  - lib/tphases/version.rb
133
137
  - spec/fixtures/database.sqlite3