remarkable_activerecord 3.1.6 → 3.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,98 +1,100 @@
1
- * Added :token and :separator to deal with :tokenizer in validates_length_of [#77]
1
+ * Ensure quick subject bypass protected attributes [#87]
2
2
 
3
- * Deprecated validate_format_of. It does not have the same API as the respective
4
- ActiveRecord macro, raising questions frequentely about its usage [#76]
5
-
6
- * allow_mass_assignment_of when called without arguments checks if any mass
7
- assignment is possible [#80]
8
-
9
- * Add :table_name option to have_index (thanks to Lawrence Pit) [#79]
10
-
11
- * Allow default subject attributes to be given [#74]
12
- You can even mix with a fixture replacement tool and still use quick subjects:
13
-
14
- describe Post
15
- # Fixjour example
16
- subject_attributes { valid_post_attributes }
17
-
18
- describe :published => true do
19
- should_validate_presence_of :published_at
20
- end
21
- end
22
-
23
- * Bug fix when a symbol is given has join table to habtm association [#75]
24
-
25
- * Association matchers now searches in the right database for tables [#73]
26
-
27
- * validate_length_of accepts :with_kind_of to enable it to work with associations [#69]
28
- In your Post specs now you can write:
29
-
30
- should_validate_length_of :comments, :maximum => 10, :with_kind_of => Comment
31
-
32
- # v3.1
33
-
34
- * Allow validate_presence_of to work with associations [#63]
35
-
36
- * Allow validate_uniqueness_of to work when scopes are not stringfiable values.
37
- You can now give timestamps, datetime, date and boolean as scopes [#60]
38
-
39
- * Allow subjects to be overwriten quickly (quick subjects):
40
-
41
- describe Post
42
- should_validate_presente_of :title
43
-
44
- describe :published => true do
45
- should_validate_presence_of :published_at
46
- end
3
+ * Added :token and :separator to deal with :tokenizer in validates_length_of [#77]
4
+
5
+ * Deprecated validate_format_of. It does not have the same API as the respective
6
+ ActiveRecord macro, raising questions frequentely about its usage [#76]
7
+
8
+ * allow_mass_assignment_of when called without arguments checks if any mass
9
+ assignment is possible [#80]
10
+
11
+ * Add :table_name option to have_index (thanks to Lawrence Pit) [#79]
12
+
13
+ * Allow default subject attributes to be given [#74]
14
+ You can even mix with a fixture replacement tool and still use quick subjects:
15
+
16
+ describe Post
17
+ # Fixjour example
18
+ subject_attributes { valid_post_attributes }
19
+
20
+ describe :published => true do
21
+ should_validate_presence_of :published_at
22
+ end
47
23
  end
48
-
49
- Is the same as:
50
-
51
- describe Post
52
- should_validate_presente_of :title
53
-
54
- describe "when published is true" do
55
- subject { Post.new(:published => true) }
56
- should_validate_presence_of :published_at
57
- end
58
- end
59
-
60
- And the string can be also localized using I18n [#57]
61
-
62
- [COMPATIBILITY] validate_associated no longer accepts a block to confgure the
63
- builder:
64
-
65
- should_validate_associated(:tasks){ |p| p.tasks.build(:captcha => 'i_am_a_robot') }
66
-
67
- The right way to do this is by giving an option called builder and a proc:
68
-
69
- should_validate_associated :tasks, :builder => proc{ |p| p.tasks.build(:captcha => 'i_am_a_robot') }
70
-
71
- * validate_uniqueness_of and accept_nested_attributes_for now use the new
72
- interpolation option {{sentence}} [#58]
73
-
74
- * Added accept_nested_attributes_for matcher [#39]
75
-
76
- * Added have_default_scope matcher [#38]
77
-
78
- * Allow :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly,
79
- :group, :having, :from, :lock as quick accessors to have_scope matcher
80
-
81
- * Allow all kind of objects to be sent to have_scope (including datetimes, arrays,
82
- booleans and nil) (thanks to Szymon Nowak and Nolan Eakins) [#53]
83
-
84
- * Added support to sql options in association_matcher: select, conditions, include,
85
- group, having, order, limit and offset, plus finder_sql and counter_sql. [#48]
86
-
87
- * :source and :source_type are now supported by association matcher [#47]
88
-
89
- * validate_inclusion_of became smarter since it now tests invalid values too [#36]
90
-
91
- * Fixed three bugs in validate_uniqueness_of matcher [#42] [#40] [#37]
92
-
24
+
25
+ * Bug fix when a symbol is given has join table to habtm association [#75]
26
+
27
+ * Association matchers now searches in the right database for tables [#73]
28
+
29
+ * validate_length_of accepts :with_kind_of to enable it to work with associations [#69]
30
+ In your Post specs now you can write:
31
+
32
+ should_validate_length_of :comments, :maximum => 10, :with_kind_of => Comment
33
+
34
+ # v3.1
35
+
36
+ * Allow validate_presence_of to work with associations [#63]
37
+
38
+ * Allow validate_uniqueness_of to work when scopes are not stringfiable values.
39
+ You can now give timestamps, datetime, date and boolean as scopes [#60]
40
+
41
+ * Allow subjects to be overwriten quickly (quick subjects):
42
+
43
+ describe Post
44
+ should_validate_presente_of :title
45
+
46
+ describe :published => true do
47
+ should_validate_presence_of :published_at
48
+ end
49
+ end
50
+
51
+ Is the same as:
52
+
53
+ describe Post
54
+ should_validate_presente_of :title
55
+
56
+ describe "when published is true" do
57
+ subject { Post.new(:published => true) }
58
+ should_validate_presence_of :published_at
59
+ end
60
+ end
61
+
62
+ And the string can be also localized using I18n [#57]
63
+
64
+ [COMPATIBILITY] validate_associated no longer accepts a block to confgure the
65
+ builder:
66
+
67
+ should_validate_associated(:tasks){ |p| p.tasks.build(:captcha => 'i_am_a_robot') }
68
+
69
+ The right way to do this is by giving an option called builder and a proc:
70
+
71
+ should_validate_associated :tasks, :builder => proc{ |p| p.tasks.build(:captcha => 'i_am_a_robot') }
72
+
73
+ * validate_uniqueness_of and accept_nested_attributes_for now use the new
74
+ interpolation option {{sentence}} [#58]
75
+
76
+ * Added accept_nested_attributes_for matcher [#39]
77
+
78
+ * Added have_default_scope matcher [#38]
79
+
80
+ * Allow :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly,
81
+ :group, :having, :from, :lock as quick accessors to have_scope matcher
82
+
83
+ * Allow all kind of objects to be sent to have_scope (including datetimes, arrays,
84
+ booleans and nil) (thanks to Szymon Nowak and Nolan Eakins) [#53]
85
+
86
+ * Added support to sql options in association_matcher: select, conditions, include,
87
+ group, having, order, limit and offset, plus finder_sql and counter_sql. [#48]
88
+
89
+ * :source and :source_type are now supported by association matcher [#47]
90
+
91
+ * validate_inclusion_of became smarter since it now tests invalid values too [#36]
92
+
93
+ * Fixed three bugs in validate_uniqueness_of matcher [#42] [#40] [#37]
94
+
93
95
  # v3.0
94
96
 
95
- * Added more options to associations matcher. Previously it was handling just
97
+ * Added more options to associations matcher. Previously it was handling just
96
98
  :dependent and :through options. Now it deals with:
97
99
 
98
100
  :through, :class_name, :foreign_key, :dependent, :join_table, :uniq,
@@ -130,9 +132,9 @@ subject definitions on rspec. This was also fixed.
130
132
 
131
133
  # v2.x
132
134
 
133
- * Added associations, allow_mass_assignment, allow_values_for, have_column,
134
- have_index, have_scope, have_readonly_attributes, validate_acceptance_of,
135
- validate_associated, validate_confirmation_of, validate_exclusion_of,
136
- validate_inclusion_of, validate_length_of, validate_numericality_of,
135
+ * Added associations, allow_mass_assignment, allow_values_for, have_column,
136
+ have_index, have_scope, have_readonly_attributes, validate_acceptance_of,
137
+ validate_associated, validate_confirmation_of, validate_exclusion_of,
138
+ validate_inclusion_of, validate_length_of, validate_numericality_of,
137
139
  validate_presence_of and validate_uniqueness_of matchers.
138
140
 
@@ -1,6 +1,7 @@
1
1
  module Remarkable
2
2
  module ActiveRecord
3
- class Base < Remarkable::Base
3
+ class Base < Remarkable::Base
4
+ I18N_COLLECTION = [ :attributes, :associations ]
4
5
 
5
6
  # Provides a way to send options to all ActiveRecord matchers.
6
7
  #
@@ -206,12 +207,14 @@ module Remarkable
206
207
  @spec.send(:described_class)
207
208
  end
208
209
 
209
- if RAILS_I18N && described_class.respond_to?(:human_attribute_name) && self.class.matcher_arguments[:collection]
210
+ if i18n_collection? && described_class.respond_to?(:human_attribute_name)
210
211
  options = {}
211
212
 
212
213
  collection_name = self.class.matcher_arguments[:collection].to_sym
213
214
  if collection = instance_variable_get("@#{collection_name}")
214
- collection.map!{|attr| described_class.human_attribute_name(attr.to_s, :locale => Remarkable.locale).downcase }
215
+ collection = collection.map do |attr|
216
+ described_class.human_attribute_name(attr.to_s, :locale => Remarkable.locale).downcase
217
+ end
215
218
  options[collection_name] = array_to_sentence(collection)
216
219
  end
217
220
 
@@ -225,6 +228,12 @@ module Remarkable
225
228
  else
226
229
  super
227
230
  end
231
+ end
232
+
233
+ # Returns true if the given collection should be translated.
234
+ #
235
+ def i18n_collection? #:nodoc:
236
+ RAILS_I18N && I18N_COLLECTION.include?(self.class.matcher_arguments[:collection])
228
237
  end
229
238
 
230
239
  end
@@ -137,7 +137,7 @@ module Remarkable
137
137
  #
138
138
  example_group = super(*args) do
139
139
  write_inheritable_hash(:describe_subject_attributes, attributes)
140
- subject { self.class.described_class.new(subject_attributes) }
140
+ set_described_subject!
141
141
  instance_eval(&block)
142
142
  end
143
143
  else
@@ -160,9 +160,16 @@ module Remarkable
160
160
  #
161
161
  def subject_attributes(options=nil, &block)
162
162
  write_inheritable_attribute(:default_subject_attributes, options || block)
163
- subject { self.class.described_class.new(subject_attributes) }
163
+ set_described_subject!
164
164
  end
165
165
 
166
+ def set_described_subject!
167
+ subject {
168
+ record = self.class.described_class.new
169
+ record.send(:attributes=, subject_attributes, false)
170
+ record
171
+ }
172
+ end
166
173
  end
167
174
 
168
175
  # Returns a hash with the subject attributes declared using the
@@ -186,7 +193,7 @@ module Remarkable
186
193
 
187
194
  default.merge(self.class.describe_subject_attributes || {})
188
195
  end
189
-
196
+
190
197
  end
191
198
  end
192
199
  end
@@ -3,18 +3,18 @@ module Remarkable
3
3
  module Matchers
4
4
  class AllowMassAssignmentOfMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
5
  arguments :collection => :attributes, :as => :attribute
6
-
6
+
7
7
  assertion :allows?
8
8
  collection_assertions :is_protected?, :is_accessible?
9
9
 
10
10
  protected
11
-
12
- # If no attribute is given, check if no attribute is being protected,
13
- # otherwise it fails.
14
- #
15
- def allows?
16
- !@attributes.empty? || protected_attributes.empty?
17
- end
11
+
12
+ # If no attribute is given, check if no attribute is being protected,
13
+ # otherwise it fails.
14
+ #
15
+ def allows?
16
+ !@attributes.empty? || protected_attributes.empty?
17
+ end
18
18
 
19
19
  def is_protected?
20
20
  protected_attributes.empty? || !protected_attributes.include?(@attribute.to_s)
@@ -22,28 +22,41 @@ module Remarkable
22
22
 
23
23
  def is_accessible?
24
24
  accessible_attributes.empty? || accessible_attributes.include?(@attribute.to_s)
25
- end
26
-
27
- def interpolation_options
28
- if @subject
29
- { :protected_attributes => array_to_sentence(protected_attributes.to_a, false, '[]') }
30
- else
31
- {}
32
- end
33
- end
34
-
35
- private
36
-
37
- def accessible_attributes
38
- @accessible_attributes ||= subject_class.accessible_attributes || []
39
- end
40
-
41
- def protected_attributes
42
- @protected_attributes ||= subject_class.protected_attributes || []
25
+ end
26
+
27
+ def interpolation_options
28
+ if @subject
29
+ { :protected_attributes => array_to_sentence(protected_attributes.to_a, false, '[]') }
30
+ else
31
+ {}
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def accessible_attributes
38
+ @accessible_attributes ||= subject_class.accessible_attributes || []
39
+ end
40
+
41
+ def protected_attributes
42
+ @protected_attributes ||= subject_class.protected_attributes || []
43
43
  end
44
44
  end
45
45
 
46
- # Ensures that the attribute can be set on mass update.
46
+ # Ensures that the attribute can be set on mass update.
47
+ #
48
+ # Beware that when used in the negative form, this matcher fails if any of
49
+ # the values fail. For example, let's assume we have a accessible and a
50
+ # protected attribute called :accessible and :protected. The following
51
+ # assertion WILL pass:
52
+ #
53
+ # should_not_allow_mass_assignment_of :protected, :accessible
54
+ #
55
+ # If you want to assert that all values fail, you have to do:
56
+ #
57
+ # %w(first_protected second_protected).each do |protected|
58
+ # should_not_allow_mass_assignment_of protected
59
+ # end
47
60
  #
48
61
  # == Examples
49
62
  #
@@ -63,10 +63,19 @@ module Remarkable
63
63
 
64
64
  end
65
65
 
66
- # Ensures that the attribute can be set to the given values.
67
- #
68
- # Note: this matcher accepts at once just one attribute to test.
69
- # Note: this matcher is also aliased as "validate_format_of".
66
+ # Ensures that the attribute can be set to the given values.
67
+ #
68
+ # Beware that when used in the negative form, this matcher fails if any of
69
+ # the values fail. For example, let's assume we have a valid and invalid
70
+ # value called "valid" and "invalid". The following assertion WILL pass:
71
+ #
72
+ # should_not_allow_values_for :attribute, "valid", "invalid"
73
+ #
74
+ # If you want to assert that all values fail, you have to do:
75
+ #
76
+ # %w(first_invalid second_invalid).each do |invalid|
77
+ # should_not_allow_values_for invalid
78
+ # end
70
79
  #
71
80
  # == Options
72
81
  #
@@ -78,25 +87,22 @@ module Remarkable
78
87
  # == Examples
79
88
  #
80
89
  # should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
81
- # should_not_allow_values_for :isbn, "bad 1", "bad 2"
82
- #
83
90
  # it { should allow_values_for(:isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0") }
84
- # it { should_not allow_values_for(:isbn, "bad 1", "bad 2") }
85
91
  #
86
92
  def allow_values_for(attribute, *args, &block)
87
93
  options = args.extract_options!
88
94
  AllowValuesForMatcher.new(attribute, options.merge!(:in => args), &block).spec(self)
89
- end
90
-
91
- # Deprecated. Use allow_values_for instead.
92
- #
93
- def validate_format_of(*args)
94
- if caller[0] =~ /\macros.rb/
95
- warn "[DEPRECATION] should_validate_format_of is deprecated, use should_allow_values_for instead."
96
- else
97
- warn "[DEPRECATION] validate_format_of is deprecated, use allow_values_for instead. Called from #{caller[0]}."
98
- end
99
- allow_values_for(*args)
95
+ end
96
+
97
+ # Deprecated. Use allow_values_for instead.
98
+ #
99
+ def validate_format_of(*args)
100
+ if caller[0] =~ /\macros.rb/
101
+ warn "[DEPRECATION] should_validate_format_of is deprecated, use should_allow_values_for instead."
102
+ else
103
+ warn "[DEPRECATION] validate_format_of is deprecated, use allow_values_for instead. Called from #{caller[0]}."
104
+ end
105
+ allow_values_for(*args)
100
106
  end
101
107
 
102
108
  end
@@ -4,11 +4,11 @@ module Remarkable
4
4
  class AssociationMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
5
  arguments :macro, :collection => :associations, :as => :association
6
6
 
7
- optionals :through, :source, :source_type, :class_name, :foreign_key, :dependent, :join_table, :as
7
+ optionals :through, :source, :source_type, :class_name, :foreign_key, :dependent, :join_table, :as
8
8
  optionals :select, :conditions, :include, :group, :having, :order, :limit, :offset, :finder_sql, :counter_sql
9
9
  optionals :uniq, :readonly, :validate, :autosave, :polymorphic, :counter_cache, :default => true
10
10
 
11
- collection_assertions :association_exists?, :macro_matches?, :through_exists?, :source_exists?,
11
+ collection_assertions :association_exists?, :macro_matches?, :through_exists?, :source_exists?,
12
12
  :klass_exists?, :join_table_exists?, :foreign_key_exists?, :polymorphic_exists?,
13
13
  :counter_cache_exists?, :options_match?
14
14
 
@@ -16,38 +16,38 @@ module Remarkable
16
16
 
17
17
  def association_exists?
18
18
  reflection
19
- end
20
-
19
+ end
20
+
21
21
  def macro_matches?
22
22
  reflection.macro == @macro
23
23
  end
24
24
 
25
25
  def through_exists?
26
- return true unless @options.key?(:through)
26
+ return true unless @options.key?(:through)
27
27
  reflection.through_reflection rescue false
28
- end
29
-
30
- def source_exists?
31
- return true unless @options.key?(:through)
32
- reflection.source_reflection rescue false
33
- end
34
-
35
- # Polymorphic associations does not have a klass.
36
- #
37
- def klass_exists?
38
- return true if @options[:polymorphic]
39
- reflection.klass rescue nil
40
28
  end
41
-
42
- # has_and_belongs_to_many only works if the tables are in the same
43
- # database, so we always look for the table in the subject connection.
29
+
30
+ def source_exists?
31
+ return true unless @options.key?(:through)
32
+ reflection.source_reflection rescue false
33
+ end
34
+
35
+ # Polymorphic associations does not have a klass.
36
+ #
37
+ def klass_exists?
38
+ return true if @options[:polymorphic]
39
+ reflection.klass rescue nil
40
+ end
41
+
42
+ # has_and_belongs_to_many only works if the tables are in the same
43
+ # database, so we always look for the table in the subject connection.
44
44
  #
45
45
  def join_table_exists?
46
46
  return true unless reflection.macro == :has_and_belongs_to_many
47
47
  subject_class.connection.tables.include?(reflection.options[:join_table].to_s)
48
48
  end
49
49
 
50
- def foreign_key_exists?
50
+ def foreign_key_exists?
51
51
  return true unless foreign_key_table
52
52
  table_has_column?(foreign_key_table_class, foreign_key_table, reflection_foreign_key)
53
53
  end
@@ -61,18 +61,18 @@ module Remarkable
61
61
  return true unless @options[:counter_cache]
62
62
  klass_table_has_column?(reflection.klass, reflection.counter_cache_column.to_s)
63
63
  end
64
-
65
- def options_match?
66
- actual_options = {}
67
-
68
- @options.keys.each do |key|
69
- method = :"reflection_#{key}"
70
-
71
- @options[key] = @options[key].to_s
72
- actual_options[key] = (respond_to?(method, true) ? send(method) : reflection.options[key]).to_s
73
- end
74
-
75
- return @options == actual_options, :actual => actual_options.inspect
64
+
65
+ def options_match?
66
+ actual_options = {}
67
+
68
+ @options.keys.each do |key|
69
+ method = :"reflection_#{key}"
70
+
71
+ @options[key] = @options[key].to_s
72
+ actual_options[key] = (respond_to?(method, true) ? send(method) : reflection.options[key]).to_s
73
+ end
74
+
75
+ return @options == actual_options, :actual => actual_options.inspect
76
76
  end
77
77
 
78
78
  private
@@ -80,15 +80,15 @@ module Remarkable
80
80
  def reflection
81
81
  @reflection ||= subject_class.reflect_on_association(@association.to_sym)
82
82
  end
83
-
83
+
84
84
  def subject_table_name
85
85
  subject_class.table_name.to_s
86
- end
86
+ end
87
87
 
88
88
  def reflection_class_name
89
89
  reflection.class_name.to_s rescue nil
90
- end
91
-
90
+ end
91
+
92
92
  def reflection_table_name
93
93
  reflection.klass.table_name.to_s rescue nil
94
94
  end
@@ -99,24 +99,24 @@ module Remarkable
99
99
 
100
100
  def table_has_column?(klass, table_name, column)
101
101
  klass.connection.columns(table_name, 'Remarkable column retrieval').any?{|c| c.name == column }
102
- end
103
-
104
- def klass_table_has_column?(klass, column)
105
- table_has_column?(klass, klass.table_name, column)
106
102
  end
107
103
 
108
- # In through we don't check the foreign_key, because it's spread
109
- # accross the through and the source reflection which should be tested
110
- # with their own macros.
111
- #
104
+ def klass_table_has_column?(klass, column)
105
+ table_has_column?(klass, klass.table_name, column)
106
+ end
107
+
108
+ # In through we don't check the foreign_key, because it's spread
109
+ # accross the through and the source reflection which should be tested
110
+ # with their own macros.
111
+ #
112
112
  # In cases a join table exists (has_and_belongs_to_many and through
113
113
  # associations), we check the foreign key in the join table.
114
114
  #
115
115
  # On belongs to, the foreign_key is in the subject class table and in
116
116
  # other cases it's on the reflection class table.
117
117
  #
118
- def foreign_key_table
119
- if reflection.options.key?(:through)
118
+ def foreign_key_table
119
+ if reflection.options.key?(:through)
120
120
  nil
121
121
  elsif reflection.macro == :has_and_belongs_to_many
122
122
  reflection.options[:join_table]
@@ -125,22 +125,22 @@ module Remarkable
125
125
  else
126
126
  reflection_table_name
127
127
  end
128
- end
129
-
130
- # Returns the foreign key table class to use the proper connection
131
- # when searching for the table and foreign key.
132
- #
133
- def foreign_key_table_class
128
+ end
129
+
130
+ # Returns the foreign key table class to use the proper connection
131
+ # when searching for the table and foreign key.
132
+ #
133
+ def foreign_key_table_class
134
134
  if [:belongs_to, :has_and_belongs_to_many].include?(reflection.macro)
135
135
  subject_class
136
136
  else
137
137
  reflection.klass
138
- end
139
- end
138
+ end
139
+ end
140
140
 
141
141
  def interpolation_options
142
- options = {}
143
- options[:macro] = Remarkable.t(@macro, :scope => matcher_i18n_scope, :default => @macro.to_s.gsub("_", ""))
142
+ options = {}
143
+ options[:macro] = Remarkable.t(@macro, :scope => matcher_i18n_scope, :default => @macro.to_s.gsub("_", ""))
144
144
  options[:options] = @options.inspect
145
145
 
146
146
  if @subject && reflection
@@ -150,8 +150,8 @@ module Remarkable
150
150
  :reflection_table => reflection_table_name.inspect,
151
151
  :foreign_key_table => foreign_key_table.inspect,
152
152
  :polymorphic_column => reflection_foreign_key.sub(/_id$/, '_type').inspect,
153
- :counter_cache_column => reflection.counter_cache_column.to_s.inspect,
154
- :join_table => reflection.options[:join_table].inspect,
153
+ :counter_cache_column => reflection.counter_cache_column.to_s.inspect,
154
+ :join_table => reflection.options[:join_table].inspect,
155
155
  :foreign_key => reflection_foreign_key.inspect
156
156
  )
157
157
  end
@@ -175,9 +175,9 @@ module Remarkable
175
175
  # It also checks if the column actually exists in the table.
176
176
  # * <tt>:polymorphic</tt> - if the association should be polymorphic or not.
177
177
  # When true it also checks for the association_type column in the subject table.
178
- #
179
- # Plus all supported sql conditions options: :select, :conditions, :order,
180
- # :limit, :offset, :include, :group, :having.
178
+ #
179
+ # Plus all supported sql conditions options: :select, :conditions, :order,
180
+ # :limit, :offset, :include, :group, :having.
181
181
  #
182
182
  # == Examples
183
183
  #
@@ -199,9 +199,9 @@ module Remarkable
199
199
  # * <tt>:uniq</tt> - checks wether uniq is true or false.
200
200
  # * <tt>:readonly</tt> - checks wether readonly is true or false.
201
201
  # * <tt>:validate</tt> - checks wether validate is true or false.
202
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
203
- #
204
- # Plus all supported sql conditions options: :select, :conditions, :order,
202
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
203
+ #
204
+ # Plus all supported sql conditions options: :select, :conditions, :order,
205
205
  # :limit, :offset, :include, :group, :having.
206
206
  #
207
207
  # == Examples
@@ -221,8 +221,8 @@ module Remarkable
221
221
  #
222
222
  # * <tt>:class_name</tt> - the expected associted class name.
223
223
  # * <tt>:through</tt> - the expected join model which to perform the query.
224
- # It also checks if the through table exists.
225
- # * <tt>:source</tt> - the source of the through association.
224
+ # It also checks if the through table exists.
225
+ # * <tt>:source</tt> - the source of the through association.
226
226
  # * <tt>:source_type</tt> - the source type of the through association.
227
227
  # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
228
228
  # When used with :through, it will check for the foreign key in the join table.
@@ -230,9 +230,9 @@ module Remarkable
230
230
  # * <tt>:uniq</tt> - checks wether uniq is true or false.
231
231
  # * <tt>:readonly</tt> - checks wether readonly is true or false.
232
232
  # * <tt>:validate</tt> - checks wether validate is true or false.
233
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
234
- #
235
- # Plus all supported sql conditions options: :select, :conditions, :order,
233
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
234
+ #
235
+ # Plus all supported sql conditions options: :select, :conditions, :order,
236
236
  # :limit, :offset, :include, :group, :having.
237
237
  #
238
238
  # == Examples
@@ -257,16 +257,16 @@ module Remarkable
257
257
  #
258
258
  # * <tt>:class_name</tt> - the expected associted class name.
259
259
  # * <tt>:through</tt> - the expected join model which to perform the query.
260
- # It also checks if the through table exists.
261
- # * <tt>:source</tt> - the source of the through association.
260
+ # It also checks if the through table exists.
261
+ # * <tt>:source</tt> - the source of the through association.
262
262
  # * <tt>:source_type</tt> - the source type of the through association.
263
263
  # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
264
264
  # When used with :through, it will check for the foreign key in the join table.
265
265
  # * <tt>:dependent</tt> - the expected dependent value for the association.
266
266
  # * <tt>:validate</tt> - checks wether validate is true or false.
267
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
268
- #
269
- # Plus all supported sql conditions options: :select, :conditions, :order,
267
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
268
+ #
269
+ # Plus all supported sql conditions options: :select, :conditions, :order,
270
270
  # :limit, :offset, :include, :group, :having.
271
271
  #
272
272
  # == Examples
@@ -5,9 +5,9 @@ module Remarkable
5
5
  arguments :scope_name
6
6
  assertions :is_scope?, :options_match?
7
7
 
8
- optionals :with, :splat => true
9
- optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
10
- :readonly, :group, :having, :from, :lock
8
+ optionals :with, :splat => true
9
+ optionals :conditions, :include, :joins, :limit, :offset, :order, :select,
10
+ :readonly, :group, :having, :from, :lock
11
11
 
12
12
  protected
13
13
 
@@ -41,8 +41,8 @@ module Remarkable
41
41
  #
42
42
  # * <tt>with</tt> - Options to be sent to the named scope
43
43
  #
44
- # All options that the named scope would pass on to find: :conditions,
45
- # :include, :joins, :limit, :offset, :order, :select, :readonly, :group,
44
+ # All options that the named scope would pass on to find: :conditions,
45
+ # :include, :joins, :limit, :offset, :order, :select, :readonly, :group,
46
46
  # :having, :from, :lock.
47
47
  #
48
48
  # == Examples
@@ -10,12 +10,12 @@ module Remarkable
10
10
  protected
11
11
 
12
12
  def valid_values
13
- if @in_range
14
- [ @options[:in].first - 1, @options[:in].last + 1 ]
15
- elsif @options[:in].empty?
16
- []
17
- else
18
- [ @options[:in].map(&:to_s).max.to_s.next ]
13
+ if @in_range
14
+ [ @options[:in].first - 1, @options[:in].last + 1 ]
15
+ elsif @options[:in].empty?
16
+ []
17
+ else
18
+ [ @options[:in].map(&:to_s).max.to_s.next ]
19
19
  end
20
20
  end
21
21
 
@@ -26,9 +26,9 @@ module Remarkable
26
26
  end
27
27
 
28
28
  # Ensures that given values are not valid for the attribute. If a range
29
- # is given, ensures that the attribute is not valid in the given range.
30
- #
31
- # If you give that :username does not accept ["admin", "user"], it will
29
+ # is given, ensures that the attribute is not valid in the given range.
30
+ #
31
+ # If you give that :username does not accept ["admin", "user"], it will
32
32
  # test that "uses" (the next of the array max value) is allowed.
33
33
  #
34
34
  # == Options
@@ -14,21 +14,21 @@ module Remarkable
14
14
  end
15
15
 
16
16
  def invalid_values
17
- if @in_range
18
- [ @options[:in].first - 1, @options[:in].last + 1 ]
19
- elsif @options[:in].empty?
20
- []
21
- else
22
- [ @options[:in].map(&:to_s).max.to_s.next ]
17
+ if @in_range
18
+ [ @options[:in].first - 1, @options[:in].last + 1 ]
19
+ elsif @options[:in].empty?
20
+ []
21
+ else
22
+ [ @options[:in].map(&:to_s).max.to_s.next ]
23
23
  end
24
24
  end
25
25
 
26
26
  end
27
27
 
28
28
  # Ensures that given values are valid for the attribute. If a range
29
- # is given, ensures that the attribute is valid in the given range.
30
- #
31
- # If you give that :size accepts ["S", "M", "L"], it will test that "T"
29
+ # is given, ensures that the attribute is valid in the given range.
30
+ #
31
+ # If you give that :size accepts ["S", "M", "L"], it will test that "T"
32
32
  # (the next of the array max value) is not allowed.
33
33
  #
34
34
  # == Options
@@ -5,10 +5,10 @@ module Remarkable
5
5
  arguments :collection => :attributes, :as => :attribute
6
6
 
7
7
  optional :within, :alias => :in
8
- optional :minimum, :maximum, :is
8
+ optional :minimum, :maximum, :is
9
9
  optional :token, :separator, :with_kind_of
10
10
  optional :allow_nil, :allow_blank, :default => true
11
- optional :message, :too_short, :too_long, :wrong_length
11
+ optional :message, :too_short, :too_long, :wrong_length
12
12
 
13
13
  collection_assertions :less_than_min_length?, :exactly_min_length?,
14
14
  :more_than_max_length?, :exactly_max_length?,
@@ -56,12 +56,12 @@ module Remarkable
56
56
  @max_value.nil? || @min_value == @max_value || good?(value_for_length(@max_value), default_message_for(:too_long))
57
57
  end
58
58
 
59
- def value_for_length(value)
60
- if @options[:with_kind_of]
61
- [@options[:with_kind_of].new] * value
62
- else
63
- ([@options.fetch(:token, 'x')] * value).join(@options.fetch(:separator, ''))
64
- end
59
+ def value_for_length(value)
60
+ if @options[:with_kind_of]
61
+ [@options[:with_kind_of].new] * value
62
+ else
63
+ ([@options.fetch(:token, 'x')] * value).join(@options.fetch(:separator, ''))
64
+ end
65
65
  end
66
66
 
67
67
  def interpolation_options
@@ -101,23 +101,23 @@ module Remarkable
101
101
  # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % range.last</tt>
102
102
  # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
103
103
  # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.wrong_length') % value</tt>
104
- #
105
- # It also accepts an extra option called :with_kind_of. If you are validating
106
- # the size of an association array, you have to specify the kind of the array
107
- # being validated. For example, if your post accepts maximum 10 comments, you
108
- # can do:
109
- #
110
- # should_validate_length_of :comments, :maximum => 10, :with_kind_of => Comment
111
- #
112
- # Finally, it also accepts :token and :separator, to specify how the
113
- # tokenizer should work. For example, if you are splitting the attribute
114
- # per word:
115
- #
116
- # validates_length_of :essay, :minimum => 100, :tokenizer => lambda {|str| str.scan(/\w+/) }
117
- #
118
- # You could do this:
119
- #
120
- # should_validate_length_of :essay, :minimum => 100, :token => "word", :separator => " "
104
+ #
105
+ # It also accepts an extra option called :with_kind_of. If you are validating
106
+ # the size of an association array, you have to specify the kind of the array
107
+ # being validated. For example, if your post accepts maximum 10 comments, you
108
+ # can do:
109
+ #
110
+ # should_validate_length_of :comments, :maximum => 10, :with_kind_of => Comment
111
+ #
112
+ # Finally, it also accepts :token and :separator, to specify how the
113
+ # tokenizer should work. For example, if you are splitting the attribute
114
+ # per word:
115
+ #
116
+ # validates_length_of :essay, :minimum => 100, :tokenizer => lambda {|str| str.scan(/\w+/) }
117
+ #
118
+ # You could do this:
119
+ #
120
+ # should_validate_length_of :essay, :minimum => 100, :token => "word", :separator => " "
121
121
  #
122
122
  # == Gotcha
123
123
  #
@@ -131,16 +131,16 @@ module Remarkable
131
131
  # it { should validate_length_of(:password).maximum(20) }
132
132
  # it { should validate_length_of(:password).minimum(6) }
133
133
  # it { should validate_length_of(:age).is(18) }
134
- #
134
+ #
135
135
  # should_validate_length_of :password, :within => 6..20
136
136
  # should_validate_length_of :password, :maximum => 20
137
137
  # should_validate_length_of :password, :minimum => 6
138
- # should_validate_length_of :age, :is => 18
139
- #
140
- # should_validate_length_of :password do |m|
141
- # m.minimum 6
142
- # m.maximum 20
143
- # end
138
+ # should_validate_length_of :age, :is => 18
139
+ #
140
+ # should_validate_length_of :password do |m|
141
+ # m.minimum 6
142
+ # m.maximum 20
143
+ # end
144
144
  #
145
145
  def validate_length_of(*attributes, &block)
146
146
  ValidateLengthOfMatcher.new(*attributes, &block).spec(self)
data/locale/en.yml CHANGED
@@ -1,13 +1,13 @@
1
1
  en:
2
2
  remarkable:
3
- active_record:
4
- describe:
5
- each: "{{key}} is {{value}}"
6
- prepend: "when "
7
- connector: " and "
3
+ active_record:
4
+ describe:
5
+ each: "{{key}} is {{value}}"
6
+ prepend: "when "
7
+ connector: " and "
8
8
  expectations:
9
9
  allow_nil: "{{subject_name}} to {{not}}allow nil values for {{attribute}}"
10
- allow_blank: "{{subject_name}} to {{not}}allow blank values for {{attribute}}"
10
+ allow_blank: "{{subject_name}} to {{not}}allow blank values for {{attribute}}"
11
11
  optionals:
12
12
  allow_nil:
13
13
  positive: "allowing nil values"
@@ -15,24 +15,24 @@ en:
15
15
  allow_blank:
16
16
  positive: "allowing blank values"
17
17
  negative: "not allowing blank values"
18
-
19
- accept_nested_attributes_for:
20
- description: "accept nested attributes for {{associations}}"
21
- expectations:
22
- association_exists: "{{subject_name}} to have association {{association}}, but does not"
23
- is_autosave: "{{subject_name}} to have association {{association}} with autosave true, got false"
24
- responds_to_attributes: "{{subject_name}} to respond to :{{association}}_attributes=, but does not"
25
- allows_destroy: "{{subject_name}} with allow destroy equals to {{allow_destroy}}, got {{actual}}"
26
- accepts: "{{subject_name}} to accept attributes {{attributes}} for {{association}}, but does not"
27
- rejects: "{{subject_name}} to reject attributes {{attributes}} for {{association}}, but does not"
28
- optionals:
29
- allow_destroy:
30
- positive: "allowing destroy"
31
- negative: "not allowing destroy"
32
- accept:
33
- positive: "accepting {{sentence}}"
34
- reject:
35
- positive: "rejecting {{sentence}}"
18
+
19
+ accept_nested_attributes_for:
20
+ description: "accept nested attributes for {{associations}}"
21
+ expectations:
22
+ association_exists: "{{subject_name}} to have association {{association}}, but does not"
23
+ is_autosave: "{{subject_name}} to have association {{association}} with autosave true, got false"
24
+ responds_to_attributes: "{{subject_name}} to respond to :{{association}}_attributes=, but does not"
25
+ allows_destroy: "{{subject_name}} with allow destroy equals to {{allow_destroy}}, got {{actual}}"
26
+ accepts: "{{subject_name}} to accept attributes {{attributes}} for {{association}}, but does not"
27
+ rejects: "{{subject_name}} to reject attributes {{attributes}} for {{association}}, but does not"
28
+ optionals:
29
+ allow_destroy:
30
+ positive: "allowing destroy"
31
+ negative: "not allowing destroy"
32
+ accept:
33
+ positive: "accepting {{sentence}}"
34
+ reject:
35
+ positive: "rejecting {{sentence}}"
36
36
 
37
37
  allow_values_for:
38
38
  description: "allow {{in}} as values for {{attributes}}"
@@ -41,7 +41,7 @@ en:
41
41
 
42
42
  allow_mass_assignment_of:
43
43
  description: "allow mass assignment of {{attributes}}"
44
- expectations:
44
+ expectations:
45
45
  allows: "{{subject_name}} to allow mass assignment ({{subject_name}} is protecting {{protected_attributes}})"
46
46
  is_protected: "{{subject_name}} to allow mass assignment of {{attribute}} ({{subject_name}} is protecting {{attribute}})"
47
47
  is_accessible: "{{subject_name}} to allow mass assignment of {{attribute}} ({{subject_name}} has not made {{attribute}} accessible)"
@@ -53,22 +53,22 @@ en:
53
53
  has_one: have one
54
54
  description: "{{macro}} {{associations}}"
55
55
  expectations:
56
- association_exists: "{{subject_name}} records {{macro}} {{association}}, but the association does not exist"
56
+ association_exists: "{{subject_name}} records {{macro}} {{association}}, but the association does not exist"
57
57
  macro_matches: "{{subject_name}} records {{macro}} {{association}}, got {{subject_name}} records {{actual_macro}} {{association}}"
58
- through_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, through association does not exist"
59
- source_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, source association does not exist"
58
+ through_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, through association does not exist"
59
+ source_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, source association does not exist"
60
60
  klass_exists: "{{subject_name}} records {{macro}} {{association}}, but the association class does not exist"
61
61
  join_table_exists: "join table {{join_table}} to exist, but does not"
62
62
  foreign_key_exists: "foreign key {{foreign_key}} to exist on {{foreign_key_table}}, but does not"
63
63
  polymorphic_exists: "{{subject_table}} to have {{polymorphic_column}} as column, but does not"
64
- counter_cache_exists: "{{reflection_table}} to have {{counter_cache_column}} as column, but does not"
64
+ counter_cache_exists: "{{reflection_table}} to have {{counter_cache_column}} as column, but does not"
65
65
  options_match: "{{subject_name}} records {{macro}} {{association}} with options {{options}}, got {{actual}}"
66
66
  optionals:
67
67
  through:
68
- positive: "through {{value}}"
69
- source:
70
- positive: "with source {{inspect}}"
71
- source_type:
68
+ positive: "through {{value}}"
69
+ source:
70
+ positive: "with source {{inspect}}"
71
+ source_type:
72
72
  positive: "with source type {{inspect}}"
73
73
  class_name:
74
74
  positive: "with class name {{inspect}}"
@@ -94,23 +94,23 @@ en:
94
94
  positive: "through the polymorphic interface {{inspect}}"
95
95
  counter_cache:
96
96
  positive: "with counter cache {{inspect}}"
97
- negative: "without counter cache"
98
- select:
99
- positive: "selecting {{inspect}}"
100
- conditions:
101
- positive: "with conditions {{inspect}}"
102
- include:
103
- positive: "including {{inspect}}"
104
- group:
105
- positive: "grouping by {{inspect}}"
106
- having:
107
- positive: "having {{inspect}}"
108
- order:
109
- positive: "with order {{inspect}}"
110
- limit:
111
- positive: "with limit {{inspect}}"
112
- offset:
113
- positive: "with offset {{inspect}}"
97
+ negative: "without counter cache"
98
+ select:
99
+ positive: "selecting {{inspect}}"
100
+ conditions:
101
+ positive: "with conditions {{inspect}}"
102
+ include:
103
+ positive: "including {{inspect}}"
104
+ group:
105
+ positive: "grouping by {{inspect}}"
106
+ having:
107
+ positive: "having {{inspect}}"
108
+ order:
109
+ positive: "with order {{inspect}}"
110
+ limit:
111
+ positive: "with limit {{inspect}}"
112
+ offset:
113
+ positive: "with offset {{inspect}}"
114
114
 
115
115
  have_column:
116
116
  description: "have column(s) named {{columns}}"
@@ -127,8 +127,8 @@ en:
127
127
  positive: "with default value {{inspect}}"
128
128
  negative: "with default value {{inspect}}"
129
129
  limit:
130
- positive: "with limit {{inspect}}"
131
-
130
+ positive: "with limit {{inspect}}"
131
+
132
132
  have_default_scope:
133
133
  description: "have a default scope with {{options}}"
134
134
  expectations:
@@ -142,8 +142,8 @@ en:
142
142
  optionals:
143
143
  unique:
144
144
  positive: "with unique values"
145
- negative: "with non unique values"
146
- table_name:
145
+ negative: "with non unique values"
146
+ table_name:
147
147
  positive: "on table {{value}}"
148
148
 
149
149
  have_readonly_attributes:
@@ -207,8 +207,8 @@ en:
207
207
  minimum:
208
208
  positive: "is minimum {{inspect}} characters"
209
209
  is:
210
- positive: "is equal to {{inspect}} characters"
211
- with_kind_of:
210
+ positive: "is equal to {{inspect}} characters"
211
+ with_kind_of:
212
212
  positive: "with kind of {{value}}"
213
213
 
214
214
  validate_numericality_of:
@@ -257,4 +257,4 @@ en:
257
257
  case_sensitive:
258
258
  positive: "case sensitive"
259
259
  negative: "case insensitive"
260
-
260
+
@@ -20,14 +20,14 @@ describe 'allow_mass_assignment_of' do
20
20
  @matcher = allow_mass_assignment_of(:title, :category)
21
21
  @matcher.description.should == 'allow mass assignment of title and category'
22
22
  end
23
-
24
- it 'should set allows? message' do
23
+
24
+ it 'should set allows? message' do
25
25
  define_and_validate(:protected => true)
26
26
  @matcher = allow_mass_assignment_of
27
27
  @matcher.matches?(@model)
28
28
  @matcher.failure_message.should == 'Expected Product to allow mass assignment (Product is protecting category and title)'
29
- end
30
-
29
+ end
30
+
31
31
  it 'should set is_protected? message' do
32
32
  @matcher = define_and_validate(:protected => true)
33
33
  @matcher.matches?(@model)
@@ -47,23 +47,23 @@ describe 'allow_mass_assignment_of' do
47
47
  it { should define_and_validate(:accessible => true) }
48
48
 
49
49
  it { should_not define_and_validate(:protected => true) }
50
- it { should_not define_and_validate(:accessible => [:another]) }
51
-
52
- describe 'with no argument' do
53
- it 'should allow mass assignment if no attribute is accessible or protected' do
54
- define_and_validate
55
- should allow_mass_assignment_of
56
- end
57
-
58
- it 'should allow mass assignment if attributes are accessible' do
59
- define_and_validate(:accessible => true)
60
- should allow_mass_assignment_of
61
- end
62
-
63
- it 'should not allow mass assignment if attributes are protected' do
64
- define_and_validate(:protected => true)
65
- should_not allow_mass_assignment_of
66
- end
50
+ it { should_not define_and_validate(:accessible => [:another]) }
51
+
52
+ describe 'with no argument' do
53
+ it 'should allow mass assignment if no attribute is accessible or protected' do
54
+ define_and_validate
55
+ should allow_mass_assignment_of
56
+ end
57
+
58
+ it 'should allow mass assignment if attributes are accessible' do
59
+ define_and_validate(:accessible => true)
60
+ should allow_mass_assignment_of
61
+ end
62
+
63
+ it 'should not allow mass assignment if attributes are protected' do
64
+ define_and_validate(:protected => true)
65
+ should_not allow_mass_assignment_of
66
+ end
67
67
  end
68
68
  end
69
69
 
@@ -49,13 +49,13 @@ describe 'allow_values_for' do
49
49
  describe 'macros' do
50
50
  before(:each){ define_and_validate(:with => /X|Y|Z/) }
51
51
 
52
- should_allow_values_for :title, 'X'
53
- should_not_allow_values_for :title, 'A'
54
-
55
- describe 'deprecation' do
56
- it { should validate_format_of(:title, 'X') }
57
- should_not_validate_format_of :title, 'A'
58
- end
52
+ should_allow_values_for :title, 'X'
53
+ should_not_allow_values_for :title, 'A'
54
+
55
+ describe 'deprecation' do
56
+ it { should validate_format_of(:title, 'X') }
57
+ should_not_validate_format_of :title, 'A'
58
+ end
59
59
  end
60
60
  end
61
61
 
@@ -5,9 +5,9 @@ RAILS_I18n = true
5
5
  class Post
6
6
  attr_accessor :published, :public, :deleted
7
7
 
8
- def initialize(attributes={})
8
+ def attributes=(attributes={}, guard=true)
9
9
  attributes.each do |key, value|
10
- send(:"#{key}=", value)
10
+ send(:"#{key}=", value) unless guard
11
11
  end
12
12
  end
13
13
 
@@ -143,31 +143,31 @@ describe 'validate_length_of' do
143
143
  it { should define_and_validate(:is => 3).is(3) }
144
144
  it { should_not define_and_validate(:is => 3).is(2) }
145
145
  it { should_not define_and_validate(:is => 3).is(4) }
146
- end
147
-
148
- describe "with token and separator options" do
149
- describe "and words as tokens" do
150
- before(:each) do
151
- @matcher = define_and_validate(:within => 3..5, :tokenizer => lambda { |str| str.scan(/\w+/) })
152
- end
153
-
154
- it { should @matcher.within(3..5).token("word").separator(" ") }
155
- it { should_not @matcher.within(2..5).token("word").separator(" ") }
156
- it { should_not @matcher.within(4..5).token("word").separator(" ") }
157
- it { should_not @matcher.within(3..4).token("word").separator(" ") }
158
- it { should_not @matcher.within(3..6).token("word").separator(" ") }
159
- it { should_not @matcher.within(3..5).token("word").separator("") }
160
- it { should_not @matcher.within(3..5).token("word").separator(" a ") }
161
- end
162
-
163
- describe "and digits as tokens" do
164
- before(:each) do
165
- @matcher = define_and_validate(:within => 3..5, :tokenizer => lambda { |str| str.scan(/\d+/) })
166
- end
167
-
168
- it { should @matcher.within(3..5).token("1").separator(" ") }
169
- it { should_not @matcher.within(3..5).token("a").separator("") }
170
- end
146
+ end
147
+
148
+ describe "with token and separator options" do
149
+ describe "and words as tokens" do
150
+ before(:each) do
151
+ @matcher = define_and_validate(:within => 3..5, :tokenizer => lambda { |str| str.scan(/\w+/) })
152
+ end
153
+
154
+ it { should @matcher.within(3..5).token("word").separator(" ") }
155
+ it { should_not @matcher.within(2..5).token("word").separator(" ") }
156
+ it { should_not @matcher.within(4..5).token("word").separator(" ") }
157
+ it { should_not @matcher.within(3..4).token("word").separator(" ") }
158
+ it { should_not @matcher.within(3..6).token("word").separator(" ") }
159
+ it { should_not @matcher.within(3..5).token("word").separator("") }
160
+ it { should_not @matcher.within(3..5).token("word").separator(" a ") }
161
+ end
162
+
163
+ describe "and digits as tokens" do
164
+ before(:each) do
165
+ @matcher = define_and_validate(:within => 3..5, :tokenizer => lambda { |str| str.scan(/\d+/) })
166
+ end
167
+
168
+ it { should @matcher.within(3..5).token("1").separator(" ") }
169
+ it { should_not @matcher.within(3..5).token("a").separator("") }
170
+ end
171
171
  end
172
172
 
173
173
  describe "with with kind of" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remarkable_activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.6
4
+ version: 3.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Brando
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2009-06-06 00:00:00 +02:00
14
+ date: 2009-07-05 00:00:00 +02:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,7 @@ dependencies:
32
32
  requirements:
33
33
  - - ">="
34
34
  - !ruby/object:Gem::Version
35
- version: 3.1.6
35
+ version: 3.1.7
36
36
  version:
37
37
  description: "Remarkable ActiveRecord: collection of matchers and macros with I18n for ActiveRecord"
38
38
  email: