ryana-inequal_opportunity 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/README +36 -0
- data/Rakefile +11 -0
- data/lib/inequal_opportunity.rb +124 -0
- data/test/database.example.yml +8 -0
- data/test/inequal_opportunity_test.rb +79 -0
- data/test/test_helper.rb +4 -0
- metadata +59 -0
data/README
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
= Inequal Opportunity
|
2
|
+
|
3
|
+
ActiveRecord is a ruby ORM released with Ruby on Rails. It has a hash syntax
|
4
|
+
for specifying SQL conditions:
|
5
|
+
|
6
|
+
YourModel.count(:conditions => {:id => 5})
|
7
|
+
YourModel.all(:limit => 5, :order => :created_at, :conditions => {:user_id => 5})
|
8
|
+
|
9
|
+
But this hash format lacks inequalities. In order to generate:
|
10
|
+
|
11
|
+
SELECT * from your_models where id <> '42';
|
12
|
+
|
13
|
+
You have to write:
|
14
|
+
|
15
|
+
YourModel.count(:conditions => ['id <> ?', 42])
|
16
|
+
|
17
|
+
With Inequal Opportunity, you can write:
|
18
|
+
|
19
|
+
YourModel.count(:conditions => {:id => ne(42)})
|
20
|
+
|
21
|
+
Where Object#ne wraps 42 in a ActiveRecord::Inequality::NotEqual class,
|
22
|
+
which is then used to insert the proper operator into the generated SQL.
|
23
|
+
|
24
|
+
Test coverage is real sparse right now. I also am not completely satisfied with
|
25
|
+
the way I overwrite ActiveRecord.expand_range_bind_variables, but it works for now.
|
26
|
+
|
27
|
+
|
28
|
+
== License
|
29
|
+
|
30
|
+
Inequal Opportunity is released under the MIT license.
|
31
|
+
|
32
|
+
|
33
|
+
== Support
|
34
|
+
|
35
|
+
Just email me at ryan@angilly.com with questions, bugs,
|
36
|
+
or patches
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "inequal_opportunity"
|
5
|
+
gemspec.summary = "Adds mergable, stackable inequality statements to ActiveRecord conditions"
|
6
|
+
gemspec.email = "ryan@angilly.com"
|
7
|
+
gemspec.homepage = "http://github.com/ryana/inequal_opportunity"
|
8
|
+
gemspec.description = "Adds mergable, stackable inequality statements to ActiveRecord conditions"
|
9
|
+
gemspec.authors = ["Ryan Angilly"]
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Inequality
|
3
|
+
|
4
|
+
class Base
|
5
|
+
attr_accessor :value
|
6
|
+
|
7
|
+
def initialize(val)
|
8
|
+
self.value = val
|
9
|
+
end
|
10
|
+
|
11
|
+
def operator
|
12
|
+
raise('Nope')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class GreaterThanEqual < Base
|
17
|
+
def operator
|
18
|
+
'>='
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class GreaterThan < Base
|
23
|
+
def operator
|
24
|
+
'>'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class LessThanEqual < Base
|
29
|
+
def operator
|
30
|
+
'<='
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class LessThan < Base
|
35
|
+
def operator
|
36
|
+
'<'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class NotEqual < Base
|
41
|
+
def operator
|
42
|
+
'<>'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Like < Base
|
47
|
+
def operator
|
48
|
+
'LIKE'
|
49
|
+
end
|
50
|
+
|
51
|
+
def value
|
52
|
+
"%#{super}%"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module WrapperMethods
|
57
|
+
|
58
|
+
def lte(val)
|
59
|
+
ActiveRecord::Inequality::LessThanEqual.new(val)
|
60
|
+
end
|
61
|
+
|
62
|
+
def lt(val)
|
63
|
+
ActiveRecord::Inequality::LessThan.new(val)
|
64
|
+
end
|
65
|
+
|
66
|
+
def gte(val)
|
67
|
+
ActiveRecord::Inequality::GreaterThanEqual.new(val)
|
68
|
+
end
|
69
|
+
|
70
|
+
def gt(val)
|
71
|
+
ActiveRecord::Inequality::GreaterThan.new(val)
|
72
|
+
end
|
73
|
+
|
74
|
+
def ne(val)
|
75
|
+
ActiveRecord::Inequality::NotEqual.new(val)
|
76
|
+
end
|
77
|
+
|
78
|
+
def like(val)
|
79
|
+
ActiveRecord::Inequality::Like.new(val)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
class Base
|
87
|
+
class << self
|
88
|
+
alias attribute_condition_orig attribute_condition
|
89
|
+
def attribute_condition(quoted_column_name, argument)
|
90
|
+
if argument.is_a? ActiveRecord::Inequality::Base
|
91
|
+
"#{quoted_column_name} #{argument.operator} ?"
|
92
|
+
else
|
93
|
+
attribute_condition_orig(quoted_column_name, argument)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Copied this from AR. Not ideal.
|
98
|
+
alias expand_range_bind_variables_orig expand_range_bind_variables
|
99
|
+
def expand_range_bind_variables(bind_vars)
|
100
|
+
expanded = []
|
101
|
+
|
102
|
+
bind_vars.each do |var|
|
103
|
+
next if var.is_a?(Hash)
|
104
|
+
|
105
|
+
if var.is_a?(Range)
|
106
|
+
expanded << var.first
|
107
|
+
expanded << var.last
|
108
|
+
elsif var.is_a?(ActiveRecord::Inequality::Base)
|
109
|
+
expanded << var.value
|
110
|
+
else
|
111
|
+
expanded << var
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
expanded
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
include ActiveRecord::Inequality::WrapperMethods
|
124
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'ruby-debug'
|
3
|
+
|
4
|
+
DB = YAML::load(File.open(File.join(File.dirname(__FILE__), 'database.yml'))).symbolize_keys!
|
5
|
+
ActiveRecord::Base.establish_connection(DB[:source])
|
6
|
+
|
7
|
+
TABLES = %w(mains seconds)
|
8
|
+
|
9
|
+
class Main < ActiveRecord::Base
|
10
|
+
belongs_to :seconds
|
11
|
+
named_scope :newer_than, lambda {|time| {:conditions => {:created_at => gte(time) }} }
|
12
|
+
end
|
13
|
+
|
14
|
+
class Second < ActiveRecord::Base
|
15
|
+
has_many :mains
|
16
|
+
end
|
17
|
+
|
18
|
+
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
19
|
+
|
20
|
+
class InequalOpportunityTest < Test::Unit::TestCase
|
21
|
+
|
22
|
+
def setup
|
23
|
+
TABLES.each do |t|
|
24
|
+
ActiveRecord::Base.connection.execute("create table #{t} (id integer, val integer, seconds_id integer, mains_id integer, created_at datetime default null);")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def teardown
|
29
|
+
TABLES.each do |t|
|
30
|
+
ActiveRecord::Base.connection.execute("drop table #{t};")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "a model" do
|
35
|
+
setup do
|
36
|
+
@model = Main
|
37
|
+
end
|
38
|
+
|
39
|
+
should "respond to gte" do
|
40
|
+
assert @model.respond_to?(:gte)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "should work with a named_scope" do
|
44
|
+
assert_equal Main.newer_than(2.days.ago), []
|
45
|
+
end
|
46
|
+
|
47
|
+
should "properly scope based on gte" do
|
48
|
+
time = 2.days.ago
|
49
|
+
num = 3
|
50
|
+
num.times { Main.create(:val => 3) }
|
51
|
+
num.times { Main.create(:val => 1) }
|
52
|
+
|
53
|
+
assert_equal Main.count(:conditions => {:val => gte(2)}), num
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "an instance" do
|
59
|
+
setup do
|
60
|
+
@main = Main.new
|
61
|
+
end
|
62
|
+
|
63
|
+
should "respond to gte" do
|
64
|
+
assert @main.respond_to?(:gte)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
context "a parent" do
|
70
|
+
setup do
|
71
|
+
@second = Second.new
|
72
|
+
end
|
73
|
+
|
74
|
+
should "see through assocaitions" do
|
75
|
+
assert @second.mains.respond_to?(:gte)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ryana-inequal_opportunity
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Angilly
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Adds mergable, stackable inequality statements to ActiveRecord conditions
|
17
|
+
email: ryan@angilly.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- lib/inequal_opportunity.rb
|
27
|
+
- test/database.example.yml
|
28
|
+
- test/inequal_opportunity_test.rb
|
29
|
+
- test/test_helper.rb
|
30
|
+
- README
|
31
|
+
has_rdoc: true
|
32
|
+
homepage: http://github.com/ryana/inequal_opportunity
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options:
|
35
|
+
- --charset=UTF-8
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
version:
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 1.2.0
|
54
|
+
signing_key:
|
55
|
+
specification_version: 2
|
56
|
+
summary: Adds mergable, stackable inequality statements to ActiveRecord conditions
|
57
|
+
test_files:
|
58
|
+
- test/inequal_opportunity_test.rb
|
59
|
+
- test/test_helper.rb
|