condition_builder 0.1.0

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