lupa 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83dad7fde61871e8d0333b609958b6eadaccc23c
4
- data.tar.gz: 1a1eb1e14ede2f72d5f7eb029c38b2511e9182f6
3
+ metadata.gz: 46daf9ac53354ecc21016d968c78de4d322a1bb5
4
+ data.tar.gz: 62c8cde8889723041b1d622ed2bc1bec5f784ff6
5
5
  SHA512:
6
- metadata.gz: e6f6127f879df5ec3bcee9e4c0c479df20aa53c17389fedf7a10d1403900da7920372a6bf2dab44ddad82843465c71834fe3343e515f506d63f331b4feec23b3
7
- data.tar.gz: 84e3f845e779bdb383410f32509b99b4f7ae5fcda658dbb5e3dd49e8110b735c66b47c49ff583a2942822df800fc656fe8315c2f52bdb3b6807e476a5c7b06e0
6
+ metadata.gz: 010ba896da1a30da488d2726646616ca4e1c7091dd5907ae20150756af248b8173266e4b68f501470c35cbf12d933f0f6f530b8943920b2b0f874bff9a782599
7
+ data.tar.gz: 36a3ac1ee305f13318d990f250a40b97ab5f6cb90661c1e546ca4f0b0218e746a05d321d7069944ba100c484e8343125ccb2a8123cc2b15b46e9539e918168e1
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.5
6
+ - 2.2.1
@@ -0,0 +1,4 @@
1
+ ## 1.0.1
2
+
3
+ * enhancements
4
+ * A **Lupa::DefaultSearchAttributesError** exception will be raised if `default_search_attributes` does not return a hash.
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in lupa.gemspec
4
4
  gemspec
5
+
6
+ gem 'coveralls', require: false
data/README.md CHANGED
@@ -2,53 +2,65 @@
2
2
 
3
3
  Lupa means *Magnifier* in spanish.
4
4
 
5
- Lupa lets you create simple, robust and scaleable search filters with ease using regular Ruby classes and object oriented design patterns. It's Framework and ORM agnostic.
5
+ [![Build Status](https://travis-ci.org/edelpero/lupa.svg?branch=master)](https://travis-ci.org/edelpero/lupa) [![Coverage Status](https://coveralls.io/repos/edelpero/lupa/badge.svg?branch=master)](https://coveralls.io/r/edelpero/lupa?branch=master) [![Code Climate](https://codeclimate.com/github/edelpero/lupa/badges/gpa.svg)](https://codeclimate.com/github/edelpero/lupa) [![Inline docs](http://inch-ci.org/github/edelpero/lupa.svg?branch=master)](http://inch-ci.org/github/edelpero/lupa)
6
6
 
7
- ## Search Class
7
+ Lupa lets you create simple, robust and scaleable search filters with ease using regular Ruby classes and object oriented design patterns.
8
8
 
9
- ### Usage
9
+ Lupa it's Framework and ORM agnostic. It will work with any ORM or Object that can build a query using **chained method calls**, like ActiveRecord: `
10
+ Product.where(name: 'Digital').where(category: '23').limit(2)`.
10
11
 
11
- The example will explain how to use the class on a Rails application:
12
+ **Table of Contents:**
12
13
 
13
- - Define a custom form:
14
+ * [Search Class](https://github.com/edelpero/lupa#search-class)
15
+ * [Overview](https://github.com/edelpero/lupa#overview)
16
+ * [Definition](https://github.com/edelpero/lupa#definition)
17
+ * [Public Methods](https://github.com/edelpero/lupa#public-methods)
18
+ * [Default Search Scope](https://github.com/edelpero/lupa#default-search-scope)
19
+ * [Default Search Attributes](https://github.com/edelpero/lupa#default-search-attributes)
20
+ * [Combining Search Classes](https://github.com/edelpero/lupa#combining-search-classes)
21
+ * [Usage with Rails](https://github.com/edelpero/lupa#usage-with-rails)
22
+ * [Testing](https://github.com/edelpero/lupa#testing)
23
+ * [Testing Default Scope](https://github.com/edelpero/lupa#testing-default-scope)
24
+ * [Testing Default Search Attributes](https://github.com/edelpero/lupa#testing-default-search-attributes)
25
+ * [Testing Each Scope Method Individually](https://github.com/edelpero/lupa#testing-each-scope-method-individually)
26
+ * [Installation](https://github.com/edelpero/lupa#installation)
14
27
 
15
- ```haml
16
- # app/views/products/_search.html.haml
17
28
 
18
- = form_tag products_path, method: :get do
19
- = text_field_tag 'name'
20
- = select_tag 'category', options_from_collection_for_select(@categories, 'id', 'name')
21
- = date_field_tag 'created_between[start_date]'
22
- = date_field_tag 'created_between[end_date]'
23
- = submit_tag :search
24
- ```
25
- - Create a new instance of your search class and pass a collection to which all search conditions will be applied and specify the search params you want to apply:
29
+ ## Search Class
30
+
31
+ ### Overview
26
32
 
27
33
  ```ruby
28
- # app/controllers/products_controller.rb
34
+ products = ProductSearch.new(current_user.products).search(name: 'digital', category: '23')
29
35
 
30
- class ProductsController < ApplicationController
31
- def index
32
- @products = ProductSearch.new(current_user.products).search(search_params)
33
- end
34
-
35
- protected
36
- def search_params
37
- params.permit(:name, :category, created_between: [:start_date, :end_date])
38
- end
36
+ # Iterate over the search results
37
+ products.each do |product|
38
+ # Your logic goes here
39
39
  end
40
40
  ```
41
- - Loop through the search results on your view.
41
+ Calling **.each** on the instance will build a search by chaining calls to **name** and **category** methods defined in our **ProductSearch::Scope** class.
42
42
 
43
- ```haml
44
- # app/views/products/index.html.haml
43
+ ```ruby
44
+ # app/searches/product_search.rb
45
45
 
46
- %h1 Products
46
+ class ProductSearch < Lupa::Search
47
+ # Scope class holds all your search methods.
48
+ class Scope
47
49
 
48
- %ul
49
- - @products.each do |product|
50
- %li
51
- = "#{product.name} - #{product.price} - #{product.category}"
50
+ # Search method
51
+ def name
52
+ if search_attributes[:name].present?
53
+ scope.where('name iLIKE ?', "%#{search_attributes[:name]}%")
54
+ end
55
+ end
56
+
57
+ # Search method
58
+ def category
59
+ scope.where(category_id: search_attributes[:category])
60
+ end
61
+
62
+ end
63
+ end
52
64
  ```
53
65
 
54
66
  ### Definition
@@ -65,7 +77,7 @@ end
65
77
  Inside your **Scope** class you must define your scope methods. You'll also be able to access to the following methods inside your scope class: **scope** and **search_attributes**.
66
78
 
67
79
  * **`scope:`** returns the current scope when the scope method is called.
68
- * **`search_attributes:`** returns a hash containing the all search attributes specified.
80
+ * **`search_attributes:`** returns a hash containing the all search attributes specified including the default ones.
69
81
 
70
82
  <u>**Note:**</u> All keys of **`search_attributes`** are symbolized.
71
83
 
@@ -75,32 +87,32 @@ Inside your **Scope** class you must define your scope methods. You'll also be a
75
87
  class ProductSearch < Lupa::Search
76
88
  # Scope class holds all your search methods.
77
89
  class Scope
78
-
90
+
79
91
  # Search method
80
92
  def name
81
93
  if search_attributes[:name].present?
82
94
  scope.where('name LIKE ?', "%#{search_attributes[:name]}%")
83
95
  end
84
96
  end
85
-
97
+
86
98
  # Search method
87
99
  def created_between
88
100
  if created_start_date && created_end_date
89
101
  scope.where(created_at: created_start_date..created_end_date)
90
102
  end
91
103
  end
92
-
104
+
93
105
  # Search method
94
106
  def category
95
- scope.where(category_id: search_attributes[:category])
107
+ scope.where(category_id: search_attributes[:category])
96
108
  end
97
-
109
+
98
110
  private
99
111
  # Parses search_attributes[:created_between][:start_date]
100
112
  def created_start_date
101
113
  search_attributes[:created_between] && search_attributes[:created_between][:start_date].try(:to_date)
102
114
  end
103
-
115
+
104
116
  # Parses search_attributes[:created_between][:end_date]
105
117
  def created_end_date
106
118
  search_attributes[:created_between] && search_attributes[:created_between][:end_date].try(:to_date)
@@ -154,7 +166,7 @@ search.unexisting_method
154
166
  # => Lupa::ResultMethodNotImplementedError: The resulting scope does not respond to unexisting_method method.
155
167
  ```
156
168
 
157
- ## Default Search Scope
169
+ ### Default Search Scope
158
170
 
159
171
  You can define a default search scope if you want to use a search class with an specific resource by overriding the initialize method as follows:
160
172
 
@@ -165,7 +177,7 @@ class ProductSearch < Lupa::Search
165
177
  class Scope
166
178
  ...
167
179
  end
168
-
180
+
169
181
  # Be careful not to change the scope variable name,
170
182
  # otherwise you will experiment some issues.
171
183
  def initialize(scope = Product.all)
@@ -183,7 +195,7 @@ search.first
183
195
  # => #<Product id: 1, name: 'Eames Chair', category_id: 23, created_at: "2015-04-06 18:54:13", updated_at: "2015-04-06 18:54:13" >
184
196
  ```
185
197
 
186
- ## Default Search Attributes
198
+ ### Default Search Attributes
187
199
 
188
200
  Defining default search attributes will cause the scope method to be invoked always.
189
201
 
@@ -194,7 +206,7 @@ class ProductSearch < Lupa::Search
194
206
  class Scope
195
207
  ...
196
208
  end
197
-
209
+
198
210
  # This should always return a hash
199
211
  def default_search_attributes
200
212
  { category: 23 }
@@ -210,7 +222,7 @@ search.search_attributes
210
222
  # => { name: 'chair', category: 42 }
211
223
  ```
212
224
 
213
- ## Combining Search Classes
225
+ ### Combining Search Classes
214
226
 
215
227
  You can reuse your search class in order to keep them DRY.
216
228
 
@@ -221,27 +233,27 @@ A common example is searching records created between two dates. So lets create
221
233
 
222
234
  class CreatedAtSearch < Lupa::Search
223
235
  class Scope
224
-
236
+
225
237
  def created_before
226
238
  ...
227
239
  end
228
-
240
+
229
241
  def created_after
230
242
  ...
231
243
  end
232
-
244
+
233
245
  def created_between
234
246
  if created_start_date && created_end_date
235
247
  scope.where(created_at: created_start_date..created_end_date)
236
248
  end
237
249
  end
238
-
250
+
239
251
  private
240
252
 
241
253
  def created_start_date
242
254
  search_attributes[:created_between] && search_attributes[:created_between][:start_date].try(:to_date)
243
255
  end
244
-
256
+
245
257
  def created_end_date
246
258
  search_attributes[:created_between] && search_attributes[:created_between][:end_date].try(:to_date)
247
259
  end
@@ -256,26 +268,74 @@ Now we can use it in our **ProductSearch** class:
256
268
 
257
269
  class ProductSearch < Lupa::Search
258
270
  class Scope
259
-
271
+
260
272
  def name
261
273
  ...
262
274
  end
263
-
275
+
264
276
  # We use CreatedAtSearch class to perform the search
265
277
  def created_between
266
278
  if search_attributes[:created_between]
267
279
  CreadtedAtSearch.new(scope).search(created_between: search_attributes[:created_between])
268
280
  end
269
281
  end
270
-
282
+
271
283
  def category
272
284
  ...
273
285
  end
274
-
286
+
275
287
  end
276
288
  end
277
289
  ```
278
290
 
291
+ ## Usage with Rails
292
+
293
+ ### Forms
294
+
295
+ Define a custom form:
296
+
297
+ ```haml
298
+ # app/views/products/_search.html.haml
299
+
300
+ = form_tag products_path, method: :get do
301
+ = text_field_tag 'name'
302
+ = select_tag 'category', options_from_collection_for_select(@categories, 'id', 'name')
303
+ = date_field_tag 'created_between[start_date]'
304
+ = date_field_tag 'created_between[end_date]'
305
+ = submit_tag :search
306
+ ```
307
+
308
+ ### Controllers
309
+
310
+ Create a new instance of your search class and pass a collection to which all search conditions will be applied and specify the search params you want to apply:
311
+
312
+ ```ruby
313
+ # app/controllers/products_controller.rb
314
+
315
+ class ProductsController < ApplicationController
316
+ def index
317
+ @products = ProductSearch.new(current_user.products).search(search_params)
318
+ end
319
+
320
+ protected
321
+ def search_params
322
+ params.permit(:name, :category, created_between: [:start_date, :end_date])
323
+ end
324
+ end
325
+ ```
326
+ - Loop through the search results on your view.
327
+
328
+ ```haml
329
+ # app/views/products/index.html.haml
330
+
331
+ %h1 Products
332
+
333
+ %ul
334
+ - @products.each do |product|
335
+ %li
336
+ = "#{product.name} - #{product.price} - #{product.category}"
337
+ ```
338
+
279
339
  ## Testing
280
340
 
281
341
  This is a list of things you should test when creating a search class:
data/Rakefile CHANGED
@@ -8,4 +8,4 @@ Rake::TestTask.new do |t|
8
8
  t.verbose = true
9
9
  end
10
10
 
11
-
11
+ task :default => :test
@@ -2,6 +2,7 @@ require "lupa/version"
2
2
 
3
3
  module Lupa
4
4
  DefaultScopeError = Class.new(StandardError)
5
+ DefaultSearchAttributesError = Class.new(StandardError)
5
6
  ScopeMethodNotImplementedError = Class.new(NotImplementedError)
6
7
  ResultMethodNotImplementedError = Class.new(NotImplementedError)
7
8
  SearchAttributesError = Class.new(StandardError)
@@ -314,9 +314,18 @@ module Lupa
314
314
  #
315
315
  # Sets @search_attributes by merging default search attributes with the ones passed to search method.
316
316
  def set_search_attributes(attributes)
317
+ attributes = merge_search_attributes(attributes)
317
318
  attributes = symbolize_keys(attributes)
318
319
  attributes = remove_blank_attributes(attributes)
319
- @search_attributes = default_search_attributes.merge(attributes)
320
+
321
+ @search_attributes = attributes
322
+ end
323
+
324
+ # Internal: Merge search attributes with default search attributes
325
+ def merge_search_attributes(attributes)
326
+ return default_search_attributes.merge(attributes) if default_search_attributes.kind_of?(Hash)
327
+
328
+ raise Lupa::DefaultSearchAttributesError, "default_search_attributes doesn't return a Hash."
320
329
  end
321
330
 
322
331
  # Internal: Symbolizes all keys passed to the search attributes.
@@ -1,3 +1,3 @@
1
1
  module Lupa
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
@@ -32,6 +32,22 @@ class ClassWithoutDefaultSearchAttributesSearch < Lupa::Search
32
32
 
33
33
  end
34
34
 
35
+ class ClassWithInvalidDefaultSearchAttributesSearch < Lupa::Search
36
+
37
+ class Scope
38
+ def reverse; end
39
+ end
40
+
41
+ def initialize(scope = [1, 2, 3, 4])
42
+ @scope = scope
43
+ end
44
+
45
+ def default_search_attributes
46
+ 1
47
+ end
48
+
49
+ end
50
+
35
51
 
36
52
  describe Lupa::Search do
37
53
  before do
@@ -61,6 +77,12 @@ describe Lupa::Search do
61
77
  search.default_search_attributes.must_equal params
62
78
  end
63
79
  end
80
+
81
+ context 'when default_search_attributes does not return a Hash' do
82
+ it 'raises a Lupa::DefaultSearchAttributesError exception' do
83
+ proc { ClassWithInvalidDefaultSearchAttributesSearch.search({}).results }.must_raise Lupa::DefaultSearchAttributesError
84
+ end
85
+ end
64
86
  end
65
87
 
66
88
  describe '#results' do
@@ -1,3 +1,6 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
1
4
  require 'minitest/autorun'
2
5
 
3
6
  def context(*args, &block)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lupa
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezequiel Delpero
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-08 00:00:00.000000000 Z
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -61,6 +61,8 @@ extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
63
  - .gitignore
64
+ - .travis.yml
65
+ - CHANGELOG.md
64
66
  - Gemfile
65
67
  - LICENSE.txt
66
68
  - README.md