mundane-search 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +138 -0
- data/Rakefile +42 -0
- data/bin/rake +16 -0
- data/lib/mundane-search.rb +9 -0
- data/lib/mundane-search/builder.rb +41 -0
- data/lib/mundane-search/filter_canister.rb +12 -0
- data/lib/mundane-search/filters.rb +12 -0
- data/lib/mundane-search/filters/attribute_match.rb +14 -0
- data/lib/mundane-search/filters/base.rb +25 -0
- data/lib/mundane-search/filters/blank_params_are_nil.rb +11 -0
- data/lib/mundane-search/filters/exact_match.rb +11 -0
- data/lib/mundane-search/filters/helpers.rb +44 -0
- data/lib/mundane-search/filters/typical.rb +6 -0
- data/lib/mundane-search/initial_result.rb +7 -0
- data/lib/mundane-search/result.rb +19 -0
- data/lib/mundane-search/version.rb +3 -0
- data/mundane-search.gemspec +25 -0
- data/script/console +15 -0
- data/spec/active_record_setup.rb +80 -0
- data/spec/builder_integration_spec.rb +14 -0
- data/spec/builder_spec.rb +25 -0
- data/spec/filters/attribute_match_integration_spec.rb +20 -0
- data/spec/filters/attribute_match_spec.rb +0 -0
- data/spec/filters/base_spec.rb +13 -0
- data/spec/filters/exact_match_spec.rb +22 -0
- data/spec/filters_spec.rb +9 -0
- data/spec/minitest_helper.rb +21 -0
- data/spec/result_spec.rb +35 -0
- metadata +173 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sam Schenkman-Moore
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# MundaneSearch
|
2
|
+
|
3
|
+
MundaneSearch aims to compartmentalize multi-step search.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
You know the deal:
|
8
|
+
|
9
|
+
gem 'mundane-search' # in your Gemfile, then "bundle"
|
10
|
+
# or just gem install mundane-search on your command line
|
11
|
+
require "mundane-search"
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Build a search using middleware, then run that search on a specific collection and params.
|
16
|
+
|
17
|
+
Collections are typically array-like structures (arrays, ActiveRecord or Sunsport scoped collections, etc.)
|
18
|
+
|
19
|
+
Params are hash-like structures, such as those interpreted from forms and query strings. They are optional.
|
20
|
+
|
21
|
+
built = MundaneSearch::Builder.new do
|
22
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "fruit"
|
23
|
+
end
|
24
|
+
built.call %w(apple orange blueberry), { 'fruit' => 'orange' } # ["orange"]
|
25
|
+
|
26
|
+
If you check out project, ./script/console will get you a session with everything loaded up.
|
27
|
+
|
28
|
+
## Middleware
|
29
|
+
|
30
|
+
Make your own filters! Here's how:
|
31
|
+
|
32
|
+
class MustContainVowel < MundaneSearch::Filters::Base
|
33
|
+
def filtered_collection
|
34
|
+
collection.select {|e| e =~ /[aeiouy]/i} # only elements that contain a vowel
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Then you can reference that filter when you build a search:
|
39
|
+
|
40
|
+
built = MundaneSearch::Builder.new do
|
41
|
+
use MustContainVowel
|
42
|
+
end
|
43
|
+
built.call %w(CA TX NY FL IL) # ['CA','NY','IL']
|
44
|
+
|
45
|
+
Filters are more useful when they are reusable. Arguments passed after the filter name (use Filter, arguments) will be passed into the filter's constructer.
|
46
|
+
The Base filter in these examples sets an "options" variable with this argument.
|
47
|
+
|
48
|
+
class MustMatch < MundaneSearch::Filters::Base
|
49
|
+
def filtered_collection
|
50
|
+
collection.select {|e| e.match(options[:regex]) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
built = MundaneSearch::Builder.new do
|
54
|
+
use MustMatch, regex: /\A[a-m]+\Z/i
|
55
|
+
use MustMatch, regex: /L/
|
56
|
+
end
|
57
|
+
built.call %w(CA TX NY FL IL) # ["FL", "IL"]
|
58
|
+
|
59
|
+
Filters will often be configured to consider input on a specific search. So, you'd configure your filter to pull values from params to limit results.
|
60
|
+
|
61
|
+
class MatchIfNameEqual < MundaneSearch::Filters::Base
|
62
|
+
def filtered_collection
|
63
|
+
collection.select {|e| e == params[:name] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
built = MundaneSearch::Builder.new do
|
67
|
+
use MatchIfNameEqual
|
68
|
+
end
|
69
|
+
built.call %w(Bill Bush Barack), { name: "Bill" } # ["Bill"]
|
70
|
+
|
71
|
+
This is another filter that would be more useful if instead of being hard-wired to look at params[:name], it could be configured when it is used.
|
72
|
+
A supplied filter: ExactMatch, does just this.
|
73
|
+
|
74
|
+
built = MundaneSearch::Builder.new do
|
75
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "title"
|
76
|
+
end
|
77
|
+
built.call %w(Private Sergeant Lieutenant), { "title" => "Sergeant" } # ["Sergeant"]
|
78
|
+
|
79
|
+
It also ignores empty params:
|
80
|
+
|
81
|
+
built = MundaneSearch::Builder.new do
|
82
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "title"
|
83
|
+
end
|
84
|
+
built.call %w(Private Sergeant Lieutenant), { "title" => nil } # ["Private", "Sergeant", "Lieutenant"]
|
85
|
+
|
86
|
+
Unless you tell it not to (in the following case, the filter will look for an exact match on nil, and not find it):
|
87
|
+
|
88
|
+
built = MundaneSearch::Builder.new do
|
89
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "title", required: true
|
90
|
+
end
|
91
|
+
built.call %w(Private Sergeant Lieutenant), { "title" => nil } # []
|
92
|
+
|
93
|
+
You can alter params as well, in a similar fashion.
|
94
|
+
|
95
|
+
class AlwaysSearchingForGumbo < MundaneSearch::Filters::Base
|
96
|
+
def filtered_params
|
97
|
+
params.merge({ options[:param_key] => "Gumbo" })
|
98
|
+
end
|
99
|
+
end
|
100
|
+
built = MundaneSearch::Builder.new do
|
101
|
+
use AlwaysSearchingForGumbo, param_key: "food"
|
102
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "food"
|
103
|
+
end
|
104
|
+
built.call %w(Pizza Pasta Antipasto Gumbo), { "food" => "Pizza" } # ["Gumbo"]
|
105
|
+
built.call %w(Pizza Pasta Antipasto Gumbo) # ["Gumbo"]
|
106
|
+
|
107
|
+
So yeah, it's fun. Here's a more practical example ... if you have clients that pass in groups of empty parameters (intending for those to not influence the search) BlankParamsAreNil will turn those empty strings into nil values.
|
108
|
+
|
109
|
+
built = MundaneSearch::Builder.new do
|
110
|
+
use MundaneSearch::Filters::BlankParamsAreNil
|
111
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "food"
|
112
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "noms"
|
113
|
+
end
|
114
|
+
built.call %w(Pizza Pasta Antipasto Gumbo), { "food" => "", "noms" => "Gumbo" } # ["Gumbo"]
|
115
|
+
|
116
|
+
## ActiveRecord
|
117
|
+
|
118
|
+
MundaneSearch can work with any collection object that can be passed around and modified. Filters can be designed to work with several types of collection.
|
119
|
+
|
120
|
+
class OnlyManagers < MundaneSearch::Filters::Base
|
121
|
+
def filtered_collection
|
122
|
+
case collection
|
123
|
+
when ActiveRecord::Relation
|
124
|
+
collection.where(postion: "manager")
|
125
|
+
else
|
126
|
+
collection.select {|e| e.position == "manager" }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
## Contributing
|
133
|
+
|
134
|
+
1. Fork it
|
135
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
136
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
137
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
138
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
namespace 'test' do
|
6
|
+
test_files = FileList['spec/**/*_spec.rb']
|
7
|
+
integration_test_files = FileList['spec/**/*_integration_spec.rb']
|
8
|
+
unit_test_files = test_files - integration_test_files
|
9
|
+
|
10
|
+
desc "Run unit tests"
|
11
|
+
Rake::TestTask.new('unit') do |t|
|
12
|
+
t.libs.push "lib"
|
13
|
+
t.test_files = unit_test_files
|
14
|
+
t.verbose = false
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run integration tests"
|
18
|
+
Rake::TestTask.new('integration') do |t|
|
19
|
+
t.libs.push "lib"
|
20
|
+
t.test_files = integration_test_files
|
21
|
+
t.verbose = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
namespace 'database' do
|
26
|
+
desc "Setup test database"
|
27
|
+
task :test_setup do
|
28
|
+
require './spec/active_record_setup'
|
29
|
+
ActiveRecord::Migration.create_table :books do |t|
|
30
|
+
t.string :title
|
31
|
+
t.string :author
|
32
|
+
t.date :publication_date
|
33
|
+
t.timestamp :first_purchased_at
|
34
|
+
t.integer :sold
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#Rake::Task['test'].clear
|
40
|
+
desc "Run all tests"
|
41
|
+
task 'test' => %w[test:unit test:integration]
|
42
|
+
task 'default' => 'test'
|
data/bin/rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rake' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rake', 'rake')
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative './filters'
|
2
|
+
|
3
|
+
module MundaneSearch
|
4
|
+
class Builder
|
5
|
+
include MundaneSearch::Filters
|
6
|
+
|
7
|
+
def initialize(&block)
|
8
|
+
@use = []
|
9
|
+
|
10
|
+
instance_eval(&block) if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def use(filter, *args, &block)
|
14
|
+
@use << filter_canister.new(filter, *args, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def filter_canister
|
18
|
+
FilterCanister
|
19
|
+
end
|
20
|
+
|
21
|
+
def filters
|
22
|
+
@use
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(collection, params = {})
|
26
|
+
result = result_for(collection, params)
|
27
|
+
result.collection
|
28
|
+
end
|
29
|
+
|
30
|
+
def result_for(collection, params = {})
|
31
|
+
initial_result = InitialResult.new(collection, params)
|
32
|
+
filters.inject(initial_result) do |result, filter|
|
33
|
+
result.add_filter(filter)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module MundaneSearch
|
2
|
+
module Filters
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require_relative 'filters/helpers'
|
7
|
+
require_relative 'filters/base'
|
8
|
+
require_relative 'filters/typical'
|
9
|
+
require_relative 'filters/exact_match'
|
10
|
+
require_relative 'filters/blank_params_are_nil'
|
11
|
+
require_relative 'filters/attribute_match'
|
12
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module MundaneSearch::Filters
|
2
|
+
class AttributeMatch < Typical
|
3
|
+
def filtered_collection
|
4
|
+
case collection
|
5
|
+
when ActiveRecord::Relation
|
6
|
+
collection.where(param_key => params[param_key.to_s])
|
7
|
+
when :sunspot?
|
8
|
+
# nothing yet
|
9
|
+
else
|
10
|
+
collection.select {|e| e.send(param_key) == params[param_key.to_s] }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MundaneSearch::Filters
|
2
|
+
class Base
|
3
|
+
include Helpers
|
4
|
+
attr_reader :collection, :params, :options
|
5
|
+
def initialize(collection, params = {}, options= {})
|
6
|
+
@collection, @params, @options = collection, params, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def filtered_collection
|
14
|
+
collection
|
15
|
+
end
|
16
|
+
|
17
|
+
def filtered_params
|
18
|
+
params
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
[filtered_collection, filtered_params]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module MundaneSearch::Filters::Helpers
|
2
|
+
def self.included(base)
|
3
|
+
base.send :extend, ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def optional_unless_required
|
8
|
+
include Optional
|
9
|
+
end
|
10
|
+
|
11
|
+
def optional_without_match_value
|
12
|
+
include OptionalWithoutMatchValue
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_a_match_value
|
16
|
+
include MatchValue
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
module Optional
|
23
|
+
def optional?
|
24
|
+
options[:required]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module OptionalWithoutMatchValue
|
29
|
+
include Optional
|
30
|
+
def apply?
|
31
|
+
match_value || optional?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module MatchValue
|
36
|
+
def param_key
|
37
|
+
options.fetch(:param_key)
|
38
|
+
end
|
39
|
+
|
40
|
+
def match_value
|
41
|
+
params[param_key]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MundaneSearch
|
2
|
+
class Result
|
3
|
+
include Enumerable
|
4
|
+
attr_reader :collection, :params, :previous_result
|
5
|
+
def initialize(previous_result, filter)
|
6
|
+
@previous_result = previous_result
|
7
|
+
@collection, @params = filter.call(previous_result.collection, previous_result.params)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_filter(filter)
|
11
|
+
Result.new(self,filter)
|
12
|
+
end
|
13
|
+
|
14
|
+
def each(*args, &block)
|
15
|
+
return enum_for(__callee__) unless block_given?
|
16
|
+
collection.each(*args, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mundane-search/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "mundane-search"
|
8
|
+
gem.version = MundaneSearch::VERSION
|
9
|
+
gem.authors = ["Sam Schenkman-Moore"]
|
10
|
+
gem.email = ["samsm@samsm.com"]
|
11
|
+
gem.description = %q{Makes everyday search easy-ish.}
|
12
|
+
gem.summary = %q{Makes everyday search easy-ish.}
|
13
|
+
gem.homepage = "https://github.com/samsm/mundane-search"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency "minitest"
|
21
|
+
gem.add_development_dependency "rake"
|
22
|
+
gem.add_development_dependency "activerecord"
|
23
|
+
gem.add_development_dependency "sqlite3"
|
24
|
+
gem.add_development_dependency "database_cleaner"
|
25
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
FileUtils.mkdir_p "./tmp"
|
6
|
+
ActiveRecord::Base.establish_connection(
|
7
|
+
:adapter => 'sqlite3',
|
8
|
+
:database => 'tmp/test.db'
|
9
|
+
)
|
10
|
+
|
11
|
+
require 'database_cleaner'
|
12
|
+
DatabaseCleaner.strategy = :truncation
|
13
|
+
|
14
|
+
class Book < ActiveRecord::Base
|
15
|
+
# t.string :title
|
16
|
+
# t.string :author
|
17
|
+
# t.date :publication_date
|
18
|
+
# t.timestamp :first_purchased_at
|
19
|
+
# t.integer :sold
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def populate_books!
|
24
|
+
[
|
25
|
+
{
|
26
|
+
title: "A Tale of Two Cities",
|
27
|
+
author: "Charles Dickens",
|
28
|
+
publication_date: Date.parse('31-12-1859'),
|
29
|
+
first_purchased_at: Time.utc(1859,"jan",1,20,15,1),
|
30
|
+
sold: 200_000_000
|
31
|
+
},
|
32
|
+
{
|
33
|
+
title: "The Lord of the Rings",
|
34
|
+
author: "J. R. R. Tolkien",
|
35
|
+
publication_date: Date.parse('31-12-1954'),
|
36
|
+
first_purchased_at: Time.utc(1954,"jan",1,20,15,1),
|
37
|
+
sold: 150_000_000
|
38
|
+
},
|
39
|
+
{
|
40
|
+
title: "The Little Prince (Le Petit Prince)",
|
41
|
+
author: "Antoine de Saint-Exupery",
|
42
|
+
publication_date: Date.parse('31-12-1943'),
|
43
|
+
first_purchased_at: Time.utc(1943,"jan",1,20,15,1),
|
44
|
+
sold: 140_000_000
|
45
|
+
},
|
46
|
+
{
|
47
|
+
title: "The Hobbit",
|
48
|
+
author: "J. R. R. Tolkien",
|
49
|
+
publication_date: Date.parse('31-12-1937'),
|
50
|
+
first_purchased_at: Time.utc(1937,"jan",1,20,15,1),
|
51
|
+
sold: 100_000_000
|
52
|
+
},
|
53
|
+
{
|
54
|
+
title: "Hong lou meng (Dream of the Red Chamber/The Story of the Stone)",
|
55
|
+
author: "Cao Xueqin",
|
56
|
+
publication_date: Date.parse('31-12-1754'),
|
57
|
+
first_purchased_at: Time.utc(1754,"jan",1,20,15,1),
|
58
|
+
sold: 100_000_000
|
59
|
+
},
|
60
|
+
{
|
61
|
+
title: "And Then There Were None",
|
62
|
+
author: "Agatha Christie",
|
63
|
+
publication_date: Date.parse('31-12-1939'),
|
64
|
+
first_purchased_at: Time.utc(1939,"jan",1,20,15,1),
|
65
|
+
sold: 100_000_000
|
66
|
+
}
|
67
|
+
].each do |book_hash|
|
68
|
+
Book.create(book_hash)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
begin
|
73
|
+
Book.new
|
74
|
+
rescue ActiveRecord::StatementInvalid
|
75
|
+
puts ''
|
76
|
+
puts "*****************************************************************"
|
77
|
+
puts "Run: rake database:test_setup to create a database for this test."
|
78
|
+
puts "*****************************************************************"
|
79
|
+
puts ''
|
80
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Builder do
|
4
|
+
Builder = MundaneSearch::Builder
|
5
|
+
|
6
|
+
it "should limit results using exact match filter" do
|
7
|
+
|
8
|
+
built = Builder.new do
|
9
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "foo"
|
10
|
+
end
|
11
|
+
|
12
|
+
built.call(collection, params).must_equal(['bar'])
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Builder do
|
4
|
+
Builder = MundaneSearch::Builder
|
5
|
+
|
6
|
+
let(:collection) { %w(foo bar baz) }
|
7
|
+
let(:params) { { 'foo' => 'bar' } }
|
8
|
+
|
9
|
+
describe "empty search" do
|
10
|
+
let(:builder) { Builder.new }
|
11
|
+
|
12
|
+
it "should return unchanged collection on call" do
|
13
|
+
builder.call(collection, params).must_equal(collection)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should use middleware" do
|
18
|
+
builder = Builder.new do
|
19
|
+
use NothingFilterForTest
|
20
|
+
end
|
21
|
+
canister = builder.filters.first
|
22
|
+
canister.must_be_kind_of MundaneSearch::FilterCanister
|
23
|
+
canister.filter.must_equal NothingFilterForTest
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../minitest_helper'
|
2
|
+
require_relative '../active_record_setup'
|
3
|
+
|
4
|
+
describe MundaneSearch::Filters::AttributeMatch 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 something" do
|
14
|
+
built = Builder.new do
|
15
|
+
use MundaneSearch::Filters::AttributeMatch, param_key: "author"
|
16
|
+
end
|
17
|
+
|
18
|
+
built.call(all_books, {"author" => "Charles Dickens"}).must_equal([a_tale_of_two_cities])
|
19
|
+
end
|
20
|
+
end
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Filters::Base do
|
4
|
+
Base = MundaneSearch::Filters::Base
|
5
|
+
|
6
|
+
let(:collection) { %w(foo bar baz) }
|
7
|
+
let(:params) { { 'foo' => 'bar' } }
|
8
|
+
|
9
|
+
it "should pass through" do
|
10
|
+
base = Base.new(collection, params)
|
11
|
+
base.call.must_equal [collection, params]
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative '../minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Filters::ExactMatch do
|
4
|
+
ExactMatch = MundaneSearch::Filters::ExactMatch
|
5
|
+
|
6
|
+
let(:collection) { %w(foo bar baz) }
|
7
|
+
let(:params) { { 'foo' => 'bar' } }
|
8
|
+
|
9
|
+
it "should only take effect if matching param is avilable" do
|
10
|
+
options = { param_key: 'unmatched' }
|
11
|
+
em = ExactMatch.new(collection, params, options)
|
12
|
+
coll, parms = em.call
|
13
|
+
coll.must_equal(collection)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should match equivalent element" do
|
17
|
+
options = { param_key: 'foo' }
|
18
|
+
em = ExactMatch.new(collection, params, options)
|
19
|
+
coll, parms = em.call
|
20
|
+
coll.must_equal(['bar'])
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'minitest' # ensures you're using the gem, and not the built in MT
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/spec'
|
5
|
+
require 'minitest/mock'
|
6
|
+
|
7
|
+
require 'mundane-search'
|
8
|
+
require 'pry' rescue nil
|
9
|
+
|
10
|
+
class NothingFilterForTest
|
11
|
+
def initialize(a=nil) ; end
|
12
|
+
def call(c,p) ; [c,p] ; end
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection
|
16
|
+
%w(foo bar baz)
|
17
|
+
end
|
18
|
+
|
19
|
+
def params
|
20
|
+
{ 'foo' => 'bar' }
|
21
|
+
end
|
data/spec/result_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
describe "results" do
|
4
|
+
let(:collection) { %w(foo bar baz) }
|
5
|
+
let(:params) { { 'foo' => 'bar' } }
|
6
|
+
let(:initial) { MundaneSearch::InitialResult.new(collection, params) }
|
7
|
+
|
8
|
+
describe MundaneSearch::InitialResult do
|
9
|
+
InitialResult = MundaneSearch::InitialResult
|
10
|
+
it "should take a collection and params" do
|
11
|
+
initial.must_be_kind_of InitialResult
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe MundaneSearch::Result do
|
16
|
+
Result = MundaneSearch::Result
|
17
|
+
|
18
|
+
let(:result) { Result.new(initial, filter) }
|
19
|
+
let(:filter) { NothingFilterForTest.new }
|
20
|
+
|
21
|
+
it "should show collection" do
|
22
|
+
result.collection.must_equal collection
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should show params" do
|
26
|
+
result.params.must_equal params
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be iterateable" do
|
30
|
+
result.first.must_equal collection.first
|
31
|
+
result.count.must_equal collection.count
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mundane-search
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sam Schenkman-Moore
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: minitest
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: database_cleaner
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Makes everyday search easy-ish.
|
95
|
+
email:
|
96
|
+
- samsm@samsm.com
|
97
|
+
executables:
|
98
|
+
- rake
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/rake
|
108
|
+
- lib/mundane-search.rb
|
109
|
+
- lib/mundane-search/builder.rb
|
110
|
+
- lib/mundane-search/filter_canister.rb
|
111
|
+
- lib/mundane-search/filters.rb
|
112
|
+
- lib/mundane-search/filters/attribute_match.rb
|
113
|
+
- lib/mundane-search/filters/base.rb
|
114
|
+
- lib/mundane-search/filters/blank_params_are_nil.rb
|
115
|
+
- lib/mundane-search/filters/exact_match.rb
|
116
|
+
- lib/mundane-search/filters/helpers.rb
|
117
|
+
- lib/mundane-search/filters/typical.rb
|
118
|
+
- lib/mundane-search/initial_result.rb
|
119
|
+
- lib/mundane-search/result.rb
|
120
|
+
- lib/mundane-search/version.rb
|
121
|
+
- mundane-search.gemspec
|
122
|
+
- script/console
|
123
|
+
- spec/active_record_setup.rb
|
124
|
+
- spec/builder_integration_spec.rb
|
125
|
+
- spec/builder_spec.rb
|
126
|
+
- spec/filters/attribute_match_integration_spec.rb
|
127
|
+
- spec/filters/attribute_match_spec.rb
|
128
|
+
- spec/filters/base_spec.rb
|
129
|
+
- spec/filters/exact_match_spec.rb
|
130
|
+
- spec/filters_spec.rb
|
131
|
+
- spec/minitest_helper.rb
|
132
|
+
- spec/result_spec.rb
|
133
|
+
homepage: https://github.com/samsm/mundane-search
|
134
|
+
licenses: []
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
hash: 1695916401118151640
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
segments:
|
155
|
+
- 0
|
156
|
+
hash: 1695916401118151640
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 1.8.25
|
160
|
+
signing_key:
|
161
|
+
specification_version: 3
|
162
|
+
summary: Makes everyday search easy-ish.
|
163
|
+
test_files:
|
164
|
+
- spec/active_record_setup.rb
|
165
|
+
- spec/builder_integration_spec.rb
|
166
|
+
- spec/builder_spec.rb
|
167
|
+
- spec/filters/attribute_match_integration_spec.rb
|
168
|
+
- spec/filters/attribute_match_spec.rb
|
169
|
+
- spec/filters/base_spec.rb
|
170
|
+
- spec/filters/exact_match_spec.rb
|
171
|
+
- spec/filters_spec.rb
|
172
|
+
- spec/minitest_helper.rb
|
173
|
+
- spec/result_spec.rb
|