queryable 2.0.0 → 2.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: 28570cfafe1680583b92ea618a85cbca197f5c4b
4
- data.tar.gz: 981e0042933205c1bf4c10daa8db4dcecec540f0
3
+ metadata.gz: d8c4dc189756585db85f2f5b335744291f4df89c
4
+ data.tar.gz: b23cb30e1e3030e1c3690110c44bb43372c97495
5
5
  SHA512:
6
- metadata.gz: ecfd3bb32c31a300bd768cbf82d5f42628e1012259de2df4c174d68ad2ba368d2db4a0666dfb482ff7a94391dedbef9c6e658c3fba19a62c14ee2ff9fd2119ae
7
- data.tar.gz: 318dea62093ecd3e8defe4e3b87bbf0b0a5169980164d5597e1ed51bfe06193a731d577bcf05a029b96fecd3939c518ac910e970e0606258ea44c31627831d91
6
+ metadata.gz: 2d9965e1bdeb3f9b542813a7f87c50cd45651c27ee0317e39940fddf780c4c355eba91bab4c69171c3e174564b538b4fbc55978ebcb4ca52536cabfae656e3fd
7
+ data.tar.gz: 69bc201f009943a2b2864a62bdfb37d30be70e64385b1f4e118d5a09b096e0920ef71a4ef6f3c05cbef817813896b12d81e2ac94cbc349fa69885c25e24f8870
data/README.md CHANGED
@@ -2,15 +2,41 @@ Queryable
2
2
  =====================
3
3
  [![Gem Version](https://badge.fury.io/rb/queryable.svg)](http://badge.fury.io/rb/queryable)
4
4
  [![Build Status](https://travis-ci.org/ElMassimo/queryable.svg)](https://travis-ci.org/ElMassimo/queryable)
5
- [![Coverage Status](https://coveralls.io/repos/ElMassimo/queryable/badge.png)](https://coveralls.io/r/ElMassimo/queryable)
5
+ [![Code Climate](https://codeclimate.com/github/ElMassimo/queryable.png)](https://codeclimate.com/github/ElMassimo/queryable)
6
6
  [![Inline docs](http://inch-ci.org/github/ElMassimo/queryable.svg)](http://inch-ci.org/github/ElMassimo/queryable)
7
- <!-- [![Code Climate](https://codeclimate.com/github/ElMassimo/queryable.png)](https://codeclimate.com/github/ElMassimo/queryable) -->
7
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ElMassimo/queryable/blob/master/LICENSE.txt)
8
+ <!-- [![Coverage Status](https://coveralls.io/repos/ElMassimo/queryable/badge.png)](https://coveralls.io/r/ElMassimo/queryable) -->
8
9
 
9
10
  Queryable is a mixin that allows you to easily define query objects with chainable scopes.
10
11
 
12
+ ### Scopes
13
+
14
+ Scopes serve to encapsulate reusable business rules, a method is defined with
15
+ the selected name and block (or proc)
16
+
17
+ ### Scopeable Methods
18
+
19
+ While scopes are great because of their terseness, they can be limiting because
20
+ the block executes in the context of the internal query, so methods, constants,
21
+ and variables of the Queryable are not accessible.
22
+
23
+ For those cases, you can use a normal method, and then `scope` it. Queryable
24
+ will take care of setting the return value of the method as the internal query,
25
+ and return `self` at the end to make the method chainable.
26
+
27
+ ### Delegation
28
+
29
+ By default most Array methods are delegated to the internal query. It's possible
30
+ to delegate extra methods to the query by calling `delegate`.
31
+ ```ruby
32
+ def CustomersQuery
33
+ delegate :update_all, :destroy_all
34
+ end
35
+ ```
36
+
11
37
  ## Usage
12
38
  ```ruby
13
- class CustomerQuery
39
+ class CustomersQuery
14
40
  include Queryable
15
41
 
16
42
  scope(:recent) { desc(:logged_in_at) }
@@ -29,34 +55,23 @@ class CustomerQuery
29
55
  favourite_brand(:beer, :Miller)
30
56
  end
31
57
 
58
+ scope def search(field_values)
59
+ field_values.inject(customers) { |customers, (field, value)|
60
+ customers.where(field => /#{value}/i)
61
+ }
62
+ end
63
+
32
64
  def search_in_current(field_values)
33
- define_query do |customers|
34
- field_values.inject(customers) { |customers, (field, value)|
35
- customers.where(field => /#{value}/i)
36
- }
37
- end.current
65
+ search(field_values).current
38
66
  end
67
+
68
+ scope :search_in_current
39
69
  end
40
70
 
41
71
 
42
72
  CustomerQuery.new(shop.customers).miller_fans.search_in_current(last_name: 'M')
43
73
  ```
44
74
 
45
- ### Scopes
46
-
47
- Scopes serve to encapsulate reusable business rules, a method is defined with
48
- the selected name and block (or proc)
49
-
50
- ### Define Query
51
-
52
- While scopes are great because of their terseness, they can be limiting because
53
- the block executes in the context of the internal query, so methods, constants,
54
- and variables of the Queryable are not accessible.
55
-
56
- For those cases, you can use `define_query`, which is a convenience setter for
57
- the internal query, that also takes care of returning `self` at the end of the
58
- call to make the methods chainable.
59
-
60
75
  ## Advantages
61
76
 
62
77
  * Query objects are easy to understand.
@@ -69,6 +84,97 @@ You can check the [specs](https://github.com/ElMassimo/queryable/tree/master/spe
69
84
  to check how to test query objects without even having to require the ORM/ODM, or
70
85
  you can test by requiring your ORM/ODM and executing queries as usual.
71
86
 
87
+ ## Optional Modules
88
+ Besides Queryable, there are two opt-in modules that can help you when creating
89
+ query objects. These modules would need to be manually required during app
90
+ initialization or wherever necessary (in Rails, config/initializers).
91
+
92
+ ### DefaultQuery
93
+ Provides default initialization for query objects, by attempting to infer the
94
+ class name of the default collection for the query, and it also provides a
95
+ `queryable` method to specify it.
96
+
97
+ ```ruby
98
+ require 'queryable/default_query'
99
+
100
+ def CustomersQuery
101
+ include Queryable
102
+ include Queryable::DefaultQuery
103
+ end
104
+
105
+ def OldCustomersQuery < CustomersQuery
106
+ queryable ArchivedCustomers
107
+ end
108
+
109
+ CustomersQuery.new.queryable == Customer.all
110
+ OldCustomersQuery.new.queryable == ArchivedCustomers.all
111
+ ```
112
+ If you want to use common base objects for your queries, you may want want to
113
+ delay the automatic inference:
114
+ ```ruby
115
+ class BaseQuery
116
+ include Queryable
117
+ include Queryable::DefaultQuery
118
+
119
+ queryable false
120
+ end
121
+
122
+ class CustomersQuery < BaseQuery
123
+ end
124
+
125
+ CustomersQuery.new.queryable == Customer.all
126
+ ```
127
+
128
+ ### DefaultScope
129
+ Allows to define default scopes in query objects, and inherit them in query
130
+ object subclasses.
131
+
132
+ ```ruby
133
+ require 'queryable/default_scope'
134
+
135
+ def CustomersQuery
136
+ include Queryable
137
+ include Queryable::DefaultScope
138
+ include Queryable::DefaultQuery
139
+
140
+ default_scope :active
141
+ scope :active, -> { where(:last_purchase.gt => 7.days.ago) }
142
+ end
143
+
144
+ def BigCustomersQuery < CustomersQuery
145
+ default_scope :big_spender
146
+ scope :big_spender, -> { where(:total_expense.gt => 9999999) }
147
+ end
148
+
149
+ CustomersQuery.new.queryable == Customer.where(:last_purchase.gt => 7.days.ago)
150
+
151
+ BigCustomersQuery.new.queryable ==
152
+ Customer.where(:last_purchase.gt => 7.days.ago, :total_expense.gt => 9999999)
153
+ ```
154
+
155
+ ### Notes
156
+ To avoid repetition, it's a good idea to create a `BaseQuery` object
157
+ to contain both the modules inclusion, and common scopes you may reuse.
158
+
159
+ ```ruby
160
+ require 'queryable/default_query'
161
+ require 'queryable/default_scope'
162
+
163
+ def BaseQuery
164
+ include Queryable
165
+ include Queryable::DefaultScope
166
+ include Queryable::DefaultQuery
167
+
168
+ queryable false
169
+
170
+ scope :recent, ->{ where(:created_at.gt => 1.week.ago) }
171
+ end
172
+
173
+ def CustomersQuery < BaseQuery
174
+ ...
175
+ end
176
+ ```
177
+
72
178
  ## RDocs
73
179
 
74
180
  You can view the **Queryable** documentation in RDoc format here:
@@ -18,7 +18,8 @@ module Queryable
18
18
  base.extend ClassMethods
19
19
  base.class_eval do
20
20
  # Public: Gets/Sets the internal query.
21
- attr_accessor :query
21
+ attr_accessor :queryable
22
+ alias_method :query, :queryable
22
23
 
23
24
  # Internal: Delegates Array and Criteria methods to the internal query.
24
25
  delegate *Queryable.default_delegated_methods
@@ -29,7 +30,7 @@ module Queryable
29
30
  #
30
31
  # query - The internal query to build upon.
31
32
  def initialize(query)
32
- @query = query.all
33
+ @queryable = query.all
33
34
  end
34
35
 
35
36
  # Internal: Contains the Queryable class methods.
@@ -37,7 +38,7 @@ module Queryable
37
38
 
38
39
  # Public: Delegates the specified methods to the internal query.
39
40
  def delegate(*methods)
40
- methods.last.is_a?(Hash) ? super : def_delegators(:query, *methods)
41
+ methods.last.is_a?(Hash) ? super : def_delegators(:queryable, *methods)
41
42
  end
42
43
 
43
44
  # Public: Defines a new scope method, or makes an existing method chainable.
@@ -83,7 +84,7 @@ module Queryable
83
84
  # the context of the internal query object, and returns self.
84
85
  def define_scope(name, proc)
85
86
  define_method(name) do |*args|
86
- @query = query.instance_exec *args, &proc
87
+ @queryable = queryable.instance_exec *args, &proc
87
88
  self
88
89
  end
89
90
  end
@@ -103,7 +104,7 @@ module Queryable
103
104
  def self.scope_method(name)
104
105
  <<-SCOPE
105
106
  def #{name}(*args)
106
- @query = super
107
+ @queryable = super
107
108
  self
108
109
  end
109
110
  SCOPE
@@ -28,12 +28,14 @@ module Queryable
28
28
  queryable_class.all
29
29
  end
30
30
 
31
- # Internal: The default table or collection for this query object.
32
- # Provides a default based on a convention of the query object name.
31
+ # Internal: Attempts to use the parent query collection (if any), and
32
+ # provides a default based on a convention of the query object name.
33
33
  def queryable_class
34
- @queryable_class ||= if superclass.respond_to?(:queryable_class)
34
+ unless defined?(@queryable_class)
35
+ @queryable_class = superclass.respond_to?(:queryable_class) &&
35
36
  superclass.queryable_class || Object.const_get(name.gsub('sQuery', ''))
36
37
  end
38
+ @queryable_class
37
39
  end
38
40
  end
39
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: queryable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Máximo Mussini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-12 00:00:00.000000000 Z
11
+ date: 2014-08-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Queryable is a module that encapsulates query building so you don't have
14
14
  to tuck scopes inside your models.
@@ -49,3 +49,4 @@ signing_key:
49
49
  specification_version: 4
50
50
  summary: Keep your scopes and queries flexible by using Ruby
51
51
  test_files: []
52
+ has_rdoc: