robert-shoulda 2.10.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +171 -0
  4. data/Rakefile +72 -0
  5. data/bin/convert_to_should_syntax +42 -0
  6. data/lib/shoulda/action_controller/macros.rb +240 -0
  7. data/lib/shoulda/action_controller/matchers/assign_to_matcher.rb +109 -0
  8. data/lib/shoulda/action_controller/matchers/filter_param_matcher.rb +57 -0
  9. data/lib/shoulda/action_controller/matchers/render_with_layout_matcher.rb +81 -0
  10. data/lib/shoulda/action_controller/matchers/respond_with_content_type_matcher.rb +74 -0
  11. data/lib/shoulda/action_controller/matchers/respond_with_matcher.rb +81 -0
  12. data/lib/shoulda/action_controller/matchers/route_matcher.rb +93 -0
  13. data/lib/shoulda/action_controller/matchers/set_session_matcher.rb +87 -0
  14. data/lib/shoulda/action_controller/matchers/set_the_flash_matcher.rb +85 -0
  15. data/lib/shoulda/action_controller/matchers.rb +37 -0
  16. data/lib/shoulda/action_controller.rb +26 -0
  17. data/lib/shoulda/action_mailer/assertions.rb +38 -0
  18. data/lib/shoulda/action_mailer.rb +10 -0
  19. data/lib/shoulda/action_view/macros.rb +61 -0
  20. data/lib/shoulda/action_view.rb +10 -0
  21. data/lib/shoulda/active_record/assertions.rb +69 -0
  22. data/lib/shoulda/active_record/helpers.rb +27 -0
  23. data/lib/shoulda/active_record/macros.rb +571 -0
  24. data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
  25. data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
  26. data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
  27. data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
  28. data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
  29. data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
  30. data/lib/shoulda/active_record/matchers/have_db_index_matcher.rb +112 -0
  31. data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +128 -0
  32. data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
  33. data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
  34. data/lib/shoulda/active_record/matchers/validate_format_of_matcher.rb +67 -0
  35. data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
  36. data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
  37. data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
  38. data/lib/shoulda/active_record/matchers/validation_matcher.rb +57 -0
  39. data/lib/shoulda/active_record/matchers.rb +43 -0
  40. data/lib/shoulda/active_record.rb +16 -0
  41. data/lib/shoulda/assertions.rb +71 -0
  42. data/lib/shoulda/autoload_macros.rb +46 -0
  43. data/lib/shoulda/context.rb +413 -0
  44. data/lib/shoulda/helpers.rb +8 -0
  45. data/lib/shoulda/macros.rb +133 -0
  46. data/lib/shoulda/private_helpers.rb +13 -0
  47. data/lib/shoulda/proc_extensions.rb +14 -0
  48. data/lib/shoulda/rails.rb +13 -0
  49. data/lib/shoulda/rspec.rb +11 -0
  50. data/lib/shoulda/tasks/list_tests.rake +29 -0
  51. data/lib/shoulda/tasks/yaml_to_shoulda.rake +28 -0
  52. data/lib/shoulda/tasks.rb +3 -0
  53. data/lib/shoulda/test_unit.rb +22 -0
  54. data/lib/shoulda.rb +9 -0
  55. data/rails/init.rb +7 -0
  56. data/test/README +36 -0
  57. data/test/fail_macros.rb +39 -0
  58. data/test/fixtures/addresses.yml +3 -0
  59. data/test/fixtures/friendships.yml +0 -0
  60. data/test/fixtures/posts.yml +5 -0
  61. data/test/fixtures/products.yml +0 -0
  62. data/test/fixtures/taggings.yml +0 -0
  63. data/test/fixtures/tags.yml +9 -0
  64. data/test/fixtures/users.yml +6 -0
  65. data/test/functional/posts_controller_test.rb +121 -0
  66. data/test/functional/users_controller_test.rb +19 -0
  67. data/test/matchers/active_record/allow_mass_assignment_of_matcher_test.rb +68 -0
  68. data/test/matchers/active_record/allow_value_matcher_test.rb +64 -0
  69. data/test/matchers/active_record/association_matcher_test.rb +263 -0
  70. data/test/matchers/active_record/ensure_inclusion_of_matcher_test.rb +80 -0
  71. data/test/matchers/active_record/ensure_length_of_matcher_test.rb +158 -0
  72. data/test/matchers/active_record/have_db_column_matcher_test.rb +169 -0
  73. data/test/matchers/active_record/have_db_index_matcher_test.rb +91 -0
  74. data/test/matchers/active_record/have_named_scope_matcher_test.rb +65 -0
  75. data/test/matchers/active_record/have_readonly_attributes_matcher_test.rb +29 -0
  76. data/test/matchers/active_record/validate_acceptance_of_matcher_test.rb +44 -0
  77. data/test/matchers/active_record/validate_format_of_matcher_test.rb +39 -0
  78. data/test/matchers/active_record/validate_numericality_of_matcher_test.rb +52 -0
  79. data/test/matchers/active_record/validate_presence_of_matcher_test.rb +86 -0
  80. data/test/matchers/active_record/validate_uniqueness_of_matcher_test.rb +147 -0
  81. data/test/matchers/controller/assign_to_matcher_test.rb +35 -0
  82. data/test/matchers/controller/filter_param_matcher_test.rb +32 -0
  83. data/test/matchers/controller/render_with_layout_matcher_test.rb +33 -0
  84. data/test/matchers/controller/respond_with_content_type_matcher_test.rb +32 -0
  85. data/test/matchers/controller/respond_with_matcher_test.rb +106 -0
  86. data/test/matchers/controller/route_matcher_test.rb +75 -0
  87. data/test/matchers/controller/set_session_matcher_test.rb +38 -0
  88. data/test/matchers/controller/set_the_flash_matcher.rb +41 -0
  89. data/test/model_builder.rb +106 -0
  90. data/test/other/autoload_macro_test.rb +18 -0
  91. data/test/other/context_test.rb +203 -0
  92. data/test/other/convert_to_should_syntax_test.rb +63 -0
  93. data/test/other/helpers_test.rb +340 -0
  94. data/test/other/private_helpers_test.rb +32 -0
  95. data/test/other/should_test.rb +271 -0
  96. data/test/rails_root/app/controllers/application_controller.rb +25 -0
  97. data/test/rails_root/app/controllers/posts_controller.rb +87 -0
  98. data/test/rails_root/app/controllers/users_controller.rb +84 -0
  99. data/test/rails_root/app/helpers/application_helper.rb +3 -0
  100. data/test/rails_root/app/helpers/posts_helper.rb +2 -0
  101. data/test/rails_root/app/helpers/users_helper.rb +2 -0
  102. data/test/rails_root/app/models/address.rb +7 -0
  103. data/test/rails_root/app/models/flea.rb +3 -0
  104. data/test/rails_root/app/models/friendship.rb +4 -0
  105. data/test/rails_root/app/models/pets/cat.rb +7 -0
  106. data/test/rails_root/app/models/pets/dog.rb +10 -0
  107. data/test/rails_root/app/models/post.rb +12 -0
  108. data/test/rails_root/app/models/product.rb +12 -0
  109. data/test/rails_root/app/models/profile.rb +2 -0
  110. data/test/rails_root/app/models/registration.rb +2 -0
  111. data/test/rails_root/app/models/tag.rb +8 -0
  112. data/test/rails_root/app/models/tagging.rb +4 -0
  113. data/test/rails_root/app/models/treat.rb +3 -0
  114. data/test/rails_root/app/models/user.rb +32 -0
  115. data/test/rails_root/app/views/layouts/posts.rhtml +19 -0
  116. data/test/rails_root/app/views/layouts/users.rhtml +17 -0
  117. data/test/rails_root/app/views/layouts/wide.html.erb +1 -0
  118. data/test/rails_root/app/views/posts/edit.rhtml +27 -0
  119. data/test/rails_root/app/views/posts/index.rhtml +25 -0
  120. data/test/rails_root/app/views/posts/new.rhtml +26 -0
  121. data/test/rails_root/app/views/posts/show.rhtml +18 -0
  122. data/test/rails_root/app/views/users/edit.rhtml +22 -0
  123. data/test/rails_root/app/views/users/index.rhtml +22 -0
  124. data/test/rails_root/app/views/users/new.rhtml +21 -0
  125. data/test/rails_root/app/views/users/show.rhtml +13 -0
  126. data/test/rails_root/config/boot.rb +110 -0
  127. data/test/rails_root/config/database.yml +4 -0
  128. data/test/rails_root/config/environment.rb +18 -0
  129. data/test/rails_root/config/environments/test.rb +0 -0
  130. data/test/rails_root/config/initializers/new_rails_defaults.rb +15 -0
  131. data/test/rails_root/config/initializers/shoulda.rb +8 -0
  132. data/test/rails_root/config/routes.rb +6 -0
  133. data/test/rails_root/db/migrate/001_create_users.rb +19 -0
  134. data/test/rails_root/db/migrate/002_create_posts.rb +13 -0
  135. data/test/rails_root/db/migrate/003_create_taggings.rb +12 -0
  136. data/test/rails_root/db/migrate/004_create_tags.rb +11 -0
  137. data/test/rails_root/db/migrate/005_create_dogs.rb +12 -0
  138. data/test/rails_root/db/migrate/006_create_addresses.rb +14 -0
  139. data/test/rails_root/db/migrate/007_create_fleas.rb +11 -0
  140. data/test/rails_root/db/migrate/008_create_dogs_fleas.rb +12 -0
  141. data/test/rails_root/db/migrate/009_create_products.rb +17 -0
  142. data/test/rails_root/db/migrate/010_create_friendships.rb +14 -0
  143. data/test/rails_root/db/migrate/011_create_treats.rb +12 -0
  144. data/test/rails_root/db/migrate/20090506203502_create_profiles.rb +12 -0
  145. data/test/rails_root/db/migrate/20090506203536_create_registrations.rb +14 -0
  146. data/test/rails_root/db/migrate/20090513104502_create_cats.rb +12 -0
  147. data/test/rails_root/db/schema.rb +0 -0
  148. data/test/rails_root/log/test.log +8963 -0
  149. data/test/rails_root/public/404.html +30 -0
  150. data/test/rails_root/public/422.html +30 -0
  151. data/test/rails_root/public/500.html +30 -0
  152. data/test/rails_root/script/console +3 -0
  153. data/test/rails_root/script/generate +3 -0
  154. data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
  155. data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
  156. data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
  157. data/test/rspec_test.rb +207 -0
  158. data/test/test_helper.rb +28 -0
  159. data/test/unit/address_test.rb +15 -0
  160. data/test/unit/cat_test.rb +7 -0
  161. data/test/unit/dog_test.rb +9 -0
  162. data/test/unit/flea_test.rb +6 -0
  163. data/test/unit/friendship_test.rb +6 -0
  164. data/test/unit/post_test.rb +19 -0
  165. data/test/unit/product_test.rb +23 -0
  166. data/test/unit/tag_test.rb +15 -0
  167. data/test/unit/tagging_test.rb +6 -0
  168. data/test/unit/user_test.rb +80 -0
  169. metadata +225 -0
@@ -0,0 +1,148 @@
1
+ module Shoulda # :nodoc:
2
+ module ActiveRecord # :nodoc:
3
+ module Matchers
4
+
5
+ # Ensures that the model is invalid if the given attribute is not unique.
6
+ #
7
+ # Internally, this uses values from existing records to test validations,
8
+ # so this will always fail if you have not saved at least one record for
9
+ # the model being tested, like so:
10
+ #
11
+ # describe User do
12
+ # before(:each) { User.create!(:email => 'address@example.com') }
13
+ # it { should validate_uniqueness_of(:email) }
14
+ # end
15
+ #
16
+ # Options:
17
+ #
18
+ # * <tt>with_message</tt> - value the test expects to find in
19
+ # <tt>errors.on(:attribute)</tt>. <tt>Regexp</tt> or <tt>String</tt>.
20
+ # Defaults to the translation for <tt>:taken</tt>.
21
+ # * <tt>scoped_to</tt> - field(s) to scope the uniqueness to.
22
+ # * <tt>case_insensitive</tt> - ensures that the validation does not
23
+ # check case. Off by default. Ignored by non-text attributes.
24
+ #
25
+ # Examples:
26
+ # it { should validate_uniqueness_of(:keyword) }
27
+ # it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
28
+ # it { should validate_uniqueness_of(:email).scoped_to(:name) }
29
+ # it { should validate_uniqueness_of(:email).
30
+ # scoped_to(:first_name, :last_name) }
31
+ # it { should validate_uniqueness_of(:keyword).case_insensitive }
32
+ #
33
+ def validate_uniqueness_of(attr)
34
+ ValidateUniquenessOfMatcher.new(attr)
35
+ end
36
+
37
+ class ValidateUniquenessOfMatcher < ValidationMatcher # :nodoc:
38
+ include Helpers
39
+
40
+ def initialize(attribute)
41
+ @attribute = attribute
42
+ end
43
+
44
+ def scoped_to(*scopes)
45
+ @scopes = [*scopes].flatten
46
+ self
47
+ end
48
+
49
+ def with_message(message)
50
+ @expected_message = message
51
+ self
52
+ end
53
+
54
+ def case_insensitive
55
+ @case_insensitive = true
56
+ self
57
+ end
58
+
59
+ def description
60
+ result = "require "
61
+ result << "case sensitive " unless @case_insensitive
62
+ result << "unique value for #{@attribute}"
63
+ result << " scoped to #{@scopes.join(', ')}" unless @scopes.blank?
64
+ result
65
+ end
66
+
67
+ def matches?(subject)
68
+ @subject = subject.class.new
69
+ @expected_message ||= :taken
70
+ find_existing &&
71
+ set_scoped_attributes &&
72
+ validate_attribute &&
73
+ validate_after_scope_change
74
+ end
75
+
76
+ private
77
+
78
+ def find_existing
79
+ if @existing = @subject.class.find(:first)
80
+ true
81
+ else
82
+ @failure_message = "Can't find first #{class_name}"
83
+ false
84
+ end
85
+ end
86
+
87
+ def set_scoped_attributes
88
+ unless @scopes.blank?
89
+ @scopes.each do |scope|
90
+ setter = :"#{scope}="
91
+ unless @subject.respond_to?(setter)
92
+ @failure_message =
93
+ "#{class_name} doesn't seem to have a #{scope} attribute."
94
+ return false
95
+ end
96
+ @subject.send("#{scope}=", @existing.send(scope))
97
+ end
98
+ end
99
+ true
100
+ end
101
+
102
+ def validate_attribute
103
+ disallows_value_of(existing_value, @expected_message)
104
+ end
105
+
106
+ # TODO: There is a chance that we could change the scoped field
107
+ # to a value that's already taken. An alternative implementation
108
+ # could actually find all values for scope and create a unique
109
+ def validate_after_scope_change
110
+ if @scopes.blank?
111
+ true
112
+ else
113
+ @scopes.all? do |scope|
114
+ previous_value = @existing.send(scope)
115
+
116
+ # Assume the scope is a foreign key if the field is nil
117
+ previous_value ||= 0
118
+
119
+ next_value = previous_value.next
120
+
121
+ @subject.send("#{scope}=", next_value)
122
+
123
+ if allows_value_of(existing_value, @expected_message)
124
+ @negative_failure_message <<
125
+ " (with different value of #{scope})"
126
+ true
127
+ else
128
+ @failure_message << " (with different value of #{scope})"
129
+ false
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def class_name
136
+ @subject.class.name
137
+ end
138
+
139
+ def existing_value
140
+ value = @existing.send(@attribute)
141
+ value.swapcase! if @case_insensitive && value.respond_to?(:swapcase!)
142
+ value
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,57 @@
1
+ module Shoulda # :nodoc:
2
+ module ActiveRecord # :nodoc:
3
+ module Matchers
4
+
5
+ class ValidationMatcher # :nodoc:
6
+
7
+ attr_reader :failure_message
8
+
9
+ def initialize(attribute)
10
+ @attribute = attribute
11
+ end
12
+
13
+ def negative_failure_message
14
+ @negative_failure_message || @failure_message
15
+ end
16
+
17
+ def matches?(subject)
18
+ @subject = subject
19
+ false
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def allows_value_of(value, message = nil)
26
+ allow = AllowValueMatcher.
27
+ new(value).
28
+ for(@attribute).
29
+ with_message(message)
30
+ if allow.matches?(@subject)
31
+ @negative_failure_message = allow.failure_message
32
+ true
33
+ else
34
+ @failure_message = allow.negative_failure_message
35
+ false
36
+ end
37
+ end
38
+
39
+ def disallows_value_of(value, message = nil)
40
+ disallow = AllowValueMatcher.
41
+ new(value).
42
+ for(@attribute).
43
+ with_message(message)
44
+ if disallow.matches?(@subject)
45
+ @failure_message = disallow.negative_failure_message
46
+ false
47
+ else
48
+ @negative_failure_message = disallow.failure_message
49
+ true
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,43 @@
1
+ require 'shoulda/active_record/helpers'
2
+ require 'shoulda/active_record/matchers/validation_matcher'
3
+ require 'shoulda/active_record/matchers/allow_value_matcher'
4
+ require 'shoulda/active_record/matchers/ensure_length_of_matcher'
5
+ require 'shoulda/active_record/matchers/ensure_inclusion_of_matcher'
6
+ require 'shoulda/active_record/matchers/validate_presence_of_matcher'
7
+ require 'shoulda/active_record/matchers/validate_format_of_matcher'
8
+ require 'shoulda/active_record/matchers/validate_uniqueness_of_matcher'
9
+ require 'shoulda/active_record/matchers/validate_acceptance_of_matcher'
10
+ require 'shoulda/active_record/matchers/validate_numericality_of_matcher'
11
+ require 'shoulda/active_record/matchers/association_matcher'
12
+ require 'shoulda/active_record/matchers/have_db_column_matcher'
13
+ require 'shoulda/active_record/matchers/have_db_index_matcher'
14
+ require 'shoulda/active_record/matchers/have_readonly_attribute_matcher'
15
+ require 'shoulda/active_record/matchers/allow_mass_assignment_of_matcher'
16
+ require 'shoulda/active_record/matchers/have_named_scope_matcher'
17
+
18
+
19
+ module Shoulda # :nodoc:
20
+ module ActiveRecord # :nodoc:
21
+ # = Matchers for your active record models
22
+ #
23
+ # These matchers will test most of the validations and associations for your
24
+ # ActiveRecord models.
25
+ #
26
+ # describe User do
27
+ # it { should validate_presence_of(:name) }
28
+ # it { should validate_presence_of(:phone_number) }
29
+ # %w(abcd 1234).each do |value|
30
+ # it { should_not allow_value(value).for(:phone_number) }
31
+ # end
32
+ # it { should allow_value("(123) 456-7890").for(:phone_number) }
33
+ # it { should_not allow_mass_assignment_of(:password) }
34
+ # it { should have_one(:profile) }
35
+ # it { should have_many(:dogs) }
36
+ # it { should have_many(:messes).through(:dogs) }
37
+ # it { should belong_to(:lover) }
38
+ # end
39
+ #
40
+ module Matchers
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ require 'shoulda'
2
+ require 'shoulda/active_record/helpers'
3
+ require 'shoulda/active_record/matchers'
4
+ require 'shoulda/active_record/assertions'
5
+ require 'shoulda/active_record/macros'
6
+
7
+ module Test # :nodoc: all
8
+ module Unit
9
+ class TestCase
10
+ include Shoulda::ActiveRecord::Helpers
11
+ include Shoulda::ActiveRecord::Matchers
12
+ include Shoulda::ActiveRecord::Assertions
13
+ extend Shoulda::ActiveRecord::Macros
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ module Shoulda # :nodoc:
2
+ module Assertions
3
+ # Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
4
+ #
5
+ # assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
6
+ def assert_same_elements(a1, a2, msg = nil)
7
+ [:select, :inject, :size].each do |m|
8
+ [a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") }
9
+ end
10
+
11
+ assert a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h }
12
+ assert a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h }
13
+
14
+ assert_equal(a1h, a2h, msg)
15
+ end
16
+
17
+ # Asserts that the given collection contains item x. If x is a regular expression, ensure that
18
+ # at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails.
19
+ #
20
+ # assert_contains(['a', '1'], /\d/) => passes
21
+ # assert_contains(['a', '1'], 'a') => passes
22
+ # assert_contains(['a', '1'], /not there/) => fails
23
+ def assert_contains(collection, x, extra_msg = "")
24
+ collection = [collection] unless collection.is_a?(Array)
25
+ msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}"
26
+ case x
27
+ when Regexp
28
+ assert(collection.detect { |e| e =~ x }, msg)
29
+ else
30
+ assert(collection.include?(x), msg)
31
+ end
32
+ end
33
+
34
+ # Asserts that the given collection does not contain item x. If x is a regular expression, ensure that
35
+ # none of the elements from the collection match x.
36
+ def assert_does_not_contain(collection, x, extra_msg = "")
37
+ collection = [collection] unless collection.is_a?(Array)
38
+ msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg
39
+ case x
40
+ when Regexp
41
+ assert(!collection.detect { |e| e =~ x }, msg)
42
+ else
43
+ assert(!collection.include?(x), msg)
44
+ end
45
+ end
46
+
47
+ # Asserts that the given matcher returns true when +target+ is passed to #matches?
48
+ def assert_accepts(matcher, target, options = {})
49
+ if matcher.matches?(target)
50
+ assert_block { true }
51
+ if options[:message]
52
+ assert_match options[:message], matcher.negative_failure_message
53
+ end
54
+ else
55
+ assert_block(matcher.failure_message) { false }
56
+ end
57
+ end
58
+
59
+ # Asserts that the given matcher returns false when +target+ is passed to #matches?
60
+ def assert_rejects(matcher, target, options = {})
61
+ unless matcher.matches?(target)
62
+ assert_block { true }
63
+ if options[:message]
64
+ assert_match options[:message], matcher.failure_message
65
+ end
66
+ else
67
+ assert_block(matcher.negative_failure_message) { false }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,46 @@
1
+ module Shoulda # :nodoc:
2
+ # Call autoload_macros when you want to load test macros automatically in a non-Rails
3
+ # project (it's done automatically for Rails projects).
4
+ # You don't need to specify ROOT/test/shoulda_macros explicitly. Your custom macros
5
+ # are loaded automatically when you call autoload_macros.
6
+ #
7
+ # The first argument is the path to you application's root directory.
8
+ # All following arguments are directories relative to your root, which contain
9
+ # shoulda_macros subdirectories. These directories support the same kinds of globs as the
10
+ # Dir class.
11
+ #
12
+ # Basic usage (from a test_helper):
13
+ # Shoulda.autoload_macros(File.dirname(__FILE__) + '/..')
14
+ # will load everything in
15
+ # - your_app/test/shoulda_macros
16
+ #
17
+ # To load vendored macros as well:
18
+ # Shoulda.autoload_macros(APP_ROOT, 'vendor/*')
19
+ # will load everything in
20
+ # - APP_ROOT/vendor/*/shoulda_macros
21
+ # - APP_ROOT/test/shoulda_macros
22
+ #
23
+ # To load macros in an app with a vendor directory laid out like Rails':
24
+ # Shoulda.autoload_macros(APP_ROOT, 'vendor/{plugins,gems}/*')
25
+ # or
26
+ # Shoulda.autoload_macros(APP_ROOT, 'vendor/plugins/*', 'vendor/gems/*')
27
+ # will load everything in
28
+ # - APP_ROOT/vendor/plugins/*/shoulda_macros
29
+ # - APP_ROOT/vendor/gems/*/shoulda_macros
30
+ # - APP_ROOT/test/shoulda_macros
31
+ #
32
+ # If you prefer to stick testing dependencies away from your production dependencies:
33
+ # Shoulda.autoload_macros(APP_ROOT, 'vendor/*', 'test/vendor/*')
34
+ # will load everything in
35
+ # - APP_ROOT/vendor/*/shoulda_macros
36
+ # - APP_ROOT/test/vendor/*/shoulda_macros
37
+ # - APP_ROOT/test/shoulda_macros
38
+ def self.autoload_macros(root, *dirs)
39
+ dirs << File.join('test')
40
+ complete_dirs = dirs.map{|d| File.join(root, d, 'shoulda_macros')}
41
+ all_files = complete_dirs.inject([]){ |files, dir| files + Dir[File.join(dir, '*.rb')] }
42
+ all_files.each do |file|
43
+ require file
44
+ end
45
+ end
46
+ end