mundane-search 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -12,9 +12,7 @@ You know the deal:
12
12
 
13
13
  ## Usage
14
14
 
15
- Still in the process of figuring this out! But much of it works like I want, so hopefully no brutal changes.
16
-
17
- ### Typical use
15
+ *Still in the process of figuring this out! But much of it works like I want, so hopefully no brutal changes.*
18
16
 
19
17
  Build a search, then run that search on a specific collection and params.
20
18
 
@@ -30,25 +28,130 @@ Create a search:
30
28
  Add filters to it:
31
29
 
32
30
  class BookSearch < MundaneSearch::Result
33
- use MundaneSearch::Filters::AttributeMatch, param_key: "title"
31
+ use :attribute_match, param_key: "title"
34
32
  end
35
33
 
36
34
  Then use that search in your controllers:
37
35
 
38
- # params = { "title" => "A Tale of Two Cities" }
39
- @result = BookSearch.results_for(Book.scoped, params)
36
+ # params = { "book_search" => { "title" => "A Tale of Two Cities" } }
37
+ @result = BookSearch.results_for(Book.scoped, params["book_search"])
40
38
 
41
39
  The returned result is enumerable:
42
40
 
43
41
  @result.each {|book| ... }
44
42
  @result.first
45
43
 
46
- And has some Rails form compatibility:
44
+ And has some Rails-style form compatibility:
47
45
 
48
46
  <%= search_form_for(@result) do |f| %>
49
47
  <%= f.input :title %>
50
48
  <% end %>
51
49
 
50
+ As well as url-ability:
51
+
52
+ search_url_for(@result)
53
+
54
+ ## Filters
55
+
56
+ There are built in filters and you can make your own filters.
57
+
58
+ Three ways to notate filters:
59
+
60
+ class ExampleSearch < MundaneSearch::Result
61
+ use FilterClass
62
+ use :filter_class
63
+ employ :shortcut
64
+ end
65
+
66
+ 1. use FilterClass, options
67
+ The most straightforward. Under the hood, this establishes that a searched collection will be
68
+ passed through this filter.
69
+ 2. use :filter_class, options
70
+ This is the same as specifying FilterClass, except MundaneSearch will look for filter_class
71
+ in MundaneSearch::Filters if it isn't found in the Object namespace.
72
+ 3. employ :shortcut, options
73
+ This is the avenue for shortcuts, such as when you might want several filters to be created
74
+ by one designation.
75
+ I haven't spent much thought on this, it may change in the future.
76
+
77
+
78
+ ## Built in filters
79
+
80
+ ### Common options
81
+
82
+ First some options that are common to many filters.
83
+
84
+ * param_key: The key in params to examine for a matching value.
85
+ * target: The attribute to match against. By default, uses param_key.
86
+ * match_value: Usually nil. When nil, the value of params[param_key] is used.
87
+ * required: Default false. When true, will run a filter even if (for example) the match_value is nil.
88
+ * type: Gives form helpers et al a hint as to what type the match_value should be. Overrides class method param_key_type in a filter.
89
+ Available types:
90
+ 1. :string
91
+ 2. :integer
92
+ 3. :float
93
+ 4. :date
94
+ 5. :time
95
+
96
+ All those suckers in action:
97
+
98
+ class BookSearch < MundaneSearch::Result
99
+ # book.publisher == params["publisher"] even if the match_value (params["publisher"]) is nil
100
+ # (in below examples, the filter is skipped if the match_value is nil)
101
+ use :attribute_match, param_key: "publisher", required: true
102
+
103
+ # book.title == params["title"]
104
+ use :attribute_match, param_key: "title"
105
+
106
+ # book.author == params["writer"]
107
+ use :attribute_match, param_key: "writer", target: "author"
108
+
109
+ # book.publication_date > Date.parse("1900-01-01") (disregards params)
110
+ use :operator, param_key: "publication_date", operator: :>, match_value: Date.parse("1900-01-01")
111
+
112
+ # simple_form displays filter as designated type
113
+ use :attribute_match, param_key: "first_purchased_at", type: :time
114
+ end
115
+
116
+ ### AttributeMatch
117
+
118
+ Returns objects that exactly match an attribute, ex: book.title == "A Tale of Two Cities"
119
+
120
+ use :attribute_match, param_key: "title"
121
+
122
+ ### AttributeSubstring
123
+
124
+ Returns objects that match a portion of an attribute, ex: book.title =~ /Tale of/
125
+
126
+ use :attribute_substring, param_key: title
127
+
128
+ ### Operator
129
+
130
+ Returns objects that match an attribute + operator, ex: book.publication_date > Date.parse("1900-01-01")
131
+
132
+ Requires a param_key and a symbol of an operator (:>, :<, :>=, :<=)
133
+
134
+ use :operator, param_key: "publication_date", operator: :>
135
+
136
+ ### Order
137
+
138
+ Sorts a collection.
139
+
140
+ use :order, param_key: "sort", direction: "asc"
141
+
142
+
143
+ #### ExactMatch
144
+
145
+ MundaneSearch can also work with objects that aren't "attribute-y".
146
+
147
+ Return objects that are equal to the match_value. Used in a lot of examples below.
148
+
149
+ ### BlankParamsAreNil
150
+
151
+ The params can be manipulated.
152
+
153
+ Changes values of "", [], or {} to nil in params.
154
+
52
155
  ## Sans sugar
53
156
 
54
157
  MundaneSearch can be used outside of Rails on whatever sort of object you want:
@@ -0,0 +1,35 @@
1
+ module MundaneSearch::Filters
2
+ class Order < Typical
3
+ class ActiveRecord < self
4
+ def filtered_collection
5
+ collection.order("#{match_value} #{active_record_direction}")
6
+ end
7
+
8
+ def active_record_direction
9
+ direction || "ASC"
10
+ end
11
+ end
12
+
13
+ def filtered_collection
14
+ collection.sort_by(&:"#{match_value}")
15
+ backwards? ? collection.reverse : collection
16
+ end
17
+
18
+ protected
19
+ def backwards?
20
+ descending_terms.include?(direction)
21
+ end
22
+
23
+ def direction
24
+ params["direction"] || options[:direction]
25
+ end
26
+
27
+ def ascending_terms
28
+ %w(asc ascending <)
29
+ end
30
+
31
+ def descending_terms
32
+ %w(desc descending >)
33
+ end
34
+ end
35
+ end
@@ -21,11 +21,12 @@ module MundaneSearch::Filters
21
21
  end
22
22
 
23
23
  def match_value
24
- params[param_key]
24
+ options[:match_value] || params[param_key]
25
25
  end
26
26
 
27
+ # This is a duplicate of the class method?
27
28
  def param_key_type
28
- options[:type] || :string
29
+ options[:type] || self.class.param_key_type
29
30
  end
30
31
  end
31
32
  end
@@ -22,6 +22,12 @@ module MundaneSearch
22
22
  end
23
23
  end
24
24
 
25
+ # Added this for the benefit of search_url_for
26
+ # If it stays, it should replace stack.params in the method above.
27
+ def params
28
+ send(:result).stack.params
29
+ end
30
+
25
31
  def self.model_name
26
32
  name = 'GenericSearch' unless self.name
27
33
  namespace = nil
@@ -1,3 +1,3 @@
1
1
  module MundaneSearch
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,5 +1,11 @@
1
1
  module MundaneSearch
2
2
  module ViewHelpers
3
+ def search_url_for(search, change_params = {})
4
+ search_model = search.to_model
5
+ new_parms = search_model.params.merge(change_params).reject {|k,v| v.nil? }
6
+ polymorphic_url search_model, new_parms
7
+ end
8
+
3
9
  def search_form_for(record, options = {}, &block)
4
10
  # Later!
5
11
  # if block_given?
@@ -0,0 +1,24 @@
1
+ require_relative '../minitest_helper'
2
+ require_relative '../active_record_setup'
3
+
4
+ describe MundaneSearch::Filters::Order do
5
+ before do
6
+ DatabaseCleaner.clean
7
+ populate_books!
8
+ end
9
+
10
+ let(:all_books) { Book.scoped }
11
+ let(:a_tale_of_two_cities) { Book.first }
12
+
13
+ it "should match based on param_key" do
14
+ built = MundaneSearch::Builder.new do
15
+ use MundaneSearch::Filters::Order, param_key: "sort"
16
+ end
17
+
18
+ dates = built.call(all_books, {"sort" => "publication_date"})
19
+ dates.inject do |last, current|
20
+ last.publication_date.must_be :<, current.publication_date if last
21
+ current
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../minitest_helper'
2
+ require_relative '../demo_data'
3
+
4
+ describe MundaneSearch::Filters::Order do
5
+ let(:books) { open_struct_books }
6
+ let(:a_tale) { books.first }
7
+ let(:order) { MundaneSearch::Filters::Order }
8
+ it "should order by title" do
9
+ books.reverse!
10
+ filter = order.new(books, {'sort' => "title"}, {param_key: 'sort'})
11
+
12
+ filter.filtered_collection.first.must_equal(a_tale)
13
+ end
14
+
15
+ describe MundaneSearch::Filters::Order::ActiveRecord do
16
+ let(:order) { MundaneSearch::Filters::Order::ActiveRecord }
17
+ it "should filter with 'where'" do
18
+ collection = Minitest::Mock.new
19
+ params = { 'sort' => "title" }
20
+ result = Object.new
21
+
22
+ filter = order.new(collection, params, param_key: 'sort')
23
+ collection.expect(:order, result, ["title ASC"])
24
+ filter.filtered_collection.must_equal(result)
25
+ collection.verify
26
+ end
27
+ end
28
+ end
@@ -53,6 +53,10 @@ describe MundaneSearch::Filters::Typical do
53
53
  it "should return param value matching param_key" do
54
54
  typical(param_key: "foo").match_value.must_equal "bar"
55
55
  end
56
+
57
+ it "should use explicit match value when supplied" do
58
+ typical(match_value: "foo").match_value.must_equal "foo"
59
+ end
56
60
  end
57
61
 
58
62
  describe "#param_key_type" do
@@ -70,6 +70,20 @@ def params
70
70
  { 'foo' => 'bar' }
71
71
  end
72
72
 
73
+ def requirements_for_search_url_for_tests!
74
+ require 'action_dispatch/routing/polymorphic_routes'
75
+ def view_with_url_class
76
+ Class.new do
77
+ include ActionDispatch::Routing::PolymorphicRoutes
78
+ %w(generic_search_url).each do |path|
79
+ define_method path do |a=nil,b=nil|
80
+ "/#{path}"
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
73
87
  def requirements_for_form_for_tests!
74
88
  require_relative 'demo_data'
75
89
  require 'active_support/concern'
@@ -0,0 +1,20 @@
1
+ require_relative 'minitest_helper'
2
+
3
+ requirements_for_search_url_for_tests!
4
+
5
+ describe "integration search_url_for" do
6
+ let(:result_class) { Class.new(MundaneSearch::Result) }
7
+ let(:result) { result_class.new(open_struct_books, params) }
8
+ let(:result_model) { result.to_model }
9
+ let(:search_url_viewed_class) do
10
+ Class.new(view_with_url_class) do
11
+ include MundaneSearch::ViewHelpers
12
+ end
13
+ end
14
+ let(:search_url_view) { search_url_viewed_class.new }
15
+
16
+ it "should generate url" do
17
+ form = search_url_view.search_url_for(result_model) { }
18
+ form.must_match %r{\A/}
19
+ end
20
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mundane-search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-03 00:00:00.000000000 Z
12
+ date: 2013-06-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -230,6 +230,7 @@ files:
230
230
  - lib/mundane-search/filters/blank_params_are_nil.rb
231
231
  - lib/mundane-search/filters/exact_match.rb
232
232
  - lib/mundane-search/filters/operator.rb
233
+ - lib/mundane-search/filters/order.rb
233
234
  - lib/mundane-search/filters/shortcuts.rb
234
235
  - lib/mundane-search/filters/typical.rb
235
236
  - lib/mundane-search/initial_stack.rb
@@ -257,6 +258,8 @@ files:
257
258
  - spec/filters/exact_match_spec.rb
258
259
  - spec/filters/operator_integration_spec.rb
259
260
  - spec/filters/operator_spec.rb
261
+ - spec/filters/order_integration_spec.rb
262
+ - spec/filters/order_spec.rb
260
263
  - spec/filters/shortcuts_integration_spec.rb
261
264
  - spec/filters/shortcuts_spec.rb
262
265
  - spec/filters/typical_spec.rb
@@ -268,6 +271,7 @@ files:
268
271
  - spec/result_model_spec.rb
269
272
  - spec/result_spec.rb
270
273
  - spec/search_form_for_integration_spec.rb
274
+ - spec/search_url_for_integration_spec.rb
271
275
  - spec/simple_form_integration_spec.rb
272
276
  - spec/simple_search_form_for_integration_spec.rb
273
277
  - spec/stack_spec.rb
@@ -285,7 +289,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
285
289
  version: '0'
286
290
  segments:
287
291
  - 0
288
- hash: -4254395737755402307
292
+ hash: -2671507479759182852
289
293
  required_rubygems_version: !ruby/object:Gem::Requirement
290
294
  none: false
291
295
  requirements:
@@ -294,10 +298,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
294
298
  version: '0'
295
299
  segments:
296
300
  - 0
297
- hash: -4254395737755402307
301
+ hash: -2671507479759182852
298
302
  requirements: []
299
303
  rubyforge_project:
300
- rubygems_version: 1.8.25
304
+ rubygems_version: 1.8.23
301
305
  signing_key:
302
306
  specification_version: 3
303
307
  summary: Makes everyday search easy-ish.
@@ -318,6 +322,8 @@ test_files:
318
322
  - spec/filters/exact_match_spec.rb
319
323
  - spec/filters/operator_integration_spec.rb
320
324
  - spec/filters/operator_spec.rb
325
+ - spec/filters/order_integration_spec.rb
326
+ - spec/filters/order_spec.rb
321
327
  - spec/filters/shortcuts_integration_spec.rb
322
328
  - spec/filters/shortcuts_spec.rb
323
329
  - spec/filters/typical_spec.rb
@@ -329,6 +335,7 @@ test_files:
329
335
  - spec/result_model_spec.rb
330
336
  - spec/result_spec.rb
331
337
  - spec/search_form_for_integration_spec.rb
338
+ - spec/search_url_for_integration_spec.rb
332
339
  - spec/simple_form_integration_spec.rb
333
340
  - spec/simple_search_form_for_integration_spec.rb
334
341
  - spec/stack_spec.rb