condition_builder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ *~
3
+ .DS_Store
4
+ coverage
5
+ nbproject
6
+ rdoc
7
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Peter Hoeg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,36 @@
1
+ = condition_builder
2
+
3
+ ConditionBuilder generates conditions and criteria for use in ActiveRecord .find
4
+ statements to avoid manually having to construct a string of conditions and
5
+ the releveant hash with values.
6
+
7
+ It does not support fancy dependencies between the statements as it would make
8
+ the syntax so complicated that people might as well generate the condition
9
+ string and hash themselves.
10
+
11
+ = Usage
12
+
13
+ cb = ConditionBuilder.new
14
+ # add a condition "user_id < 4" in descending order
15
+ cb.add('user_id <', 4, :desc)
16
+ # add a condition "user_location like '%abc'" in ascending order
17
+ cb.add('user_location like', '%abc', :asc)
18
+ # add a condition "department_id = 18"
19
+ cb.add('department_id = ', 18)
20
+
21
+ User.find(:all, :conditions => cb.conditions, :order => cb.order, cb.criteria)
22
+
23
+ = Website
24
+
25
+ http://github.com/peterhoeg/condition_builder
26
+
27
+ = Requirements
28
+
29
+ ConditionBuilder has been tested with the following versions
30
+
31
+ == Ruby
32
+ * 1.8.7
33
+
34
+ == Copyright
35
+
36
+ Copyright (c) 2009 Peter Hoeg. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "condition_builder"
8
+ gem.summary = "This gem assists in creating conditions and criteria for use in ActiveRecord .find statements."
9
+ gem.email = "peter@hoeg.com"
10
+ gem.homepage = "http://github.com/peterhoeg/condition_builder"
11
+ gem.authors = ["Peter Hoeg", "Northwind Technologies Pte Ltd"]
12
+ gem.rubyforge_project = "cbuilder"
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+
16
+ Jeweler::RubyforgeTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :default => :spec
34
+
35
+ require 'rake/rdoctask'
36
+ Rake::RDocTask.new do |rdoc|
37
+ if File.exist?('VERSION.yml')
38
+ config = YAML.load(File.read('VERSION.yml'))
39
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
40
+ else
41
+ version = ""
42
+ end
43
+
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = "condition_builder #{version}"
46
+ rdoc.rdoc_files.include('README*')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
49
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
@@ -0,0 +1,48 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{condition_builder}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Peter Hoeg", "Northwind Technologies Pte Ltd"]
9
+ s.date = %q{2009-07-10}
10
+ s.email = %q{peter@hoeg.com}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.rdoc"
14
+ ]
15
+ s.files = [
16
+ ".document",
17
+ ".gitignore",
18
+ "LICENSE",
19
+ "README.rdoc",
20
+ "Rakefile",
21
+ "VERSION.yml",
22
+ "condition_builder.gemspec",
23
+ "lib/condition_builder.rb",
24
+ "spec/condition_builder_spec.rb",
25
+ "spec/spec_helper.rb"
26
+ ]
27
+ s.has_rdoc = true
28
+ s.homepage = %q{http://github.com/peterhoeg/condition_builder}
29
+ s.rdoc_options = ["--charset=UTF-8"]
30
+ s.require_paths = ["lib"]
31
+ s.rubyforge_project = %q{cbuilder}
32
+ s.rubygems_version = %q{1.3.1}
33
+ s.summary = %q{This gem assists in creating conditions and criteria for use in ActiveRecord .find statements.}
34
+ s.test_files = [
35
+ "spec/condition_builder_spec.rb",
36
+ "spec/spec_helper.rb"
37
+ ]
38
+
39
+ if s.respond_to? :specification_version then
40
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
41
+ s.specification_version = 2
42
+
43
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
44
+ else
45
+ end
46
+ else
47
+ end
48
+ end
@@ -0,0 +1,91 @@
1
+ require 'json'
2
+
3
+ class ConditionBuilder
4
+
5
+ DEFAULT_KIND = :and
6
+ SUPPORTED_KINDS = [ :and, :or, :xor, :not ]
7
+
8
+ def initialize(kind = DEFAULT_KIND)
9
+ super()
10
+ set_kind(kind)
11
+ @_cond = []
12
+ @_crit = {}
13
+ @_join = []
14
+ @_ordr = []
15
+ end
16
+
17
+ # TODO: add << as an alias for add - probably need to do some splatting to handle the parms
18
+ # alias_method :'<<', :add
19
+ # See README for usage.
20
+ def add(condition, criteria, order = nil)
21
+ crit_name = condition[/^(\w|\.)+/].gsub(/\s/, '_').to_s
22
+ crit_sym = crit_name.to_sym
23
+ raise ArgumentError, 'condition already exists' if @_crit.has_key?(crit_sym)
24
+ if criteria.is_a?(Array)
25
+ @_cond << "#{condition} (:#{crit_name})"
26
+ else
27
+ @_cond << "#{condition} :#{crit_name}"
28
+ end
29
+ @_crit[crit_sym] = criteria
30
+ @_ordr << "#{crit_name} #{order.to_s.upcase}" if [ :asc, :desc ].include?(order)
31
+ end
32
+
33
+ # Add tables and fields for a simple INNER JOIN
34
+ def add_join(left_table, left_field, right_table, right_field)
35
+ # TODO: move the joins into a proper structure and only generate when it gets accessed
36
+ @_join << "INNER JOIN #{right_table} ON #{left_table}.#{left_field} = #{right_table}.#{right_field}"
37
+ end
38
+
39
+ # Returns the condition string used for the :conditions parameter. See README for usage.
40
+ def conditions
41
+ @_cond.join(@join)
42
+ end
43
+
44
+ # Returns the criteria hash. See README for usage.
45
+ def criteria
46
+ @_crit
47
+ end
48
+
49
+ # Returns the join string used for the :joins parameter. See README for usage.
50
+ def joins
51
+ @_join.join(' ')
52
+ end
53
+
54
+ # Returns the order string used for the :order parameter. See README for usage.
55
+ def order
56
+ @_ordr.join(', ')
57
+ end
58
+
59
+ # Returns the number of valid statements
60
+ def statements
61
+ return valid? ? @_cond.length : 0
62
+ end
63
+
64
+ # Returns a string representation - normally used for debugging
65
+ def to_s
66
+ "conditions: #{@_cond.to_json}, criteria: #{@_crit.to_json}, ordering: #{@_ordr.to_json}"
67
+ end
68
+
69
+ # Returns true if it will generate usable output
70
+ def valid?
71
+ @_cond.length > 0 && (@_cond.length == @_crit.length)
72
+ end
73
+
74
+ # Gets the kind of condition
75
+ def kind
76
+ @kind
77
+ end
78
+
79
+ # Sets the kind of condition
80
+ def kind=(value)
81
+ set_kind(value)
82
+ end
83
+
84
+ private
85
+ def set_kind(kind)
86
+ @kind = SUPPORTED_KINDS.include?(kind) ? kind : DEFAULT_KIND
87
+ @join = " #{@kind.to_s.upcase} "
88
+ return nil
89
+ end
90
+
91
+ end
@@ -0,0 +1,269 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ConditionBuilder do
4
+
5
+ before(:each) do
6
+ @cb = ConditionBuilder.new
7
+ end
8
+
9
+ it 'should not be valid without contents' do
10
+ @cb.should_not be_valid
11
+ end
12
+
13
+ it 'should have no statements' do
14
+ @cb.statements.should == 0
15
+ end
16
+
17
+ it 'should default kind to :and' do
18
+ @cb.kind.should == :and
19
+ end
20
+
21
+ it 'should have default kind as part of list of supported kinds - NOTE: is this too internal to test??' do
22
+ ConditionBuilder::SUPPORTED_KINDS.include?(ConditionBuilder::DEFAULT_KIND).should be_true
23
+ end
24
+
25
+ it 'should support :and, :or, :xor and :not' do
26
+ [ :and, :or, :xor, :not ].each do |kind|
27
+ @cb.kind = kind
28
+ @cb.kind.should == kind
29
+ end
30
+ end
31
+
32
+ it 'should revert to :and if given invalid input' do
33
+ @cb.kind = :xxx
34
+ @cb.kind.should == :and
35
+ end
36
+
37
+ it 'should give a basic response to .to_s' do
38
+ @cb.to_s.length.should_not == 0
39
+ end
40
+
41
+ describe 'single condition/criterion' do
42
+
43
+ before(:each) do
44
+ @cb.add('something =', 'fff')
45
+ end
46
+
47
+ it 'should be valid' do
48
+ @cb.should be_valid
49
+ end
50
+
51
+ it 'should have just one condition and criterion' do
52
+ @cb.statements.should == 1
53
+ end
54
+
55
+ it 'should generate a condition' do
56
+ @cb.conditions.should == 'something = :something'
57
+ end
58
+
59
+ it 'should generate a criterion' do
60
+ @cb.criteria[:something].should == 'fff'
61
+ end
62
+
63
+ it 'should not generate an ordering' do
64
+ @cb.order.length.should == 0
65
+ end
66
+ end
67
+
68
+ describe 'single condition/criterion with ordering' do
69
+
70
+ before(:each) do
71
+ @cb.add('something =', 'fff', :asc)
72
+ end
73
+
74
+ it 'should be valid' do
75
+ @cb.should be_valid
76
+ end
77
+
78
+ it 'should have just one condition and criterion' do
79
+ @cb.statements.should == 1
80
+ end
81
+
82
+ it 'should generate a condition' do
83
+ @cb.conditions.should == 'something = :something'
84
+ end
85
+
86
+ it 'should generate a criterion' do
87
+ @cb.criteria[:something].should == 'fff'
88
+ end
89
+
90
+ it 'should generate an ordering' do
91
+ @cb.order.should == 'something ASC'
92
+ end
93
+ end
94
+
95
+ describe 'being passed an array' do
96
+
97
+ before(:each) do
98
+ @cb.add('something in', [ 1, 2, 3 ])
99
+ end
100
+
101
+ it 'should be valid' do
102
+ @cb.should be_valid
103
+ end
104
+
105
+ it 'should have just one condition and criterion' do
106
+ @cb.statements.should == 1
107
+ end
108
+
109
+ it 'should generate a condition' do
110
+ @cb.conditions.should == 'something in (:something)'
111
+ end
112
+
113
+ it 'should generate a criterion' do
114
+ @cb.criteria[:something].should == [1, 2, 3]
115
+ end
116
+
117
+ end
118
+
119
+ describe 'multiple conditions/criteria' do
120
+
121
+ before(:each) do
122
+ @cb.add('something =', 'fff')
123
+ @cb.add('something_else >', 123)
124
+ end
125
+
126
+ it 'should be valid' do
127
+ @cb.should be_valid
128
+ end
129
+
130
+ it 'should have two conditions and criteria' do
131
+ @cb.statements.should == 2
132
+ end
133
+
134
+ it 'should generate conditions' do
135
+ @cb.conditions.should == 'something = :something AND something_else > :something_else'
136
+ end
137
+
138
+ it 'should generate criteria' do
139
+ @cb.criteria[:something].should == 'fff'
140
+ @cb.criteria[:something_else].should == 123
141
+ end
142
+
143
+ describe 'experiencing duplicate conditions' do
144
+
145
+ it 'should raise exception on duplicate conditions' do
146
+ lambda {
147
+ @cb.add('something =', 'ggg')
148
+ }.should raise_error(ArgumentError)
149
+ @cb.statements.should == 2
150
+ end
151
+ end
152
+
153
+ describe 'as type :or' do
154
+
155
+ before(:each) do
156
+ @cb.kind = :or
157
+ end
158
+
159
+ it 'should generate conditions' do
160
+ @cb.conditions.should == 'something = :something OR something_else > :something_else'
161
+ end
162
+
163
+ it 'should generate criteria' do
164
+ @cb.criteria[:something].should == 'fff'
165
+ @cb.criteria[:something_else].should == 123
166
+ end
167
+ end
168
+
169
+ describe 'as type :xor' do
170
+
171
+ before(:each) do
172
+ @cb.kind = :xor
173
+ end
174
+
175
+ it 'should generate conditions' do
176
+ @cb.conditions.should == 'something = :something XOR something_else > :something_else'
177
+ end
178
+
179
+ it 'should generate criteria' do
180
+ @cb.criteria[:something].should == 'fff'
181
+ @cb.criteria[:something_else].should == 123
182
+ end
183
+ end
184
+
185
+ describe 'as type :not' do
186
+
187
+ before(:each) do
188
+ @cb.kind = :not
189
+ end
190
+
191
+ it 'should generate conditions' do
192
+ @cb.conditions.should == 'something = :something NOT something_else > :something_else'
193
+ end
194
+
195
+ it 'should generate criteria' do
196
+ @cb.criteria[:something].should == 'fff'
197
+ @cb.criteria[:something_else].should == 123
198
+ end
199
+ end
200
+ end
201
+
202
+ describe 'multiple conditions/criteria with ordering' do
203
+
204
+ before(:each) do
205
+ @cb.add('something =', 'fff', :asc)
206
+ @cb.add('something_else >', 123, :desc)
207
+ end
208
+
209
+ it 'should be valid' do
210
+ @cb.should be_valid
211
+ end
212
+
213
+ it 'should have two conditions and criteria' do
214
+ @cb.statements.should == 2
215
+ end
216
+
217
+ it 'should generate conditions' do
218
+ @cb.conditions.should == 'something = :something AND something_else > :something_else'
219
+ end
220
+
221
+ it 'should generate criteria' do
222
+ @cb.criteria[:something].should == 'fff'
223
+ @cb.criteria[:something_else].should == 123
224
+ end
225
+
226
+ it 'should generate an ordering' do
227
+ @cb.order.should == 'something ASC, something_else DESC'
228
+ end
229
+ end
230
+
231
+ describe 'with table names' do
232
+
233
+ before(:each) do
234
+ @cb.add('some.thing =', 'fff')
235
+ @cb.add('some.thing._else >', 123)
236
+ end
237
+
238
+ it 'should be valid' do
239
+ @cb.should be_valid
240
+ end
241
+
242
+ it 'should have two conditions and criteria' do
243
+ @cb.statements.should == 2
244
+ end
245
+
246
+ it 'should generate conditions' do
247
+ @cb.conditions.should == 'some.thing = :some.thing AND some.thing._else > :some.thing._else'
248
+ end
249
+
250
+ it 'should generate criteria' do
251
+ @cb.criteria[:'some.thing'].should == 'fff'
252
+ @cb.criteria[:'some.thing._else'].should == 123
253
+ end
254
+ end
255
+
256
+ describe 'joins' do
257
+
258
+ it 'a single join' do
259
+ @cb.add_join('table_a', 'field_a', 'table_b', 'field_b')
260
+ @cb.joins.should == 'INNER JOIN table_b ON table_a.field_a = table_b.field_b'
261
+ end
262
+
263
+ it 'multiple joins' do
264
+ @cb.add_join('table_a', 'field_a', 'table_b', 'field_b')
265
+ @cb.add_join('table_X', 'field_X', 'table_Y', 'field_Y')
266
+ @cb.joins.should == 'INNER JOIN table_b ON table_a.field_a = table_b.field_b INNER JOIN table_Y ON table_X.field_X = table_Y.field_Y'
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec'
2
+
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ require 'condition_builder'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: condition_builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Hoeg
8
+ - Northwind Technologies Pte Ltd
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-07-10 00:00:00 +08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description:
18
+ email: peter@hoeg.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - LICENSE
25
+ - README.rdoc
26
+ files:
27
+ - .document
28
+ - .gitignore
29
+ - LICENSE
30
+ - README.rdoc
31
+ - Rakefile
32
+ - VERSION.yml
33
+ - condition_builder.gemspec
34
+ - lib/condition_builder.rb
35
+ - spec/condition_builder_spec.rb
36
+ - spec/spec_helper.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/peterhoeg/condition_builder
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --charset=UTF-8
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project: cbuilder
59
+ rubygems_version: 1.3.1
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: This gem assists in creating conditions and criteria for use in ActiveRecord .find statements.
63
+ test_files:
64
+ - spec/condition_builder_spec.rb
65
+ - spec/spec_helper.rb