queryable 2.0.0 → 2.0.1

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.
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: