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.
Files changed (65) hide show
  1. data/Guardfile +11 -0
  2. data/README.md +61 -9
  3. data/Rakefile +1 -1
  4. data/bin/coderay +16 -0
  5. data/bin/erubis +16 -0
  6. data/bin/guard +16 -0
  7. data/bin/pry +16 -0
  8. data/bin/rackup +16 -0
  9. data/bin/rake +1 -1
  10. data/bin/sprockets +16 -0
  11. data/bin/thor +16 -0
  12. data/bin/tilt +16 -0
  13. data/lib/columns_hash.rb +38 -0
  14. data/lib/mundane-search.rb +14 -6
  15. data/lib/mundane-search/buildable.rb +25 -0
  16. data/lib/mundane-search/builder.rb +32 -18
  17. data/lib/mundane-search/filter_canister.rb +27 -3
  18. data/lib/mundane-search/filters.rb +7 -8
  19. data/lib/mundane-search/filters/attribute_match.rb +6 -7
  20. data/lib/mundane-search/filters/attribute_substring.rb +14 -0
  21. data/lib/mundane-search/filters/base.rb +5 -2
  22. data/lib/mundane-search/filters/blank_params_are_nil.rb +1 -1
  23. data/lib/mundane-search/filters/operator.rb +18 -0
  24. data/lib/mundane-search/filters/shortcuts.rb +33 -0
  25. data/lib/mundane-search/filters/typical.rb +28 -3
  26. data/lib/mundane-search/initial_stack.rb +13 -0
  27. data/lib/mundane-search/railtie.rb +7 -0
  28. data/lib/mundane-search/result.rb +23 -8
  29. data/lib/mundane-search/result_model.rb +65 -0
  30. data/lib/mundane-search/stack.rb +38 -0
  31. data/lib/mundane-search/version.rb +1 -1
  32. data/lib/mundane-search/view_helpers.rb +24 -0
  33. data/mundane-search.gemspec +7 -0
  34. data/script/console +6 -0
  35. data/spec/active_record_setup.rb +2 -45
  36. data/spec/buildable_integration_spec.rb +14 -0
  37. data/spec/buildable_spec.rb +19 -0
  38. data/spec/builder_integration_spec.rb +26 -5
  39. data/spec/builder_spec.rb +13 -18
  40. data/spec/columns_hash_spec.rb +37 -0
  41. data/spec/demo_data.rb +50 -0
  42. data/spec/filter_canister_spec.rb +46 -0
  43. data/spec/filters/attribute_match_integration_spec.rb +2 -2
  44. data/spec/filters/attribute_match_spec.rb +27 -0
  45. data/spec/filters/attribute_substring_spec.rb +27 -0
  46. data/spec/filters/base_spec.rb +39 -7
  47. data/spec/filters/blank_params_are_nil_spec.rb +11 -0
  48. data/spec/filters/operator_integration_spec.rb +20 -0
  49. data/spec/filters/operator_spec.rb +28 -0
  50. data/spec/filters/shortcuts_integration_spec.rb +16 -0
  51. data/spec/filters/shortcuts_spec.rb +15 -0
  52. data/spec/filters/typical_spec.rb +68 -0
  53. data/spec/form_integration_spec.rb +29 -0
  54. data/spec/initial_stack_spec.rb +13 -0
  55. data/spec/minitest_helper.rb +93 -4
  56. data/spec/result_integration_spec.rb +24 -0
  57. data/spec/result_model_spec.rb +50 -0
  58. data/spec/result_spec.rb +10 -28
  59. data/spec/search_form_for_integration_spec.rb +19 -0
  60. data/spec/simple_form_integration_spec.rb +36 -0
  61. data/spec/simple_search_form_for_integration_spec.rb +25 -0
  62. data/spec/stack_spec.rb +40 -0
  63. metadata +167 -6
  64. data/lib/mundane-search/filters/helpers.rb +0 -44
  65. 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
@@ -1,17 +1,67 @@
1
1
  require 'rubygems'
2
- gem 'minitest' # ensures you're using the gem, and not the built in MT
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 NothingFilterForTest
11
- def initialize(a=nil) ; end
12
- def call(c,p) ; [c,p] ; end
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 "results" do
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
- 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 }
5
+ # Isolate this more.
6
+ let(:result) { MundaneSearch::Result.new(collection, params) }
20
7
 
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
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