mundane-search 0.0.1 → 0.0.2
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/Guardfile +11 -0
- data/README.md +61 -9
- data/Rakefile +1 -1
- data/bin/coderay +16 -0
- data/bin/erubis +16 -0
- data/bin/guard +16 -0
- data/bin/pry +16 -0
- data/bin/rackup +16 -0
- data/bin/rake +1 -1
- data/bin/sprockets +16 -0
- data/bin/thor +16 -0
- data/bin/tilt +16 -0
- data/lib/columns_hash.rb +38 -0
- data/lib/mundane-search.rb +14 -6
- data/lib/mundane-search/buildable.rb +25 -0
- data/lib/mundane-search/builder.rb +32 -18
- data/lib/mundane-search/filter_canister.rb +27 -3
- data/lib/mundane-search/filters.rb +7 -8
- data/lib/mundane-search/filters/attribute_match.rb +6 -7
- data/lib/mundane-search/filters/attribute_substring.rb +14 -0
- data/lib/mundane-search/filters/base.rb +5 -2
- data/lib/mundane-search/filters/blank_params_are_nil.rb +1 -1
- data/lib/mundane-search/filters/operator.rb +18 -0
- data/lib/mundane-search/filters/shortcuts.rb +33 -0
- data/lib/mundane-search/filters/typical.rb +28 -3
- data/lib/mundane-search/initial_stack.rb +13 -0
- data/lib/mundane-search/railtie.rb +7 -0
- data/lib/mundane-search/result.rb +23 -8
- data/lib/mundane-search/result_model.rb +65 -0
- data/lib/mundane-search/stack.rb +38 -0
- data/lib/mundane-search/version.rb +1 -1
- data/lib/mundane-search/view_helpers.rb +24 -0
- data/mundane-search.gemspec +7 -0
- data/script/console +6 -0
- data/spec/active_record_setup.rb +2 -45
- data/spec/buildable_integration_spec.rb +14 -0
- data/spec/buildable_spec.rb +19 -0
- data/spec/builder_integration_spec.rb +26 -5
- data/spec/builder_spec.rb +13 -18
- data/spec/columns_hash_spec.rb +37 -0
- data/spec/demo_data.rb +50 -0
- data/spec/filter_canister_spec.rb +46 -0
- data/spec/filters/attribute_match_integration_spec.rb +2 -2
- data/spec/filters/attribute_match_spec.rb +27 -0
- data/spec/filters/attribute_substring_spec.rb +27 -0
- data/spec/filters/base_spec.rb +39 -7
- data/spec/filters/blank_params_are_nil_spec.rb +11 -0
- data/spec/filters/operator_integration_spec.rb +20 -0
- data/spec/filters/operator_spec.rb +28 -0
- data/spec/filters/shortcuts_integration_spec.rb +16 -0
- data/spec/filters/shortcuts_spec.rb +15 -0
- data/spec/filters/typical_spec.rb +68 -0
- data/spec/form_integration_spec.rb +29 -0
- data/spec/initial_stack_spec.rb +13 -0
- data/spec/minitest_helper.rb +93 -4
- data/spec/result_integration_spec.rb +24 -0
- data/spec/result_model_spec.rb +50 -0
- data/spec/result_spec.rb +10 -28
- data/spec/search_form_for_integration_spec.rb +19 -0
- data/spec/simple_form_integration_spec.rb +36 -0
- data/spec/simple_search_form_for_integration_spec.rb +25 -0
- data/spec/stack_spec.rb +40 -0
- metadata +167 -6
- data/lib/mundane-search/filters/helpers.rb +0 -44
- data/lib/mundane-search/initial_result.rb +0 -7
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative '../minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Filters::Shortcuts do
|
4
|
+
let(:shortcutted) do
|
5
|
+
shortcutted = Object.new
|
6
|
+
shortcutted.extend(MundaneSearch::Filters::Shortcuts)
|
7
|
+
shortcutted
|
8
|
+
end
|
9
|
+
|
10
|
+
# urg
|
11
|
+
it "should compose a filter with employ" do
|
12
|
+
shortcutted.expects(:use)
|
13
|
+
shortcutted.employ :attribute_filter
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative '../minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Filters::Typical do
|
4
|
+
# let(:typical) { MundaneSearch::Filters::Typical.new(collection, params) }
|
5
|
+
let(:standin) { Object.new }
|
6
|
+
def typical(options = {})
|
7
|
+
MundaneSearch::Filters::Typical.new(collection, params, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#target" do
|
11
|
+
it "should use options[:target]" do
|
12
|
+
typical(target: "foo").target.must_equal "foo"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should default to param_key" do
|
16
|
+
typical(param_key: "foo").target.must_equal "foo"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#optional?" do
|
21
|
+
it "should use options[:required]" do
|
22
|
+
typical(required: true).must_be :optional?
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should default to optional" do
|
26
|
+
typical.wont_be :optional?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#apply?" do
|
31
|
+
it "should be true if there is a match_value" do
|
32
|
+
filter = typical
|
33
|
+
def filter.match_value ; true ; end
|
34
|
+
assert filter.apply?
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be true if the filter isn't optional" do
|
38
|
+
filter = typical
|
39
|
+
def filter.match_value ; false ; end
|
40
|
+
def filter.optional? ; true ; end
|
41
|
+
assert filter.apply?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#param_key" do
|
46
|
+
it "should take param_key from options" do
|
47
|
+
param_key = Object.new
|
48
|
+
typical(param_key: param_key).param_key.must_equal param_key
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#match_value" do
|
53
|
+
it "should return param value matching param_key" do
|
54
|
+
typical(param_key: "foo").match_value.must_equal "bar"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#param_key_type" do
|
59
|
+
it "should default to :string" do
|
60
|
+
typical.param_key_type.must_equal :string
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should use options[:type]" do
|
64
|
+
type = Object.new
|
65
|
+
typical(type: type).param_key_type.must_equal type
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
requirements_for_form_for_tests!
|
3
|
+
|
4
|
+
describe "integration with Rails forms" do
|
5
|
+
let(:result_class) { Class.new(MundaneSearch::Result) }
|
6
|
+
let(:result) { result_class.new(open_struct_books, params) }
|
7
|
+
let(:result_model) { result.to_model }
|
8
|
+
|
9
|
+
describe "with Rails' form_for" do
|
10
|
+
let(:formed) { formed_class.new }
|
11
|
+
|
12
|
+
it "should convert to model" do
|
13
|
+
formed.convert_to_model(result).must_equal result.to_model
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should generate form from search result" do
|
17
|
+
form = formed.form_for(result) { }
|
18
|
+
form.must_match %r{<form}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should extract values from param_key for text_field accessors" do
|
22
|
+
result_class.builder.use MundaneSearch::Filters::AttributeMatch, param_key: 'title'
|
23
|
+
form = formed.form_for(result_model) do |f|
|
24
|
+
f.text_field :title
|
25
|
+
end
|
26
|
+
form.must_match %{<input id="#{search_prefix}_title" name="#{search_prefix}[title]" size="30" type="text" />}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::InitialStack do
|
4
|
+
let(:initial) { MundaneSearch::InitialStack.new(collection, params) }
|
5
|
+
|
6
|
+
it "should take a collection and params" do
|
7
|
+
initial.must_be_kind_of MundaneSearch::InitialStack
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should always return empty array on filters" do
|
11
|
+
initial.all_filters.must_equal []
|
12
|
+
end
|
13
|
+
end
|
data/spec/minitest_helper.rb
CHANGED
@@ -1,17 +1,67 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
gem 'minitest' # ensures
|
2
|
+
gem 'minitest' # ensures we're using the gem, and not the built in MT
|
3
|
+
|
4
|
+
$:.unshift File.dirname(__FILE__) + "/../lib"
|
5
|
+
|
3
6
|
require 'minitest/autorun'
|
4
7
|
require 'minitest/spec'
|
5
8
|
require 'minitest/mock'
|
9
|
+
require "mocha/setup"
|
6
10
|
|
7
11
|
require 'mundane-search'
|
8
12
|
require 'pry' rescue nil
|
9
13
|
|
10
|
-
class
|
11
|
-
def
|
12
|
-
|
14
|
+
class AgressiveBacktraceFilter < Minitest::BacktraceFilter
|
15
|
+
def gem_paths
|
16
|
+
return @gem_paths if @gem_paths
|
17
|
+
raw_paths = `gem env gempath`
|
18
|
+
@gem_paths = raw_paths.split(':')
|
19
|
+
end
|
20
|
+
|
21
|
+
def project_path
|
22
|
+
@project_path ||= File.expand_path(File.dirname(__FILE__) + "/../")
|
23
|
+
end
|
24
|
+
|
25
|
+
def filter_paths
|
26
|
+
gem_paths + [project_path]
|
27
|
+
end
|
28
|
+
|
29
|
+
def filter(bt)
|
30
|
+
original_filter = super(bt)
|
31
|
+
original_filter.collect do |line|
|
32
|
+
filter_paths.inject(line) do |sum, path|
|
33
|
+
sum.sub(/\A#{path}/,'')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Minitest.backtrace_filter = AgressiveBacktraceFilter.new
|
40
|
+
|
41
|
+
# fail_fast hack
|
42
|
+
module MiniTest
|
43
|
+
class Unit
|
44
|
+
def puke_with_immediate_feedback(klass, meth, e)
|
45
|
+
# Workaround for minitest weirdness: When puke gets called *again* after
|
46
|
+
# @exiting has been set to true down below, exit immediately so we don't
|
47
|
+
# get an extra SystemExit stack trace. Exiting without exclamation mark
|
48
|
+
# doesn't get the non-zero exit code through, but all teardown handlers
|
49
|
+
# have been run at this point, so it's OK to use a hard exit here.
|
50
|
+
exit! 1 if @exiting_from_puke
|
51
|
+
result = puke_without_immediate_feedback(klass, meth, e)
|
52
|
+
unless e.is_a?(MiniTest::Skip)
|
53
|
+
# Failure or Error, so print the report we just wrote and exit.
|
54
|
+
puts "\n#{@report.pop}\n"
|
55
|
+
@exiting_from_puke = true
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
alias_method_chain :puke, :immediate_feedback
|
61
|
+
end
|
13
62
|
end
|
14
63
|
|
64
|
+
|
15
65
|
def collection
|
16
66
|
%w(foo bar baz)
|
17
67
|
end
|
@@ -19,3 +69,42 @@ end
|
|
19
69
|
def params
|
20
70
|
{ 'foo' => 'bar' }
|
21
71
|
end
|
72
|
+
|
73
|
+
def requirements_for_form_for_tests!
|
74
|
+
require_relative 'demo_data'
|
75
|
+
require 'active_support/concern'
|
76
|
+
%w(capture url sanitize text form).each do |name|
|
77
|
+
require "action_view/helpers/#{name}_helper"
|
78
|
+
end
|
79
|
+
require 'action_controller/record_identifier'
|
80
|
+
require 'action_view'
|
81
|
+
def formed_class
|
82
|
+
Class.new do
|
83
|
+
include ActionView::Helpers::FormHelper
|
84
|
+
include ActionController::RecordIdentifier
|
85
|
+
|
86
|
+
%w(generic_search_path).each do |path|
|
87
|
+
define_method path do |a=nil,b=nil|
|
88
|
+
"/#{path}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
attr_accessor :output_buffer
|
93
|
+
def protect_against_forgery?
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def search_prefix
|
100
|
+
"generic_search"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def requirements_for_simple_form!
|
105
|
+
require 'active_support/concern'
|
106
|
+
%w(form_options).each do |name|
|
107
|
+
require "action_view/helpers/#{name}_helper"
|
108
|
+
end
|
109
|
+
require 'simple_form'
|
110
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
describe MundaneSearch::Result do
|
4
|
+
let(:result_class) do
|
5
|
+
Class.new(MundaneSearch::Result) do
|
6
|
+
use MundaneSearch::Filters::ExactMatch, param_key: "foo"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:result) { result_class.new(collection, params) }
|
11
|
+
|
12
|
+
it "should run search from result class" do
|
13
|
+
result.to_a.must_equal ["bar"]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return result in same class" do
|
17
|
+
result.must_be_kind_of result_class
|
18
|
+
result.first.must_equal "bar"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return result model" do
|
22
|
+
result.to_model.must_be_kind_of(MundaneSearch::ResultModel)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe MundaneSearch::ResultModel do
|
5
|
+
let(:builder) do
|
6
|
+
builder, filter_canister = Object.new, Object.new
|
7
|
+
def filter_canister.param_key ; "foo" ; end
|
8
|
+
def filter_canister.param_key_type ; :date ; end
|
9
|
+
builder.define_singleton_method :filter_canisters, -> { [filter_canister] }
|
10
|
+
builder
|
11
|
+
end
|
12
|
+
let(:result_class) do
|
13
|
+
result_class = OpenStruct.new(builder: builder, options: {})
|
14
|
+
end
|
15
|
+
let(:model_class) { MundaneSearch::ResultModel.model_class_for(result_class) }
|
16
|
+
let(:result_model) { model_class.new(result) }
|
17
|
+
let(:result) do
|
18
|
+
result = OpenStruct.new
|
19
|
+
result.stack = mock_stack
|
20
|
+
result
|
21
|
+
end
|
22
|
+
let(:mock_stack) do
|
23
|
+
stack = Object.new
|
24
|
+
def stack.params ; { "foo" => "bar" } ; end
|
25
|
+
stack
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".model_class_for" do
|
29
|
+
|
30
|
+
it "should create class based on ResultModel" do
|
31
|
+
model_class.superclass.must_equal MundaneSearch::ResultModel
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should crate class with param_key accessors" do
|
35
|
+
model_class.instance_methods.include?(:foo)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should set type to param_key_type" do
|
40
|
+
result_model.column_for_attribute("foo").type.must_equal :date
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create accessors for params_keys" do
|
44
|
+
result_model.foo.must_equal 'bar'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should not be considered to be persisted" do
|
48
|
+
result_model.wont_be :persisted?
|
49
|
+
end
|
50
|
+
end
|
data/spec/result_spec.rb
CHANGED
@@ -1,35 +1,17 @@
|
|
1
1
|
require_relative 'minitest_helper'
|
2
2
|
|
3
|
-
describe
|
4
|
-
let(:collection) { %w(foo bar baz) }
|
5
|
-
let(:params) { { 'foo' => 'bar' } }
|
6
|
-
let(:initial) { MundaneSearch::InitialResult.new(collection, params) }
|
3
|
+
describe MundaneSearch::Result do
|
7
4
|
|
8
|
-
|
9
|
-
|
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 }
|
5
|
+
# Isolate this more.
|
6
|
+
let(:result) { MundaneSearch::Result.new(collection, params) }
|
20
7
|
|
21
|
-
|
22
|
-
|
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
|
8
|
+
it "should show collection" do
|
9
|
+
result.to_a.must_equal collection
|
33
10
|
end
|
34
11
|
|
12
|
+
it "should be iterateable" do
|
13
|
+
def result.call ; collection ; end
|
14
|
+
result.first.must_equal collection.first
|
15
|
+
result.count.must_equal collection.count
|
16
|
+
end
|
35
17
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
requirements_for_form_for_tests!
|
3
|
+
|
4
|
+
describe "integration search_form_for" do
|
5
|
+
let(:result_class) { Class.new(MundaneSearch::Result) }
|
6
|
+
let(:result) { result_class.new(open_struct_books, params) }
|
7
|
+
let(:result_model) { result.to_model }
|
8
|
+
let(:search_formed_class) do
|
9
|
+
Class.new(formed_class) do
|
10
|
+
include MundaneSearch::ViewHelpers
|
11
|
+
end
|
12
|
+
end
|
13
|
+
let(:formed) { search_formed_class.new }
|
14
|
+
|
15
|
+
it "should generate form with method=get" do
|
16
|
+
form = formed.search_form_for(result_model) { }
|
17
|
+
form.must_match %r{<form[^>]+method="get"}
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
requirements_for_form_for_tests!
|
4
|
+
requirements_for_simple_form!
|
5
|
+
|
6
|
+
describe "intgration with simple_form" do
|
7
|
+
let(:result_class) { Class.new(MundaneSearch::Result) }
|
8
|
+
let(:result) { result_class.new(open_struct_books, params) }
|
9
|
+
let(:result_model) { result.to_model }
|
10
|
+
|
11
|
+
let(:simple_formed_class) do
|
12
|
+
Class.new(formed_class) do
|
13
|
+
include SimpleForm::ActionViewExtensions::FormHelper
|
14
|
+
|
15
|
+
# In simple_form, FormBuilder in lookup_action asks controller for action
|
16
|
+
def controller ; OpenStruct.new(action: :create) ; end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
let(:formed) { simple_formed_class.new }
|
20
|
+
|
21
|
+
it "should generate simple_form" do
|
22
|
+
form = formed.simple_form_for(result) { }
|
23
|
+
form.must_match %r{<form}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should determine input" do
|
27
|
+
result_class.builder.use MundaneSearch::Filters::AttributeMatch, param_key: 'title'
|
28
|
+
form = formed.simple_form_for(result_model) do |f|
|
29
|
+
f.input :title
|
30
|
+
end
|
31
|
+
form.must_match %{<input class="string optional" id="#{search_prefix}_title"
|
32
|
+
name="#{search_prefix}[title]"
|
33
|
+
size="50" type="text" />}.gsub(/\s+/,' ')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'minitest_helper'
|
2
|
+
|
3
|
+
requirements_for_form_for_tests!
|
4
|
+
requirements_for_simple_form!
|
5
|
+
|
6
|
+
describe "integration simple_search_form_for" do
|
7
|
+
let(:result_class) { Class.new(MundaneSearch::Result) }
|
8
|
+
let(:result) { result_class.new(open_struct_books, params) }
|
9
|
+
let(:result_model) { result.to_model }
|
10
|
+
let(:search_formed_class) do
|
11
|
+
Class.new(formed_class) do
|
12
|
+
include MundaneSearch::ViewHelpers
|
13
|
+
include SimpleForm::ActionViewExtensions::FormHelper
|
14
|
+
|
15
|
+
# In simple_form, FormBuilder in lookup_action asks controller for action
|
16
|
+
def controller ; OpenStruct.new(action: :create) ; end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
let(:formed) { search_formed_class.new }
|
20
|
+
|
21
|
+
it "should generate form with method=get" do
|
22
|
+
form = formed.simple_search_form_for(result_model) { }
|
23
|
+
form.must_match %r{<form[^>]+method="get"}
|
24
|
+
end
|
25
|
+
end
|