Skip to content

Instantly share code, notes, and snippets.

@charleseff
Created January 26, 2026 16:33
Show Gist options
  • Select an option

  • Save charleseff/c66857e1844ae09ce0bba56633aa8e47 to your computer and use it in GitHub Desktop.

Select an option

Save charleseff/c66857e1844ae09ce0bba56633aa8e47 to your computer and use it in GitHub Desktop.
TPhases - Transactional Phases for Rails (flattened from github.com/charleseff/tphases)

TPhases - Gist Version

Original Repository: https://github.com/charleseff/tphases

TPhases (Transactional Phases) is a support framework that helps you build your Rails request life cycles into read-only and write-only phases.

File Structure

This gist flattens the original directory structure. -- represents / in paths.

To Reconstruct the Original Structure:

# Clone this gist
git clone https://gist.github.com/YOUR_GIST_ID.git tphases
cd tphases

# Run this to restore directory structure:
for f in *--*; do
  original=$(echo "$f" | sed 's|--|/|g')
  mkdir -p "$(dirname "$original")"
  mv "$f" "$original"
done

Original Directory Layout:

tphases/
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── tphases.gemspec
├── lib/
│   ├── tphases.rb
│   └── tphases/
│       ├── config.rb
│       ├── initialization.rb
│       ├── transactional_violation.rb
│       ├── version.rb
│       ├── modes/
│       │   ├── collect_mode.rb
│       │   ├── exceptions_mode.rb
│       │   ├── pass_through_mode.rb
│       │   └── helpers/
│       │       ├── rails_helper.rb
│       │       └── transactional_violations_helper.rb
│       └── rails/
│           ├── no_transactions_in_controller.rb
│           └── no_transactions_in_controller_pass_through.rb
└── spec/
    ├── spec_helper.rb
    ├── fixtures/
    │   └── database.yml
    ├── support/
    │   └── setup_modes_specs_context.rb
    └── lib/tphases/modes/
        ├── collect_mode_spec.rb
        ├── exceptions_mode_spec.rb
        ├── pass_through_mode_spec.rb
        └── helpers/
            └── transactional_violations_helper_spec.rb

Running Tests (after reconstruction):

bundle install
bundle exec rspec

TPhases

Build Status Code Climate

TPhases (Transactional Phases) is a support framework that helps you isolate database transactional code in your Ruby app by providing read-only, write-only, and no-transaction-allowed phases.

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:

class BarsController < ApplicationController

  def update
    TPhases.read_phase do
      @bar = Bar.find(params[:id])
    end
    
    TPhases.write_phase do
      @bar.update_attributes(params[:bar])
    end

    TPhases.no_transactions_phase do
      process(@bar)
      redirect_to @bar
    end
  end
end

** Currently supports ActiveRecord only. Planned support includes Memcached, Redis, MongoDB, and more.

Installation

Add this line to your application's Gemfile:

gem 'tphases'

And then execute:

$ bundle

Or install it yourself as:

$ gem install tphases

Somewhere in the initialization process of your app, call

TPhases.initiate!

Usage

Environments

In production:

The read_phase, write_phase, and no_transaction_phase methods simply yield to the block given.

In development:

read_phase

throws an exception if a database transaction is attempted within its block which is a write. This is known as a "read transactional violation".

write_phase

throws an exception if a database transaction is attempted within its block which is a read. This is a write transactional violation.

no_transactions_phase

throws an exception if any database transaction is attempted within its block.

In test:

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.

Methods

ensure_no_transactions_on

Call ensure_no_transactions_on on controllers to prevent DB transactions within the view and action of a controller action. e.g.:

class BarsController < ApplicationController

  ensure_no_transactions_on [:show,:update]
end

ignore_phases

Call ignore_phases to disable TPhases within the block passed

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request
source 'https://rubygems.org'
# Specify your gem's dependencies in tphases.gemspec
gemspec
module TPhases
module Config
extend ActiveSupport::Concern
module ClassMethods
# allow for configuration of TPhases
def configure(&block)
yield config
end
# the config
# settings options are:
#
# - mode
# - collect_mode_failures_on - defaults to true, but can be turned off temporarily to disable failures on
# transaction violations
#
# sets default value `mode` value based on presence of Rails and environment type
# the default setting is the safest, :pass_through, which means TPhases does nothing.
#
def config
@config ||= begin
default_mode = begin
if defined? ::Rails
case ::Rails.env
when 'production', 'staging', 'demo'
:pass_through
when 'development'
:exceptions
when 'test'
:collect
else
:pass_through
end
else
:pass_through
end
end
Struct.new(:mode, :collect_mode_failures_on).new(default_mode, true)
end
end
end
end
end
module TPhases
module Initialization
extend ActiveSupport::Concern
module ClassMethods
# initiates TPhases. Any overrides to config mode need to be made prior to running this.
def initiate!
add_mode_methods!
add_rails_methods! if defined? ::Rails
end
private
def add_mode_methods!
case config.mode
when :pass_through
require 'tphases/modes/pass_through_mode'
include TPhases::Modes::PassThroughMode
when :exceptions
require 'tphases/modes/exceptions_mode'
include TPhases::Modes::ExceptionsMode
when :collect
require 'tphases/modes/collect_mode'
include TPhases::Modes::CollectMode
else
raise "TPhases mode must be one of :pass_through, :exceptions, or :collect, but instead is #{config.mode}"
end
end
end
end
end
require 'tphases/transactional_violation'
require 'tphases/modes/helpers/transactional_violations_helper'
require 'tphases/modes/helpers/rails_helper'
# the default 'test' mode, Collect Mode collects incidents of
# immediately inside of a TPhase block if a transactional violation occurs
module TPhases
module Modes
module CollectMode
extend ActiveSupport::Concern
include Helpers::TransactionalViolationsHelper
include Helpers::RailsHelper if defined? ::Rails
included do
add_rspec_after! if defined?(RSpec)
add_cucumber_after! if defined?(Cucumber)
@violations = []
end
module ClassMethods
attr_accessor :violations
private
def write_violation_action(sql, call_stack)
violations << { :type => :write, :call_stack => call_stack, :sql => sql }
end
def read_violation_action(sql, call_stack)
violations << { :type => :read, :call_stack => call_stack, :sql => sql }
end
def no_transactions_violation_action(sql, call_stack)
violations << { :type => :no_transactions, :call_stack => call_stack, :sql => sql }
end
# adds an after block for all rspec tests that cause them to fail if any transactional violations are present
def add_rspec_after!
RSpec.configure do |config|
config.after(:each, &after_test_fail_if_violations_proc)
end
end
def add_cucumber_after!
# todo: get me working
#require 'cucumber/rb_support/rb_dsl'
#Cucumber::RbSupport::RbDsl.register_rb_hook('after', [], after_test_fail_if_violations_proc)
end
# fails if there were any transactional violations
def after_test_fail_if_violations_proc
Proc.new do
begin
if TPhases.config.collect_mode_failures_on && !TPhases.violations.empty?
fail_message = "This spec had #{TPhases.violations.count} transactional violations:\n"
TPhases.violations.each_with_index.map do |violation, index|
fail_message << "*"*50 + "\n"
fail_message << "Violation ##{index+1}, type: #{violation[:type]}\n"
fail_message << "SQL: #{violation[:sql]}\n"
fail_message << "Call Stack: \n\t\t#{TPhases.cleaned_call_stack(violation[:call_stack]).join("\n\t\t")}\n"
end
fail fail_message
end
ensure
TPhases.violations = [] # reset violations list
end
end
end
public
# taken from https://github.com/rails/rails/blob/77977f34a5a4ea899f59e31ad869b582285fa5c1/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L148 :
# shows a cleaned stack for Rails apps by default
def cleaned_call_stack(call_stack)
defined?(::Rails) && ::Rails.respond_to?(:backtrace_cleaner) ?
::Rails.backtrace_cleaner.clean(call_stack, :silent) :
call_stack
end
end
end
end
end
require 'tphases/transactional_violation'
require 'tphases/modes/helpers/transactional_violations_helper'
require 'tphases/modes/helpers/rails_helper'
# the default 'development' mode, Exceptions Mode means that an exception will be raised
# immediately inside of a TPhase block if a transactional violation occurs
module TPhases
module Modes
module ExceptionsMode
extend ActiveSupport::Concern
include Helpers::TransactionalViolationsHelper
include Helpers::RailsHelper if defined? Rails
module ClassMethods
private
def write_violation_action(sql, caller)
raise TransactionalViolation.new "#{sql} ran inside of a 'write_phase' block."
end
def read_violation_action(sql, caller)
raise TransactionalViolation.new "#{sql} ran inside of a 'read_phase' block."
end
def no_transactions_violation_action(sql, caller)
raise TransactionalViolation.new "#{sql} ran inside of a 'no_transactions_phase' block."
end
end
end
end
end
module TPhases::Modes
module Helpers
module RailsHelper
extend ActiveSupport::Concern
module ClassMethods
def add_rails_methods!
add_render_alias_method_chain!
require 'tphases/rails/no_transactions_in_controller'
ActionController::Base.send :include, TPhases::Rails::NoTransactionsInController
end
private
def add_render_alias_method_chain!
unless Gem.loaded_specs.values.map { |value| value.full_gem_path }.any? { |n| n.include? "actionpack-3." }
raise "TPhases currently expects Rails version 3.*.* for patching ActionView template."
end
ActionView::Template.class_eval do
def render_with_tphases_no_transactions(view, locals, &block)
controller_class = view.controller.class
if controller_class.class_variable_defined?(:@@no_transaction_actions) &&
controller_class.class_variable_get(:@@no_transaction_actions).include?(view.action_name.to_sym)
TPhases.no_transactions_phase do
render_without_tphases_no_transactions(view, locals, &block)
end
else
render_without_tphases_no_transactions(view, locals, &block)
end
end
alias_method_chain :render, :tphases_no_transactions
end
end
end
end
end
end
require 'active_support/notifications'
require 'active_support/version'
require 'active_support/core_ext/object/try'
module TPhases
module Modes
module Helpers
# this helper is included by the CollectMode and the ExceptionsMode modules.
# methods expected to be implemented by those modes are #write_violation_action, #read_violation_action, and
# #no_transactions_violation_action
module TransactionalViolationsHelper
extend ActiveSupport::Concern
included do
define_phase_methods!
end
module ClassMethods
def define_phase_methods!
%w{read write no_transactions}.each do |phase_type|
define_singleton_method(:"#{phase_type}_phase") do |&block|
if phase_stack.last.try(:ignored?)
return block.call
end
phase = Phase.new
phase_stack << phase
begin
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |name, date, date2, sha, args|
next unless phase_stack.last == phase
send(:"#{phase_type}_violation_action", args[:sql], caller) if send(:"#{phase_type}_violation?", args[:sql])
end
return block.call
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
phase_stack.pop
end
end
end
end
# used to keep track of nested phases. a nested phase overrides any prior phase.
def phase_stack
Thread.current[:tphases_phase_stack] ||= []
end
def ignore_phases
phase_stack << Phase.new(ignore: true)
yield
ensure
phase_stack.pop
end
private
READ_QUERIES = %w{show select describe}
WRITE_QUERIES = %w{update commit insert delete}
RAILS_IGNORABLE_QUERIES = %w{describe}
def rails_ignorable_read_queries
@rails_ignorable_read_queries ||= READ_QUERIES - RAILS_IGNORABLE_QUERIES
end
# determines if this query is a read transactional violation (if it is anything besides a read)
def read_violation?(sql)
WRITE_QUERIES.include?(first_word(sql))
end
# determines if this query is a write transactional violation (if it is anything besides a write)
def write_violation?(sql)
query_types = (Object.const_defined? :Rails) ? rails_ignorable_read_queries : READ_QUERIES
query_types.include?(first_word(sql))
end
# violation unless it's Rails and we are running an ignorable query
def no_transactions_violation?(sql)
if Object.const_defined? :Rails
!RAILS_IGNORABLE_QUERIES.include?(first_word(sql))
else
true
end
end
def first_word(str)
str.split(' ').first.downcase
end
end
# simple class to represent a phase on the stack of phases. Used to determine which phase is active
class Phase;
def initialize(opts={ ignore: false })
@ignore = opts[:ignore]
end
def ignored?
@ignore
end
end
end
end
end
end
# the default 'production' mode, PassThrough mode does nothing but called the yielded block
module TPhases
module Modes
module PassThroughMode
extend ActiveSupport::Concern
module ClassMethods
def read_phase
yield
end
def write_phase
yield
end
def no_transactions_phase
yield
end
def ignore_phases
yield
end
private
def add_rails_methods!
require 'tphases/rails/no_transactions_in_controller_pass_through'
ActionController::Base.send :include, TPhases::Rails::NoTransactionsInControllerPassThrough
end
end
end
end
end
module TPhases
module Rails
module NoTransactionsInController
extend ActiveSupport::Concern
module ClassMethods
def ensure_no_transactions_on(*actions)
actions_array = *actions
class_variable_set(:@@no_transaction_actions, actions_array.flatten)
around_filter :no_transactions_around_filter, :only => actions_array
end
end
private
def no_transactions_around_filter
TPhases.no_transactions_phase { yield }
end
end
end
end
module TPhases
module Rails
module NoTransactionsInControllerPassThrough
extend ActiveSupport::Concern
module ClassMethods
def ensure_no_transactions_on(*actions)
# do nothing
end
end
end
end
end
class TransactionalViolation < StandardError
end
module Tphases
VERSION = "0.2.5"
end
require 'active_support/concern'
require "tphases/version"
require "tphases/config"
require "tphases/initialization"
module TPhases
include TPhases::Config
include TPhases::Initialization
end
Copyright (c) 2012 Charles Finkel
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require "bundler/gem_tasks"
adapter: sqlite3
database: temp/database.sqlite3
pool: 5
timeout: 5000
require 'spec_helper'
require 'active_record'
require 'tphases/modes/collect_mode'
describe TPhases::Modes::CollectMode do
subject { Module.new { include TPhases::Modes::CollectMode } }
let(:sql) { "SELECT 1 FROM foo" }
let(:call_stack) { caller }
context "violation actions" do
describe '.write_violation_action' do
it "should add to the violations list" do
expect { subject.send(:write_violation_action, sql, call_stack) }.
to change { subject.violations }.
from([]).
to([{ :type => :write, :call_stack => call_stack, :sql => sql }])
end
end
describe '.read_violation_action' do
it "should add to the violations list" do
expect { subject.send(:read_violation_action, sql, call_stack) }.
to change { subject.violations }.
from([]).
to([{ :type => :read, :call_stack => call_stack, :sql => sql }])
end
end
describe '.no_transactions_violation_action' do
it "should add to the violations list" do
expect { subject.send(:no_transactions_violation_action, sql, call_stack) }.
to change { subject.violations }.
from([]).
to([{ :type => :no_transactions, :call_stack => call_stack, :sql => sql }])
end
end
context "multiple violation actions" do
it "should add multiple values to the violations list" do
expect {
subject.send(:no_transactions_violation_action, sql, call_stack)
subject.send(:read_violation_action, sql, call_stack)
subject.send(:write_violation_action, sql, call_stack)
}.
to change { subject.violations }.
from([]).
to([
{ :type => :no_transactions, :call_stack => call_stack, :sql => sql },
{ :type => :read, :call_stack => call_stack, :sql => sql },
{ :type => :write, :call_stack => call_stack, :sql => sql },
])
end
end
end
end
require 'spec_helper'
require 'active_record'
require 'tphases/modes/exceptions_mode'
describe TPhases::Modes::ExceptionsMode do
subject { Module.new { include TPhases::Modes::ExceptionsMode } }
let(:sql) { "SELECT 1 FROM foo" }
let(:call_stack) { caller }
context "violation actions" do
describe '.write_violation_action' do
it "should raise" do
expect { subject.send(:write_violation_action, sql, call_stack) }.
to raise_error(TransactionalViolation, "#{sql} ran inside of a 'write_phase' block.")
end
end
describe '.read_violation_action' do
it "should raise" do
expect { subject.send(:read_violation_action, sql, call_stack) }.
to raise_error(TransactionalViolation, "#{sql} ran inside of a 'read_phase' block.")
end
end
describe '.no_transactions_violation_action' do
it "should raise" do
expect { subject.send(:no_transactions_violation_action, sql, call_stack) }.
to raise_error(TransactionalViolation, "#{sql} ran inside of a 'no_transactions_phase' block.")
end
end
end
end
require 'spec_helper'
require 'active_record'
require 'tphases/modes/helpers/transactional_violations_helper'
describe TPhases::Modes::Helpers::TransactionalViolationsHelper do
include_context "setup mode specs"
subject { Module.new { include TPhases::Modes::Helpers::TransactionalViolationsHelper } }
let(:write_queries) {
[
"UPDATE `users` SET `email` = '[email protected]' WHERE `users`.`id` = 1",
"INSERT INTO tablename (col1, col2) VALUES('data1', 'data2' )",
"COMMIT",
"DELETE FROM example WHERE age='15'"
]
}
let(:read_queries) {
[
"select * from foobar",
"show variables like 'version'"
]
}
describe "#read_transactional_violation?" do
it "should detect correctly" do
read_queries.each { |read_query| expect(subject.send(:read_violation?, read_query)).to eq(false) }
write_queries.each { |write_query| expect(subject.send(:read_violation?, write_query)).to eq(true) }
end
end
describe "#write_violation?" do
it "should detect correctly" do
read_queries.each { |read_query| expect(subject.send(:write_violation?, read_query)).to be_true }
write_queries.each { |write_query| expect(subject.send(:write_violation?, write_query)).to be_false }
end
context "describe queries" do
context "when Rails is present" do
it "should detect correctly" do
Object.should_receive(:const_defined?).with(:Rails).and_return(true)
expect(subject.send(:write_violation?, "describe foo")).to be_false
end
end
context "when Rails is not present" do
it "should detect correctly" do
Object.should_receive(:const_defined?).with(:Rails).and_return(false)
expect(subject.send(:write_violation?, "describe foo")).to be_true
end
end
end
end
describe "#no_transactions_violation?" do
context "when Rails is present" do
it "should detect correctly" do
Object.stub(:const_defined?).with(:Rails).and_return(true)
expect(subject.send(:no_transactions_violation?, "describe foo")).to be_false
expect(subject.send(:no_transactions_violation?, "select * from foo")).to be_true
end
end
context "when Rails is not present" do
it "should detect correctly" do
Object.stub(:const_defined?).with(:Rails).and_return(false)
expect(subject.send(:no_transactions_violation?, "describe foo")).to be_true
expect(subject.send(:no_transactions_violation?, "select * from foo")).to be_true
end
end
end
describe '.no_transactions_phase' do
it "should send a no_transactions_violation_action for reads" do
subject.should_receive :no_transactions_violation_action
subject.no_transactions_phase { ActiveRecord::Base.connection.select_all(read_sql) }
end
it "should send a no_transactions_violation_action for writes" do
subject.should_receive :no_transactions_violation_action
subject.no_transactions_phase { ActiveRecord::Base.connection.select_all(write_sql) }
end
end
describe '.read_phase' do
it "should allow read transactions" do
subject.should_not_receive :read_violation_action
subject.read_phase { ActiveRecord::Base.connection.select_all(read_sql) }
end
it "should disallow write transactions" do
subject.should_receive :read_violation_action
subject.read_phase { ActiveRecord::Base.connection.select_all(write_sql) }
end
end
describe '.write_phase' do
it "should allow write transactions" do
subject.should_not_receive :write_violation_action
subject.write_phase { ActiveRecord::Base.connection.select_all(write_sql) }
end
it "should disallow read transactions" do
subject.should_receive :write_violation_action
subject.write_phase { ActiveRecord::Base.connection.select_all(read_sql) }
end
end
describe "nested phases" do
context "read_phase inside of a no_transactions_phase" do
it "should allow read transactions" do
subject.should_not_receive :no_transactions_violation_action
subject.no_transactions_phase do
subject.read_phase { ActiveRecord::Base.connection.select_all(read_sql) }
end
end
end
context "no_transactions_phase inside a read_phase" do
it "should disallow transactions" do
subject.should_receive :no_transactions_violation_action
subject.read_phase do
subject.no_transactions_phase do
ActiveRecord::Base.connection.select_all(read_sql)
end
end
end
end
it "should have the right phase_stack sizes" do
subject.send(:phase_stack).should be_empty
subject.read_phase do
subject.send(:phase_stack).size.should == 1
subject.no_transactions_phase do
subject.send(:phase_stack).size.should == 2
end
subject.send(:phase_stack).size.should == 1
end
subject.send(:phase_stack).should be_empty
end
context "ignore_phases inside of a no_transactions_phase" do
it "should disallow transactions after the ignore phase" do
subject.should_receive :no_transactions_violation_action
subject.no_transactions_phase do
subject.ignore_phases { }
ActiveRecord::Base.connection.select_all(read_sql)
end
end
it "should allow transactions in the ignore phase" do
subject.should_not_receive :no_transactions_violation_action
subject.no_transactions_phase do
subject.ignore_phases do
ActiveRecord::Base.connection.select_all(read_sql)
end
end
end
end
context "no_transactions_phase inside of a ignore_phases" do
it "should allow transactions inside the no_transactions_phase block" do
subject.should_not_receive :no_transactions_violation_action
subject.ignore_phases do
subject.no_transactions_phase { ActiveRecord::Base.connection.select_all(read_sql) }
end
end
it "should allow transactions after the no_transactions_phase block" do
subject.should_not_receive :no_transactions_violation_action
subject.ignore_phases do
subject.no_transactions_phase { }
ActiveRecord::Base.connection.select_all(read_sql)
end
end
end
end
end
require 'spec_helper'
require 'active_record'
require 'tphases/modes/pass_through_mode'
describe TPhases::Modes::PassThroughMode do
subject { Module.new { include TPhases::Modes::PassThroughMode } }
include_context "setup mode specs"
describe '.no_transactions_phase, .read_phase, .write_phase' do
it "should allow anything and return the block" do
subject.no_transactions_phase do
ActiveRecord::Base.connection.select_all(read_sql)
ActiveRecord::Base.connection.select_all(write_sql)
:return_val
end.should == :return_val
subject.write_phase do
ActiveRecord::Base.connection.select_all(read_sql)
ActiveRecord::Base.connection.select_all(write_sql)
:return_val
end.should == :return_val
subject.read_phase do
ActiveRecord::Base.connection.select_all(read_sql)
ActiveRecord::Base.connection.select_all(write_sql)
:return_val
end.should == :return_val
subject.ignore_phases do
ActiveRecord::Base.connection.select_all(read_sql)
ActiveRecord::Base.connection.select_all(write_sql)
:return_val
end.should == :return_val
end
end
end
LIB_ROOT = File.expand_path(File.dirname(__FILE__) + "/..")
# This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# Require this file using `require "spec_helper"` to ensure that it is only
# loaded once.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
config.filter_run :focus
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = 'random'
end
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
require File.join(File.expand_path('../../', __FILE__), 'lib', 'tphases')
shared_context "setup mode specs" do
#before(:suite) do
before(:all) do
dbconfig = YAML::load(File.open(LIB_ROOT + '/spec/fixtures/database.yml'))
dbconfig['database'] = LIB_ROOT + '/' + dbconfig['database']
FileUtils.mkdir_p LIB_ROOT + '/temp'
ActiveRecord::Base.establish_connection(dbconfig)
ActiveRecord::Base.connection.execute("CREATE TABLE IF NOT EXISTS posts (t1 string)")
ActiveRecord::Base.connection.execute("DELETE FROM posts")
end
let(:read_sql) { 'select * from posts' }
let(:write_sql) { "insert into posts values ('foobaz')" }
end
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'tphases/version'
Gem::Specification.new do |gem|
gem.name = "tphases"
gem.version = Tphases::VERSION
gem.authors = ["Charles Finkel"]
gem.email = ["[email protected]"]
description = %q{TPhases (Transactional Phases) is a support framework that helps you build your Rails request life cycles into read-only and write-only phases.}
gem.description = description
gem.summary = description
gem.homepage = "https://github.com/charleseff/tphases"
gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]
gem.add_dependency 'activesupport'
gem.add_development_dependency 'rspec'
gem.add_development_dependency 'byebug'
gem.add_development_dependency 'sqlite3'
gem.add_development_dependency 'activerecord'
gem.add_development_dependency 'pry'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment