conditions_fu 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 1.0.0 / 2010-01-03
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.txt ADDED
@@ -0,0 +1,74 @@
1
+ conditions_fu
2
+ by Cameron Barrie
3
+ http://wiki.github.com/whalec/conditions_fu
4
+
5
+ == DESCRIPTION:
6
+
7
+ A little DSL to allow you to map url parameters to an Active Record conditions array.
8
+
9
+ == TODO:
10
+ Everything. I've only onlined my intentions here.
11
+
12
+ == FEATURES/PROBLEMS:
13
+
14
+ allows you to map rules to url parameters when posting from a form with a get.
15
+
16
+ i.e. if you're request was:
17
+ http://local.host/users/search?admin=1&email=camwritescode
18
+
19
+ it would map to an active record conditions array like
20
+
21
+ ["admin IS ? and email ~* ?", true, 'camwritescode']
22
+
23
+ == SYNOPSIS:
24
+
25
+ ConditionsFu::Builder.blueprint(:user) do
26
+ is_true("admin" => params[:admin])
27
+ includes({:parents_last_name => params[:surname]}, :or) do
28
+ includes({:last_name => params[:surname]}, :or)
29
+ is_like("parent_email" => params[:email]) do
30
+ is_true(:child => params[:child])
31
+ end
32
+ end
33
+ end
34
+ params = {:surname => "Barrie", :email => "cam@snepo.com", :child => false, :admin => true}
35
+ conditions = ConditionsFu::Builder.make(params)
36
+ # => ["admin = ? AND (parents_last_name ~* ? OR last_name ~* ? OR (parent_email ILIKE ? AND child = ?))", true, "Barrie", "Barrie", "%cam@snepo.com%", true]
37
+
38
+ So then you can
39
+ User.find(:all, :conditions => ConditionsFu::Builder.make(params))
40
+
41
+ For more examples check the specs directory.
42
+
43
+ == REQUIREMENTS:
44
+
45
+ Currently it only works for Postgres as it's the only DB that I work with. Patches are happily accepted though :D
46
+
47
+ == INSTALL:
48
+
49
+ sudo gem install conditions_fu
50
+
51
+ == LICENSE:
52
+
53
+ (The MIT License)
54
+
55
+ Copyright (c) 2009 FIXME (different license?)
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining
58
+ a copy of this software and associated documentation files (the
59
+ 'Software'), to deal in the Software without restriction, including
60
+ without limitation the rights to use, copy, modify, merge, publish,
61
+ distribute, sublicense, and/or sell copies of the Software, and to
62
+ permit persons to whom the Software is furnished to do so, subject to
63
+ the following conditions:
64
+
65
+ The above copyright notice and this permission notice shall be
66
+ included in all copies or substantial portions of the Software.
67
+
68
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
69
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
70
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
71
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
72
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
73
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
74
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+
2
+ begin
3
+ require 'bones'
4
+ rescue LoadError
5
+ abort '### Please install the "bones" gem ###'
6
+ end
7
+
8
+ ensure_in_path 'lib'
9
+ require 'conditions_fu'
10
+
11
+ task :default => 'test:run'
12
+ task 'gem:release' => 'test:run'
13
+
14
+ Bones {
15
+ name 'conditions_fu'
16
+ authors 'Cameron Barrie'
17
+ email 'camwritescode@gmail.com'
18
+ url 'http://wiki.github.com/whalec/conditions_fu'
19
+ version ConditionsFu::VERSION
20
+ }
21
+
22
+ # EOF
@@ -0,0 +1,184 @@
1
+ module ConditionsFu
2
+
3
+ class ConditionsArray < Array
4
+
5
+ def initialize(*args)
6
+ super
7
+ end
8
+
9
+ def create_active_record_conditions
10
+ conditions = ""
11
+ self.each do |condition|
12
+ if self.last == condition
13
+ conditions << "#{condition[0]}"
14
+ else
15
+ conditions << "#{condition[0]} #{condition[2]} "
16
+ end
17
+ end
18
+ [conditions.strip, self.map{|i| i[1]}].flatten
19
+ end
20
+
21
+ end
22
+
23
+ class Lathe
24
+
25
+ def self.run(*args)
26
+ blueprint = Builder.blueprint
27
+ if args.first.is_a?(Symbol)
28
+ named_blueprint = Builder.blueprint(args.shift)
29
+ raise "No blueprint found" if named_blueprint.nil?
30
+ end
31
+ lathe = self.new(args.shift)
32
+ lathe.instance_eval(&named_blueprint) if named_blueprint
33
+ lathe.conditions.create_active_record_conditions
34
+ end
35
+
36
+ attr_reader :conditions
37
+
38
+ def initialize(_params)
39
+ @params = _params
40
+ @conditions = ConditionsArray.new
41
+ end
42
+
43
+ def params
44
+ @params
45
+ end
46
+
47
+ private
48
+
49
+ # Warning: Postgres ONLY
50
+ def includes(options = {}, binding = :and, &block)
51
+ return if options.values.include?(nil)
52
+ if block_given?
53
+ @conditions << ["(#{options.keys.first} ~* ?", options.values.first, binding.to_s.upcase]
54
+ yield
55
+ @conditions.last.first << ")"
56
+ else
57
+ @conditions << ["#{options.keys.first} ~* ?", options.values.first, binding.to_s.upcase]
58
+ end
59
+ end
60
+
61
+ #Warning: Postgres ONLY
62
+ def is_like(options = {}, binding = :and, &block)
63
+ return if options.values.include?(nil)
64
+ if block_given?
65
+ @conditions << ["(#{options.keys.first} ILIKE ?", "%#{options.values.first}%", binding.to_s.upcase]
66
+ yield
67
+ @conditions.last.first << ")"
68
+ else
69
+ @conditions << ["#{options.keys.first} ILIKE ?", "%#{options.values.first}%", binding.to_s.upcase]
70
+ end
71
+ end
72
+
73
+ def not_equal_to(options = {}, binding = :and, &block)
74
+ return if options.values.include?(nil)
75
+ if block_given?
76
+ @conditions << ["(#{options.keys.first} != ?", options.values.first, binding.to_s.upcase]
77
+ yield
78
+ @conditions.last.first << ")"
79
+ else
80
+ @conditions << ["#{options.keys.first} != ?", options.values.first, binding.to_s.upcase]
81
+ end
82
+ end
83
+
84
+ def equal_to(options = {}, binding = :and, &block)
85
+ return if options.values.include?(nil)
86
+ if block_given?
87
+ @conditions << ["(#{options.keys.first} = ?", options.values.first, binding.to_s.upcase]
88
+ yield
89
+ @conditions.last.first << ")"
90
+ else
91
+ @conditions << ["#{options.keys.first} = ?", options.values.first, binding.to_s.upcase]
92
+ end
93
+ end
94
+
95
+ def greater_than_or_equal_to(options = {}, binding = :and, &block)
96
+ return if options.values.include?(nil)
97
+ if block_given?
98
+ @conditions << ["(#{options.keys.first} >= ?", options.values.first, binding.to_s.upcase]
99
+ yield
100
+ @conditions.last.first << ")"
101
+ else
102
+ @conditions << ["#{options.keys.first} >= ?", options.values.first, binding.to_s.upcase]
103
+ end
104
+ end
105
+
106
+ def greater_than(options = {}, binding = :and, &block)
107
+ return if options.values.include?(nil)
108
+ if block_given?
109
+ @conditions << ["(#{options.keys.first} > ?", options.values.first, binding.to_s.upcase]
110
+ yield
111
+ @conditions.last.first << ")"
112
+ else
113
+ @conditions << ["#{options.keys.first} > ?", options.values.first, binding.to_s.upcase]
114
+ end
115
+ end
116
+
117
+ def less_than_or_equal_to(options = {}, binding = :and, &block)
118
+ return if options.values.include?(nil)
119
+ if block_given?
120
+ @conditions << ["(#{options.keys.first} <= ?", options.values.first, binding.to_s.upcase]
121
+ yield
122
+ @conditions.last.first << ")"
123
+ else
124
+ @conditions << ["#{options.keys.first} <= ?", options.values.first, binding.to_s.upcase]
125
+ end
126
+ end
127
+
128
+ def less_than(options = {}, binding = :and, &block)
129
+ return if options.values.include?(nil)
130
+ if block_given?
131
+ @conditions << ["(#{options.keys.first} < ?", options.values.first, binding.to_s.upcase]
132
+ yield
133
+ @conditions.last.first << ")"
134
+ else
135
+ @conditions << ["#{options.keys.first} < ?", options.values.first, binding.to_s.upcase]
136
+ end
137
+ end
138
+
139
+ def is_true(options = {}, binding = :and, &block)
140
+ return if options.values.include?(nil)
141
+ if block_given?
142
+ @conditions << ["(#{options.keys.first} = ?", true, binding.to_s.upcase]
143
+ yield
144
+ @conditions.last.first << ")"
145
+ else
146
+ @conditions << ["#{options.keys.first} = ?", true, binding.to_s.upcase]
147
+ end
148
+ end
149
+
150
+ def is_false(options = {}, binding = :and, &block)
151
+ return if options.values.include?(nil)
152
+ if block_given?
153
+ @conditions << ["(#{options.keys.first} IS NOT ?", true, binding.to_s.upcase]
154
+ yield
155
+ @conditions.last.first << ")"
156
+ else
157
+ @conditions << ["#{options.keys.first} IS NOT ?", true, binding.to_s.upcase]
158
+ end
159
+ end
160
+
161
+ end
162
+
163
+ class Builder
164
+
165
+ def self.blueprint(name = :master, &blueprint)
166
+ @conditions = ConditionsArray.new
167
+ @prints ||= {}
168
+ @prints[name] = blueprint if block_given?
169
+ @prints[name]
170
+ end
171
+
172
+ def self.make(blueprint, params)
173
+ Lathe.run(blueprint, params)
174
+ end
175
+
176
+ def self.named_blueprints
177
+ @blueprints.reject{|name,_| name == :master }.keys
178
+ end
179
+
180
+ def self.clear_blueprints!
181
+ @blueprints = {}
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,48 @@
1
+
2
+ module ConditionsFu
3
+
4
+ # :stopdoc:
5
+ VERSION = '0.5.0'
6
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
7
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
8
+ # :startdoc:
9
+
10
+ # Returns the version string for the library.
11
+ #
12
+ def self.version
13
+ VERSION
14
+ end
15
+
16
+ # Returns the library path for the module. If any arguments are given,
17
+ # they will be joined to the end of the libray path using
18
+ # <tt>File.join</tt>.
19
+ #
20
+ def self.libpath( *args )
21
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
22
+ end
23
+
24
+ # Returns the lpath for the module. If any arguments are given,
25
+ # they will be joined to the end of the path using
26
+ # <tt>File.join</tt>.
27
+ #
28
+ def self.path( *args )
29
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
30
+ end
31
+
32
+ # Utility method used to require all files ending in .rb that lie in the
33
+ # directory below this file that has the same name as the filename passed
34
+ # in. Optionally, a specific _directory_ name can be passed in such that
35
+ # the _filename_ does not have to be equivalent to the directory.
36
+ #
37
+ def self.require_all_libs_relative_to( fname, dir = nil )
38
+ dir ||= ::File.basename(fname, '.*')
39
+ search_me = ::File.expand_path(
40
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
41
+
42
+ Dir.glob(search_me).sort.each {|rb| require rb}
43
+ end
44
+
45
+ end # module ConditionsFu
46
+
47
+ ConditionsFu.require_all_libs_relative_to(__FILE__)
48
+
@@ -0,0 +1,83 @@
1
+ require File.join(File.dirname(__FILE__), %w[../ spec_helper])
2
+ describe ConditionsFu::Builder do
3
+
4
+ it "should initialize" do
5
+ ConditionsFu::Builder.blueprint(:user) do
6
+ is_true "admin" => params[:content] if params[:admin] == "1"
7
+ includes "parents_last_name" => params[:content] if params[:filter] == "surname" && !params[:content].nil?
8
+ is_like "parent_email" => params[:content] if params[:filter] == "emails" && !params[:content].nil?
9
+ is_like "nickname" => params[:content] if params[:filter] == "nickname" && !params[:content].nil?
10
+ is_like "locations.name" => params[:content] if params[:filter] == "location" && !params[:content].nil?
11
+ end
12
+ end
13
+
14
+ it "should be able to return an ActiveRecord conditions array" do
15
+ params = {:admin => "1", :filter => "emails", :content => "cameron@snepo.com"}
16
+ parameters = ConditionsFu::Builder.make(:user, params)
17
+ parameters.should eql(["admin = ? AND parent_email ILIKE ?", true, "%cameron@snepo.com%"])
18
+ end
19
+
20
+ it "should bind conditions" do
21
+ ConditionsFu::Builder.blueprint(:master) do
22
+ is_true "admin" => params[:admin]
23
+ includes "parents_last_name" => params[:surname]
24
+ is_like "parent_email" => params[:email]
25
+ is_like "nick" => params[:nickname]
26
+ is_like "locations.name" => params[:location]
27
+ end
28
+
29
+ params = {:admin => "1", :surname => "Barrie", :email => "snepo.com", :nickname => "whalec", :location => "Annandale"}
30
+ parameters = ConditionsFu::Builder.make(:master, params)
31
+ parameters.should eql(["admin = ? AND parents_last_name ~* ? AND parent_email ILIKE ? AND nick ILIKE ? AND locations.name ILIKE ?", true, "Barrie", "%snepo.com%", "%whalec%", "%Annandale%"])
32
+ end
33
+
34
+ it "should bind only conditions that are passed in" do
35
+ ConditionsFu::Builder.blueprint(:master) do
36
+ is_true "admin" => params[:admin]
37
+ includes "parents_last_name" => params[:surname]
38
+ is_like "parent_email" => params[:email]
39
+ is_like "nick" => params[:nickname]
40
+ is_like "locations.name" => params[:location]
41
+ end
42
+
43
+ params = {:admin => "1", :surname => "Barrie"}
44
+ parameters = ConditionsFu::Builder.make(:master, params)
45
+ parameters.should eql(["admin = ? AND parents_last_name ~* ?", true, "Barrie"])
46
+ end
47
+
48
+ it "should be able to bind conditions with an OR statement" do
49
+ ConditionsFu::Builder.blueprint(:or_binding) do
50
+ is_true("admin" => params[:admin])
51
+ includes({:parents_last_name => params[:surname]}, :or) do
52
+ includes({:last_name => params[:surname]})
53
+ end
54
+ is_like("nick" => params[:nickname])
55
+ is_like("locations.name" => params[:location])
56
+ is_like("parent_email" => params[:email])
57
+ end
58
+
59
+ params = {:surname => "Barrie", :email => "cam@snepo.com", :admin => true}
60
+ parameters = ConditionsFu::Builder.make(:or_binding, params)
61
+ parameters.should eql(["admin = ? AND (parents_last_name ~* ? OR last_name ~* ?) AND parent_email ILIKE ?",
62
+ true, "Barrie", "Barrie", "%cam@snepo.com%"])
63
+ end
64
+
65
+ it "should bind and number of conditions together in parenthesis" do
66
+ ConditionsFu::Builder.blueprint(:or_binding) do
67
+ is_true("admin" => params[:admin])
68
+ includes({:parents_last_name => params[:surname]}, :or) do
69
+ includes({:last_name => params[:surname]}, :or)
70
+ is_like("parent_email" => params[:email]) do
71
+ is_true(:child => params[:child])
72
+ end
73
+ end
74
+ end
75
+
76
+ params = {:surname => "Barrie", :email => "cam@snepo.com", :child => false, :admin => true}
77
+ parameters = ConditionsFu::Builder.make(:or_binding, params)
78
+ expectation = ["admin = ? AND (parents_last_name ~* ? OR last_name ~* ? OR (parent_email ILIKE ? AND child = ?))",
79
+ true, "Barrie", "Barrie", "%cam@snepo.com%", true]
80
+ parameters.should eql(expectation)
81
+ end
82
+
83
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe ConditionsFu do
5
+ end
6
+
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib conditions_fu]))
5
+
6
+ Spec::Runner.configure do |config|
7
+ # == Mock Framework
8
+ #
9
+ # RSpec uses it's own mocking framework by default. If you prefer to
10
+ # use mocha, flexmock or RR, uncomment the appropriate line:
11
+ #
12
+ # config.mock_with :mocha
13
+ # config.mock_with :flexmock
14
+ # config.mock_with :rr
15
+ end
16
+
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: conditions_fu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Cameron Barrie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-06 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bones
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 3.2.0
24
+ version:
25
+ description: A little DSL to allow you to map url parameters to an Active Record conditions array.
26
+ email: camwritescode@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - History.txt
33
+ - README.txt
34
+ files:
35
+ - History.txt
36
+ - README.txt
37
+ - Rakefile
38
+ - lib/conditions_fu.rb
39
+ - lib/conditions_fu/builder.rb
40
+ - spec/conditions_fu/builder_spec.rb
41
+ - spec/conditions_fu_spec.rb
42
+ - spec/spec_helper.rb
43
+ has_rdoc: true
44
+ homepage: http://wiki.github.com/whalec/conditions_fu
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --main
50
+ - README.txt
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project: conditions_fu
68
+ rubygems_version: 1.3.5
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: A little DSL to allow you to map url parameters to an Active Record conditions array
72
+ test_files:
73
+ - spec/conditions_fu/builder_spec.rb
74
+ - spec/conditions_fu_spec.rb