riot_rails 0.0.8 → 0.0.9.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG +122 -0
  2. data/MIT-LICENSE +1 -1
  3. data/README.markdown +22 -7
  4. data/Rakefile +3 -2
  5. data/VERSION +1 -1
  6. data/lib/riot/action_controller/assertion_macros.rb +48 -34
  7. data/lib/riot/action_controller/context_helper.rb +12 -0
  8. data/lib/riot/action_controller/context_macros.rb +58 -12
  9. data/lib/riot/action_controller/situation_macros.rb +73 -6
  10. data/lib/riot/action_controller.rb +2 -0
  11. data/lib/riot/active_record/assertion_macros.rb +3 -158
  12. data/lib/riot/active_record/context_helper.rb +19 -0
  13. data/lib/riot/active_record/database_macros.rb +58 -0
  14. data/lib/riot/active_record/reflection_macros.rb +106 -0
  15. data/lib/riot/active_record/validation_macros.rb +187 -0
  16. data/lib/riot/active_record.rb +2 -0
  17. data/lib/riot/rails.rb +1 -2
  18. data/lib/riot/rails_context.rb +84 -0
  19. data/riot_rails.gemspec +35 -9
  20. data/test/action_controller/controller_context_test.rb +39 -9
  21. data/test/action_controller/redirected_to_test.rb +6 -11
  22. data/test/action_controller/renders_template_test.rb +7 -7
  23. data/test/action_controller/renders_test.rb +6 -6
  24. data/test/action_controller/response_status_test.rb +11 -11
  25. data/test/active_record/allowing_values_test.rb +9 -9
  26. data/test/active_record/attribute_is_invalid_test.rb +20 -0
  27. data/test/active_record/belongs_to_test.rb +22 -0
  28. data/test/active_record/has_and_belongs_to_many_test.rb +22 -0
  29. data/test/active_record/has_database_index_on_test.rb +73 -0
  30. data/test/active_record/has_many_test.rb +7 -3
  31. data/test/active_record/has_one_test.rb +22 -0
  32. data/test/active_record/validates_length_of_test.rb +31 -0
  33. data/test/active_record/validates_presence_of_test.rb +1 -1
  34. data/test/active_record/validates_uniqueness_of_test.rb +3 -3
  35. data/test/rails_context_test.rb +103 -0
  36. data/test/rails_root/config/environment.rb +46 -0
  37. data/test/rails_root/config/routes.rb +3 -4
  38. data/test/rails_root/db/schema.rb +1 -2
  39. data/test/teststrap.rb +44 -69
  40. metadata +39 -6
@@ -1,158 +1,3 @@
1
- module RiotRails
2
- module ActiveRecord
3
-
4
- class AssertionMacro < ::Riot::AssertionMacro
5
- def error_from_writing_value(model, attribute, value)
6
- model.write_attribute(attribute, value)
7
- model.valid?
8
- model.errors.on(attribute)
9
- end
10
- end
11
-
12
- # An ActiveRecord assertion that expects to fail when a given attribute is validated after a nil value
13
- # is provided to it.
14
- #
15
- # context "a User" do
16
- # setup { User.new }
17
- # topic.validates_presence_of(:name)
18
- # end
19
- class ValidatesPresenceOfMacro < AssertionMacro
20
- register :validates_presence_of
21
-
22
- def evaluate(actual, attribute)
23
- if error_from_writing_value(actual, attribute, nil)
24
- pass("validates presence of #{attribute.inspect}")
25
- else
26
- fail("expected to validate presence of #{attribute.inspect}")
27
- end
28
- end
29
- end
30
-
31
- # An ActiveRecord assertion that expects to pass with a given value or set of values for a given
32
- # attribute.
33
- #
34
- # context "a User" do
35
- # setup { User.new }
36
- # topic.allows_values_for :email, "a@b.cd"
37
- # topic.allows_values_for :email, "a@b.cd", "e@f.gh"
38
- # end
39
- class AllowsValuesForMacro < AssertionMacro
40
- register :allows_values_for
41
-
42
- def evaluate(actual, attribute, *values)
43
- bad_values = []
44
- values.each do |value|
45
- bad_values << value if error_from_writing_value(actual, attribute, value)
46
- end
47
- failure_msg = "expected %s to allow value(s) %s"
48
- bad_values.empty? ? pass : fail(failure_msg % [attribute.inspect, bad_values.inspect])
49
- end
50
- end
51
-
52
- # An ActiveRecord assertion that expects to fail with a given value or set of values for a given
53
- # attribute.
54
- #
55
- # context "a User" do
56
- # setup { User.new }
57
- # topic.does_not_allow_values_for :email, "a"
58
- # topic.does_not_allow_values_for :email, "a@b", "e f@g.h"
59
- # end
60
- class DoesNotAllowValuesForMacro < AssertionMacro
61
- register :does_not_allow_values_for
62
- def evaluate(actual, attribute, *values)
63
- good_values = []
64
- values.each do |value|
65
- good_values << value unless error_from_writing_value(actual, attribute, value)
66
- end
67
- failure_msg = "expected %s not to allow value(s) %s"
68
- good_values.empty? ? pass : fail(failure_msg % [attribute.inspect, good_values.inspect])
69
- end
70
- end
71
-
72
- # An ActiveRecord assertion that expects to fail with invalid value for an attribute. Optionally, the
73
- # error message can be provided as the exact string or as regular expression.
74
- #
75
- # context "a User" do
76
- # setup { User.new }
77
- # topic.is_invalid_when :email, "fake", "is invalid"
78
- # topic.is_invalid_when :email, "another fake", /invalid/
79
- # end
80
- class IsInvalidWhenMacro < AssertionMacro
81
- register :is_invalid_when
82
-
83
- def evaluate(actual, attribute, value, expected_error=nil)
84
- actual_errors = Array(error_from_writing_value(actual, attribute, value))
85
- if actual_errors.empty?
86
- fail("expected #{attribute.inspect} to be invalid when value is #{value.inspect}")
87
- elsif expected_error && !has_error_message?(expected_error, actual_errors)
88
- message = "expected %s to be invalid with error message %s"
89
- fail(message % [attribute.inspect, expected_error.inspect])
90
- else
91
- pass("attribute #{attribute.inspect} is invalid")
92
- end
93
- end
94
- private
95
- def has_error_message?(expected, errors)
96
- return true unless expected
97
- expected.kind_of?(Regexp) ? errors.any? {|e| e =~ expected } : errors.any? {|e| e == expected }
98
- end
99
- end
100
-
101
- # An ActiveRecord assertion that expects to fail with an attribute is not valid for record because the
102
- # value of the attribute is not unique. Requires the topic of the context to be a created record; one
103
- # that returns false for a call to +new_record?+.
104
- #
105
- # context "a User" do
106
- # setup { User.create(:email => "a@b.cde", ... ) }
107
- # topic.validates_uniqueness_of :email
108
- # end
109
- class ValidatesUniquenessOfMacro < AssertionMacro
110
- register :validates_uniqueness_of
111
-
112
- def evaluate(actual, attribute)
113
- actual_record = actual
114
- if actual_record.new_record?
115
- fail("topic is not a new record when testing uniqueness of #{attribute.inspect}")
116
- else
117
- copied_model = actual_record.class.new
118
- actual_record.attributes.each do |dup_attribute, dup_value|
119
- copied_model.write_attribute(dup_attribute, dup_value)
120
- end
121
- copied_value = actual_record.read_attribute(attribute)
122
- if error_from_writing_value(copied_model, attribute, copied_value)
123
- pass("#{attribute.inspect} is unique")
124
- else
125
- fail("expected to fail because #{attribute.inspect} is not unique")
126
- end
127
- end
128
- end
129
- end
130
-
131
- # An ActiveRecord assertion macro that expects to pass when a given attribute is defined as +has_many+
132
- # association. Will fail if an association is not defined for the attribute and if the association is
133
- # not +has_many.jekyll
134
- #
135
- # context "a Room" do
136
- # setup { Room.new }
137
- #
138
- # topic.has_many(:doors)
139
- # topic.has_many(:floors) # should probably fail given our current universe :)
140
- # end
141
- class HasManyMacro < AssertionMacro
142
- register :has_many
143
-
144
- def evaluate(actual, attribute)
145
- reflection = actual.class.reflect_on_association(attribute)
146
- static_msg = "expected #{attribute.inspect} to be a has_many association, but was "
147
- if reflection.nil?
148
- fail(static_msg + "not")
149
- elsif "has_many" != reflection.macro.to_s
150
- fail(static_msg + "a #{reflection.macro} instead")
151
- else
152
- pass("has many #{attribute.inspect}")
153
- end
154
- end
155
- end
156
-
157
- end # ActiveRecord
158
- end # RiotRails
1
+ require 'riot/active_record/validation_macros'
2
+ require 'riot/active_record/reflection_macros'
3
+ require 'riot/active_record/database_macros'
@@ -0,0 +1,19 @@
1
+ module RiotRails
2
+ register_context_helper do
3
+ def prepare_context(context)
4
+ context.premium_setup { context.description.new } if active_record_context?(context)
5
+
6
+ context.transaction do |&original_block|
7
+ ::ActiveRecord::Base.transaction do
8
+ original_block.call
9
+ raise ::ActiveRecord::Rollback
10
+ end
11
+ end
12
+ end
13
+ private
14
+ def active_record_context?(context)
15
+ description = context.description
16
+ description.kind_of?(Class) && description.ancestors.include?(::ActiveRecord::Base)
17
+ end
18
+ end
19
+ end # RiotRails
@@ -0,0 +1,58 @@
1
+ module RiotRails
2
+ module ActiveRecord
3
+
4
+ # An ActiveRecord assertion macro that looks for an index on a given set of attributes in the table
5
+ # used by the model under test (aka: topic).
6
+ #
7
+ # asserts_topic.has_database_index_on :name
8
+ # asserts_topic.has_database_index_on :email, :group_name
9
+ #
10
+ # In the form used above, the assertion will pass if any index is found with the attributes listed
11
+ # (unique or not). To be specific about uniqueness, provide the +:unique+ option.
12
+ #
13
+ # asserts_topic.has_database_index_on :email, :unique => true
14
+ # asserts_topic.has_database_index_on :name, :unique => false
15
+ #
16
+ # The last example will require that the index not be a unique one.
17
+ class HasDatabaseIndexOnMacro < Riot::AssertionMacro
18
+ register :has_database_index_on
19
+
20
+ def initialize(database_connection=nil) # Good for testing :)
21
+ @database_connection = database_connection
22
+ end
23
+
24
+ def evaluate(actual, *attributes_and_options)
25
+ attributes, options = extract_options_from(attributes_and_options)
26
+ unique = options[:unique]
27
+
28
+ index = find_index(actual, attributes, unique)
29
+
30
+ static_message = "#{unique ? "unique" : ""} index on #{attributes.inspect}".strip
31
+ index.nil? ? fail("expected #{static_message}") : pass("has #{static_message}")
32
+ end
33
+ private
34
+ def database_connection; @database_connection || ::ActiveRecord::Base.connection; end
35
+
36
+ def find_index(model, attributes, uniqueness, &block)
37
+ database_connection.indexes(model.class.table_name).find do |the_index|
38
+ unique_enough?(uniqueness, the_index) && attributes_match?(attributes, the_index)
39
+ end
40
+ end
41
+
42
+ def unique_enough?(uniqueness, index)
43
+ return true if uniqueness.nil?
44
+ index.unique == uniqueness
45
+ end
46
+
47
+ def attributes_match?(attributes, index)
48
+ Set.new(attributes.map(&:to_s)) == Set.new(index.columns)
49
+ end
50
+
51
+ def extract_options_from(attributes)
52
+ options = attributes.last.kind_of?(Hash) ? attributes.pop : {}
53
+ [attributes, options]
54
+ end
55
+ end
56
+
57
+ end # ActiveRecord
58
+ end # RiotRails
@@ -0,0 +1,106 @@
1
+ module RiotRails
2
+ module ActiveRecord
3
+ protected
4
+
5
+ class ReflectionAssertionMacro < Riot::AssertionMacro
6
+ private
7
+ def reflection_match?(expected, reflection)
8
+ !reflection.nil? && (expected == reflection.macro.to_s)
9
+ end
10
+
11
+ def options_match_for_reflection?(reflection, options)
12
+ options.all? { |k, v| reflection.options[k] == v }
13
+ end
14
+
15
+ def assert_reflection(expected, record, attribute, options=nil)
16
+ options ||= {}
17
+ reflection = record.class.reflect_on_association(attribute)
18
+ if reflection_match?(expected, reflection)
19
+ if options_match_for_reflection?(reflection, options)
20
+ pass new_message(attribute).is_a.push(expected).association
21
+ else
22
+ fail expected_message.push("#{expected} #{attribute.inspect}").with(options)
23
+ end
24
+ else
25
+ fail new_message(attribute).is_not_a.push(expected).association
26
+ end
27
+ end
28
+ end
29
+
30
+ public
31
+
32
+ # An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a +has_many+
33
+ # association. Will fail if an association is not defined for the attribute or if the association is
34
+ # not +has_many+.
35
+ #
36
+ # context "a Room" do
37
+ # setup { Room.new }
38
+ #
39
+ # asserts_topic.has_many(:doors)
40
+ # asserts_topic.has_many(:floors) # should probably fail given our current universe :)
41
+ # end
42
+ class HasManyMacro < ReflectionAssertionMacro
43
+ register :has_many
44
+
45
+ def evaluate(actual, *expectings)
46
+ attribute, options = *expectings
47
+ assert_reflection("has_many", actual, attribute, options)
48
+ end
49
+ end
50
+
51
+ # An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a
52
+ # +has_one+ association. Will fail if an association is not defined for the attribute or if the
53
+ # association is not +has_one+.
54
+ #
55
+ # context "a Room" do
56
+ # setup { Room.new }
57
+ #
58
+ # asserts_topic.has_one(:floor)
59
+ # end
60
+ class HasOneMacro < ReflectionAssertionMacro
61
+ register :has_one
62
+
63
+ def evaluate(actual, *expectings)
64
+ attribute, options = *expectings
65
+ assert_reflection("has_one", actual, attribute, options)
66
+ end
67
+ end
68
+
69
+ # An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a
70
+ # +belongs_to+ association. Will fail if an association is not defined for the attribute or if the
71
+ # association is not +belongs_to+.
72
+ #
73
+ # context "a Room" do
74
+ # setup { Room.new }
75
+ #
76
+ # asserts_topic.belongs_to(:house)
77
+ # end
78
+ class BelongsToMacro < ReflectionAssertionMacro
79
+ register :belongs_to
80
+
81
+ def evaluate(actual, *expectings)
82
+ attribute, options = *expectings
83
+ assert_reflection("belongs_to", actual, attribute, options)
84
+ end
85
+ end
86
+
87
+ # An ActiveRecord assertion macro that expects to pass when a given attribute is defined as a
88
+ # +has_and_belongs_to_many+ association. Will fail if an association is not defined for the attribute or
89
+ # if the association is not +has_and_belongs_to_many+.
90
+ #
91
+ # context "a Room" do
92
+ # setup { Room.new }
93
+ #
94
+ # asserts_topic.has_and_belongs_to_many(:walls)
95
+ # end
96
+ class HasAndBelongsToManyMacro < ReflectionAssertionMacro
97
+ register :has_and_belongs_to_many
98
+
99
+ def evaluate(actual, *expectings)
100
+ attribute, options = *expectings
101
+ assert_reflection("has_and_belongs_to_many", actual, attribute, options)
102
+ end
103
+ end
104
+
105
+ end # ActiveRecord
106
+ end # RiotRails
@@ -0,0 +1,187 @@
1
+ module RiotRails
2
+ module ActiveRecord
3
+ protected
4
+
5
+ class ValidationAssertionMacro < Riot::AssertionMacro
6
+ private
7
+ def errors_from_writing_value(model, attribute, value)
8
+ # TODO: Fix me to not use __send__
9
+ model.__send__(:write_attribute, attribute, value)
10
+ model.valid?
11
+ model.errors[attribute]
12
+ end
13
+
14
+ def errors_from_writing_value?(*args)
15
+ errors_from_writing_value(*args).any?
16
+ end
17
+ end
18
+
19
+ public
20
+
21
+ # An ActiveRecord assertion that expects to pass with a given value or set of values for a given
22
+ # attribute.
23
+ #
24
+ # rails_context User do
25
+ # asserts_topic.allows_values_for :email, "a@b.cd"
26
+ # asserts_topic.allows_values_for :email, "a@b.cd", "e@f.gh"
27
+ # end
28
+ class AllowsValuesForMacro < ValidationAssertionMacro
29
+ register :allows_values_for
30
+
31
+ def evaluate(actual, attribute, *values)
32
+ bad_values = []
33
+ values.each do |value|
34
+ bad_values << value if errors_from_writing_value?(actual, attribute, value)
35
+ end
36
+ bad_values.empty? ? pass : fail(expected_message(attribute).to_allow_values(bad_values))
37
+ end
38
+ end
39
+
40
+ # An ActiveRecord assertion that expects to fail with a given value or set of values for a given
41
+ # attribute.
42
+ #
43
+ # rails_context User do
44
+ # asserts_topic.does_not_allow_values_for :email, "a"
45
+ # asserts_topic.does_not_allow_values_for :email, "a@b", "e f@g.h"
46
+ # end
47
+ class DoesNotAllowValuesForMacro < ValidationAssertionMacro
48
+ register :does_not_allow_values_for
49
+ def evaluate(actual, attribute, *values)
50
+ good_values = []
51
+ values.each do |value|
52
+ good_values << value unless errors_from_writing_value?(actual, attribute, value)
53
+ end
54
+ good_values.empty? ? pass : fail(expected_message(attribute).not_to_allow_values(good_values))
55
+ end
56
+ end
57
+
58
+ # An ActiveRecord assertion that expects to fail with invalid value for an attribute. Optionally, the
59
+ # error message can be provided as the exact string or as regular expression.
60
+ #
61
+ # rails_context User do
62
+ # asserts_topic.is_invalid_when :email, "fake", "is invalid"
63
+ # asserts_topic.is_invalid_when :email, "another fake", /invalid/
64
+ # end
65
+ class IsInvalidWhenMacro < ValidationAssertionMacro
66
+ register :is_invalid_when
67
+
68
+ def evaluate(actual, attribute, value, expected_error=nil)
69
+ actual_errors = errors_from_writing_value(actual, attribute, value)
70
+ if actual_errors.empty?
71
+ fail expected_message(attribute).to_be_invalid_when_value_is(value)
72
+ elsif expected_error && !has_error_message?(expected_error, actual_errors)
73
+ fail expected_message(attribute).to_be_invalid_with_error_message(expected_error)
74
+ else
75
+ pass new_message.attribute(attribute).is_invalid
76
+ end
77
+ end
78
+ private
79
+ def has_error_message?(expected, errors)
80
+ return true unless expected
81
+ expected.kind_of?(Regexp) ? errors.any? {|e| e =~ expected } : errors.any? {|e| e == expected }
82
+ end
83
+ end
84
+
85
+ # An ActiveRecord assertion that expects to fail when a given attribute is validated after a nil value
86
+ # is provided to it.
87
+ #
88
+ # rails_context User do
89
+ # asserts_topic.validates_presence_of(:name)
90
+ # end
91
+ class ValidatesPresenceOfMacro < ValidationAssertionMacro
92
+ register :validates_presence_of
93
+
94
+ def evaluate(actual, attribute)
95
+ if errors_from_writing_value?(actual, attribute, nil)
96
+ pass new_message.validates_presence_of(attribute)
97
+ else
98
+ fail expected_message.to_validate_presence_of(attribute)
99
+ end
100
+ end
101
+ end
102
+
103
+ # An ActiveRecord assertion that expects to fail with an attribute is not valid for record because the
104
+ # value of the attribute is not unique. Requires the topic of the context to be a created record; one
105
+ # that returns false for a call to +new_record?+.
106
+ #
107
+ # rails_context User do
108
+ # setup { User.create(:email => "a@b.cde", ... ) }
109
+ # asserts_topic.validates_uniqueness_of :email
110
+ # end
111
+ class ValidatesUniquenessOfMacro < ValidationAssertionMacro
112
+ register :validates_uniqueness_of
113
+
114
+ def evaluate(actual, attribute)
115
+ actual_record = actual
116
+ if actual_record.new_record?
117
+ fail new_message.must_use_a_persisted_record_when_testing_uniqueness_of(attribute)
118
+ else
119
+ copied_model = actual_record.class.new
120
+ actual_record.attributes.each do |dup_attribute, dup_value|
121
+ copied_model.__send__(:write_attribute, dup_attribute, dup_value)
122
+ end
123
+ copied_value = actual_record.__send__(:read_attribute, attribute)
124
+ if errors_from_writing_value?(copied_model, attribute, copied_value)
125
+ pass new_message(attribute).is_unique
126
+ else
127
+ fail expected_message.to_fail_because(attribute).is_not_unique
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ # An ActiveRecord assertion to test that the length of the value of an attribute must be within a
134
+ # specified range. Assertion fails if: there are errors when min/max characters are used, there are no
135
+ # errors when min-1/max+1 characters are used.
136
+ #
137
+ # rails_context User do
138
+ # asserts_topic.validates_length_of :name, (2..36)
139
+ # end
140
+ #
141
+ # TODO: allow for options on what to validate
142
+ class ValidatesLengthOfMacro < ValidationAssertionMacro
143
+ register :validates_length_of
144
+
145
+ def evaluate(actual, attribute, range)
146
+ min, max = range.first, range.last
147
+ [min, max].each do |length|
148
+ if errors_from_writing_value?(actual, attribute, "r" * length)
149
+ return fail(new_message(attribute).should_be_able_to_be(length).characters)
150
+ end
151
+ end
152
+
153
+ if (min-1) > 0 && !errors_from_writing_value?(actual, attribute, "r" * (min-1))
154
+ fail new_message(attribute).expected_to_be_more_than(min - 1).characters
155
+ elsif !errors_from_writing_value?(actual, attribute, "r" * (max+1))
156
+ fail new_message(attribute).expected_to_be_less_than(max + 1).characters
157
+ else
158
+ pass new_message.validates_length_of(attribute).is_within(range)
159
+ end
160
+ end
161
+ end
162
+
163
+ # An ActiveRecord assertion to test that an attribute is invalid along with the expected error message
164
+ # (or error message partial). The assumption is that a value has already been set.
165
+ #
166
+ # rails_context User do
167
+ # hookup { topic.bio = "I'm a goofy clown" }
168
+ # asserts_topic.attribute_is_invalid :bio, "cannot contain adjectives"
169
+ # end
170
+ class AttributeIsInvalidMacro < ValidationAssertionMacro
171
+ register :attribute_is_invalid
172
+
173
+ def evaluate(actual, attribute, error_message)
174
+ actual.valid?
175
+ errors = actual.errors[attribute]
176
+ if errors.empty?
177
+ fail new_message(attribute).expected_to_be_invalid
178
+ elsif errors.include?(error_message)
179
+ pass new_message(attribute).is_invalid
180
+ else
181
+ fail new_message(attribute).is_invalid.but(error_message).is_not_a_valid_error_message
182
+ end
183
+ end
184
+ end
185
+
186
+ end # ActiveRecord
187
+ end # RiotRails
@@ -1 +1,3 @@
1
+ require 'riot/rails'
1
2
  require 'riot/active_record/assertion_macros'
3
+ require 'riot/active_record/context_helper'
data/lib/riot/rails.rb CHANGED
@@ -1,3 +1,2 @@
1
1
  require 'riot'
2
- require 'riot/active_record'
3
- require 'riot/action_controller'
2
+ require 'riot/rails_context'
@@ -0,0 +1,84 @@
1
+ module RiotRails
2
+ def self.helpers; @helpers ||= []; end
3
+ def self.register_context_helper(&handler_block)
4
+ helpers << Class.new(&handler_block).new
5
+ end
6
+
7
+ class RailsContext < Riot::Context
8
+ def initialize(description, parent=nil, &definition)
9
+ @options = {:transactional => false}
10
+ transaction { |&default_block| raise Exception, "No transaction handler" }
11
+ super(description, parent, &definition)
12
+ apply_helpers
13
+ end
14
+
15
+ # We're going to allow any helper to help out. Not just one.
16
+ def apply_helpers
17
+ RiotRails.helpers.each { |helper| helper.prepare_context(self) }
18
+ end
19
+
20
+ # Set options for the specific rails_context. For instance, you can tell the context to be transactional
21
+ #
22
+ # rails_context "Foo" do
23
+ # set :transactional, true
24
+ # end
25
+ def set(property, value) options[property] = value; end
26
+
27
+ # Technically, this is a secret ... but whatever. It's ruby. Basically, just make this setup more
28
+ # important than any of the others.
29
+ #
30
+ # Yes I can. See ... I just did!
31
+ def premium_setup(&definition)
32
+ @setups.unshift(::Riot::Setup.new(&definition)).first;
33
+ end
34
+
35
+ # Returns true if current context or a parent context has the transactional option enabled. To enable,
36
+ # anywhere within a rails_context or a child context thereof, do:
37
+ #
38
+ # rails_context Foo do
39
+ # context "sub context" do
40
+ # set :transactional, true
41
+ # end
42
+ # end
43
+ #
44
+ # Transactional support is disabled by default. When enabled, all transactions are rolled back when the
45
+ # context is done executing.
46
+ def transactional?
47
+ options[:transactional] || (parent.respond_to?(:transactional?) && parent.transactional?)
48
+ end
49
+
50
+ # TODO: cleanup how we handle transactions and context helpers
51
+ def transaction(&block) @transaction_block = block; end
52
+
53
+ def local_run(*args)
54
+ transactional? ? @transaction_block.call { super(*args) } : super
55
+ end
56
+ private
57
+ attr_reader :options
58
+ end
59
+
60
+ module Root
61
+ # Things an Object needs at the root level
62
+ #
63
+ # rails_context SomeKindOfClass do
64
+ # end
65
+ def rails_context(description, &definition)
66
+ context(description, RailsContext, &definition)
67
+ end
68
+ end # Root
69
+
70
+ module Context
71
+ # Things a running context needs
72
+ #
73
+ # context "Something" do
74
+ # rails_context SomeKindOfClass do
75
+ # end
76
+ # end
77
+ def rails_context(description, &definition)
78
+ new_context(description, RailsContext, &definition)
79
+ end
80
+ end # Context
81
+ end # RiotRails
82
+
83
+ Object.instance_eval { include RiotRails::Root }
84
+ Riot::Context.instance_eval { include RiotRails::Context }