meta_search 0.9.10 → 0.9.11

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ Changes since 0.9.10 (2010-11-18):
2
+ * Skip attempts to sort if someone passes an empty string to meta_sort
3
+ * Allow conditions on search_methods, (attr|assoc)_(un)?searchable using :if.
4
+ Option should be an object that responds to call and accepts the
5
+ MetaSearch::Builder instance as a parameter. Unused options passed to the
6
+ Model.search method will be available for your conditions to act on.
7
+ * Access attribute setters if a param is supplied - @search.attr_name(val)
8
+ behaves like @search.attr_name = val
9
+
1
10
  Changes since 0.9.9 (2010-11-15):
2
11
  * Fix bug introduced by new polymorphic belongs_to association code in
3
12
  honoring :url param to form_for
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.10
1
+ 0.9.11
@@ -22,38 +22,28 @@ module MetaSearch
22
22
  include ModelCompatibility
23
23
  include Utility
24
24
 
25
- attr_reader :base, :relation, :search_key, :search_attributes, :join_dependency, :errors
25
+ attr_reader :base, :relation, :search_key, :search_attributes, :join_dependency, :errors, :options
26
26
  delegate *RELATION_METHODS + [:to => :relation]
27
27
 
28
28
  # Initialize a new Builder. Requires a base model to wrap, and supports a couple of options
29
29
  # for how it will expose this model and its associations to your controllers/views.
30
30
  def initialize(base_or_relation, opts = {})
31
+ opts = opts.dup
31
32
  @relation = base_or_relation.scoped
32
33
  @base = @relation.klass
33
- @search_key = opts[:search_key] ? opts[:search_key].to_s : 'search'
34
+ @search_key = (opts.delete(:search_key) || 'search').to_s
35
+ @options = opts # Let's just hang on to other options for use in authorization blocks
34
36
  @join_dependency = build_join_dependency
35
37
  @search_attributes = {}
36
38
  @errors = ActiveModel::Errors.new(self)
37
39
  end
38
40
 
39
41
  def get_column(column, base = @base)
40
- base.columns_hash[column.to_s] unless base_excludes_attribute(base, column)
41
- end
42
-
43
- def base_excludes_attribute(base, column)
44
- base._metasearch_include_attributes.blank? ?
45
- base._metasearch_exclude_attributes.include?(column.to_s) :
46
- !base._metasearch_include_attributes.include?(column.to_s)
42
+ base.columns_hash[column.to_s] if base._metasearch_attribute_authorized?(column, self)
47
43
  end
48
44
 
49
45
  def get_association(assoc, base = @base)
50
- base.reflect_on_association(assoc.to_sym) unless base_excludes_association(base, assoc)
51
- end
52
-
53
- def base_excludes_association(base, assoc)
54
- base._metasearch_include_associations.blank? ?
55
- base._metasearch_exclude_associations.include?(assoc.to_s) :
56
- !base._metasearch_include_associations.include?(assoc.to_s)
46
+ base.reflect_on_association(assoc.to_sym) if base._metasearch_association_authorized?(assoc, self)
57
47
  end
58
48
 
59
49
  def get_attribute(name, parent = @join_dependency.join_base)
@@ -134,16 +124,16 @@ module MetaSearch
134
124
  def method_missing(method_id, *args, &block)
135
125
  method_name = method_id.to_s
136
126
  if method_name =~ /^meta_sort=?$/
137
- method_name =~ /=$/ ? set_sort(args.first) : get_sort
127
+ (args.any? || method_name =~ /=$/) ? set_sort(args.first) : get_sort
138
128
  elsif match = method_name.match(/^(.*)\(([0-9]+).*\)$/) # Multiparameter reader
139
129
  method_name, index = match.captures
140
130
  vals = self.send(method_name)
141
131
  vals.is_a?(Array) ? vals[index.to_i - 1] : nil
142
132
  elsif match = matches_named_method(method_name)
143
- method_name =~ /=$/ ? set_named_method_value(match, args.first) : get_named_method_value(match)
133
+ (args.any? || method_name =~ /=$/) ? set_named_method_value(match, args.first) : get_named_method_value(match)
144
134
  elsif match = matches_attribute_method(method_id)
145
135
  attribute, predicate = match.captures
146
- method_name =~ /=$/ ? set_attribute_method_value(attribute, predicate, args.first) : get_attribute_method_value(attribute, predicate)
136
+ (args.any? || method_name =~ /=$/) ? set_attribute_method_value(attribute, predicate, args.first) : get_attribute_method_value(attribute, predicate)
147
137
  else
148
138
  super
149
139
  end
@@ -151,7 +141,7 @@ module MetaSearch
151
141
 
152
142
  def matches_named_method(name)
153
143
  method_name = name.to_s.sub(/\=$/, '')
154
- return method_name if @base._metasearch_methods.has_key?(method_name)
144
+ return method_name if @base._metasearch_method_authorized?(method_name, self)
155
145
  end
156
146
 
157
147
  def matches_attribute_method(method_id)
@@ -172,6 +162,7 @@ module MetaSearch
172
162
  end
173
163
 
174
164
  def set_sort(val)
165
+ return if val.blank?
175
166
  column, direction = val.split('.')
176
167
  direction ||= 'asc'
177
168
  if ['asc','desc'].include?(direction)
@@ -199,7 +190,7 @@ module MetaSearch
199
190
  end
200
191
 
201
192
  def set_named_method_value(name, val)
202
- meth = @base._metasearch_methods[name]
193
+ meth = @base._metasearch_methods[name][:method]
203
194
  search_attributes[name] = meth.cast_param(val)
204
195
  if meth.validate(search_attributes[name])
205
196
  return_value = meth.evaluate(@relation, search_attributes[name])
@@ -22,25 +22,27 @@ module MetaSearch
22
22
 
23
23
  protected
24
24
 
25
- def build_with_metasearch(association, parent = nil, join_type = Arel::Nodes::InnerJoin, polymorphic_class = nil)
25
+ def build_with_metasearch(associations, parent = nil, join_type = Arel::Nodes::InnerJoin, polymorphic_class = nil)
26
26
  parent ||= @joins.last
27
- case association
27
+
28
+ case associations
28
29
  when Symbol, String
29
- reflection = parent.reflections[association.to_s.intern] or
30
- raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?"
31
- if reflection.options[:polymorphic]
30
+ reflection = parent.reflections[associations.to_s.intern] or
31
+ raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?"
32
+ unless (association = find_join_association(reflection, parent)) && (!polymorphic_class || association.active_record == polymorphic_class)
32
33
  @reflections << reflection
33
- association = build_polymorphic_join_association(reflection, parent, polymorphic_class)
34
- association.join_type = join_type
35
- @joins << association
36
- else
37
- @reflections << reflection
38
- association = build_join_association(reflection, parent)
34
+ if reflection.options[:polymorphic]
35
+ raise ArgumentError, "You can't create a polymorphic belongs_to join without specifying the polymorphic class!" unless polymorphic_class
36
+ association = build_polymorphic_join_association(reflection, parent, polymorphic_class)
37
+ else
38
+ association = build_join_association(reflection, parent)
39
+ end
39
40
  association.join_type = join_type
40
41
  @joins << association
41
42
  end
43
+ association
42
44
  else
43
- build(association, parent, join_type) # Shouldn't get here.
45
+ build(associations, parent, join_type)
44
46
  end
45
47
  end
46
48
 
@@ -58,12 +60,12 @@ module MetaSearch
58
60
  @join_dependency = join_dependency
59
61
  @parent = parent || join_dependency.join_base
60
62
  @reflection = reflection.clone
61
- @reflection.instance_eval "def klass; #{polymorphic_class} end"
63
+ @reflection.instance_variable_set(:"@klass", polymorphic_class)
62
64
  @aliased_prefix = "t#{ join_dependency.joins.size }"
63
65
  @parent_table_name = @parent.active_record.table_name
64
66
  @aliased_table_name = aliased_table_name_for(table_name)
65
67
  @join = nil
66
- @join_type = Arel::Nodes::InnerJoin
68
+ @join_type = Arel::Nodes::InnerJoin
67
69
  end
68
70
 
69
71
  def ==(other)
@@ -81,15 +83,11 @@ module MetaSearch
81
83
 
82
84
  @join = [
83
85
  aliased_table[options[:primary_key] || reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name]),
84
- parent_table[options[:foreign_type]].eq(active_record.base_class.name)
86
+ parent_table[options[:foreign_type]].eq(active_record.name)
85
87
  ]
86
88
 
87
- unless klass.descends_from_active_record?
88
- sti_column = aliased_table[klass.inheritance_column]
89
- sti_condition = sti_column.eq(klass.sti_name)
90
- klass.descendants.each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) }
91
-
92
- @join << sti_condition
89
+ if options[:conditions]
90
+ @join << interpolate_sql(sanitize_sql(options[:conditions], aliased_table_name))
93
91
  end
94
92
 
95
93
  @join
@@ -1,5 +1,6 @@
1
1
  en:
2
2
  meta_search:
3
+ or: 'or'
3
4
  predicates:
4
5
  equals: "%{attribute} equals"
5
6
  does_not_equal: "%{attribute} doesn't equal"
@@ -58,13 +58,16 @@ module MetaSearch
58
58
  if method_name
59
59
  predicate = Where.get(method_name)[:name]
60
60
  predicate_attribute = method_name.sub(/_#{predicate}=?$/, '')
61
+ predicate_attributes = predicate_attribute.split(/_or_/).map { |att|
62
+ klass.human_attribute_name(att)
63
+ }.join(" #{I18n.translate(:"meta_search.or", :default => 'or')} ")
61
64
  defaults << :"meta_search.predicates.#{predicate}"
62
65
  end
63
66
 
64
67
  defaults << options.delete(:default) if options[:default]
65
68
  defaults << attribute.to_s.humanize
66
69
 
67
- options.reverse_merge! :count => 1, :default => defaults, :attribute => klass.human_attribute_name(predicate_attribute || attribute)
70
+ options.reverse_merge! :count => 1, :default => defaults, :attribute => predicate_attributes || klass.human_attribute_name(attribute)
68
71
  I18n.translate(defaults.shift, options)
69
72
  end
70
73
  end
@@ -17,7 +17,7 @@ module MetaSearch
17
17
  self._metasearch_include_attributes =
18
18
  self._metasearch_exclude_attributes =
19
19
  self._metasearch_exclude_associations =
20
- self._metasearch_include_associations = []
20
+ self._metasearch_include_associations = {}
21
21
  self._metasearch_methods = {}
22
22
  end
23
23
  end
@@ -34,6 +34,30 @@ module MetaSearch
34
34
 
35
35
  alias_method :search, :metasearch unless respond_to?(:search)
36
36
 
37
+ def _metasearch_method_authorized?(name, metasearch_object)
38
+ name = name.to_s
39
+ meth = self._metasearch_methods[name]
40
+ meth && (meth[:if] ? meth[:if].call(metasearch_object) : true)
41
+ end
42
+
43
+ def _metasearch_attribute_authorized?(name, metasearch_object)
44
+ name = name.to_s
45
+ if self._metasearch_include_attributes.empty?
46
+ !_metasearch_excludes_attribute?(name, metasearch_object)
47
+ else
48
+ _metasearch_includes_attribute?(name, metasearch_object)
49
+ end
50
+ end
51
+
52
+ def _metasearch_association_authorized?(name, metasearch_object)
53
+ name = name.to_s
54
+ if self._metasearch_include_associations.empty?
55
+ !_metasearch_excludes_association?(name, metasearch_object)
56
+ else
57
+ _metasearch_includes_association?(name, metasearch_object)
58
+ end
59
+ end
60
+
37
61
  private
38
62
 
39
63
  # Excludes model attributes from searchability. This means that searches can't be created against
@@ -43,10 +67,15 @@ module MetaSearch
43
67
  # like <tt>:user_id_equals</tt>, nor will an Article.search accept the parameter
44
68
  # <tt>:comments_user_id_equals</tt>.
45
69
  def attr_unsearchable(*args)
70
+ opts = args.extract_options!
46
71
  args.flatten.each do |attr|
47
72
  attr = attr.to_s
48
73
  raise(ArgumentError, "No persisted attribute (column) named #{attr} in #{self}") unless self.columns_hash.has_key?(attr)
49
- self._metasearch_exclude_attributes = (self._metasearch_exclude_attributes + [attr]).uniq
74
+ self._metasearch_exclude_attributes = self._metasearch_exclude_attributes.merge(
75
+ attr => {
76
+ :if => opts[:if]
77
+ }
78
+ )
50
79
  end
51
80
  end
52
81
 
@@ -54,10 +83,15 @@ module MetaSearch
54
83
  # <tt>attr_searchable</tt> and <tt>attr_unsearchable</tt> are present, the latter
55
84
  # is ignored.
56
85
  def attr_searchable(*args)
86
+ opts = args.extract_options!
57
87
  args.flatten.each do |attr|
58
88
  attr = attr.to_s
59
89
  raise(ArgumentError, "No persisted attribute (column) named #{attr} in #{self}") unless self.columns_hash.has_key?(attr)
60
- self._metasearch_include_attributes = (self._metasearch_include_attributes + [attr]).uniq
90
+ self._metasearch_include_attributes = self._metasearch_include_attributes.merge(
91
+ attr => {
92
+ :if => opts[:if]
93
+ }
94
+ )
61
95
  end
62
96
  end
63
97
 
@@ -66,31 +100,68 @@ module MetaSearch
66
100
  # searching by declaring <tt>assoc_unsearchable :comments</tt> won't make any of the
67
101
  # <tt>comments_*</tt> methods available.
68
102
  def assoc_unsearchable(*args)
103
+ opts = args.extract_options!
69
104
  args.flatten.each do |assoc|
70
105
  assoc = assoc.to_s
71
106
  raise(ArgumentError, "No such association #{assoc} in #{self}") unless self.reflect_on_all_associations.map {|a| a.name.to_s}.include?(assoc)
72
- self._metasearch_exclude_associations = (self._metasearch_exclude_associations + [assoc]).uniq
107
+ self._metasearch_exclude_associations = self._metasearch_exclude_associations.merge(
108
+ assoc => {
109
+ :if => opts[:if]
110
+ }
111
+ )
73
112
  end
74
113
  end
75
114
 
76
115
  # As with <tt>attr_searchable</tt> this is the whitelist version of
77
116
  # <tt>assoc_unsearchable</tt>
78
117
  def assoc_searchable(*args)
118
+ opts = args.extract_options!
79
119
  args.flatten.each do |assoc|
80
120
  assoc = assoc.to_s
81
121
  raise(ArgumentError, "No such association #{assoc} in #{self}") unless self.reflect_on_all_associations.map {|a| a.name.to_s}.include?(assoc)
82
- self._metasearch_include_associations = (self._metasearch_include_associations + [assoc]).uniq
122
+ self._metasearch_include_associations = self._metasearch_include_associations.merge(
123
+ assoc => {
124
+ :if => opts[:if]
125
+ }
126
+ )
83
127
  end
84
128
  end
85
129
 
86
130
  def search_methods(*args)
87
- opts = args.last.is_a?(Hash) ? args.pop : {}
131
+ opts = args.extract_options!
132
+ authorizer = opts.delete(:if)
88
133
  args.flatten.map(&:to_s).each do |arg|
89
- self._metasearch_methods[arg] = MetaSearch::Method.new(arg, opts)
134
+ self._metasearch_methods = self._metasearch_methods.merge(
135
+ arg => {
136
+ :method => MetaSearch::Method.new(arg, opts),
137
+ :if => authorizer
138
+ }
139
+ )
90
140
  end
91
141
  end
92
142
 
93
143
  alias_method :search_method, :search_methods
144
+
145
+ def _metasearch_includes_attribute?(name, metasearch_object)
146
+ attr = self._metasearch_include_attributes[name]
147
+ attr && (attr[:if] ? attr[:if].call(metasearch_object) : true)
148
+ end
149
+
150
+ def _metasearch_excludes_attribute?(name, metasearch_object)
151
+ attr = self._metasearch_exclude_attributes[name]
152
+ attr && (attr[:if] ? attr[:if].call(metasearch_object) : true)
153
+ end
154
+
155
+ def _metasearch_includes_association?(name, metasearch_object)
156
+ assoc = self._metasearch_include_associations[name]
157
+ assoc && (assoc[:if] ? assoc[:if].call(metasearch_object) : true)
158
+ end
159
+
160
+ def _metasearch_excludes_association?(name, metasearch_object)
161
+ assoc = self._metasearch_exclude_associations[name]
162
+ assoc && (assoc[:if] ? assoc[:if].call(metasearch_object) : true)
163
+ end
164
+
94
165
  end
95
166
  end
96
167
 
data/lib/meta_search.rb CHANGED
@@ -32,9 +32,15 @@ module MetaSearch
32
32
  ['is_not_null', {:types => ALL_TYPES, :predicate => :not_eq, :skip_compounds => true, :cast => :boolean, :formatter => Proc.new {|param| nil}}]
33
33
  ]
34
34
 
35
- RELATION_METHODS = [:joins, :includes, :select, :order, :where, :having,
36
- :to_a, :all, :count, :length, :size, :to_sql, :debug_sql, :paginate,
37
- :find_each, :first, :last, :each, :arel]
35
+ RELATION_METHODS = [
36
+ # Query construction
37
+ :joins, :includes, :select, :order, :where, :having, :group,
38
+ # Results, debug, array methods
39
+ :to_a, :all, :length, :size, :to_sql, :debug_sql, :paginate,
40
+ :find_each, :first, :last, :each, :arel, :in_groups_of, :group_by,
41
+ # Calculations
42
+ :count, :average, :minimum, :maximum, :sum
43
+ ]
38
44
  end
39
45
 
40
46
  require 'active_record'
data/meta_search.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{meta_search}
8
- s.version = "0.9.10"
8
+ s.version = "0.9.11"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ernie Miller"]
12
- s.date = %q{2010-11-18}
12
+ s.date = %q{2011-01-06}
13
13
  s.description = %q{
14
14
  Allows simple search forms to be created against an AR3 model
15
15
  and its associations, has useful view helpers for sort links
@@ -4,18 +4,18 @@ class Company < ActiveRecord::Base
4
4
  has_many :slackers, :class_name => "Developer", :conditions => {:slacker => true}
5
5
  has_many :notes, :as => :notable
6
6
  has_many :data_types
7
-
7
+
8
8
  scope :backwards_name, lambda {|name| where(:name => name.reverse)}
9
9
  scope :with_slackers_by_name_and_salary_range,
10
10
  lambda {|name, low, high|
11
11
  joins(:slackers).where(:developers => {:name => name, :salary => low..high})
12
12
  }
13
- search_methods :backwards_name, :backwards_name_as_string
13
+ search_methods :backwards_name, :backwards_name_as_string, :if => proc {|s| s.options[:user] != 'blocked'}
14
14
  search_methods :with_slackers_by_name_and_salary_range,
15
15
  :splat_param => true, :type => [:string, :integer, :integer]
16
- attr_unsearchable :updated_at
17
- assoc_unsearchable :notes
18
-
16
+ attr_unsearchable :updated_at, :if => proc {|s| s.options[:user] == 'blocked' || !s.options[:user]}
17
+ assoc_unsearchable :notes, :if => proc {|s| s.options[:user] == 'blocked' || !s.options[:user]}
18
+
19
19
  def self.backwards_name_as_string(name)
20
20
  name.reverse
21
21
  end
@@ -3,8 +3,8 @@ class Developer < ActiveRecord::Base
3
3
  has_and_belongs_to_many :projects
4
4
  has_many :notes, :as => :notable
5
5
 
6
- attr_searchable :name, :salary
7
- assoc_searchable :notes, :projects, :company
6
+ attr_searchable :name, :salary, :if => proc {|s| !s.options[:user] || s.options[:user] == 'privileged'}
7
+ assoc_searchable :notes, :projects, :company, :if => proc {|s| !s.options[:user] || s.options[:user] == 'privileged'}
8
8
 
9
9
  scope :sort_by_salary_and_name_asc, order('salary ASC, name ASC')
10
10
  scope :sort_by_salary_and_name_desc, order('salary DESC, name DESC')
@@ -3,9 +3,14 @@ flanders:
3
3
  attributes:
4
4
  company:
5
5
  name: "Company name-diddly"
6
+ developer:
7
+ name: "Developer name-diddly"
8
+ salary: "Developer salary-doodly"
6
9
  meta_search:
10
+ or: 'or-diddly'
7
11
  predicates:
8
12
  contains: "%{attribute} contains-diddly"
13
+ equals: "%{attribute} equals-diddly"
9
14
  attributes:
10
15
  company:
11
16
  reverse_name: "Company reverse name-diddly"
data/test/test_search.rb CHANGED
@@ -2,6 +2,78 @@ require 'helper'
2
2
 
3
3
  class TestSearch < Test::Unit::TestCase
4
4
 
5
+ context "A Company search where options[:user] = 'blocked'" do
6
+ setup do
7
+ @s = Company.search({}, :user => 'blocked')
8
+ end
9
+
10
+ should "not respond_to? a search against backwards_name" do
11
+ assert !@s.respond_to?(:backwards_name), "The search responded to :backwards_name"
12
+ end
13
+
14
+ should "raise an error if we try to search on backwards_name" do
15
+ assert_raise NoMethodError do
16
+ @s.backwards_name = 'blah'
17
+ end
18
+ end
19
+
20
+ should "not respond_to? a search against updated_at_eq" do
21
+ assert !@s.respond_to?(:updated_at_eq), "The search responded to :updated_at_eq"
22
+ end
23
+
24
+ should "raise an error if we try to search on updated_at" do
25
+ assert_raise NoMethodError do
26
+ @s.updated_at_eq = 'blah'
27
+ end
28
+ end
29
+
30
+ should "not respond_to? a search against notes_note_matches" do
31
+ assert !@s.respond_to?(:notes_note_matches), "The search responded to :notes_note_matches"
32
+ end
33
+
34
+ should "raise an error if we try to search on notes_note_matches" do
35
+ assert_raise NoMethodError do
36
+ @s.notes_note_matches = '%blah%'
37
+ end
38
+ end
39
+ end
40
+
41
+ context "A Developer search where options[:user] = 'privileged'" do
42
+ setup do
43
+ @s = Developer.search({}, :user => 'privileged')
44
+ end
45
+
46
+ should "respond_to? a search against name_eq" do
47
+ assert_respond_to @s, :name_eq
48
+ end
49
+
50
+ should "not raise an error on a search against name_eq" do
51
+ assert_nothing_raised do
52
+ @s.name_eq = 'blah'
53
+ end
54
+ end
55
+
56
+ should "respond_to? a search against company_name_eq" do
57
+ assert_respond_to @s, :company_name_eq
58
+ end
59
+
60
+ should "not raise an error on a search against name_eq" do
61
+ assert_nothing_raised do
62
+ @s.company_name_eq = 'blah'
63
+ end
64
+ end
65
+
66
+ should "respond_to? a search against company_updated_at_eq" do
67
+ assert_respond_to @s, :company_updated_at_eq
68
+ end
69
+
70
+ should "not raise an error on a search against company_updated_at_eq" do
71
+ assert_nothing_raised do
72
+ @s.company_updated_at_eq = Time.now
73
+ end
74
+ end
75
+ end
76
+
5
77
  [{:name => 'Company', :object => Company},
6
78
  {:name => 'Company as a Relation', :object => Company.scoped}].each do |object|
7
79
  context_a_search_against object[:name], object[:object] do
@@ -86,31 +158,57 @@ class TestSearch < Test::Unit::TestCase
86
158
  end
87
159
  end
88
160
 
89
- context "sorted by name in ascending order" do
161
+ context "when meta_sort value is empty string" do
90
162
  setup do
91
- @s.meta_sort = 'name.asc'
163
+ @s.meta_sort = ''
92
164
  end
93
165
 
94
- should "sort by name in ascending order" do
95
- assert_equal Company.order('name asc').all,
96
- @s.all
166
+ should "not raise an error, just ignore sorting" do
167
+ assert_nothing_raised do
168
+ assert_equal Company.all, @s.all
169
+ end
97
170
  end
98
171
  end
99
172
 
100
- context "sorted by name in descending order" do
173
+ should "sort by name in ascending order" do
174
+ @s.meta_sort = 'name.asc'
175
+ assert_equal Company.order('name asc').all,
176
+ @s.all
177
+ end
178
+
179
+ should "sort by name in ascending order as a method call" do
180
+ @s.meta_sort 'name.asc'
181
+ assert_equal Company.order('name asc').all,
182
+ @s.all
183
+ end
184
+
185
+ should "sort by name in descending order" do
186
+ @s.meta_sort = 'name.desc'
187
+ assert_equal Company.order('name desc').all,
188
+ @s.all
189
+ end
190
+
191
+ context "where name contains optical" do
101
192
  setup do
102
- @s.meta_sort = 'name.desc'
193
+ @s.name_contains = 'optical'
103
194
  end
104
195
 
105
- should "sort by name in descending order" do
106
- assert_equal Company.order('name desc').all,
107
- @s.all
196
+ should "return one result" do
197
+ assert_equal 1, @s.all.size
198
+ end
199
+
200
+ should "return a company named Advanced Optical Solutions" do
201
+ assert_contains @s.all, Company.where(:name => 'Advanced Optical Solutions').first
202
+ end
203
+
204
+ should "not return a company named Initech" do
205
+ assert_does_not_contain @s.all, Company.where(:name => "Initech").first
108
206
  end
109
207
  end
110
208
 
111
- context "where name contains optical" do
209
+ context "where name contains optical as a method call" do
112
210
  setup do
113
- @s.name_contains = 'optical'
211
+ @s.name_contains 'optical'
114
212
  end
115
213
 
116
214
  should "return one result" do
@@ -217,6 +315,20 @@ class TestSearch < Test::Unit::TestCase
217
315
  end
218
316
  end
219
317
 
318
+ context "where backwards name is hcetinI as a method call" do
319
+ setup do
320
+ @s.backwards_name 'hcetinI'
321
+ end
322
+
323
+ should "return 1 result" do
324
+ assert_equal 1, @s.all.size
325
+ end
326
+
327
+ should "return a company named Initech" do
328
+ assert_contains @s.all, Company.where(:name => 'Initech').first
329
+ end
330
+ end
331
+
220
332
  context "where backwards name is hcetinI" do
221
333
  setup do
222
334
  @s.backwards_name = 'hcetinI'
@@ -63,6 +63,10 @@ class TestViewHelpers < ActionView::TestCase
63
63
  assert_match /Company reverse name-diddly/, @f1.label(:reverse_name)
64
64
  assert_match /Developer name-diddly contains-aroonie/, @f2.label(:name_like)
65
65
  end
66
+
67
+ should "localize more than one attribute when joined with or" do
68
+ assert_match /Developer name-diddly or-diddly Developer salary-doodly equals-diddly/, @f2.label(:name_or_salary_eq)
69
+ end
66
70
  end
67
71
  end
68
72
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 10
9
- version: 0.9.10
8
+ - 11
9
+ version: 0.9.11
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ernie Miller
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-18 00:00:00 -05:00
17
+ date: 2011-01-06 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency