shoulda-activemodel 0.0.2
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/lib/shoulda/active_model.rb +16 -0
- data/lib/shoulda/active_model/assertions.rb +61 -0
- data/lib/shoulda/active_model/helpers.rb +31 -0
- data/lib/shoulda/active_model/macros.rb +268 -0
- data/lib/shoulda/active_model/matchers.rb +30 -0
- data/lib/shoulda/active_model/matchers/allow_value_matcher.rb +102 -0
- data/lib/shoulda/active_model/matchers/ensure_inclusion_of_matcher.rb +87 -0
- data/lib/shoulda/active_model/matchers/ensure_length_of_matcher.rb +141 -0
- data/lib/shoulda/active_model/matchers/validate_acceptance_of_matcher.rb +41 -0
- data/lib/shoulda/active_model/matchers/validate_format_of_matcher.rb +67 -0
- data/lib/shoulda/active_model/matchers/validate_numericality_of_matcher.rb +39 -0
- data/lib/shoulda/active_model/matchers/validate_presence_of_matcher.rb +60 -0
- data/lib/shoulda/active_model/matchers/validate_uniqueness_of_matcher.rb +148 -0
- data/lib/shoulda/active_model/matchers/validation_matcher.rb +57 -0
- data/test/fail_macros.rb +39 -0
- data/test/matchers/active_model/ensure_inclusion_of_matcher_test.rb +80 -0
- data/test/matchers/active_model/ensure_length_of_matcher_test.rb +158 -0
- data/test/matchers/active_model/validate_acceptance_of_matcher_test.rb +44 -0
- data/test/matchers/active_model/validate_format_of_matcher_test.rb +39 -0
- data/test/matchers/active_model/validate_numericality_of_matcher_test.rb +52 -0
- data/test/matchers/active_model/validate_presence_of_matcher_test.rb +86 -0
- data/test/matchers/active_model/validate_uniqueness_of_matcher_test.rb +147 -0
- data/test/model_builder.rb +106 -0
- data/test/rspec_test.rb +207 -0
- data/test/test_helper.rb +20 -0
- metadata +106 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class ValidatePresenceOfMatcherTest < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "a required attribute" do
|
6
|
+
setup do
|
7
|
+
define_model :example, :attr => :string do
|
8
|
+
validates_presence_of :attr
|
9
|
+
end
|
10
|
+
@model = Example.new
|
11
|
+
end
|
12
|
+
|
13
|
+
should "require a value" do
|
14
|
+
assert_accepts validate_presence_of(:attr), @model
|
15
|
+
end
|
16
|
+
|
17
|
+
should "not override the default message with a blank" do
|
18
|
+
assert_accepts validate_presence_of(:attr).with_message(nil), @model
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "an optional attribute" do
|
23
|
+
setup do
|
24
|
+
@model = define_model(:example, :attr => :string).new
|
25
|
+
end
|
26
|
+
|
27
|
+
should "not require a value" do
|
28
|
+
assert_rejects validate_presence_of(:attr), @model
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "a required has_many association" do
|
33
|
+
setup do
|
34
|
+
define_model :child
|
35
|
+
@model = define_model :parent do
|
36
|
+
has_many :children
|
37
|
+
validates_presence_of :children
|
38
|
+
end.new
|
39
|
+
end
|
40
|
+
|
41
|
+
should "require the attribute to be set" do
|
42
|
+
assert_accepts validate_presence_of(:children), @model
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "an optional has_many association" do
|
47
|
+
setup do
|
48
|
+
define_model :child
|
49
|
+
@model = define_model :parent do
|
50
|
+
has_many :children
|
51
|
+
end.new
|
52
|
+
end
|
53
|
+
|
54
|
+
should "not require the attribute to be set" do
|
55
|
+
assert_rejects validate_presence_of(:children), @model
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "a required has_and_belongs_to_many association" do
|
60
|
+
setup do
|
61
|
+
define_model :child
|
62
|
+
@model = define_model :parent do
|
63
|
+
has_and_belongs_to_many :children
|
64
|
+
validates_presence_of :children
|
65
|
+
end.new
|
66
|
+
end
|
67
|
+
|
68
|
+
should "require the attribute to be set" do
|
69
|
+
assert_accepts validate_presence_of(:children), @model
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "an optional has_and_belongs_to_many association" do
|
74
|
+
setup do
|
75
|
+
define_model :child
|
76
|
+
@model = define_model :parent do
|
77
|
+
has_and_belongs_to_many :children
|
78
|
+
end.new
|
79
|
+
end
|
80
|
+
|
81
|
+
should "not require the attribute to be set" do
|
82
|
+
assert_rejects validate_presence_of(:children), @model
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
2
|
+
|
3
|
+
class ValidateUniquenessOfMatcherTest < ActiveSupport::TestCase # :nodoc:
|
4
|
+
|
5
|
+
context "a unique attribute" do
|
6
|
+
setup do
|
7
|
+
@model = define_model(:example, :attr => :string,
|
8
|
+
:other => :integer) do
|
9
|
+
validates_uniqueness_of :attr
|
10
|
+
end.new
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with an existing value" do
|
14
|
+
setup do
|
15
|
+
@existing = Example.create!(:attr => 'value', :other => 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
should "require a unique value for that attribute" do
|
19
|
+
assert_accepts validate_uniqueness_of(:attr), @model
|
20
|
+
end
|
21
|
+
|
22
|
+
should "pass when the subject is an existing record" do
|
23
|
+
assert_accepts validate_uniqueness_of(:attr), @existing
|
24
|
+
end
|
25
|
+
|
26
|
+
should "fail when a scope is specified" do
|
27
|
+
assert_rejects validate_uniqueness_of(:attr).scoped_to(:other), @model
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "without an existing value" do
|
32
|
+
setup do
|
33
|
+
assert_nil Example.find(:first)
|
34
|
+
@matcher = validate_uniqueness_of(:attr)
|
35
|
+
end
|
36
|
+
|
37
|
+
should "fail to require a unique value" do
|
38
|
+
assert_rejects @matcher, @model
|
39
|
+
end
|
40
|
+
|
41
|
+
should "alert the tester that an existing value is not present" do
|
42
|
+
@matcher.matches?(@model)
|
43
|
+
assert @matcher.negative_failure_message =~ /^Can't find first .*/
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "a unique attribute with a custom error and an existing value" do
|
49
|
+
setup do
|
50
|
+
@model = define_model(:example, :attr => :string) do
|
51
|
+
validates_uniqueness_of :attr, :message => 'Bad value'
|
52
|
+
end.new
|
53
|
+
Example.create!
|
54
|
+
end
|
55
|
+
|
56
|
+
should "fail when checking the default message" do
|
57
|
+
assert_rejects validate_uniqueness_of(:attr), @model
|
58
|
+
end
|
59
|
+
|
60
|
+
should "fail when checking a message that doesn't match" do
|
61
|
+
assert_rejects validate_uniqueness_of(:attr).with_message(/abc/i), @model
|
62
|
+
end
|
63
|
+
|
64
|
+
should "pass when checking a message that matches" do
|
65
|
+
assert_accepts validate_uniqueness_of(:attr).with_message(/bad/i), @model
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "a scoped unique attribute with an existing value" do
|
70
|
+
setup do
|
71
|
+
@model = define_model(:example, :attr => :string,
|
72
|
+
:scope1 => :integer,
|
73
|
+
:scope2 => :integer) do
|
74
|
+
validates_uniqueness_of :attr, :scope => [:scope1, :scope2]
|
75
|
+
end.new
|
76
|
+
@existing = Example.create!(:attr => 'value', :scope1 => 1, :scope2 => 2)
|
77
|
+
end
|
78
|
+
|
79
|
+
should "pass when the correct scope is specified" do
|
80
|
+
assert_accepts validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2),
|
81
|
+
@model
|
82
|
+
end
|
83
|
+
|
84
|
+
should "pass when the subject is an existing record" do
|
85
|
+
assert_accepts validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2),
|
86
|
+
@existing
|
87
|
+
end
|
88
|
+
|
89
|
+
should "fail when a different scope is specified" do
|
90
|
+
assert_rejects validate_uniqueness_of(:attr).scoped_to(:scope1), @model
|
91
|
+
end
|
92
|
+
|
93
|
+
should "fail when no scope is specified" do
|
94
|
+
assert_rejects validate_uniqueness_of(:attr), @model
|
95
|
+
end
|
96
|
+
|
97
|
+
should "fail when a non-existent attribute is specified as a scope" do
|
98
|
+
assert_rejects validate_uniqueness_of(:attr).scoped_to(:fake), @model
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "a non-unique attribute with an existing value" do
|
103
|
+
setup do
|
104
|
+
@model = define_model(:example, :attr => :string).new
|
105
|
+
Example.create!(:attr => 'value')
|
106
|
+
end
|
107
|
+
|
108
|
+
should "not require a unique value for that attribute" do
|
109
|
+
assert_rejects validate_uniqueness_of(:attr), @model
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "a case sensitive unique attribute with an existing value" do
|
114
|
+
setup do
|
115
|
+
@model = define_model(:example, :attr => :string) do
|
116
|
+
validates_uniqueness_of :attr, :case_sensitive => true
|
117
|
+
end.new
|
118
|
+
Example.create!(:attr => 'value')
|
119
|
+
end
|
120
|
+
|
121
|
+
should "not require a unique, case-insensitive value for that attribute" do
|
122
|
+
assert_rejects validate_uniqueness_of(:attr).case_insensitive, @model
|
123
|
+
end
|
124
|
+
|
125
|
+
should "require a unique, case-sensitive value for that attribute" do
|
126
|
+
assert_accepts validate_uniqueness_of(:attr), @model
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "a case sensitive unique integer attribute with an existing value" do
|
131
|
+
setup do
|
132
|
+
@model = define_model(:example, :attr => :integer) do
|
133
|
+
validates_uniqueness_of :attr, :case_sensitive => true
|
134
|
+
end.new
|
135
|
+
Example.create!(:attr => 'value')
|
136
|
+
end
|
137
|
+
|
138
|
+
should "require a unique, case-insensitive value for that attribute" do
|
139
|
+
assert_accepts validate_uniqueness_of(:attr).case_insensitive, @model
|
140
|
+
end
|
141
|
+
|
142
|
+
should "require a unique, case-sensitive value for that attribute" do
|
143
|
+
assert_accepts validate_uniqueness_of(:attr), @model
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
class ActiveSupport::TestCase
|
2
|
+
def create_table(table_name, &block)
|
3
|
+
connection = ActiveRecord::Base.connection
|
4
|
+
|
5
|
+
begin
|
6
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
7
|
+
connection.create_table(table_name, &block)
|
8
|
+
@created_tables ||= []
|
9
|
+
@created_tables << table_name
|
10
|
+
connection
|
11
|
+
rescue Exception => e
|
12
|
+
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
13
|
+
raise e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def define_constant(class_name, base, &block)
|
18
|
+
class_name = class_name.to_s.camelize
|
19
|
+
|
20
|
+
klass = Class.new(base)
|
21
|
+
Object.const_set(class_name, klass)
|
22
|
+
|
23
|
+
klass.class_eval(&block) if block_given?
|
24
|
+
|
25
|
+
@defined_constants ||= []
|
26
|
+
@defined_constants << class_name
|
27
|
+
|
28
|
+
klass
|
29
|
+
end
|
30
|
+
|
31
|
+
def define_model_class(class_name, &block)
|
32
|
+
define_constant(class_name, ActiveRecord::Base, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def define_model(name, columns = {}, &block)
|
36
|
+
class_name = name.to_s.pluralize.classify
|
37
|
+
table_name = class_name.tableize
|
38
|
+
|
39
|
+
create_table(table_name) do |table|
|
40
|
+
columns.each do |name, type|
|
41
|
+
table.column name, type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
define_model_class(class_name, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
def define_controller(class_name, &block)
|
49
|
+
class_name = class_name.to_s
|
50
|
+
class_name << 'Controller' unless class_name =~ /Controller$/
|
51
|
+
define_constant(class_name, ActionController::Base, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def define_routes(&block)
|
55
|
+
@replaced_routes = ActionController::Routing::Routes
|
56
|
+
new_routes = ActionController::Routing::RouteSet.new
|
57
|
+
silence_warnings do
|
58
|
+
ActionController::Routing.const_set('Routes', new_routes)
|
59
|
+
end
|
60
|
+
new_routes.draw(&block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_response(&block)
|
64
|
+
klass = define_controller('Examples')
|
65
|
+
block ||= lambda { render :nothing => true }
|
66
|
+
klass.class_eval { define_method(:example, &block) }
|
67
|
+
define_routes do |map|
|
68
|
+
map.connect 'examples', :controller => 'examples', :action => 'example'
|
69
|
+
end
|
70
|
+
|
71
|
+
@controller = klass.new
|
72
|
+
@request = ActionController::TestRequest.new
|
73
|
+
@response = ActionController::TestResponse.new
|
74
|
+
get :example
|
75
|
+
|
76
|
+
@controller
|
77
|
+
end
|
78
|
+
|
79
|
+
def teardown_with_models
|
80
|
+
if @defined_constants
|
81
|
+
@defined_constants.each do |class_name|
|
82
|
+
Object.send(:remove_const, class_name)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
if @created_tables
|
87
|
+
@created_tables.each do |table_name|
|
88
|
+
ActiveRecord::Base.
|
89
|
+
connection.
|
90
|
+
execute("DROP TABLE IF EXISTS #{table_name}")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
if @replaced_routes
|
95
|
+
ActionController::Routing::Routes.clear!
|
96
|
+
silence_warnings do
|
97
|
+
ActionController::Routing.const_set('Routes', @replaced_routes)
|
98
|
+
end
|
99
|
+
@replaced_routes.reload!
|
100
|
+
end
|
101
|
+
|
102
|
+
teardown_without_models
|
103
|
+
end
|
104
|
+
alias_method :teardown_without_models, :teardown
|
105
|
+
alias_method :teardown, :teardown_with_models
|
106
|
+
end
|
data/test/rspec_test.rb
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
begin
|
4
|
+
gem 'rspec'
|
5
|
+
gem 'rspec-rails'
|
6
|
+
rescue LoadError => exception
|
7
|
+
puts exception.message
|
8
|
+
puts "RSpec integration was not tested because RSpec is not available"
|
9
|
+
else
|
10
|
+
|
11
|
+
class RspecTest < ActiveSupport::TestCase
|
12
|
+
|
13
|
+
SHOULDA_ROOT =
|
14
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
|
15
|
+
|
16
|
+
def setup
|
17
|
+
build_gemspec
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
FileUtils.rm_rf(project_dir)
|
22
|
+
FileUtils.rm_rf("#{shoulda_root}/pkg")
|
23
|
+
end
|
24
|
+
|
25
|
+
should "integrate correctly when using config.gem in test.rb" do
|
26
|
+
create_project
|
27
|
+
insert(rspec_dependencies, "config/environments/test.rb")
|
28
|
+
vendor_gems('test')
|
29
|
+
configure_spec_rails
|
30
|
+
assert_configured
|
31
|
+
end
|
32
|
+
|
33
|
+
should "integrate correctly when using config.gem in environment.rb" do
|
34
|
+
create_project
|
35
|
+
insert(rspec_dependencies,
|
36
|
+
"config/environment.rb",
|
37
|
+
/Rails::Initializer\.run/)
|
38
|
+
vendor_gems('development')
|
39
|
+
configure_spec_rails
|
40
|
+
assert_configured
|
41
|
+
end
|
42
|
+
|
43
|
+
should "integrate correctly when using require in spec_helper" do
|
44
|
+
create_project
|
45
|
+
configure_spec_rails
|
46
|
+
insert(%{gem 'shoulda'; require 'shoulda'},
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
%{require 'spec/rails'})
|
49
|
+
assert_configured
|
50
|
+
end
|
51
|
+
|
52
|
+
should "integrate correctly when unpacked and required in spec_helper" do
|
53
|
+
create_project
|
54
|
+
configure_spec_rails
|
55
|
+
insert(%{require 'shoulda'},
|
56
|
+
"spec/spec_helper.rb",
|
57
|
+
%{require 'spec/rails'})
|
58
|
+
unpack_gems
|
59
|
+
assert_configured
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_project
|
63
|
+
command "rails #{project_dir}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def vendor_gems(env)
|
67
|
+
project_command "rake gems:unpack RAILS_ENV=#{env}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def unpack_gems
|
71
|
+
FileUtils.mkdir_p "#{project_dir}/vendor/gems"
|
72
|
+
FileUtils.cd "#{project_dir}/vendor/gems" do
|
73
|
+
%w(rspec rspec-rails shoulda).each do |gem|
|
74
|
+
command "gem unpack #{gem}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
insert('config.load_paths += Dir["#{RAILS_ROOT}/vendor/gems/*/lib"]',
|
79
|
+
"config/environment.rb",
|
80
|
+
/Rails::Initializer\.run/)
|
81
|
+
end
|
82
|
+
|
83
|
+
def command(command)
|
84
|
+
output = `GEM_PATH=#{shoulda_root}/pkg #{command} 2>&1`
|
85
|
+
unless $? == 0
|
86
|
+
flunk("Command failed with status #{$?}\n#{command}\n#{output}")
|
87
|
+
end
|
88
|
+
@command_output ||= ''
|
89
|
+
@command_output << output
|
90
|
+
output
|
91
|
+
end
|
92
|
+
|
93
|
+
def project_command(command)
|
94
|
+
result = nil
|
95
|
+
FileUtils.cd project_dir do
|
96
|
+
result = command(command)
|
97
|
+
end
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
def shoulda_command(command)
|
102
|
+
FileUtils.cd shoulda_root do
|
103
|
+
command(command)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def project_name
|
108
|
+
'example_rails_project'
|
109
|
+
end
|
110
|
+
|
111
|
+
def project_dir
|
112
|
+
File.expand_path(File.join(File.dirname(__FILE__), project_name))
|
113
|
+
end
|
114
|
+
|
115
|
+
def insert(content, path, after = nil)
|
116
|
+
path = File.join(project_dir, path)
|
117
|
+
contents = IO.read(path)
|
118
|
+
if after
|
119
|
+
contents.gsub!(/^(.*#{after}.*)$/, "\\1\n#{content}")
|
120
|
+
else
|
121
|
+
contents << "\n" << content
|
122
|
+
end
|
123
|
+
File.open(path, 'w') {|file| file.write(contents) }
|
124
|
+
end
|
125
|
+
|
126
|
+
def rspec_dependencies
|
127
|
+
return <<-EOS
|
128
|
+
config.gem 'rspec', :lib => 'spec'
|
129
|
+
config.gem 'rspec-rails', :lib => false
|
130
|
+
config.gem 'shoulda', :lib => 'shoulda'
|
131
|
+
EOS
|
132
|
+
end
|
133
|
+
|
134
|
+
def configure_spec_rails
|
135
|
+
project_command "script/generate rspec"
|
136
|
+
end
|
137
|
+
|
138
|
+
def assert_configured
|
139
|
+
create_model
|
140
|
+
migrate
|
141
|
+
create_controller
|
142
|
+
assert_spec_passes
|
143
|
+
end
|
144
|
+
|
145
|
+
def create_model
|
146
|
+
project_command "script/generate rspec_model person name:string"
|
147
|
+
insert "validates_presence_of :name",
|
148
|
+
"app/models/person.rb",
|
149
|
+
/class Person/
|
150
|
+
insert "it { should validate_presence_of(:name) }",
|
151
|
+
"spec/models/person_spec.rb",
|
152
|
+
/describe Person do/
|
153
|
+
end
|
154
|
+
|
155
|
+
def create_controller
|
156
|
+
project_command "script/generate rspec_controller people"
|
157
|
+
insert "def index; render :text => 'Hello'; end",
|
158
|
+
"app/controllers/people_controller.rb",
|
159
|
+
/class PeopleController/
|
160
|
+
shoulda_controller_example = <<-EOS
|
161
|
+
describe PeopleController, "on GET index" do
|
162
|
+
integrate_views
|
163
|
+
subject { controller }
|
164
|
+
before(:each) { get :index }
|
165
|
+
it { should respond_with(:success) }
|
166
|
+
end
|
167
|
+
EOS
|
168
|
+
insert shoulda_controller_example,
|
169
|
+
"spec/controllers/people_controller_spec.rb"
|
170
|
+
end
|
171
|
+
|
172
|
+
def migrate
|
173
|
+
project_command "rake db:migrate"
|
174
|
+
end
|
175
|
+
|
176
|
+
def assert_spec_passes
|
177
|
+
result = project_command("rake spec SPEC_OPTS=-fs")
|
178
|
+
assert_match /should require name to be set/, result
|
179
|
+
assert_match /should respond with 200/, result
|
180
|
+
end
|
181
|
+
|
182
|
+
def shoulda_root
|
183
|
+
SHOULDA_ROOT
|
184
|
+
end
|
185
|
+
|
186
|
+
def build_gemspec
|
187
|
+
backup_gemspec do
|
188
|
+
shoulda_command "rake gemspec"
|
189
|
+
shoulda_command "rake gem"
|
190
|
+
shoulda_command "gem install --no-ri --no-rdoc -i pkg pkg/shoulda*.gem"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def backup_gemspec
|
195
|
+
actual = "#{shoulda_root}/shoulda.gemspec"
|
196
|
+
backup = "#{shoulda_root}/backup.gemspec"
|
197
|
+
FileUtils.mv(actual, backup)
|
198
|
+
begin
|
199
|
+
yield
|
200
|
+
ensure
|
201
|
+
FileUtils.mv(backup, actual)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|