filter_fu 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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