queryable_with 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,5 @@
1
+ = QueryableWith Changelog
2
+
3
+ == 0.1.0
4
+
5
+ * First release. Supports query_set, queryable_with, and default_scope.
data/README.rdoc ADDED
@@ -0,0 +1,88 @@
1
+ = QueryableWith
2
+
3
+ QueryableWith is an ActiveRecord library for creating and combining reusable sets of scopes. Instead of building up
4
+ your query using if-conditions checking for the existence of certain parameters--a common use case in reporting and
5
+ controller query logic--QueryableWith combines them together, and only uses the ones the params you pass need.
6
+
7
+ For example,
8
+
9
+ class User < ActiveRecord::Base
10
+ named_scope :born_after, lambda {|date|
11
+ { :conditions => ["birthdate >= ?", date] }
12
+ }
13
+
14
+ named_scope :active, :conditions => { :active => true }
15
+
16
+ query_set :filter do
17
+ add_scope :active
18
+ queryable_with :email
19
+ queryable_with(:born_after) { |d| Date.parse(d) }
20
+ end
21
+ end
22
+
23
+ will add a method, <tt>User.filter</tt>, that knows how to filter on the <tt>email</tt> and <tt>born_after</tt>
24
+ parameters by, respectively, performing an equality search against that column, and using the defined name
25
+ scope (after passing the given date value, in this case a string, through the block). It will always add the
26
+ <tt>active</tt> scope. For example,
27
+
28
+ User.filter
29
+ #=> User.active
30
+
31
+ User.filter(:email => "gthreepwood@melee.gov")
32
+ #=> User.active.scoped(:conditions => { :email => "gthreepwood@melee.gov"})
33
+
34
+ User.filter(:born_after => "10/4/2010")
35
+ #=> User.active.born_after(#<Date: 4910947/2,0,2299161>)
36
+
37
+ See QueryableWith::ClassMethods#query_set for more information.
38
+
39
+ == Another Example
40
+
41
+ class User < ActiveRecord::Base
42
+ query_set :search do
43
+ # If queried by :name, execute a LIKE query on both the :first_name and :last_name columns.
44
+ # User.scoped(:conditions => ["(users.first_name LIKE ?) OR (users.last_name LIKE ?)", ...])
45
+ queryable_with :name, :columns => [ :first_name, :last_name ], :wildcard => true
46
+
47
+ # If queried by :username, execute a LIKE query on the the email column.
48
+ # User.scoped(:conditions => ["(users.email LIKE ?)", ...])
49
+ queryable_with :username, :column => :email, :wildcard => true
50
+ end
51
+ end
52
+
53
+ User.search(:name => ["Guy", "Three"])
54
+ #=> User.scoped(:conditions => ["(users.first_name LIKE ?) OR (users.last_name LIKE ?) OR ...", "%Guy%", "%Three%", "%Guy%", "%Three%"]
55
+
56
+ User.search(:username => "gthree")
57
+ #=> User.scoped(:conditions => { :email => "%gthree%"})
58
+
59
+ == Installation and usage
60
+
61
+ QueryableWith is available as a gem. It has a dependency on ActiveRecord, which it will automatically extend with
62
+ the necessary class methods when required. It is not yet compatible with Rails3.
63
+
64
+ gem install queryable_with
65
+ require 'queryable_with'
66
+
67
+ == License
68
+
69
+ Copyright (c) 2010 Brian Guthrie
70
+
71
+ Permission is hereby granted, free of charge, to any person obtaining
72
+ a copy of this software and associated documentation files (the
73
+ "Software"), to deal in the Software without restriction, including
74
+ without limitation the rights to use, copy, modify, merge, publish,
75
+ distribute, sublicense, and/or sell copies of the Software, and to
76
+ permit persons to whom the Software is furnished to do so, subject to
77
+ the following conditions:
78
+
79
+ The above copyright notice and this permission notice shall be
80
+ included in all copies or substantial portions of the Software.
81
+
82
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
83
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
84
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
85
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
86
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
87
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
88
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+
4
+ require 'spec'
5
+ require 'spec/rake/spectask'
6
+
7
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
8
+ require "queryable_with/version"
9
+
10
+ task :default => :spec
11
+
12
+ Spec::Rake::SpecTask.new do |t|
13
+ t.spec_opts = ['--colour', '--format progress', '--backtrace']
14
+ end
15
+
16
+ Rake::RDocTask.new do |rd|
17
+ rd.main = "README.rdoc"
18
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
19
+ end
20
+
21
+ namespace :gem do
22
+ task :clean do
23
+ system "rm -f *.gem"
24
+ end
25
+
26
+ task :build => :clean do
27
+ system "gem build queryable_with.gemspec"
28
+ end
29
+
30
+ task :release => :build do
31
+ system "gem push queryable_with-#{QueryableWith::Version::STRING}"
32
+ end
33
+ end
@@ -0,0 +1,194 @@
1
+ require 'active_record'
2
+
3
+ # See README.rdoc for an extended introduction. The QueryableWith::ClassMethods#query_set,
4
+ # QueryableWith::QuerySet#queryable_with and QueryableWith::QuerySet#add_scope methods may also
5
+ # be of interest.
6
+ module QueryableWith
7
+
8
+ def self.included(active_record) # :nodoc:
9
+ active_record.send :extend, QueryableWith::ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def query_sets # :nodoc:
14
+ read_inheritable_attribute(:query_sets) || write_inheritable_hash(:query_sets, {})
15
+ end
16
+
17
+ # Defines a query set with the given name. This has the effect of defining a method that calls
18
+ # every implicit or explicit scope added to that query set.
19
+ #
20
+ # When a block is given, that block is evaluated in the context of either a newly-created query
21
+ # set or (in the case of inherited classes) the pre-existing set of that name. See
22
+ # QueryableWith::QuerySet#queryable_with and QueryableWith::QuerySet#add_scope for more details.
23
+ #
24
+ # When <tt>parent</tt> is given as an option, the new query set will inherit all of the scopes from
25
+ # the named parent.
26
+ def query_set(set_name, options={}, &block) # :yields:
27
+ set = query_set_for(set_name, options).tap { |s| s.instance_eval(&block) if block_given? }
28
+
29
+ class_eval <<-RUBY
30
+ def self.#{set_name}(params={})
31
+ self.query_sets["#{set_name}"].query(self, params)
32
+ end
33
+ RUBY
34
+ end
35
+
36
+ protected
37
+
38
+ def query_set_for(set_name, options) # :nodoc:
39
+ query_sets[set_name.to_s] || query_sets.store(set_name.to_s, QueryableWith::QuerySet.new(options))
40
+ end
41
+ end
42
+
43
+ class QuerySet
44
+
45
+ def initialize(options={}) # :nodoc:
46
+ @queryables = []
47
+
48
+ if options.has_key?(:parent)
49
+ @queryables << QueryableWith::ImplicitScopeParameter.new(options[:parent])
50
+ end
51
+ end
52
+
53
+ # Make this QuerySet queryable with the named parameter(s). If no other options are given,
54
+ # this will result in a query on either the column or (if defined) scope of the same
55
+ # name of the base scope and values passed to #query. It also accepts the following options:
56
+ #
57
+ # * <tt>scope</tt> - Map the incoming parameter to this scope. The argument by be a symbol (name of the
58
+ # scope), a Hash (scope conditions) or a lambda.
59
+ # * <tt>column</tt> - Map the incoming parameter to this column.
60
+ # * <tt>default</tt> - Default the incoming parameter to this value even if it isn't provided.
61
+ # * <tt>wildcard</tt> - If true, generate a SQL LIKE query with the incoming parameter. Used only
62
+ # if the <tt>scope</tt> option is absent or a block is not provided.
63
+ # * <tt>allow_blank</tt> - If true, treat incoming parameters mapped to nil or a blank string as
64
+ # IS NULL for the purposes of SQL query generation. Used only if the <tt>scope</tt> option is absent.
65
+ #
66
+ # If a block is provided, incoming parameters to the query will be passed through that function first.
67
+ # For example,
68
+ #
69
+ # queryable_with(:company_name, :scope => :by_company) do |name|
70
+ # Company.find_by_name(name)
71
+ # end
72
+ #
73
+ # will attempt to look up a company name first, then pass it to a pre-defined scope called
74
+ # <tt>by_company</tt>.
75
+ def queryable_with(*expected_parameters, &block)
76
+ options = expected_parameters.extract_options!
77
+
78
+ @queryables += expected_parameters.map do |parameter|
79
+ QueryableWith::QueryableParameter.new(parameter, options, &block)
80
+ end
81
+ end
82
+
83
+ # Add a scope that is always applied to any calls to #query. This may be a symbol (the name of
84
+ # the scope to add), a Hash (scope conditions) or a lambda. Useful when, for example, you only
85
+ # ever want to see records with an <tt>active</tt> flag set to true.
86
+ #
87
+ # add_scope :active
88
+ # add_scope :conditions => { :active => true }
89
+ def add_scope(scope)
90
+ @queryables << QueryableWith::ImplicitScopeParameter.new(scope)
91
+ end
92
+
93
+ # Applies all of the defined queryable and added scopes in this query set to the given base scope
94
+ # (usually an ActiveRecord class, but can also be a pre-existing NamedScope object) based on the
95
+ # query parameters and returns a new scope, ready to be queried.
96
+ def query(base_scope, params={}) # :nodoc:
97
+ @queryables.inject(base_scope) do |scope, queryer|
98
+ queryer.query(scope, params)
99
+ end.scoped({})
100
+ end
101
+
102
+ end
103
+
104
+ class ImplicitScopeParameter # :nodoc:
105
+
106
+ def initialize(scope)
107
+ @scope = scope
108
+ end
109
+
110
+ def query(queryer, params={})
111
+ if @scope.is_a? Symbol
112
+ queryer.send @scope, params
113
+ else
114
+ queryer.scoped @scope
115
+ end
116
+ end
117
+
118
+ end
119
+
120
+ class QueryableParameter # :nodoc:
121
+ attr_reader :expected_parameter, :column_name
122
+
123
+ def initialize(expected_parameter, options={}, &block)
124
+ @scope, @wildcard, @default_value, @allow_blank = options.values_at(:scope, :wildcard, :default, :allow_blank)
125
+ @expected_parameter = expected_parameter.to_sym
126
+ @column_name = options[:column] || @expected_parameter.to_s
127
+ @value_mapper = block || lambda {|o| o}
128
+ end
129
+
130
+ def scoped?; !@scope.blank?; end
131
+ def wildcard?; @wildcard == true; end
132
+ def blank_allowed?; @allow_blank == true; end
133
+ def has_default?; !@default_value.nil?; end
134
+ def scope_name; @scope || self.expected_parameter; end
135
+
136
+ def query(queryer, params={})
137
+ params = params.with_indifferent_access
138
+ params_contain_queryable_value, queried_value = determine_queried_value(params[@expected_parameter])
139
+
140
+ return queryer unless params_contain_queryable_value
141
+ queried_value = @value_mapper.call(queried_value)
142
+
143
+ if scoped? || queryer_scoped?(queryer)
144
+ queryer.send scope_name, queried_value
145
+ else
146
+ queryer.scoped(:conditions => conditions_for(queryer, queried_value))
147
+ end
148
+ end
149
+
150
+ protected
151
+
152
+ def determine_queried_value(value_in_params)
153
+ if value_in_params.blank? && value_in_params != false
154
+ if blank_allowed?
155
+ return true, nil
156
+ elsif has_default?
157
+ return true, @default_value
158
+ else
159
+ return false, nil
160
+ end
161
+ else
162
+ return true, value_in_params
163
+ end
164
+ end
165
+
166
+ def queryer_scoped?(queryer)
167
+ queryer.scopes.keys.include?(@expected_parameter)
168
+ end
169
+
170
+ def conditions_for(queryer, value)
171
+ query_string = if wildcard?
172
+ "(#{queryer.table_name}.#{self.column_name} LIKE ?)"
173
+ else
174
+ "(#{queryer.table_name}.#{self.column_name} = ?)"
175
+ end
176
+
177
+ final_values = [ value ].flatten.map do |value|
178
+ wildcard? ? "%#{value}%" : value
179
+ end
180
+
181
+ final_query_string = ( [ query_string ] * final_values.size ).join(" OR ")
182
+
183
+ [ final_query_string ] + final_values
184
+ end
185
+
186
+ end
187
+
188
+ end
189
+
190
+ module ActiveRecord # :nodoc:
191
+ class Base # :nodoc:
192
+ include QueryableWith
193
+ end
194
+ end
@@ -0,0 +1,9 @@
1
+ module QueryableWith #:nodoc:
2
+ module Version #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,239 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ describe QueryableWith do
4
+ before :each do
5
+ User.delete_all
6
+ User.query_sets.clear
7
+ end
8
+
9
+ it "includes itself in ActiveRecord" do
10
+ ActiveRecord::Base.ancestors.should include(QueryableWith)
11
+ end
12
+
13
+ describe "query_set" do
14
+ it "exposes a new method named after the defined query set" do
15
+ User.query_set :test
16
+ User.methods.should include("test")
17
+ end
18
+
19
+ it "returns a scope that points to an empty result set if the query set is empty" do
20
+ User.query_set :test
21
+ User.test.should == [ ]
22
+ end
23
+
24
+ describe ":parent => [query_set_name]" do
25
+ it "applies a parent set that adds a scope" do
26
+ User.query_set(:test) { add_scope(:conditions => { :active => true }) }
27
+ User.query_set(:supertest, :parent => :test) { add_scope(:conditions => { :name => "Guybrush" }) }
28
+
29
+ active_guy = User.create! :name => "Guybrush", :active => true
30
+ inactive_guy = User.create! :name => "Guybrush", :active => false
31
+
32
+ User.supertest.should == [ active_guy ]
33
+ end
34
+
35
+ it "applies a parent set that is itself queryable" do
36
+ User.query_set(:test) { queryable_with(:name) }
37
+ User.query_set(:supertest, :parent => :test) { add_scope(:conditions => { :active => true }) }
38
+
39
+ active_guy = User.create! :name => "Guybrush", :active => true
40
+ inactive_guy = User.create! :name => "Guybrush", :active => false
41
+ active_gal = User.create! :name => "Elaine", :active => true
42
+
43
+ User.supertest(:name => "Guybrush").should == [ active_guy ]
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "queryable_with" do
49
+ it "maps a parameter directly to a column" do
50
+ guybrush = User.create! :name => "Guybrush"
51
+ elaine = User.create! :name => "Elaine"
52
+ User.query_set(:test) { queryable_with(:name) }
53
+
54
+ User.test(:name => "Guybrush").should == [ guybrush ]
55
+ end
56
+
57
+ it "maps multiple parameters, each to their own column" do
58
+ guybrush = User.create! :name => "Guybrush", :active => true
59
+ elaine = User.create! :name => "Elaine", :active => false
60
+ User.query_set(:test) { queryable_with(:name, :active) }
61
+
62
+ # User.test(:name => "Guybrush").should == [ guybrush ]
63
+ User.test(:active => false).should == [ elaine ]
64
+ end
65
+
66
+ it "uses the correct table name when referring to columns with potentially conflicting names" do
67
+ # The employers table also has a name column.
68
+ User.query_set(:test) { queryable_with(:name) }
69
+
70
+ lambda do
71
+ User.test(:name => "Guybrush").all(:joins => :employer)
72
+ end.should_not raise_error(ActiveRecord::StatementInvalid)
73
+ end
74
+
75
+ it "selects any one of a given list of values" do
76
+ guybrush = User.create! :name => "Guybrush"
77
+ elaine = User.create! :name => "Elaine"
78
+ User.query_set(:test) { queryable_with(:name) }
79
+
80
+ User.test(:name => ["Guybrush", "Elaine"]).should include(guybrush, elaine)
81
+ end
82
+
83
+ it "returns a scope that points to an empty result set if queried with an empty set of params" do
84
+ User.query_set(:test) { queryable_with(:name) }
85
+ User.test.should == [ ]
86
+ end
87
+
88
+ it "applies multiple parameters if multiple parameters are queried" do
89
+ active_bob = User.create! :name => "Bob", :active => true
90
+ lazy_bob = User.create! :name => "Bob", :active => false
91
+ User.query_set(:test) { queryable_with(:name, :active) }
92
+
93
+ User.test(:name => "Bob", :active => true).should == [ active_bob ]
94
+ end
95
+
96
+ it "delegates the underlying filter to a pre-existing named scope if one of that name is defined" do
97
+ guybrush = User.create! :name => "Guybrush"
98
+ User.named_scope(:naym, lambda { |name| { :conditions => { :name => name } } })
99
+ User.query_set(:test) { queryable_with(:naym) }
100
+
101
+ User.test(:naym => "Guybrush").should == [ guybrush ]
102
+ User.test(:naym => "Herrman").should == [ ]
103
+ end
104
+
105
+ it "ignores blank values" do
106
+ guybrush = User.create! :name => "Guybrush"
107
+ User.query_set(:test) { queryable_with(:name) }
108
+ User.test(:name => "").should == [ guybrush ]
109
+ User.test(:name => nil).should == [ guybrush ]
110
+ end
111
+
112
+ describe ":scope => [scope_name]" do
113
+ it "delegates the underlying filter to a pre-existing scope if passed as an option" do
114
+ guybrush = User.create! :name => "Guybrush"
115
+ User.named_scope(:naym, lambda { |name| { :conditions => { :name => name } } })
116
+ User.query_set(:test) { queryable_with(:nizame, :scope => :naym) }
117
+
118
+ User.test(:nizame => "Guybrush").should == [ guybrush ]
119
+ User.test(:nizame => "Herrman").should == [ ]
120
+ end
121
+ end
122
+
123
+ describe ":wildcard => true" do
124
+ it "wildcards the given value" do
125
+ guybrush = User.create! :name => "Guybrush"
126
+ User.query_set(:test) { queryable_with(:name, :wildcard => true) }
127
+
128
+ User.test(:name => "uybru").should == [ guybrush ]
129
+ User.test(:name => "Elaine").should == [ ]
130
+ end
131
+
132
+ it "ORs multiple wildcarded values" do
133
+ guybrush = User.create! :name => "Guybrush"
134
+ elaine = User.create! :name => "Elaine"
135
+ User.query_set(:test) { queryable_with(:name, :wildcard => true) }
136
+
137
+ User.test(:name => ["uybru", "lain"]).should include(guybrush, elaine)
138
+ end
139
+ end
140
+
141
+ describe ":column => [column_name]" do
142
+ it "maps the parameter to the given column name" do
143
+ guybrush = User.create! :name => "Guybrush"
144
+ elaine = User.create! :name => "Elaine"
145
+ User.query_set(:test) { queryable_with(:naym, :column => :name) }
146
+
147
+ User.test(:naym => "Guybrush").should == [ guybrush ]
148
+ end
149
+ end
150
+
151
+ describe ":default => [value]" do
152
+ it "provides a default value if none is given in the query" do
153
+ guybrush = User.create! :name => "Guybrush"
154
+ elaine = User.create! :name => "Elaine"
155
+ User.query_set(:test) { queryable_with(:name, :default => "Guybrush") }
156
+
157
+ User.test.should == [ guybrush ]
158
+ end
159
+ end
160
+
161
+ describe ":allow_blank => [boolean]" do
162
+ it "accepts, and queries on, blank values" do
163
+ guybrush = User.create! :name => "Guybrush"
164
+ User.query_set(:test) { queryable_with(:name, :allow_blank => true) }
165
+ User.test(:name => "").should == [ ]
166
+ User.test(:name => nil).should == [ ]
167
+ end
168
+ end
169
+
170
+ describe "with a block" do
171
+ it "permits you to transform the incoming value with a standard column lookup" do
172
+ guybrush = User.create! :name => "Guybrush"
173
+ elaine = User.create! :name => "Elaine"
174
+ User.query_set(:test) { queryable_with(:name) { |str| str.gsub(/fawkes/, "brush") } }
175
+
176
+ User.test(:name => "Guyfawkes").should == [ guybrush ]
177
+ end
178
+
179
+ it "permits you to transform the incoming value with a scope" do
180
+ guybrush1 = User.create! :name => "Guybrush", :employer => Employer.create!(:name => "Threepwood Nautical Services LLC")
181
+ guybrush2 = User.create! :name => "Guybrush", :employer => Employer.create!(:name => "LeChuck LeLumber, Inc.")
182
+
183
+ User.named_scope :by_employer, lambda { |employer|
184
+ { :conditions => { :employer_id => employer } }
185
+ }
186
+
187
+ User.query_set(:test) do
188
+ queryable_with :employer_name, :scope => :by_employer do |name|
189
+ Employer.find_by_name(name)
190
+ end
191
+ end
192
+
193
+ User.test(:employer_name => "Threepwood Nautical Services LLC").should == [ guybrush1 ]
194
+ end
195
+ end
196
+ end
197
+
198
+ describe "add_scope" do
199
+ it "adds the given named scope to every query" do
200
+ active = User.create! :active => true
201
+ inactive = User.create! :active => false
202
+ User.named_scope(:only_active, :conditions => { :active => true })
203
+ User.query_set(:test) { add_scope(:only_active) }
204
+
205
+ User.test.all.should == [ active ]
206
+ end
207
+
208
+ it "adds the given ad hoc scope to every query" do
209
+ active = User.create! :active => true
210
+ inactive = User.create! :active => false
211
+ User.query_set(:test) { add_scope(:conditions => { :active => true }) }
212
+
213
+ User.test.all.should == [ active ]
214
+ end
215
+ end
216
+
217
+ describe "(subclassed)" do
218
+ it "inherits the query sets from its superclass" do
219
+ User.query_set(:test) { add_scope(:conditions => { :active => true }) }
220
+ class Pirate < User; end
221
+ active = Pirate.create! :active => true
222
+ inactive = Pirate.create! :active => false
223
+
224
+ Pirate.test.should == [ active ]
225
+ end
226
+
227
+ it "allows query sets to be extended by the subclass" do
228
+ User.query_set(:test) { add_scope(:conditions => { :active => true }) }
229
+ class Pirate < User; end
230
+ Pirate.query_set(:test) { add_scope(:conditions => { :name => "Guybrush" }) }
231
+
232
+ active_guy = Pirate.create! :name => "Guybrush", :active => true
233
+ inactive_guy = Pirate.create! :name => "Guybrush", :active => false
234
+
235
+ Pirate.test.should == [ active_guy ]
236
+ end
237
+ end
238
+
239
+ end
@@ -0,0 +1,37 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'spec'
5
+ require 'queryable_with'
6
+
7
+ LOGFILE = File.open(File.dirname(__FILE__) + '/../tmp/database.log', 'a')
8
+ ActiveRecord::Base.logger = Logger.new(LOGFILE)
9
+ ActiveRecord::Base.configurations = true
10
+ ActiveRecord::Schema.verbose = false
11
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
12
+
13
+ ActiveRecord::Schema.define(:version => 1) do
14
+ create_table :users do |t|
15
+ t.string "name"
16
+ t.date "birthdate"
17
+ t.string "email"
18
+ t.string "join_date"
19
+ t.integer "income"
20
+ t.integer "employer_id"
21
+ t.string "type"
22
+ t.boolean "active"
23
+ end
24
+
25
+ create_table :employers do |t|
26
+ t.string "name"
27
+ t.string "email"
28
+ t.timestamps
29
+ end
30
+ end
31
+
32
+ class User < ActiveRecord::Base
33
+ belongs_to :employer
34
+ end
35
+
36
+ class Employer < ActiveRecord::Base
37
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: queryable_with
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Brian Guthrie
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-16 00:00:00 +05:30
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 0
31
+ version: 2.3.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ description: Tie query parameters to scopes, or create dynamic scopes on the fly. Define sets of reusable scopes for use in reporting and filtering.
47
+ email:
48
+ - btguthrie@gmail.com
49
+ executables: []
50
+
51
+ extensions: []
52
+
53
+ extra_rdoc_files: []
54
+
55
+ files:
56
+ - lib/queryable_with/version.rb
57
+ - lib/queryable_with.rb
58
+ - README.rdoc
59
+ - CHANGELOG
60
+ - Rakefile
61
+ has_rdoc: true
62
+ homepage: http://github.com/bguthrie/queryable_with
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options: []
67
+
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.3.6
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: An ActiveRecord library for creating reusable sets of scopes.
91
+ test_files:
92
+ - spec/queryable_with_spec.rb
93
+ - spec/spec_helper.rb