filter_fu 0.5.0 → 0.6.0

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.
@@ -1,159 +1,158 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/fixtures/employee')
1
+ require 'spec_helper'
3
2
 
4
3
  describe FilterFu::ActiveRecord do
5
-
4
+
6
5
  it "should add a filter_fu class method to ActiveRecord::Base" do
7
6
  ActiveRecord::Base.should respond_to(:filter_fu)
8
7
  end
9
8
 
10
- describe "filter_fu" do
11
-
9
+ describe ".filter_fu" do
10
+
12
11
  it "should accept an options hash" do
13
12
  lambda { ActiveRecord::Base.filter_fu({}) }.should_not raise_error(ArgumentError)
14
13
  end
15
-
14
+
16
15
  it "should not require an options hash" do
17
16
  lambda { ActiveRecord::Base.filter_fu }.should_not raise_error(ArgumentError)
18
17
  end
19
-
18
+
20
19
  it "should add a new singleton method called filtered_by" do
21
20
  Employee.should respond_to(:filtered_by)
22
21
  end
23
-
22
+
24
23
  it "should not accept invalid options" do
25
24
  lambda { ActiveRecord::Base.filter_fu(:invalid_option => 'some value') }.should raise_error
26
25
  end
27
-
26
+
28
27
  %w(only except).each do |option|
29
28
  it "should accept :#{option} as an option" do
30
29
  lambda { ActiveRecord::Base.filter_fu(option => 'some value') }.should_not raise_error
31
30
  end
32
31
  end
33
-
32
+
34
33
  it "should not accept :except and :only option at the same time" do
35
34
  lambda { ActiveRecord::Base.filter_fu(:only => 'some value', :except => 'some other value') }.should raise_error(/Use either :only or :except/)
36
35
  end
37
-
36
+
38
37
  end
39
-
40
- describe "filtered_by" do
41
-
38
+
39
+ describe ".filtered_by" do
40
+
42
41
  before(:each) do
43
42
  @plain_class = Class.new(Employee)
44
43
  @class = @plain_class.clone
45
44
  @class.filter_fu if @class.respond_to?(:filter_fu)
46
45
  end
47
-
46
+
48
47
  it "should require a hash with filter params" do
49
48
  lambda { @class.filtered_by }.should raise_error(ArgumentError)
50
49
  end
51
-
50
+
52
51
  it "should not fail if the hash with filter params is nil" do
53
52
  lambda { @class.filtered_by(nil) }.should_not raise_error(NoMethodError)
54
53
  end
55
-
54
+
56
55
  it "should not filter anything if the hash is nil" do
57
56
  @class.filtered_by(nil).should == @class.all
58
57
  end
59
-
58
+
60
59
  it "should not filter anything if the hash is empty" do
61
60
  @class.filtered_by({}).should == @class.all
62
61
  end
63
-
62
+
64
63
  it "should not return nil if all scopes were skipped" do
65
64
  # This is ugly. Is there a better solution to this?
66
65
  klass = @plain_class.filter_fu :only => :salary
67
66
  klass.filtered_by({ :country => 'Whatever' }).should_not be_nil
68
67
  end
69
-
68
+
70
69
  it "should handle HashWithIndifferentAccess correctly" do
71
70
  @class.filtered_by(HashWithIndifferentAccess.new('salary' => 100000)).should == @class.all(:conditions => 'salary = 100000')
72
71
  @class.filtered_by(HashWithIndifferentAccess.new('boss' => true)).should == @class.all(:conditions => "position = 'Boss'")
73
72
  end
74
-
75
- it "should return an instace of ActiveRecord::NamedScope::Scope" do
76
- @class.filtered_by({ :boss => nil }).class.should == ActiveRecord::NamedScope::Scope
73
+
74
+ it "should return an instace of ActiveRecord::NamedScope::Scope" do
75
+ @class.filtered_by({ :boss => nil }).class.should == ActiveRecord::Relation
77
76
  end
78
-
77
+
79
78
  it "should call named scopes if specified in the filter params" do
80
79
  @class.should_receive(:boss)
81
80
  @class.filtered_by({ :boss => '' })
82
81
  end
83
-
82
+
84
83
  it "should pass the value to the named scope" do
85
84
  @class.should_receive(:country).with('some value')
86
85
  @class.filtered_by({ :country => 'some value'})
87
86
  end
88
-
87
+
89
88
  it "should only call the specified named scope if it is available" do
90
89
  @class.should_not_receive(:unavailable)
91
90
  @class.filtered_by({ :unavailable => '' })
92
91
  end
93
-
92
+
94
93
  it "should allow multiple scopes at once and combine them" do
95
94
  @class.filtered_by({ :position => 'Worker', :country => 'Country 1'}).should == @class.all(:conditions => { :position => 'Worker', :country => 'Country 1'})
96
95
  end
97
-
96
+
98
97
  describe "when the given named scope is not available" do
99
-
98
+
100
99
  it "should create an anonymous scope using the filter options as conditions" do
101
100
  @class.filtered_by(:salary => 100000).should == @class.all(:conditions => 'salary = 100000')
102
101
  end
103
-
102
+
104
103
  it "should not create an anonymous scope if there is no column for it" do
105
104
  lambda { @class.filtered_by(:non_existing_column => 'some value').all }.should_not raise_error(/no such column/)
106
105
  end
107
-
106
+
108
107
  it "should not create an anonymous scope if the value is blank" do
109
108
  @class.filtered_by(:salary => '').should == @class.all()
110
109
  end
111
-
110
+
112
111
  it "should create an anonymous scope that is able to handle an array of possible values for the filter" do
113
112
  @class.filtered_by(:salary => [80000, 90000]).should == @class.all(:conditions => 'salary IN (80000, 90000)')
114
113
  end
115
-
114
+
116
115
  end
117
116
 
118
117
  it "should not filter by scopes defined in :except option" do
119
118
  klass = @plain_class.clone
120
119
  klass.filter_fu :except => :dont_access_me
121
- klass.named_scope :dont_access_me, {}
122
- klass.named_scope :access_me, {}
123
-
120
+ klass.scope :dont_access_me, {}
121
+ klass.scope :access_me, {}
122
+
124
123
  klass.should_not_receive(:dont_access_me)
125
124
  klass.filtered_by(:dont_access_me => '')
126
125
  end
127
-
126
+
128
127
  it "should filter by scopes not defined in :except option" do
129
128
  klass = @plain_class.clone
130
129
  klass.filter_fu :except => :dont_access_me
131
- klass.named_scope :dont_access_me, {}
132
- klass.named_scope :access_me, {}
133
-
130
+ klass.scope :dont_access_me, {}
131
+ klass.scope :access_me, {}
132
+
134
133
  klass.should_receive(:access_me)
135
134
  klass.filtered_by(:access_me => '')
136
135
  end
137
-
136
+
138
137
  it "should only filter by scopes define in :only option" do
139
138
  klass = @plain_class.clone
140
139
  klass.filter_fu :only => :only_access_me
141
- klass.named_scope :only_access_me, {}
142
- klass.named_scope :dont_access_me, {}
143
-
140
+ klass.scope :only_access_me, {}
141
+ klass.scope :dont_access_me, {}
142
+
144
143
  klass.should_receive(:only_access_me)
145
144
  klass.filtered_by(:only_access_me => '')
146
145
  end
147
-
146
+
148
147
  it "should not filter by scopes not defined in :only option" do
149
148
  klass = @plain_class.clone
150
149
  klass.filter_fu :only => :only_access_me
151
- klass.named_scope :only_access_me, {}
152
- klass.named_scope :dont_access_me, {}
153
-
150
+ klass.scope :only_access_me, {}
151
+ klass.scope :dont_access_me, {}
152
+
154
153
  klass.should_not_receive(:dont_access_me)
155
154
  klass.filtered_by(:dont_access_me => '')
156
155
  end
157
156
  end
158
-
157
+
159
158
  end
data/spec/db/database.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  sqlite3:
2
2
  database: ":memory:"
3
- adapter: sqlite3
3
+ adapter: sqlite3
data/spec/db/debug.log ADDED
@@ -0,0 +1,42 @@
1
+ # Logfile created on Thu Dec 09 17:00:27 +0100 2010 by logger.rb/22285
2
+ SQL (0.1ms)  SELECT name
3
+ FROM sqlite_master
4
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
5
+ 
6
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 1', 'Employee 0', 100000, 'Boss')
7
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 2', 'Employee 1', 20000, 'Worker')
8
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 3', 'Employee 2', 30000, 'Worker')
9
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 4', 'Employee 3', 40000, 'Worker')
10
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 5', 'Employee 4', 0, 'Worker')
11
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 6', 'Employee 5', 10000, 'Worker')
12
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 7', 'Employee 6', 20000, 'Worker')
13
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 8', 'Employee 7', 30000, 'Worker')
14
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 9', 'Employee 8', 40000, 'Worker')
15
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 10', 'Employee 9', 0, 'Worker')
16
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 1', 'Employee 10', 10000, 'Worker')
17
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 2', 'Employee 11', 20000, 'Worker')
18
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 3', 'Employee 12', 30000, 'Worker')
19
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 4', 'Employee 13', 40000, 'Worker')
20
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 5', 'Employee 14', 0, 'Worker')
21
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 6', 'Employee 15', 10000, 'Worker')
22
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 7', 'Employee 16', 20000, 'Worker')
23
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 8', 'Employee 17', 30000, 'Worker')
24
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 9', 'Employee 18', 40000, 'Worker')
25
+ AREL (0.1ms) INSERT INTO "employees" ("country", "name", "salary", "position") VALUES ('Country 10', 'Employee 19', 0, 'Worker')
26
+  Load (0.6ms) SELECT "employees".* FROM "employees"
27
+  Load (0.6ms) SELECT "employees".* FROM "employees"
28
+  Load (0.6ms) SELECT "employees".* FROM "employees"
29
+  Load (0.6ms) SELECT "employees".* FROM "employees"
30
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE (salary = 100000)
31
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE ("employees"."salary" = 100000)
32
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE (position = 'Boss')
33
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE (position = 'Boss')
34
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE ("employees"."country" = 'Country 1') AND ("employees"."position" = 'Worker')
35
+  Load (0.3ms) SELECT "employees".* FROM "employees" WHERE (country = 'Country 1') AND ("employees"."position" = 'Worker')
36
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE (salary = 100000)
37
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE ("employees"."salary" = 100000)
38
+  Load (0.5ms) SELECT "employees".* FROM "employees"
39
+  Load (0.6ms) SELECT "employees".* FROM "employees"
40
+  Load (0.6ms) SELECT "employees".* FROM "employees"
41
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE (salary IN (80000, 90000))
42
+  Load (0.2ms) SELECT "employees".* FROM "employees" WHERE ("employees"."salary" IN (80000, 90000))
data/spec/db/schema.rb CHANGED
@@ -6,5 +6,5 @@ ActiveRecord::Schema.define(:version => 0) do
6
6
  t.string :position
7
7
  t.integer :salary
8
8
  end
9
-
10
- end
9
+
10
+ end
@@ -1,13 +1,13 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe FilterFu do
4
-
4
+
5
5
  it "should include FilterFu::ViewHelper into ActionView::Base" do
6
6
  ActionView::Base.ancestors.should include(FilterFu::ViewHelper)
7
7
  end
8
-
8
+
9
9
  it "should include FilterFu::ActiveRecord into ActiveRecord::Base" do
10
10
  ActiveRecord::Base.ancestors.should include(FilterFu::ActiveRecord)
11
11
  end
12
-
12
+
13
13
  end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe FilterFu::ViewHelper do
4
+
5
+ before(:each) do
6
+ helper.controller = DummyController.new
7
+ end
8
+
9
+ it "should provide a filter_form_for method" do
10
+ helper.should respond_to(:filter_form_for)
11
+ end
12
+
13
+ it "should prodive a filter_form method as an alias for filter_form" do
14
+ helper.should respond_to(:filter_form)
15
+ end
16
+
17
+ it "should require a block" do
18
+ expect { helper.filter_form_for }.to raise_error(ArgumentError, /Missing block/)
19
+ end
20
+
21
+ it "should accept options" do
22
+ expect { helper.filter_form_for({}) {} }.to_not raise_error(ArgumentError)
23
+ end
24
+
25
+ it "should not require options" do
26
+ expect { helper.filter_form_for() {} }.to_not raise_error(ArgumentError)
27
+ end
28
+
29
+ it "should accept a name together with options" do
30
+ expect { helper.filter_form_for(:other, {}) {} }.to_not raise_error(ArgumentError)
31
+ end
32
+
33
+ it "should call the associated block" do
34
+ expect {
35
+ helper.filter_form_for() { throw :done }
36
+ }.to throw_symbol(:done)
37
+ end
38
+
39
+ it "should pass a ActionView::Helpers::FormBuilder to the block" do
40
+ helper.filter_form_for { |f| f.should be_kind_of(ActionView::Helpers::FormBuilder) }
41
+ end
42
+
43
+ it "should include the erb of the block" do
44
+ html = helper.filter_form_for { "<div>Some random HTML</div>" }
45
+ html.should contain('Some random HTML')
46
+ end
47
+
48
+ it "should include a form tag" do
49
+ html = helper.filter_form_for { }
50
+ html.should have_selector('form')
51
+ end
52
+
53
+ it "should set the form method attribute to GET" do
54
+ html = helper.filter_form_for { }
55
+ html.should have_selector('form', :method => 'get')
56
+ end
57
+
58
+ it "should set the form action attribute to the current url" do
59
+ html = helper.filter_form_for { }
60
+ html.should have_selector('form', :action => '/foo/bar')
61
+ end
62
+
63
+ it "should use :filter as the default namespace in form fields" do
64
+ html = helper.filter_form_for { |f| f.text_field :name }
65
+ html.should have_selector('input', :name => 'filter[name]')
66
+ end
67
+
68
+ it "should use another name as namespace if it's provided as the first argument" do
69
+ html = helper.filter_form_for(:other) { |f| f.text_field :name }
70
+ html.should have_selector('input', :name => 'other[name]')
71
+ end
72
+
73
+ it "should pass options to the form_for helper" do
74
+ html = helper.filter_form_for(:html => { :class => 'filter' }) { }
75
+ html.should have_selector('form', :class => 'filter')
76
+ end
77
+
78
+ it "should preserve the page's parameters with hidden fields" do
79
+ helper.params.merge!({ :some_param => 'some value', :some_other_param => 'some other value' })
80
+ html = helper.filter_form_for() { }
81
+ html.should have_selector('input', :type => 'hidden', :name => 'some_param', :value => 'some value')
82
+ html.should have_selector('input', :type => 'hidden', :name => 'some_other_param', :value => 'some other value')
83
+ end
84
+
85
+ it "should preserve the page's nested parameters with hidden fields" do
86
+ helper.params.merge!({ :some_param => 'some value', :nested => { :some_other_param => 'some other value', :deeply_nested => { :down_here => 'yet another value' } } })
87
+ html = helper.filter_form_for() { }
88
+ html.should have_selector('input', :type => 'hidden', :name => 'some_param', :value => 'some value')
89
+ html.should have_selector('input', :type => 'hidden', :name => 'nested[some_other_param]', :value => 'some other value')
90
+ html.should have_selector('input', :type => 'hidden', :name => 'nested[deeply_nested][down_here]', :value => 'yet another value')
91
+ end
92
+
93
+ it "should not preserve the page's parameters for the current filter" do
94
+ helper.params.merge!({ :other => { :name => 'some value' }})
95
+ html = helper.filter_form_for(:other) { }
96
+ html.should_not have_selector('input', :type => 'hidden', :name => 'other')
97
+ html.should_not have_selector('input', :type => 'hidden', :name => 'other[name]', :value => 'some value')
98
+ end
99
+
100
+ it "should not preserve the controller and action params" do
101
+ helper.params.merge!({ :controller => 'foo', :action => 'bar' })
102
+ html = helper.filter_form_for() { }
103
+ html.should_not have_selector('input', :type => 'hidden', :name => 'controller', :value => 'foo')
104
+ html.should_not have_selector('input', :type => 'hidden', :name => 'action', :value => 'bar')
105
+ end
106
+
107
+ it "should not preserve params specified in :ignore_parameters" do
108
+ helper.params.merge!({ :some_param => 'some value', :some_other_param => 'some other value' })
109
+ html = helper.filter_form_for(:ignore_parameters => [:some_other_param]) { }
110
+ html.should have_selector('input', :type => 'hidden', :name => 'some_param', :value => 'some value')
111
+ html.should_not have_selector('input', :type => 'hidden', :name => 'some_other_param', :value => 'some other value')
112
+ end
113
+
114
+ it "should use the current filter params as defaults for the form" do
115
+ helper.params.merge!({ :filter => { :some_param => 'some value' } })
116
+ html = helper.filter_form_for() { |f| f.text_field :some_param }
117
+ html.should have_selector('input', :type => 'text', :name => 'filter[some_param]', :value => 'some value')
118
+ end
119
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,20 +1,16 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
-
4
- begin
5
- require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
6
- rescue LoadError
7
- puts "You need to install rspec in your base app"
8
- exit
9
- end
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ ENV["RAILS_ENV"] ||= 'test'
10
4
 
5
+ require 'rubygems'
6
+ require 'rails/all'
11
7
  require 'filter_fu'
12
8
 
13
- Spec::Runner.configure do |config|
9
+ require File.dirname(__FILE__) + "/../tmp/sandbox/config/environment"
14
10
 
15
- end
11
+ require 'rspec/rails'
16
12
 
17
- ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), 'debug.log'))
13
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), 'db', 'debug.log'))
18
14
 
19
15
  configuration = YAML.load_file(File.join(File.dirname(__FILE__), 'db', 'database.yml'))
20
16
  ActiveRecord::Base.establish_connection(configuration[ENV["DB"] || "sqlite3"])
@@ -22,4 +18,23 @@ ActiveRecord::Base.establish_connection(configuration[ENV["DB"] || "sqlite3"])
22
18
  ActiveRecord::Base.silence do
23
19
  ActiveRecord::Migration.verbose = false
24
20
  load(File.join(File.dirname(__FILE__), "db", "schema.rb"))
25
- end
21
+ end
22
+
23
+ # Requires supporting files with custom matchers and macros, etc,
24
+ # in ./support/ and its subdirectories.
25
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
26
+
27
+ RSpec.configure do |config|
28
+ # == Mock Framework
29
+ #
30
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
31
+ #
32
+ # config.mock_with :mocha
33
+ # config.mock_with :flexmock
34
+ # config.mock_with :rr
35
+ config.mock_with :rspec
36
+
37
+ # If you'd prefer not to run each of your examples within a transaction,
38
+ # uncomment the following line.
39
+ # config.use_transactional_examples false
40
+ end
@@ -0,0 +1,13 @@
1
+ # Taken from mislav's will_paginate http://github.com/mislav/will_paginate/tree/master
2
+
3
+ class DummyController < ActionView::TestCase::TestController
4
+ def initialize
5
+ super
6
+ @params.merge!(:controller => 'foo', :action => 'bar')
7
+ @request.path_parameters = @params
8
+ end
9
+ end
10
+
11
+ Rails.application.routes.draw do
12
+ match "foo/bar", :controller => 'foo', :action => 'bar'
13
+ end
@@ -1,7 +1,7 @@
1
1
  class Employee < ActiveRecord::Base
2
-
3
- named_scope :boss, :conditions => "position = 'Boss'"
4
- named_scope :country, lambda { |country| { :conditions => ["country = ?", country] } }
2
+
3
+ scope :boss, :conditions => "position = 'Boss'"
4
+ scope :country, lambda { |country| { :conditions => ["country = ?", country] } }
5
5
 
6
6
  end
7
7
 
@@ -10,5 +10,3 @@ end
10
10
  salary = (n == 0) ? 100000 : (((n+1) % 5) * 10000)
11
11
  Employee.create(:name => "Employee #{n}", :country => "Country #{(n % 10) + 1}", :position => position, :salary => salary)
12
12
  end
13
-
14
- #puts Employee.all.inspect