filterrific 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,8 +20,15 @@ def index
20
20
  * :debug => false # if true, prints out debug info. This also exists in view helper. Maybe one to
21
21
  logger/STDOUT, the other to view?
22
22
  * :param_prefix => "filterrific" # the param prefix used to shuttle params between view and controller.
23
-
23
+
24
24
  @publications = Publication.filterrific_find(@filterrific).paginate....
25
25
  @publications = current_user.publications.filterrific_find(@filterrific).paginate....
26
26
  ...
27
27
  end
28
+
29
+ @filterrific = Filterrific.new(User, params_hash)
30
+ @users = User.filterrific_find(@filterrific).where(...)
31
+
32
+ @filterrific = Filterrific.new(self, User)
33
+ @filterrific = filterrific_init(User, options) (loads and persists in session)
34
+ @users = User.filterrific_find(@filterrific).paginate(:page => params[:page])
data/doc/meta.md ADDED
@@ -0,0 +1,27 @@
1
+ Workflow to Maintain This Gem
2
+ =============================
3
+
4
+ I use the gem-release gem
5
+
6
+ For more info see: https://github.com/svenfuchs/gem-release#usage
7
+
8
+ Steps for an update
9
+ -------------------
10
+
11
+ 1. Update code and commit it.
12
+ 2. Add entry to CHANGELOG:
13
+ * h1 for major release
14
+ * h2 for minor release
15
+ * h3 for patch release
16
+ 3. Bump the version with one of these commands:
17
+ * `gem bump --version 1.1.1` # Bump the gem version to the given version number
18
+ * `gem bump --version major` # 0.0.1 -> 1.0.0
19
+ * `gem bump --version minor` # 0.0.1 -> 0.1.0
20
+ * `gem bump --version patch` # 0.0.1 -> 0.0.2
21
+ 4. Release it.
22
+ * `gem release`
23
+ 5. Create a git tag and push to origin.
24
+ `gem tag`
25
+
26
+
27
+ http://prioritized.net/blog/gemify-assets-for-rails/
data/lib/filterrific.rb CHANGED
@@ -1,11 +1,5 @@
1
- # = The Rails User Interface Solution for Filtering Your ActiveRecord Lists
2
- #
3
- module Filterrific
4
-
5
- if defined?(Rails) && Rails::VERSION::MAJOR == 3
6
- require 'filterrific/railtie'
7
- else
8
- raise "Filterrific requires Rails 3"
9
- end
1
+ require 'filterrific/version'
2
+ require 'filterrific/engine'
10
3
 
4
+ module Filterrific
11
5
  end
@@ -0,0 +1,15 @@
1
+ #
2
+ # Adds view helpers to ActionView
3
+ #
4
+ module Filterrific::ActionViewExtension
5
+
6
+ # Renders a spinner while the list is being updated
7
+ def render_filterrific_spinner
8
+ %(
9
+ <span class="filterrific_spinner" style="display:none;">
10
+ #{ image_tag('filterrific-spinner.gif') }
11
+ </span>
12
+ ).html_safe
13
+ end
14
+
15
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # Adds filterrific methods to ActiveRecord::Base and sub classes.
3
+ #
4
+ require 'filterrific/param_set'
5
+
6
+ module Filterrific::ActiveRecordExtension
7
+
8
+ module ClassMethods
9
+
10
+ # Adds filterrific behavior to class when called like so:
11
+ #
12
+ # filterrific(
13
+ # :default_settings => { :sorted_by => "created_at_asc" },
14
+ # :filter_names => [:sorted_by, :search_query, :with_state]
15
+ # )
16
+ #
17
+ # @params[Hash] options
18
+ # Required keys are:
19
+ # * :filter_names: a list of filter_names to be exposed by Filterrific
20
+ # Optional keys are:
21
+ # * :default_settings: default filter settings
22
+ def filterrific(options)
23
+ cattr_accessor :filterrific_default_settings
24
+ cattr_accessor :filterrific_filter_names
25
+
26
+ options.stringify_keys!
27
+
28
+ # Raise exception if not filter_names are given
29
+ self.filterrific_filter_names = (
30
+ options['filter_names'] || options['scope_names'] || []
31
+ ).map { |e| e.to_s }
32
+ raise(ArgumentError, ":filter_names can't be empty") if filterrific_filter_names.blank?
33
+
34
+ self.filterrific_default_settings = (
35
+ options['default_settings'] || options['defaults'] || {}
36
+ ).stringify_keys
37
+ # Raise exception if defaults contain keys that are not present in filter_names
38
+ if (
39
+ invalid_defaults = (filterrific_default_settings.keys - filterrific_filter_names)
40
+ ).any?
41
+ raise(ArgumentError, "Invalid default keys: #{ invalid_defaults.inspect }")
42
+ end
43
+ end
44
+
45
+ # Returns ActiveRecord relation based on given filterrific_param_set.
46
+ # Use like so:
47
+ # ModelClass.filterrific_find(@filterrific_param_set)
48
+ #
49
+ # @param[Filterrific::ParamSet] filterrific_param_set
50
+ # @return[ActiveRecord::Relation] an ActiveRecord relation.
51
+ def filterrific_find(filterrific_param_set)
52
+ unless filterrific_param_set.is_a?(Filterrific::ParamSet)
53
+ raise(ArgumentError, "Invalid Filterrific::ParamSet: #{ filterrific_param_set.inspect }")
54
+ end
55
+
56
+ # set initial ar_proxy to including class
57
+ ar_proxy = self
58
+
59
+ # apply filterrific params
60
+ self.filterrific_filter_names.each do |filter_name|
61
+ filter_param = filterrific_param_set.send(filter_name)
62
+ next if filter_param.blank? # skip blank filter_params
63
+ ar_proxy = ar_proxy.send(filter_name, filter_param)
64
+ end
65
+
66
+ ar_proxy
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails'
2
+
3
+ module Filterrific
4
+ class Engine < ::Rails::Engine
5
+
6
+ # It's an engine so that we can add javascript and image assets
7
+ # to the asset pipeline.
8
+
9
+ require 'filterrific/param_set'
10
+
11
+ initializer "filterrific.active_record_extension" do |app|
12
+ require 'filterrific/active_record_extension'
13
+ class ::ActiveRecord::Base
14
+ extend Filterrific::ActiveRecordExtension::ClassMethods
15
+ end
16
+ end
17
+
18
+ initializer "filterrific.action_view_extension" do |app|
19
+ require 'filterrific/action_view_extension'
20
+ class ::ActionView::Base
21
+ include Filterrific::ActionViewExtension
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -1,21 +1,23 @@
1
+ require 'active_support/all'
2
+
1
3
  module Filterrific
2
4
 
3
- # FilterParamSet is a container to store FilterParams for a resource class that is filterrific
5
+ # FilterParamSet is a container to store FilterParams
4
6
  class ParamSet
5
7
 
6
8
  attr_accessor :resource_class
7
9
 
8
- def initialize(resource_class, filterrific_params = {})
10
+ def initialize(a_resource_class, filterrific_params = {})
9
11
 
10
- self.resource_class = resource_class
12
+ self.resource_class = a_resource_class
11
13
 
12
- # use either passed in options or resource class' default list_options
13
- # don't merge them. This causes trouble if an option is set to nil
14
- # by the user, then it will be overriden by default list_options
14
+ # Use either passed in filterrific_params or resource class' default_settings.
15
+ # Don't merge the hashes. This causes trouble if an option is set to nil
16
+ # by the user, then it will be overriden by default_settings.
15
17
  # You might wonder "what if I want to change only one thing from the defaults?"
16
18
  # Persistence, baby. By the time you submit changes to one dimension, all the others
17
19
  # will be already initialized with the defaults.
18
- filterrific_params = resource_class.default_filterrific_params if filterrific_params.blank?
20
+ filterrific_params = resource_class.filterrific_default_settings if filterrific_params.blank?
19
21
 
20
22
  # force all keys to strings
21
23
  filterrific_params.stringify_keys!
@@ -27,47 +29,54 @@ module Filterrific
27
29
  # evaulate Procs
28
30
  filterrific_params[key] = val.call
29
31
  when val.is_a?(Array)
30
- # type cast integers
32
+ # type cast integers in the array
31
33
  filterrific_params[key] = filterrific_params[key].map { |e| e =~ /^\d+$/ ? e.to_i : e }
32
34
  when val =~ /^\d+$/
33
- # type cast integers
35
+ # type cast integer
34
36
  filterrific_params[key] = filterrific_params[key].to_i
35
37
  end
36
38
  end
37
39
 
38
- # Define attr_accessor for each FilterrificScope
40
+ # Define attr_accessor for each filterrific_filter_name
39
41
  # on Filterrific::ParamSet instance and assign values from options
40
- resource_class.filterrific_scope_names.each do |scope_name|
41
- self.class.send(:attr_accessor, scope_name)
42
- v = filterrific_params[scope_name.to_s]
43
- self.send("#{ scope_name }=", v) if v.present?
42
+ resource_class.filterrific_filter_names.each do |filter_name|
43
+ self.class.send(:attr_accessor, filter_name)
44
+ v = filterrific_params[filter_name]
45
+ self.send("#{ filter_name }=", v) if v.present?
44
46
  end
45
47
 
46
48
  end
47
49
 
48
- # Returns FilterrificParams as hash (used for URL params and serialization)
50
+ # Returns Filterrific::ParamSet as hash (used for URL params and serialization)
49
51
  def to_hash
50
52
  {}.tap { |h|
51
- resource_class.filterrific_scope_names.each do |scope_name|
52
- param_value = self.send(scope_name)
53
+ resource_class.filterrific_filter_names.each do |filter_name|
54
+ param_value = self.send(filter_name)
53
55
  case
54
56
  when param_value.blank?
55
57
  # do nothing
56
58
  when param_value.is_a?(Proc)
57
59
  # evaluate Proc so it can be serialized
58
- h[scope_name.to_s] = param_value.call
60
+ h[filter_name] = param_value.call
59
61
  else
60
- h[scope_name.to_s] = param_value
62
+ h[filter_name] = param_value
61
63
  end
62
64
  end
63
65
  }
64
66
  end
65
67
 
66
- # Returns true if this Filterrific::ParamSet is not the model's default.
67
- def customized?
68
- resource_class.default_filterrific_params != to_hash
68
+ def to_json
69
+ to_hash.to_json
69
70
  end
70
71
 
72
+ # Returns true if this Filterrific::ParamSet is not the model's default.
73
+ # TODO: this doesn't work for procs. I need to evaluate the
74
+ # filterrific_default_settings before comparing them to to_hash.
75
+ #
76
+ # def customized?
77
+ # resource_class.filterrific_default_settings != to_hash
78
+ # end
79
+
71
80
  end
72
81
 
73
82
  end
@@ -0,0 +1,3 @@
1
+ module Filterrific
2
+ VERSION = "1.1.0"
3
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'filterrific/action_view_extension'
3
+
4
+ class ViewContext
5
+
6
+ include Filterrific::ActionViewExtension
7
+
8
+ end
9
+
10
+ describe Filterrific::ActionViewExtension do
11
+
12
+ it "renders filterrific spinner" do
13
+ ViewContext.new.should respond_to(:render_filterrific_spinner)
14
+ end
15
+
16
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+ require 'filterrific/active_record_extension'
4
+ ::ActiveRecord::Base.extend Filterrific::ActiveRecordExtension::ClassMethods
5
+
6
+ # Container for test data
7
+ class TestData
8
+
9
+ def self.filterrific_filter_names
10
+ %w[sorted_by search_query with_country_id]
11
+ end
12
+
13
+ def self.filterrific_default_settings
14
+ { 'sorted_by' => 'name_asc' }
15
+ end
16
+
17
+ end
18
+
19
+ describe Filterrific::ActiveRecordExtension do
20
+
21
+ let(:filterrific_class){
22
+ Class.new(ActiveRecord::Base) do
23
+ filterrific(
24
+ :filter_names => TestData.filterrific_filter_names,
25
+ :default_settings => TestData.filterrific_default_settings
26
+ )
27
+ end
28
+ }
29
+
30
+ describe "Class method extensions" do
31
+
32
+ it "adds a 'filterrific' class method" do
33
+ filterrific_class.should respond_to(:filterrific)
34
+ end
35
+
36
+ it "adds a 'filterrific_find' class method" do
37
+ filterrific_class.should respond_to(:filterrific_find)
38
+ end
39
+
40
+ end
41
+
42
+ describe "Filterrific initialization" do
43
+
44
+ it "initializes filterrific_filter_names" do
45
+ filterrific_class.filterrific_filter_names.should == TestData.filterrific_filter_names
46
+ end
47
+
48
+ it "initializes filterrific_default_settings" do
49
+ filterrific_class.filterrific_default_settings.should == TestData.filterrific_default_settings
50
+ end
51
+
52
+ it "raises when no filter_names are given" do
53
+ expect {
54
+ Class.new(ActiveRecord::Base) do
55
+ filterrific(
56
+ :filter_names => []
57
+ )
58
+ end
59
+ }.to raise_error(ArgumentError)
60
+ end
61
+
62
+ it "raises when default_settings contains keys that are not in filter_names" do
63
+ expect {
64
+ Class.new(ActiveRecord::Base) do
65
+ filterrific(
66
+ :filter_names => [:one, :two],
67
+ :default_settings => { :three => '' }
68
+ )
69
+ end
70
+ }.to raise_error(ArgumentError)
71
+ end
72
+
73
+ end
74
+
75
+ describe "filterrific_find" do
76
+
77
+ it "raises when given invalid params" do
78
+ expect {
79
+ filterrific_class.filterrific_find('an invalid argument')
80
+ }.to raise_error(ArgumentError)
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Filterrific do
4
+ pending "write it"
5
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+ require 'filterrific/param_set'
3
+
4
+ # Container for test data
5
+ class TestData
6
+
7
+ def self.filterrific_filter_names
8
+ %w[
9
+ filter_proc
10
+ filter_array_int
11
+ filter_array_string
12
+ filter_int
13
+ filter_string
14
+ ]
15
+ end
16
+
17
+ def self.filterrific_default_settings
18
+ { 'filter_int' => 42 }
19
+ end
20
+
21
+ def self.filterrific_params
22
+ {
23
+ 'filter_proc' => lambda { 1 + 1 },
24
+ 'filter_array_int' => %w[1 2 3],
25
+ 'filter_array_string' => %w[one two three],
26
+ 'filter_int' => '42',
27
+ 'filter_string' => 'forty-two'
28
+ }
29
+ end
30
+
31
+ def self.filterrific_params_after_sanitizing
32
+ {
33
+ 'filter_proc' => 2,
34
+ 'filter_array_int' => [1, 2, 3],
35
+ 'filter_array_string' => %w[one two three],
36
+ 'filter_int' => 42,
37
+ 'filter_string' => 'forty-two'
38
+ }
39
+ end
40
+
41
+ end
42
+
43
+ # Simulates a class that would include the filterrific directive
44
+ class ResourceClass
45
+
46
+ def self.filterrific_default_settings
47
+ TestData.filterrific_default_settings
48
+ end
49
+ def self.filterrific_filter_names
50
+ TestData.filterrific_filter_names
51
+ end
52
+
53
+ end
54
+
55
+ describe Filterrific::ParamSet do
56
+
57
+ let(:filterrific_param_set){
58
+ Filterrific::ParamSet.new(ResourceClass, TestData.filterrific_params)
59
+ }
60
+
61
+ describe "initialization" do
62
+
63
+ it "assigns resource class" do
64
+ filterrific_param_set.resource_class.should == ResourceClass
65
+ end
66
+
67
+ describe "dynamic filter_name attr_accessors" do
68
+
69
+ TestData.filterrific_filter_names.each do |filter_name|
70
+
71
+ it "defines a getter for '#{ filter_name }'" do
72
+ filterrific_param_set.should respond_to(filter_name)
73
+ end
74
+
75
+ it "defines a setter for '#{ filter_name }'" do
76
+ filterrific_param_set.should respond_to("#{ filter_name }=")
77
+ end
78
+
79
+ end
80
+
81
+ TestData.filterrific_params.keys.each do |key|
82
+
83
+ it "assigns sanitized param to '#{ key }' attr" do
84
+ filterrific_param_set.send(key).should == TestData.filterrific_params_after_sanitizing[key]
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
93
+ describe "to_hash" do
94
+
95
+ it "returns all filterrific_params as hash" do
96
+ filterrific_param_set.to_hash.should == TestData.filterrific_params_after_sanitizing
97
+ end
98
+
99
+ end
100
+
101
+ describe "to_json" do
102
+
103
+ it "returns all filterrific_params as json string" do
104
+ filterrific_param_set.to_json.should == TestData.filterrific_params_after_sanitizing.to_json
105
+ end
106
+
107
+ end
108
+
109
+ end