rquery 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,25 +1,33 @@
1
+
1
2
  RQuery
2
3
  ======
3
4
 
4
5
  RQuery is a small DSL inspired by RSpec for building text queries in languages like SQL. It is meant to be concise, easy to read, and expressive about what the query will be asking for.
5
6
 
6
- Currently only the ActiveRecord extension is implemented with a Sqlite adapter. Mysql should follow shortly, and then support for Grove + JSON queries to Mnesia.
7
+ Currently only the ActiveRecord extension is implemented with a Sqlite adapter. Mysql should be trivial to implement, and I'm hoping to get to supporting my own project Grove.
7
8
 
8
9
  ActiveRecord
9
10
  ------------
10
11
 
11
- RQuery extend ActiveRecord to provide the `where` method. `where` accepts a single optional argument and a block that represents the query statements
12
+ ###Setup/Config
13
+
14
+ In you're rails environment file simply require rquery. The default adapter is the included Sqlite adapter but you can created and set your own with
15
+
16
+ RQuery::Config.adapter = class
12
17
 
13
- ###Example compared with `find`
18
+ You can view both Sql and Sqlite in the adapters directory if you are interested in writing your own (mysql?). As a side note it would be nice at some point to decide the adapter based on the db chosen for a given environment.
19
+
20
+ ###Examples
21
+
22
+ RQuery extend ActiveRecord to provide the `where` method. `where` accepts a single optional argument and a block that represents the query statements
14
23
 
15
24
  In a given UsersController your `show` action might find the User like so:
16
25
 
17
- @user = User.find(params[:id])
26
+ @user = User.find(params[:age])
18
27
 
19
28
  Using RQuery:
20
29
 
21
- @user = User.where { :id.is == params[:id] }
22
-
30
+ @user = User.where { |user| user.age == params[:age] }
23
31
 
24
32
  In the above case, RQuery doesn't provide much of an improvement over the traditional `find` method, but as the query becomes more complex its expressiveness begins to shine through:
25
33
 
@@ -27,43 +35,37 @@ In the above case, RQuery doesn't provide much of an improvement over the tradit
27
35
 
28
36
  RQuery:
29
37
 
30
- @users = User.where do
31
- :age.from 10..20
32
- end
33
-
34
- Or:
35
-
36
- @users = User.where do
37
- :age.between 10..20
38
+ @users = User.where do |user|
39
+ user.age.between 10..20
38
40
  end
39
41
 
40
42
  Both the `from` and `between` methods accept argument lists `10,20` or an array `[10,20]`.
41
43
 
42
-
43
44
  ###Other Examples
44
45
 
45
- RQuery supports most of the common SQL operations: =, <>, >, <, >=, <= as well as in, like (see below for specifics), and between. `:column.is_not` works for `.in`, `.between`, `.contains`, and `==`. All operations are anded as of the current version.
46
+ RQuery supports most of the common SQL operations: =, <>, >, <, >=, <= as well as in, like (see below for specifics), and between. `obj.foo.not_<operation>` works for `.in` and `.between` with the negation of == being `obj.foo.not = ` and the negation of `obj.foo.contains` as `obj.foo.without`.
46
47
 
47
48
  Operators:
48
49
 
49
- @obj = ActiveRecordObject.where do
50
- :foo.is > 2
51
- :foo.is_not == 4
50
+ @obj = ActiveRecordObject.where do |obj|
51
+ obj.foo > 2
52
+ obj.foo.not = 4
52
53
  end
54
+
53
55
  #=> conditions array: ["foo > ? and foo <> ?", 2, 4]
54
56
 
55
57
  Contains:
56
58
 
57
- @obj = ActiveRecordObject.where do
58
- :foo.contains "bar"
59
+ @obj = ActiveRecordObject.where do |obj|
60
+ obj.foo.contains "bar"
59
61
  end
60
62
  #=> conditions array: ["foo like '%' || ? || '%'", "bar"]
61
63
  #using the default sqlite adapter
62
64
 
63
65
  In:
64
66
 
65
- @obj = ActiveRecordObject.where do
66
- :foo.in "bar", "baz", "bak"
67
+ @obj = ActiveRecordObject.where do |obj|
68
+ obj.foo.in "bar", "baz", "bak"
67
69
  end
68
70
  #=> conditions array: ["foo in (?)", ["bar", "baz", "bak"]]
69
71
  #using the default sqlite adapter
@@ -73,14 +75,44 @@ You can also limit the results returned in a similar manner to the `find` method
73
75
 
74
76
  First:
75
77
 
76
- @obj = ActiveRecordObject.where(:first) do
77
- :foo.is == "bar"
78
+ @obj = ActiveRecordObject.where(:first) do |obj|
79
+ obj.foo == "bar"
78
80
  end
79
81
 
80
82
  is equivalent to the find call:
81
83
 
82
84
  @obj = ActiveRecordObject.find(:first, conditions => ["foo = ?", "bar"])
83
85
 
86
+ ###Complex queries
87
+
88
+ RQuery supports relatively complex queries including | and & operation groupings. All operations need to be on the same line and in parens and either the | operator or the & operator can be used on a singel line
89
+
90
+ User.where do |user|
91
+ (user.age > 20) | (user.age.in 16,18)
92
+ end
93
+
94
+ In the following example the & takes precedence and will be grouped with the contains "Alice" which will be or'd with the contains "George"
95
+
96
+ #=> name contains "George" or (name contains "Alice and age from 20 to 30)
97
+ User.where do |user|
98
+ (user.name.contains "George") | (user.name.contains "Alice") & (use.age.from 20..30)
99
+ end
100
+
101
+ To correct the above to the more intuitive version add parens to force precedence of the contains operations
102
+
103
+ #=> (name contains "George" or name contains "Alice) and age from 20 to 30
104
+ User.where do |user|
105
+ ((user.name.contains "George") | (user.name.contains "Alice")) & (use.age.from 20..30)
106
+ end
107
+
108
+ In this sutation it would be cleaner and easier to just move the and'd statement down a line as all seperate lines are and'd and lines have precedence from top to bottom
109
+
110
+ User.where do |user|
111
+ (user.name.contains "George") | (user.name.contains "Alice")
112
+ use.age.from 20..30
113
+ end
114
+
115
+
84
116
 
85
117
 
86
118
 
data/lib/rquery.rb CHANGED
@@ -2,24 +2,18 @@ $: << File.expand_path(File.dirname(__FILE__) + "/../lib/")
2
2
 
3
3
  #RQuery is a small DSL for building queries in query languages like SQL. It is meant to be concise, easy to read
4
4
  #and expressive.
5
- #
6
5
 
7
-
8
- require "rquery/serializers.rb"
9
- require "rquery/declarations.rb"
6
+ require "rquery/operation_collector.rb"
7
+ require "rquery/attribute_collection.rb"
10
8
  require "rquery/adapters.rb"
11
9
  require "rquery/active_record.rb"
12
10
 
13
11
  module RQuery
12
+ class Config
14
13
  @@adapter = RQuery::Adapters::Sqlite
15
-
16
- #Allows for the runtime alteration of the adapter being used
17
- #to convert the "rqueries" into the adapters query language
18
- def RQuery.adapter=(val)
19
- @@adapter = val
20
- end
21
- def RQuery.adapter
22
- @@adapter
14
+ def self.adapter=(value)
15
+ @@adapter = value
23
16
  end
17
+ def self.adapter; @@adapter end
18
+ end
24
19
  end
25
-
@@ -1,35 +1,26 @@
1
1
  module RQuery
2
- module ActiveRecord
3
- @@where_mutex = Mutex.new
4
- def where(*args, &block)
5
-
6
- #establish scope for conditions
7
- conditions = nil
8
-
9
- #make sure only one thread at a time is altering the class
10
- #variables inside RQuery::Serializers::Operations
11
- @@where_mutex.synchronize do
12
-
13
- #yielding the block will alter the Operations class
14
- yield
15
-
16
- #record altered conditions and values
17
- conditions = ::RQuery::Serializers::Operations.conditions
18
-
19
- #clear the alterations
20
- ::RQuery::Serializers::Operations.clear
21
- end
22
-
23
- #limit the records returned (:first, :all, :last)
24
- limit = args.first ? args.first : :all
25
-
26
- #call find with the conditions and values provided by the block
27
- find(limit, :conditions => conditions)
28
- end
2
+ module ActiveRecord
3
+ def where(*args, &block)
4
+ collector = RQuery::AttributeCollection.new(self.new.attribute_names)
5
+
6
+ #Passes a new AttributeCollection object to the block
7
+ #if RQuery.use_symbols has been called it may not be used
8
+ #but otherwise will take the form attr_coll_object.attribute.is ...
9
+ yield(collector)
10
+
11
+ #record altered conditions and values
12
+ conditions = collector.clauses.to_conditions
13
+
14
+ #limit the records returned (:first, :all, :last)
15
+ limit = args.first ? args.first : :all
16
+
17
+ #call find with the conditions and values provided by the block
18
+ find(limit, :conditions => conditions)
29
19
  end
20
+ end
30
21
  end
31
22
 
32
23
  #extend ActiveRecord::Base with the where method
33
24
  if Object.const_defined?(:ActiveRecord)
34
- ActiveRecord::Base.send :extend, RQuery::ActiveRecord
25
+ ActiveRecord::Base.send :extend, RQuery::ActiveRecord
35
26
  end
@@ -31,9 +31,13 @@ module RQuery
31
31
  def contains
32
32
  "like '%' + ? + '%'"
33
33
  end
34
+
35
+ def and_group(ops)
36
+ "(#{ops.join(" and ")})"
37
+ end
34
38
 
35
- def join(ops)
36
- ops.join(" and ")
39
+ def or_group(ops)
40
+ "(#{ops.join(" or ")})"
37
41
  end
38
42
 
39
43
  [:>, :>=, :<, :<=].each do |operator|
@@ -41,6 +45,8 @@ module RQuery
41
45
  "#{operator} ?"
42
46
  end
43
47
  end
48
+
49
+ alias :join :and_group
44
50
  end
45
51
  end
46
52
  end
@@ -5,7 +5,7 @@ module RQuery
5
5
  def self.contains
6
6
  "like '%' || ? || '%'"
7
7
  end
8
- def self.not_contains
8
+ def self.without
9
9
  "not #{contains}"
10
10
  end
11
11
  end
@@ -0,0 +1,57 @@
1
+ module RQuery
2
+ class AttributeCollection
3
+ attr_reader :clauses
4
+
5
+ def initialize(fields)
6
+ @fields = fields.map{ |x| x.to_s }
7
+ @clauses = OperationCollector.new
8
+ end
9
+
10
+ #if the field was added upon initialization its a valid call
11
+ #otherwise report to the user it is invalid. Reports errors at the ruby level
12
+ #instead of the data store level with something like "column doesn't exist"
13
+ #
14
+ #example
15
+ #
16
+ # >> user = RQuery::FieldCollection.new([:age, :name])
17
+ # => #<RQuery::FieldCollection:0x1a2c21c @fields=[:age, :name]>
18
+ # >> user.age
19
+ # => #<RQuery::Field:0x1a2b240 @name=:age>
20
+ # >> user.name
21
+ # => #<RQuery::Field:0x1a2a390 @name=:name>
22
+ # >> user.weight
23
+ # ArgumentError: The field 'weight' doesn't exist for this object
24
+ # from /Users/johnbender/Projects/rquery/lib/rquery/where_clause.rb:20:in `method_missing'
25
+ # from (irb):5
26
+ def method_missing(symbol, *args)
27
+ attr_str = symbol.to_s
28
+ eq_str = attr_str.gsub(/=/, '')
29
+
30
+ if @fields.include?(attr_str) #if the method is part of the attributes
31
+ add_clause(attr_str)
32
+ elsif @fields.include?(eq_str) #if the method sans '=' is part of the attributes
33
+ add_clause(eq_str)
34
+ eq(*args)
35
+ else
36
+ raise AttributeNotFoundError, "The field '#{symbol.to_s}' doesn't exist for this object"
37
+ end
38
+
39
+ #explicit return of OperationCollector, same instance returned by methods of Operation collector
40
+ #but included here for clarity
41
+ @clauses
42
+ end
43
+
44
+
45
+ private
46
+ def add_clause(str)
47
+ @clauses.add_operation(str)
48
+ end
49
+
50
+ def eq(*args)
51
+ @clauses.send(:==, *args)
52
+ end
53
+
54
+ end
55
+
56
+ class AttributeNotFoundError < ArgumentError; end
57
+ end
@@ -0,0 +1,175 @@
1
+ module RQuery
2
+ class OperationCollector
3
+ NOT_PREFIX = 'not_'
4
+ NIL_PREFIX = ''
5
+
6
+ def initialize
7
+ # @name, @prefix = optns[:name], optns[:prefix]
8
+ @operations = []
9
+ @values = []
10
+ end
11
+
12
+ def to_s
13
+ RQuery::Config.adapter.join(@operations)
14
+ end
15
+
16
+ #return a conditions array for use with ActiveRecord.find
17
+ def to_conditions
18
+ [to_s] + @values
19
+ end
20
+
21
+ #add and operation to the @operations array which will be popped
22
+ #and pushed depending on the operations sequence and arrangement
23
+ def add_operation(val)
24
+ @operations << val.to_s
25
+ self
26
+ end
27
+
28
+ #grouping is done by using the | and & operators between multiple operations
29
+ #objects on a single line.
30
+ #
31
+ #This works because each operation ie (user.age.is == 2) is
32
+ #evaluated before these two operators thus pushing
33
+ #the equivelant operation string onto the @operations array (ie 'age = ?').
34
+ #When an operation is evaluated it returns the Operations class which can be compared
35
+ #using the aforementioned operators. Those operators call the group method
36
+ #popping the last two arguments off the stack and dealing with them in one of two ways
37
+ #
38
+ #1. if the second object popped is a string both objects should be
39
+ # added to a new OperationGroup which is then put back onto the stack
40
+ #
41
+ #2. if the second object popped is an OperationGroup the firest belongs to this group as
42
+ # well (it was on the same line). It is added to the OperationGroup and put back on the
43
+ # stack
44
+ #
45
+ #TODO requires refactoring
46
+ def group(type)
47
+ second_op, first_op = @operations.pop, @operations.pop
48
+
49
+ #if the previous operation on the stack is an Operation Group we need to add to it
50
+ #and push it back on the @operations stack
51
+ if first_op.class == OperationsGroup
52
+ if first_op.type == type
53
+ first_op.ops << second_op
54
+ @operations << first_op
55
+ else
56
+ @operations << OperationsGroup.new(first_op.to_s, second_op, type)
57
+ end
58
+ else
59
+ @operations << OperationsGroup.new(first_op, second_op, type)
60
+ end
61
+
62
+ self
63
+ end
64
+
65
+ #used to group operations for anding on a single line
66
+ #example with sqlite adapter
67
+ #(user.age.in [1,2,3]) | (user.name.contains "foo")
68
+ #=>(age in (?) and name like '%' || 'foo' || '%')
69
+ def &(second)
70
+ group :and
71
+ end
72
+
73
+ def |(second)
74
+ group :or
75
+ end
76
+
77
+ def in(*args)
78
+ call_in(NIL_PREFIX, *args)
79
+ end
80
+
81
+ def not_in(*args)
82
+ call_in(NOT_PREFIX, *args)
83
+ end
84
+
85
+ def between(*args)
86
+ call_between(NIL_PREFIX, *args)
87
+ end
88
+
89
+ def not_between(*args)
90
+ call_between(NOT_PREFIX, *args)
91
+ end
92
+
93
+ def contains(str)
94
+ @values << str
95
+ chain :contains
96
+ end
97
+
98
+ def without(str)
99
+ @values << str
100
+ chain :without
101
+ end
102
+
103
+ def not=(arg)
104
+ @values << arg
105
+ chain :neq
106
+ end
107
+
108
+ [:==, :>, :>=, :<, :<=, :neq].each do |operator|
109
+ define_method(operator) do |val|
110
+ @values << val
111
+ chain operator
112
+ end
113
+ end
114
+
115
+ #allows for is.from
116
+ #examples:
117
+ #
118
+ #:id.is.from 1,2
119
+ #:is.is.from 2..10
120
+ alias :from :between
121
+ alias :not_from :not_between
122
+
123
+ private
124
+ def chain(method)
125
+ @operations[@operations.length-1] += " #{RQuery::Config.adapter.send(method)}"
126
+ self
127
+ end
128
+
129
+ def call_in(prefix=nil, *args)
130
+ #flatten our args to prevent having to check for an array first arg
131
+ args.flatten!
132
+
133
+ #if a range is passed as the first argument
134
+ #use it alone, otherwise use the args array
135
+ #examples:
136
+ #ruby => args.flatten! => stored values
137
+ #:id.between 1..100 => [1..100] => 1..100
138
+ #:id.between [1, 2, 3] => [1, 2, 3] => [1, 2, 3]
139
+ #:id.between 1, 2 => [1, 2] => [1, 2]
140
+ @values << (args.first.class == Range ? args.first : args)
141
+ chain :"#{prefix}in"
142
+ end
143
+
144
+ def call_between(prefix=nil, *args)
145
+ #flatten our args to prevent having to check for an array first arg
146
+ args.flatten!
147
+
148
+ #if a range is passed use its first/last element
149
+ #otherwise use the first and last element of the flattened args array
150
+ #examples:
151
+ #ruby => args.flatten! => stored values
152
+ #:id.between 1..100 => [1..100] => 1 100
153
+ #:id.between [1, 2, 3] => [1, 2, 3] => 1 3
154
+ #:id.between 1, 2 => [1, 2] => 1 2
155
+
156
+ @values += (args.first.class == Range ? [args.first.first, args.first.last] : [args.first, args.last])
157
+ chain :"#{prefix}between"
158
+ end
159
+ end
160
+
161
+ class OperationsGroup
162
+ attr_accessor :ops, :type
163
+
164
+ def initialize(left, right, type)
165
+ @ops = Array.new
166
+ @ops << left
167
+ @ops << right
168
+ @type = type
169
+ end
170
+
171
+ def to_s
172
+ RQuery::Config.adapter.send("#{type.to_s}_group", @ops)
173
+ end
174
+ end
175
+ end
data/rakefile.rb CHANGED
@@ -3,5 +3,6 @@ require 'spec/rake/spectask'
3
3
 
4
4
  desc "Run all specs"
5
5
  Spec::Rake::SpecTask.new('specs') do |t|
6
- t.spec_files = FileList['spec/*.rb']
6
+ t.spec_files = FileList['spec/*.rb']
7
+ t.rcov = true
7
8
  end
@@ -0,0 +1,195 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/mock_active_record.rb")
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/rquery.rb")
3
+
4
+ describe ActiveRecord do
5
+
6
+ before(:all) do
7
+ RQuery::Config.adapter = RQuery::Adapters::Sqlite
8
+ end
9
+
10
+ it "should set up a where method" do
11
+ ActiveRecord::MockObject.respond_to?(:where).should == true
12
+ end
13
+
14
+ it "should return sql with foo, the operations, and the values for mock.foo <operation> <value>" do
15
+ ActiveRecord::MockObject.where{ |mock|
16
+ mock.foo == "bar"
17
+ mock.foo = "bar"
18
+ }.should == [:all, {:conditions => ["(foo = ? and foo = ?)", "bar", "bar"]}]
19
+
20
+ ActiveRecord::MockObject.where{ |mock|
21
+ mock.foo > 1
22
+ }.should == [:all, {:conditions => ["(foo > ?)", 1]}]
23
+
24
+ ActiveRecord::MockObject.where{ |mock|
25
+ mock.foo < 2
26
+ }.should == [:all, {:conditions => ["(foo < ?)", 2]}]
27
+
28
+ ActiveRecord::MockObject.where{ |mock|
29
+ mock.foo >= 3
30
+ }.should == [:all, {:conditions => ["(foo >= ?)", 3]}]
31
+
32
+ ActiveRecord::MockObject.where{ |mock|
33
+ mock.foo <= 4
34
+ }.should == [:all, {:conditions => ["(foo <= ?)", 4]}]
35
+ end
36
+
37
+ it "should return sql with foo, the operations, and the values for mock.foo.not_<operation> <value>" do
38
+ ActiveRecord::MockObject.where{ |mock|
39
+ mock.foo.not = "bar"
40
+ }.should == [:all, {:conditions => ["(foo <> ?)", "bar"]}]
41
+
42
+ ActiveRecord::MockObject.where{ |mock|
43
+ mock.foo.not_in 1,2
44
+ }.should == [:all, {:conditions => ["(foo not in (?))", [1,2]]}]
45
+
46
+ ActiveRecord::MockObject.where{ |mock|
47
+ mock.foo.not_between 1..3
48
+ }.should == [:all, {:conditions => ["(foo not between ? and ?)", 1, 3]}]
49
+
50
+ ActiveRecord::MockObject.where{ |mock|
51
+ mock.foo.not_from 1..3
52
+ }.should == [:all, {:conditions => ["(foo not between ? and ?)", 1, 3]}]
53
+
54
+ ActiveRecord::MockObject.where{ |mock|
55
+ mock.foo.without "bar"
56
+ }.should == [:all, {:conditions => ["(foo not like '%' || ? || '%')", "bar"]}]
57
+ end
58
+
59
+ it "should return sql with foo, the operations, and values for mock.foo.in and mock.foo.in when used with a list of args, array, and range" do
60
+ resulting_conditions = [:all, {:conditions => ["(foo in (?))", [1,2,3,4]]}]
61
+
62
+ ActiveRecord::MockObject.where{ |mock|
63
+ mock.foo.in 1,2,3,4
64
+ }.should == resulting_conditions
65
+
66
+ ActiveRecord::MockObject.where{ |mock|
67
+ mock.foo.in [1,2,3,4]
68
+ }.should == resulting_conditions
69
+
70
+ ActiveRecord::MockObject.where{ |mock|
71
+ mock.foo.in 1..4
72
+ }.should == [:all, {:conditions => ["(foo in (?))", 1..4]}]
73
+
74
+ ActiveRecord::MockObject.where{ |mock|
75
+ mock.foo.in 1,2,3,4
76
+ }.should == resulting_conditions
77
+
78
+ ActiveRecord::MockObject.where{ |mock|
79
+ mock.foo.in [1,2,3,4]
80
+ }.should == resulting_conditions
81
+
82
+ ActiveRecord::MockObject.where{ |mock|
83
+ mock.foo.in 1..4
84
+ }.should == [:all, {:conditions => ["(foo in (?))", 1..4]}]
85
+ end
86
+
87
+ it "should return sql with foo, operations, and values for mock.foo.between and mock.foo.between when used with a list of args, array, and range" do
88
+ resulting_conditions = [:all, {:conditions => ["(foo between ? and ?)", 1, 2]}]
89
+
90
+ ActiveRecord::MockObject.where{ |mock|
91
+ mock.foo.between 1,2
92
+ }.should == resulting_conditions
93
+
94
+ ActiveRecord::MockObject.where{ |mock|
95
+ mock.foo.between [1,2]
96
+ }.should == resulting_conditions
97
+
98
+ ActiveRecord::MockObject.where{ |mock|
99
+ mock.foo.between 1..2
100
+ }.should == resulting_conditions
101
+
102
+ ActiveRecord::MockObject.where{ |mock|
103
+ mock.foo.between 1,2
104
+ }.should == resulting_conditions
105
+
106
+ ActiveRecord::MockObject.where{ |mock|
107
+ mock.foo.between [1,2]
108
+ }.should == resulting_conditions
109
+
110
+ ActiveRecord::MockObject.where{ |mock|
111
+ mock.foo.between 1..2
112
+ }.should == resulting_conditions
113
+ end
114
+
115
+ it "should return sql with foo, operations, and values for mock.foo.from when used with a list of args, array, and range" do
116
+ resulting_conditions = [:all, {:conditions => ["(foo between ? and ?)", 1, 2]}]
117
+
118
+ ActiveRecord::MockObject.where{ |mock|
119
+ mock.foo.from 1,2
120
+ }.should == resulting_conditions
121
+
122
+ ActiveRecord::MockObject.where{ |mock|
123
+ mock.foo.from [1,2]
124
+ }.should == resulting_conditions
125
+
126
+ ActiveRecord::MockObject.where{ |mock|
127
+ mock.foo.from 1..2
128
+ }.should == resulting_conditions
129
+
130
+ ActiveRecord::MockObject.where{ |mock|
131
+ mock.foo.from 1,2
132
+ }.should == resulting_conditions
133
+
134
+ ActiveRecord::MockObject.where{ |mock|
135
+ mock.foo.from [1,2]
136
+ }.should == resulting_conditions
137
+
138
+ ActiveRecord::MockObject.where{ |mock|
139
+ mock.foo.from 1..2
140
+ }.should == resulting_conditions
141
+ end
142
+
143
+ it "should return sql with foo, operations, and values for mock.foo.contains when used with a range, array, and list" do
144
+ resulting_conditions = [:all, {:conditions => ["(foo like '%' || ? || '%')", "bar"]}]
145
+
146
+ ActiveRecord::MockObject.where{ |mock|
147
+ mock.foo.contains "bar"
148
+ }.should == resulting_conditions
149
+ end
150
+
151
+ it "should return return the correct group of joined sql after multiple operations" do
152
+ ActiveRecord::MockObject.where{ |mock|
153
+ mock.foo == "bar"
154
+ mock.foo.not_in 1,2,3,4,5
155
+ }.should == [:all, {:conditions => ["(foo = ? and foo not in (?))", "bar", [1,2,3,4,5]]}]
156
+ end
157
+
158
+ it "should return return the correct limit value passed" do
159
+ ActiveRecord::MockObject.where(:first){ |mock|
160
+ mock.foo == "bar"
161
+ mock.foo.not_in 1,2,3,4,5
162
+ }.should == [:first, {:conditions => ["(foo = ? and foo not in (?))", "bar", [1,2,3,4,5]]}]
163
+ end
164
+
165
+ it "should have the correct 'not' keywords in alternating operations" do
166
+ ActiveRecord::MockObject.where(:first){ |mock|
167
+ mock.foo == "bar"
168
+ mock.foo.not_in 1,2,3,4,5
169
+ mock.foo > 3
170
+ }.should == [:first, {:conditions => ["(foo = ? and foo not in (?) and foo > ?)", "bar", [1,2,3,4,5], 3]}]
171
+ end
172
+
173
+ it "should return return strings as arguments when passed to between, in, and from (used for date strings)" do
174
+ ActiveRecord::MockObject.where{ |mock|
175
+ mock.foo.between "some string", "2007-01-01"
176
+ }.should == [:all, {:conditions => ["(foo between ? and ?)", "some string", "2007-01-01"]}]
177
+
178
+ ActiveRecord::MockObject.where{ |mock|
179
+ mock.foo.not_between "some string", "2007-01-01"
180
+ }.should == [:all, {:conditions => ["(foo not between ? and ?)", "some string", "2007-01-01"]}]
181
+
182
+ ActiveRecord::MockObject.where{ |mock|
183
+ mock.foo.from "some string", "2007-01-01"
184
+ }.should == [:all, {:conditions => ["(foo between ? and ?)", "some string", "2007-01-01"]}]
185
+
186
+ ActiveRecord::MockObject.where{ |mock|
187
+ mock.foo.in "some string", "2007-01-01"
188
+ }.should == [:all, {:conditions => ["(foo in (?))", ["some string", "2007-01-01"]]}]
189
+ end
190
+
191
+ it "should throw and exception when trying to use a field not in the objects attributes" do
192
+ attribute = "arbitrary_attribute_name"
193
+ lambda { ActiveRecord::MockObject.where{ |mock| mock.send(attribute) == 2 }}.should raise_error(RQuery::AttributeNotFoundError)
194
+ end
195
+ end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ class Base
3
+ def Base.find(limit, conditions)
4
+ [limit, conditions]
5
+ end
6
+ end
7
+
8
+ class MockObject < Base
9
+ def attribute_names
10
+ ["foo"]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/mock_active_record.rb")
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/rquery.rb")
3
+
4
+ describe RQuery::OperationCollector do
5
+
6
+ before(:all) do
7
+ RQuery::Config.adapter = RQuery::Adapters::Sqlite
8
+ end
9
+
10
+ it "should group two operations on the same line with parens and the 'or' keyword when the | operator is used" do
11
+
12
+ ActiveRecord::MockObject.where{ |mock|
13
+ (mock.foo == 2) | (mock.foo.in 1,2,3)
14
+ }.should == [:all, {:conditions => ["((foo = ? or foo in (?)))", 2, [1,2,3]]}]
15
+
16
+ end
17
+
18
+ it "should group two operations on the same line with parns and the 'and' keyword when the & operator is used" do
19
+
20
+ ActiveRecord::MockObject.where{ |mock|
21
+ (mock.foo == 2) & (mock.foo.in 1,2,3)
22
+ }.should == [:all, {:conditions => ["((foo = ? and foo in (?)))", 2, [1,2,3]]}]
23
+
24
+ end
25
+
26
+ it "should group two operations on the same line and continue to add subsequent operations" do
27
+
28
+ ActiveRecord::MockObject.where{ |mock|
29
+ (mock.foo == 2) & (mock.foo.in 1,2,3)
30
+ mock.foo > 3
31
+ }.should == [:all, {:conditions => ["((foo = ? and foo in (?)) and foo > ?)", 2, [1,2,3], 3]}]
32
+
33
+ end
34
+
35
+ it "should properly group multiple nested groupings on the same line" do
36
+
37
+ ActiveRecord::MockObject.where{ |mock|
38
+ (mock.foo == 2) | (mock.foo.in 1,2,3) | (mock.foo.contains "george")
39
+ mock.foo > 3
40
+ (mock.foo == 2) & (mock.foo.in 1,2,3)
41
+ }.should == [:all, {:conditions => ["((foo = ? or foo in (?) or foo like '%' || ? || '%') and foo > ? and (foo = ? and foo in (?)))", 2, [1,2,3], "george", 3, 2, [1,2,3]]}]
42
+
43
+ end
44
+
45
+ it "& should have precedence when evaluating multiple operation group types on a single line" do
46
+
47
+ ActiveRecord::MockObject.where{ |mock|
48
+ (mock.foo == 2) | (mock.foo.in 1,2,3) & (mock.foo.contains "george")
49
+ }.should == [:all, {:conditions => ["((foo = ? or (foo in (?) and foo like '%' || ? || '%')))", 2, [1,2,3], "george"]}]
50
+
51
+
52
+ end
53
+
54
+ end
@@ -15,7 +15,7 @@ describe RQuery::Adapters::Sqlite do
15
15
  @adapter.not_between.should == "not " + @adapter.between
16
16
  @adapter.neq.should == "<> ?"
17
17
  @adapter.contains.should == "like '%' || ? || '%'"
18
- @adapter.not_contains.should == "not " + @adapter.contains
18
+ @adapter.without.should == "not " + @adapter.contains
19
19
  end
20
20
 
21
21
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John bender
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2000-03-16 00:00:00 -05:00
12
+ date: 2009-08-22 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,19 +25,21 @@ files:
25
25
  - README.markdown
26
26
  - rakefile.rb
27
27
  - lib/rquery.rb
28
- - lib/rquery/declarations.rb
29
- - lib/rquery/serializers.rb
28
+ - lib/rquery/attribute_collection.rb
30
29
  - lib/rquery/active_record.rb
31
30
  - lib/rquery/active_record/base.rb
32
31
  - lib/rquery/adapters.rb
33
32
  - lib/rquery/adapters/sql.rb
34
33
  - lib/rquery/adapters/sqlite.rb
35
- - spec/active_record_base_spec.rb
36
- - spec/serializers_spec.rb
37
- - spec/declarations_spec.rb
34
+ - lib/rquery/operation_collector.rb
35
+ - spec/active_record_base_spec_attribute_collection.rb
36
+ - spec/mock_active_record.rb
37
+ - spec/or_and_operations_spec.rb
38
38
  - spec/sqlite_adapter_spec.rb
39
39
  has_rdoc: true
40
- homepage: http://nickelcode.com/rquery/
40
+ homepage: http://github.com/johnbender/rquery
41
+ licenses: []
42
+
41
43
  post_install_message:
42
44
  rdoc_options: []
43
45
 
@@ -58,9 +60,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
60
  requirements: []
59
61
 
60
62
  rubyforge_project:
61
- rubygems_version: 1.3.1
63
+ rubygems_version: 1.3.4
62
64
  signing_key:
63
- specification_version: 2
64
- summary: A ruby DSL for building data queries in SQL and other query languages.
65
+ specification_version: 3
66
+ summary: An ActiveRecord extension providing a DSL replacement for complex find queries.
65
67
  test_files: []
66
68
 
@@ -1,39 +0,0 @@
1
-
2
- module RQuery
3
- module Declarations
4
- def is
5
- ::RQuery::Serializers::IsOperations.add_operation(self)
6
- ::RQuery::Serializers::IsOperations.prefix = nil
7
- ::RQuery::Serializers::IsOperations
8
- end
9
-
10
- def is_not
11
- ::RQuery::Serializers::IsNotOperations.add_operation(self)
12
- ::RQuery::Serializers::IsNotOperations.prefix = "not_"
13
- ::RQuery::Serializers::IsNotOperations
14
- end
15
-
16
- def in(*args)
17
- ::RQuery::Serializers::IsOperations.add_operation(self)
18
- ::RQuery::Serializers::IsOperations.prefix = nil
19
- ::RQuery::Serializers::IsOperations.in(*args)
20
- end
21
-
22
- def between(*args)
23
- ::RQuery::Serializers::IsOperations.add_operation(self)
24
- ::RQuery::Serializers::IsOperations.prefix = nil
25
- ::RQuery::Serializers::IsOperations.between(*args)
26
- end
27
-
28
- def contains(val)
29
- ::RQuery::Serializers::IsOperations.add_operation(self)
30
- ::RQuery::Serializers::IsOperations.prefix = nil
31
- ::RQuery::Serializers::IsOperations.contains(val)
32
- end
33
-
34
- alias :from :between
35
- end
36
- end
37
-
38
- Symbol.send :include, RQuery::Declarations
39
-
@@ -1,118 +0,0 @@
1
- module RQuery
2
- module Serializers
3
- #The Operations serializer, handles the limiting factors imposed
4
- #by a given query. The methods in this class apply to both is and is_not
5
- #operations. An example in sql would look like:
6
- #
7
- #where foo = bar and foo > 2
8
- #
9
- #This class is a gateway to the selected RQuery.adapter methods.
10
- #Calls to methods here, will be passed on to the selected adapter
11
- class Operations
12
-
13
- @@prefix = nil
14
- @@ops = []
15
- @@values = []
16
-
17
- class << self
18
- def prefix=(val)
19
- @@prefix = val
20
- end
21
-
22
- def to_s
23
- RQuery.adapter.join(@@ops)
24
- end
25
-
26
- def conditions
27
- [to_s] + @@values
28
- end
29
-
30
- def add_operation(val)
31
- @@ops << val.to_s
32
- end
33
-
34
- def clear
35
- @@ops.clear
36
- @@values.clear
37
- end
38
-
39
- def in(*args)
40
- #flatten our args to prevent having to check for an array first arg
41
- args.flatten!
42
-
43
- #if a range is passed as the first argument
44
- #use it alone, otherwise use the args array
45
- #examples:
46
- #ruby => args.flatten! => stored values
47
- #:id.between 1..100 => [1..100] => 1..100
48
- #:id.between [1, 2, 3] => [1, 2, 3] => [1, 2, 3]
49
- #:id.between 1, 2 => [1, 2] => [1, 2]
50
- #
51
- @@values << (args.first.class == Range ? args.first : args)
52
- @@ops[@@ops.length-1] += " #{RQuery.adapter.send("#{@@prefix}in")}"
53
- end
54
-
55
- def between(*args)
56
- #flatten our args to prevent having to check for an array first arg
57
- args.flatten!
58
-
59
- #if a range is passed use its first/last element
60
- #otherwise use the first and last element of the flattened args array
61
- #examples:
62
- #ruby => args.flatten! => stored values
63
- #:id.between 1..100 => [1..100] => 1 100
64
- #:id.between [1, 2, 3] => [1, 2, 3] => 1 3
65
- #:id.between 1, 2 => [1, 2] => 1 2
66
- #
67
- @@values += (args.first.class == Range ? [args.first.first, args.first.last] : [args.first, args.last])
68
- @@ops[@@ops.length-1] += " #{RQuery.adapter.send("#{@@prefix}between")}"
69
- end
70
-
71
- def contains(str)
72
- @@values << str
73
- @@ops[@@ops.length-1] += " #{RQuery.adapter.send("#{@@prefix}contains")}"
74
- end
75
-
76
- #allows for is.from
77
- #examples:
78
- #
79
- #:id.is.from 1,2
80
- #:is.is.from 2..10
81
- alias :from :between
82
-
83
- end
84
-
85
- end
86
-
87
- #The IsOpertaions serializer defines only methods that apply to the .is operator
88
- #that is added to the Symbol class in the Declarations module.
89
- class IsOperations < Operations
90
-
91
- #define the normal operators for is to call the adapter for the equivelant sql
92
- class << self
93
- [:==, :>, :>=, :<, :<=].each do |operator|
94
- define_method(operator) do |val|
95
- @@values << val
96
- @@ops[@@ops.length-1] += " #{RQuery.adapter.send(operator)}"
97
- end
98
- end
99
- end
100
- end
101
-
102
- #The IsNotOperations serializer defines only methods that apply to the .is_not operator
103
- #that is added to the symbol class in the declarations module. Specifically, == as
104
- #ruby does not allow for the overloading of !=
105
- class IsNotOperations < Operations
106
-
107
- #define the == value for is_not to call the adapter for the equivelant sql
108
- class << self
109
- define_method(:==) do |val|
110
- @@values << val
111
- @@ops[@@ops.length-1] += " #{RQuery.adapter.send(:neq)}"
112
- end
113
- end
114
-
115
- end
116
-
117
- end
118
- end
@@ -1,220 +0,0 @@
1
- module ActiveRecord
2
- class Base
3
- def Base.find(limit, conditions)
4
- return [limit, conditions]
5
- end
6
- end
7
- end
8
-
9
- require File.expand_path(File.dirname(__FILE__) + "/../lib/rquery.rb")
10
-
11
- describe ActiveRecord do
12
-
13
- before(:all) do
14
- RQuery.adapter = RQuery::Adapters::Sqlite
15
- end
16
-
17
- #should really set up the find method defined above to use the ruby db libraries and
18
- #create the final sql string
19
- #all run with default adapter
20
-
21
- it "should set up a where method" do
22
- ActiveRecord::Base.respond_to?(:where).should == true
23
- end
24
-
25
- it "should return sql with foo, the operations, and the values for :foo.is <operation> <value>" do
26
-
27
- ActiveRecord::Base.where{
28
- :foo.is == "bar"
29
- }.should == [:all, {:conditions => ["foo = ?", "bar"]}]
30
-
31
- ActiveRecord::Base.where{
32
- :foo.is > 1
33
- }.should == [:all, {:conditions => ["foo > ?", 1]}]
34
-
35
- ActiveRecord::Base.where{
36
- :foo.is < 2
37
- }.should == [:all, {:conditions => ["foo < ?", 2]}]
38
-
39
- ActiveRecord::Base.where{
40
- :foo.is >= 3
41
- }.should == [:all, {:conditions => ["foo >= ?", 3]}]
42
-
43
- ActiveRecord::Base.where{
44
- :foo.is <= 4
45
- }.should == [:all, {:conditions => ["foo <= ?", 4]}]
46
-
47
- end
48
-
49
- it "should return sql with foo, the operations, and the values for :foo.is_not <operation> <value>" do
50
- ActiveRecord::Base.where{
51
- :foo.is_not == "bar"
52
- }.should == [:all, {:conditions => ["foo <> ?", "bar"]}]
53
-
54
- ActiveRecord::Base.where{
55
- :foo.is_not.in 1,2
56
- }.should == [:all, {:conditions => ["foo not in (?)", [1,2]]}]
57
-
58
- ActiveRecord::Base.where{
59
- :foo.is_not.between 1..3
60
- }.should == [:all, {:conditions => ["foo not between ? and ?", 1, 3]}]
61
-
62
- ActiveRecord::Base.where{
63
- :foo.is_not.from 1..3
64
- }.should == [:all, {:conditions => ["foo not between ? and ?", 1, 3]}]
65
-
66
- end
67
-
68
- it "should return sql with foo, the operations, and values for :foo.is.in and :foo.in when used with a list of args, array, and range" do
69
-
70
- resulting_conditions = [:all, {:conditions => ["foo in (?)", [1,2,3,4]]}]
71
-
72
- ActiveRecord::Base.where{
73
- :foo.is.in 1,2,3,4
74
- }.should == resulting_conditions
75
-
76
- ActiveRecord::Base.where{
77
- :foo.is.in [1,2,3,4]
78
- }.should == resulting_conditions
79
-
80
- ActiveRecord::Base.where{
81
- :foo.is.in 1..4
82
- }.should == [:all, {:conditions => ["foo in (?)", 1..4]}]
83
-
84
- ActiveRecord::Base.where{
85
- :foo.in 1,2,3,4
86
- }.should == resulting_conditions
87
-
88
- ActiveRecord::Base.where{
89
- :foo.in [1,2,3,4]
90
- }.should == resulting_conditions
91
-
92
- ActiveRecord::Base.where{
93
- :foo.in 1..4
94
- }.should == [:all, {:conditions => ["foo in (?)", 1..4]}]
95
-
96
- end
97
-
98
- it "should return sql with foo, operations, and values for :foo.is.between and :foo.between when used with a list of args, array, and range" do
99
-
100
- resulting_conditions = [:all, {:conditions => ["foo between ? and ?", 1, 2]}]
101
-
102
- ActiveRecord::Base.where{
103
- :foo.is.between 1,2
104
- }.should == resulting_conditions
105
-
106
- ActiveRecord::Base.where{
107
- :foo.is.between [1,2]
108
- }.should == resulting_conditions
109
-
110
- ActiveRecord::Base.where{
111
- :foo.is.between 1..2
112
- }.should == resulting_conditions
113
-
114
- ActiveRecord::Base.where{
115
- :foo.between 1,2
116
- }.should == resulting_conditions
117
-
118
- ActiveRecord::Base.where{
119
- :foo.between [1,2]
120
- }.should == resulting_conditions
121
-
122
- ActiveRecord::Base.where{
123
- :foo.between 1..2
124
- }.should == resulting_conditions
125
-
126
- end
127
-
128
- it "should return sql with foo, operations, and values for :foo.is.from when used with a list of args, array, and range" do
129
-
130
- resulting_conditions = [:all, {:conditions => ["foo between ? and ?", 1, 2]}]
131
-
132
- ActiveRecord::Base.where{
133
- :foo.is.from 1,2
134
- }.should == resulting_conditions
135
-
136
- ActiveRecord::Base.where{
137
- :foo.is.from [1,2]
138
- }.should == resulting_conditions
139
-
140
- ActiveRecord::Base.where{
141
- :foo.is.from 1..2
142
- }.should == resulting_conditions
143
-
144
- ActiveRecord::Base.where{
145
- :foo.from 1,2
146
- }.should == resulting_conditions
147
-
148
- ActiveRecord::Base.where{
149
- :foo.from [1,2]
150
- }.should == resulting_conditions
151
-
152
- ActiveRecord::Base.where{
153
- :foo.from 1..2
154
- }.should == resulting_conditions
155
-
156
-
157
- end
158
-
159
- it "should return sql with foo, operations, and values for :foo.contains when used with a range, array, and list" do
160
-
161
- resulting_conditions = [:all, {:conditions => ["foo like '%' || ? || '%'", "bar"]}]
162
-
163
- ActiveRecord::Base.where{
164
- :foo.contains "bar"
165
- }.should == resulting_conditions
166
-
167
- end
168
-
169
-
170
- it "should return return the correct group of joined sql after multiple operations" do
171
-
172
- ActiveRecord::Base.where{
173
- :foo.is == "bar"
174
- :foo.is_not.in 1,2,3,4,5
175
- }.should == [:all, {:conditions => ["foo = ? and foo not in (?)", "bar", [1,2,3,4,5]]}]
176
-
177
- end
178
-
179
- it "should return return the correct limit value passed" do
180
-
181
- ActiveRecord::Base.where(:first){
182
- :foo.is == "bar"
183
- :foo.is_not.in 1,2,3,4,5
184
- }.should == [:first, {:conditions => ["foo = ? and foo not in (?)", "bar", [1,2,3,4,5]]}]
185
-
186
- end
187
-
188
- it "should have the correct 'not' keywords in alternating operations" do
189
-
190
- ActiveRecord::Base.where(:first){
191
- :foo.is == "bar"
192
- :foo.is_not.in 1,2,3,4,5
193
- :foo.is > 3
194
- }.should == [:first, {:conditions => ["foo = ? and foo not in (?) and foo > ?", "bar", [1,2,3,4,5], 3]}]
195
-
196
- end
197
-
198
- it "should return return strings as arguments when passed to between, in, and from (used for date strings)" do
199
-
200
- ActiveRecord::Base.where{
201
- :foo.is.between "some string", "2007-01-01"
202
- }.should == [:all, {:conditions => ["foo between ? and ?", "some string", "2007-01-01"]}]
203
-
204
- ActiveRecord::Base.where{
205
- :foo.is_not.between "some string", "2007-01-01"
206
- }.should == [:all, {:conditions => ["foo not between ? and ?", "some string", "2007-01-01"]}]
207
-
208
- ActiveRecord::Base.where{
209
- :foo.is.from "some string", "2007-01-01"
210
- }.should == [:all, {:conditions => ["foo between ? and ?", "some string", "2007-01-01"]}]
211
-
212
- ActiveRecord::Base.where{
213
- :foo.in "some string", "2007-01-01"
214
- }.should == [:all, {:conditions => ["foo in (?)", ["some string", "2007-01-01"]]}]
215
-
216
- end
217
-
218
-
219
-
220
- end
@@ -1,47 +0,0 @@
1
-
2
- require File.expand_path(File.dirname(__FILE__) + "/../lib/rquery.rb")
3
-
4
- describe RQuery::Declarations do
5
-
6
- before(:all) do
7
- RQuery.adapter = RQuery::Adapters::Sqlite
8
- end
9
-
10
- after(:each) do
11
- RQuery::Serializers::Operations.clear
12
- end
13
-
14
- it "any Object should respond to is, is_not, in, between, from, and contains methods" do
15
- :foo.respond_to?(:is).should == true
16
- :foo.respond_to?(:is_not).should == true
17
- :foo.respond_to?(:in).should == true
18
- :foo.respond_to?(:from).should == true
19
- :foo.respond_to?(:between).should == true
20
- :foo.respond_to?(:from).should == true
21
- end
22
-
23
- it "should return an Serializer Class when is, is_not are called" do
24
- :foo.is.class.should == Class
25
- :foo.is_not.class.should == Class
26
- end
27
-
28
- it "should add an Operation for each call to is, is_not, and in" do
29
- :foo.is
30
- :bar.is
31
- RQuery::Serializers::Operations.conditions.should == ["foo and bar"]
32
- end
33
-
34
- it "should add an Operation and the arguments for each call to from, contain, and between" do
35
- :foo.between 1,2
36
- RQuery::Serializers::Operations.conditions.should == ["foo between ? and ?", 1 , 2]
37
- RQuery::Serializers::Operations.clear
38
- :bar.from 1,2
39
- RQuery::Serializers::Operations.conditions.should == ["bar between ? and ?", 1 , 2]
40
- RQuery::Serializers::Operations.clear
41
- :baz.contains "something"
42
- RQuery::Serializers::Operations.conditions.should == ["baz like '%' || ? || '%'", "something"]
43
- RQuery::Serializers::Operations.clear
44
- end
45
-
46
-
47
- end
@@ -1,30 +0,0 @@
1
-
2
- require File.expand_path(File.dirname(__FILE__) + "/../lib/rquery.rb")
3
-
4
- describe RQuery::Serializers do
5
-
6
- it "Object.is should define ==, <, <=, >, >=, in, and between" do
7
- :foo.is.respond_to?(:==).should == true
8
- :foo.is.respond_to?(:<).should == true
9
- :foo.is.respond_to?(:<=).should == true
10
- :foo.is.respond_to?(:>).should == true
11
- :foo.is.respond_to?(:>=).should == true
12
- :foo.is.respond_to?(:in).should == true
13
- :foo.is.respond_to?(:between).should == true
14
- end
15
-
16
- it "Object.is_not should define == and in" do
17
- :foo.is_not.respond_to?(:==).should == true
18
- :foo.is_not.respond_to?(:in).should == true
19
- :foo.is_not.respond_to?(:between).should == true
20
- end
21
-
22
- it "Object.is_not should not redefine <, <=, >, >= in the same way that .is did" do
23
- lambda {:foo.is_not.send(:<)}.should raise_error(ArgumentError)
24
- lambda {:foo.is_not.send(:<=)}.should raise_error(ArgumentError)
25
- lambda {:foo.is_not.send(:>)}.should raise_error(ArgumentError)
26
- lambda {:foo.is_not.send(:>=)}.should raise_error(ArgumentError)
27
- end
28
-
29
-
30
- end