conditions_fu 0.5.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/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