remarkable_activerecord 3.1.6 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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: