set_builder 2.0.0.beta2 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -6
  3. data/Rakefile +2 -2
  4. data/init.rb +1 -1
  5. data/lib/assets/javascripts/set_builder.js +122 -125
  6. data/lib/set_builder/constraint.rb +66 -50
  7. data/lib/set_builder/errors/trait_not_found.rb +3 -0
  8. data/lib/set_builder/modifier/adverb.rb +4 -4
  9. data/lib/set_builder/modifier/base.rb +74 -67
  10. data/lib/set_builder/modifier/verb.rb +1 -16
  11. data/lib/set_builder/modifier.rb +49 -49
  12. data/lib/set_builder/modifier_collection.rb +16 -16
  13. data/lib/set_builder/modifiers/date_preposition.rb +6 -48
  14. data/lib/set_builder/modifiers/number_preposition.rb +4 -25
  15. data/lib/set_builder/modifiers/string_preposition.rb +9 -43
  16. data/lib/set_builder/modifiers.rb +3 -3
  17. data/lib/set_builder/set.rb +48 -8
  18. data/lib/set_builder/trait.rb +75 -49
  19. data/lib/set_builder/traits.rb +13 -4
  20. data/lib/set_builder/value_map.rb +30 -30
  21. data/lib/set_builder/version.rb +1 -1
  22. data/lib/set_builder.rb +8 -7
  23. data/set_builder.gemspec +4 -2
  24. data/spec/commands/example_command.rb +2 -2
  25. data/spec/lib/jspec.css +4 -4
  26. data/spec/lib/jspec.growl.js +11 -11
  27. data/spec/lib/jspec.jquery.js +14 -14
  28. data/spec/lib/jspec.js +210 -210
  29. data/spec/lib/jspec.nodejs.js +2 -2
  30. data/spec/lib/jspec.shell.js +11 -11
  31. data/spec/lib/jspec.timers.js +23 -23
  32. data/spec/rhino.js +1 -1
  33. data/spec/server.rb +1 -1
  34. data/spec/unit/array.spec.js +9 -9
  35. data/spec/unit/set_builder.spec.js +71 -82
  36. data/spec/unit/spec.helper.js +1 -0
  37. data/test/constraint_test.rb +84 -0
  38. data/test/date_preposition_test.rb +17 -7
  39. data/test/modifier_test.rb +26 -1
  40. data/test/set_test.rb +51 -28
  41. data/test/string_preposition_test.rb +10 -9
  42. data/test/test_helper.rb +17 -15
  43. data/test/trait_test.rb +49 -30
  44. data/test/traits_test.rb +35 -30
  45. data/test/value_map_test.rb +1 -1
  46. metadata +37 -15
  47. data/lib/set_builder/query_builders/string.rb +0 -0
  48. data/test/inflector_test.rb +0 -27
@@ -4,9 +4,9 @@
4
4
  JSpec
5
5
  .include({
6
6
  name: 'node',
7
-
7
+
8
8
  // --- Matchers
9
-
9
+
10
10
  matchers : {
11
11
  have_enumerable_property: 'actual.propertyIsEnumerable(expected)',
12
12
  have_writable_property: 'Object.getOwnPropertyDescriptor(actual, expected).writable === true',
@@ -2,29 +2,29 @@
2
2
  // JSpec - Shell - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
3
3
 
4
4
  ;(function(){
5
-
5
+
6
6
  var _quit = quit
7
-
7
+
8
8
  Shell = {
9
-
9
+
10
10
  // --- Global
11
-
11
+
12
12
  main: this,
13
-
13
+
14
14
  // --- Commands
15
-
15
+
16
16
  commands: {
17
17
  quit: ['Terminate the shell', function(){ _quit() }],
18
18
  exit: ['Terminate the shell', function(){ _quit() }],
19
19
  p: ['Inspect an object', function(o){ return o.toSource() }]
20
20
  },
21
-
21
+
22
22
  /**
23
23
  * Start the interactive shell.
24
24
  *
25
25
  * @api public
26
26
  */
27
-
27
+
28
28
  start : function() {
29
29
  for (var name in this.commands)
30
30
  if (this.commands.hasOwnProperty(name))
@@ -33,7 +33,7 @@
33
33
  this.main.__defineGetter__(name, this.commands[name][1])
34
34
  }
35
35
  }
36
-
36
+
37
37
  Shell.start()
38
-
39
- })()
38
+
39
+ })()
@@ -2,67 +2,67 @@
2
2
  // Mock Timers - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
3
3
 
4
4
  ;(function(){
5
-
5
+
6
6
  /**
7
7
  * Localized timer stack.
8
8
  */
9
9
  var timers = [];
10
-
10
+
11
11
  // nodejs, rhino don't have a window object
12
12
  var global = this;
13
-
13
+
14
14
  // if they where mocked before this library is loaded - bad luck
15
15
  var savedGlobals = {
16
16
  setTimeout: global.setTimeout,
17
17
  setInterval: global.setInterval,
18
18
  clearInterval: global.clearInterval,
19
19
  clearTimeout: global.clearTimeout,
20
-
20
+
21
21
  // those should not be globals, but are mocked none the less, so we save them
22
22
  resetTimers: global.resetTimers,
23
23
  tick: global.tick
24
24
  };
25
25
  var hadResetTimers = 'resetTimers' in global;
26
26
  var hadTick = 'tick' in global;
27
-
27
+
28
28
  function forEachProperty(anObject, aClosure) {
29
29
  for (var key in anObject) {
30
30
  if ( ! anObject.hasOwnProperty(key))
31
31
  continue;
32
-
32
+
33
33
  aClosure(key, anObject[key]);
34
34
  }
35
35
  }
36
-
36
+
37
37
  global.MockTimers = {
38
-
38
+
39
39
  mockTimersVersion: '2.0.0',
40
-
40
+
41
41
  mockGlobalTimerFunctions: function() {
42
42
  forEachProperty(this.mocks, function(aName, aFunction) {
43
43
  global[aName] = aFunction;
44
44
  });
45
45
  },
46
-
46
+
47
47
  unmockGlobalTimerFunctions: function() {
48
48
  forEachProperty(this.savedGlobals, function(aName, aFunction) {
49
49
  global[aName] = aFunction;
50
50
  });
51
-
51
+
52
52
  if ( ! hadResetTimers)
53
53
  delete global['resetTimers'];
54
54
  if ( ! hadTick)
55
55
  delete global['tick'];
56
-
56
+
57
57
  }
58
58
  };
59
-
59
+
60
60
  function clearTimer(id) {
61
61
  return delete timers[--id];
62
62
  }
63
-
63
+
64
64
  var mocks = {
65
-
65
+
66
66
  /**
67
67
  * Set mock timeout with _callback_ and timeout of _ms_.
68
68
  *
@@ -95,7 +95,7 @@
95
95
  timers[timers.length] = callback;
96
96
  return timers.length;
97
97
  },
98
-
98
+
99
99
  /**
100
100
  * Destroy timer with _id_.
101
101
  *
@@ -106,7 +106,7 @@
106
106
  clearInterval: clearTimer,
107
107
  clearTimeout: clearTimer
108
108
  };
109
-
109
+
110
110
  // additional functions that are not originally in the global namespace
111
111
  /**
112
112
  * Reset timers.
@@ -117,7 +117,7 @@
117
117
  mocks.resetTimers = function() {
118
118
  return timers = [];
119
119
  };
120
-
120
+
121
121
  /**
122
122
  * Increment each timers internal clock by _ms_.
123
123
  *
@@ -128,10 +128,10 @@
128
128
  for (var i = 0, len = timers.length; i < len; ++i) {
129
129
  if ( ! timers[i] || ! (timers[i].current += ms))
130
130
  continue;
131
-
131
+
132
132
  if (timers[i].current - timers[i].last < timers[i].step)
133
133
  continue;
134
-
134
+
135
135
  var times = Math.floor((timers[i].current - timers[i].last) / timers[i].step);
136
136
  var remainder = (timers[i].current - timers[i].last) % timers[i].step;
137
137
  timers[i].last = timers[i].current - remainder;
@@ -139,10 +139,10 @@
139
139
  timers[i]();
140
140
  }
141
141
  };
142
-
142
+
143
143
  // make them available publicly
144
144
  MockTimers.mocks = mocks;
145
-
145
+
146
146
  JSpec.include({
147
147
  beforeSpec: function(){
148
148
  MockTimers.mockGlobalTimerFunctions();
@@ -151,4 +151,4 @@
151
151
  MockTimers.unmockGlobalTimerFunctions();
152
152
  }
153
153
  });
154
- })();
154
+ })();
data/spec/rhino.js CHANGED
@@ -7,4 +7,4 @@ load('spec/unit/spec.helper.js')
7
7
  JSpec
8
8
  .exec('spec/unit/spec.js')
9
9
  .run({ reporter: JSpec.reporters.Terminal, fixturePath: 'spec/fixtures' })
10
- .report()
10
+ .report()
data/spec/server.rb CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
2
  get '/lib/*' do |path|
3
3
  send_file File.dirname(__FILE__) + '/../lib/' + path
4
- end
4
+ end
@@ -4,20 +4,20 @@ describe 'Array'
4
4
  it 'should return an empty string if you pass a 0-length array'
5
5
  expect([].toSentence()).to(be, '');
6
6
  end
7
-
7
+
8
8
  it 'should return the lone value if you pass a 1-length array'
9
9
  expect(['banana'].toSentence()).to(be, 'banana');
10
10
  end
11
-
11
+
12
12
  it 'should concatenate only using "and" if you pass a 2-length array'
13
13
  expect(['apple', 'banana'].toSentence()).to(be, 'apple and banana');
14
14
  end
15
-
15
+
16
16
  it 'should use different concatenators for a 3+-length array'
17
17
  expect(['apple', 'banana', 'chocolate'].toSentence()).to(be, 'apple, banana, and chocolate');
18
18
  end
19
19
  end
20
-
20
+
21
21
  describe '.dup'
22
22
  it 'should create an independently modifiable array'
23
23
  var a = [1, 2, 3];
@@ -27,7 +27,7 @@ describe 'Array'
27
27
  expect(b.length).to(be, 3);
28
28
  end
29
29
  end
30
-
30
+
31
31
  describe '.each'
32
32
  it 'should correctly work through this array of arrays'
33
33
  var i = 0;
@@ -42,7 +42,7 @@ describe 'Array'
42
42
  expect(i).to(be, 4);
43
43
  end
44
44
  end
45
-
45
+
46
46
  describe '.inject'
47
47
  it 'should count 4 objects in [12,32,12,11]'
48
48
  expect([12,32,12,11].inject(0, function(i, item) {
@@ -58,7 +58,7 @@ describe 'Array'
58
58
  })).to(eql, ["big", "angry", "words"]);
59
59
  end
60
60
  end
61
-
61
+
62
62
  describe '.find'
63
63
  it 'should return the first word with an "a" in it'
64
64
  expect(["not", "me", "what?", "me"].find(function(word) {
@@ -66,7 +66,7 @@ describe 'Array'
66
66
  })).to(be, "what?")
67
67
  end
68
68
  end
69
-
69
+
70
70
  describe '.select'
71
71
  it 'should return all members of the array where fn(member) is true'
72
72
  expect(["this", "nope", "that", "this"].select(function(word){
@@ -74,7 +74,7 @@ describe 'Array'
74
74
  })).to(eql, ["this", "this"]);
75
75
  end
76
76
  end
77
-
77
+
78
78
  end
79
79
 
80
80
 
@@ -2,25 +2,32 @@ describe 'SetBuilder'
2
2
  before_each
3
3
 
4
4
  SetBuilder.registerTraits([
5
- [['string','who are'],
6
- ['negative','not'],
7
- ['name','awesome']],
8
- [['string','who'],
9
- ['negative','have not'],
10
- ['name','died']],
11
- [['string','who were'],
12
- ['name','born'],
13
- ['modifier','date']],
14
- [['string','whose'],
15
- ['name','age'],
16
- ['modifier','number']],
17
- [['string','who have'],
18
- ['negative','not'],
19
- ['name','attended'],
20
- ['direct_object_type','school']],
21
- [['string','whose'],
22
- ['name','name'],
23
- ['modifier','string']]
5
+ [["string","who "],
6
+ ["enum",["are","are not"]],
7
+ ["string", " "],
8
+ ["name","awesome"]],
9
+ [["string","who "],
10
+ ["enum",["have","have not"]],
11
+ ["string", " "],
12
+ ["name","died"]],
13
+ [["string","who were "],
14
+ ["name","born"],
15
+ ["string", " "],
16
+ ["modifier","date"]],
17
+ [["string","whose "],
18
+ ["name","age"],
19
+ ["string", " "],
20
+ ["modifier","number"]],
21
+ [["string","who "],
22
+ ["enum",["have","have not"]],
23
+ ["string", " "],
24
+ ["name","attended"],
25
+ ["string", " "],
26
+ ["direct_object_type","school"]],
27
+ [["string","whose "],
28
+ ["name","name"],
29
+ ["string", " "],
30
+ ["modifier","string"]]
24
31
  ]);
25
32
 
26
33
  SetBuilder.registerModifiers({
@@ -31,103 +38,86 @@ describe 'SetBuilder'
31
38
  is: ['string']
32
39
  }
33
40
  });
34
-
41
+
35
42
  SetBuilder.registerValueMap('school', [['1','Concordia'], ['2','McKendree']]);
36
-
43
+
37
44
  set_data = [
38
- ['awesome'],
39
- ['attended', 2],
40
- ['died'],
41
- ['name', {'is': "Jerome"}]
45
+ { trait: 'awesome', enums: ['are'] },
46
+ { trait: 'attended', enums: ['have'], school: 2 },
47
+ { trait: 'died', enums: ['have'] },
48
+ { trait: 'name', modifiers: [
49
+ { operator: 'is', values: ['Jerome'] }] }
42
50
  ];
43
-
51
+
44
52
  set_data_hash = {
45
- '0': {
46
- trait: 'awesome'
47
- },
48
- '1': {
49
- trait: 'attended',
50
- direct_object: 2
51
- },
52
- '2': {
53
- trait: 'died'
54
- },
55
- '3': {
56
- trait: 'name',
57
- modifiers: {
58
- '0': {
59
- operator: 'is',
60
- values: {
61
- '0': 'Jerome'
62
- }
63
- }
64
- }
65
- }
53
+ '0': { trait: 'awesome', enums: {'0': 'are'} },
54
+ '1': { trait: 'attended', enums: {'0': 'have'}, school: 2 },
55
+ '2': { trait: 'died', enums: {'0': 'have'} },
56
+ '3': { trait: 'name', modifiers: {
57
+ '0': { operator: 'is', values: {'0': 'Jerome'} } } }
66
58
  };
67
59
  end
68
-
69
-
70
-
71
-
60
+
61
+
62
+
63
+
72
64
  describe '.getValueMap'
73
65
  it 'should return an array of arrays'
74
66
  expect(SetBuilder.getValueMap('school')).to(eql, [['1','Concordia'], ['2','McKendree']]);
75
67
  end
76
68
  end
77
-
69
+
78
70
  describe '.getValue'
79
71
  it 'should return a value based on the key and name'
80
72
  expect(SetBuilder.getValue('school', 1)).to(be, 'Concordia')
81
73
  expect(SetBuilder.getValue('school', '1')).to(be, 'Concordia')
82
74
  end
83
-
75
+
84
76
  it 'should return what it was passed if there is no value map for the key'
85
77
  expect(SetBuilder.getValue('band', 1)).to(be, 1)
86
78
  end
87
79
  end
88
-
80
+
89
81
  describe '.getValueMaps'
90
82
  it 'should return the names of the value maps registered'
91
83
  expect(SetBuilder.getValueMaps()).to(eql, ['school']);
92
84
  end
93
85
  end
94
-
95
-
96
-
86
+
87
+
88
+
97
89
  describe '.Trait'
98
-
99
90
  describe '.constructor'
100
91
  it 'should correctly parse the name of the trait'
101
92
  var trait = new SetBuilder.Trait([['string', 'who are'], ['name', 'awesome']]);
102
93
  expect(trait.name()).to(be, 'awesome');
103
94
  end
104
-
95
+
105
96
  it 'should correctly identify when it expects a direct objects'
106
97
  var trait = new SetBuilder.Trait([['string', 'who have'], ['name', 'attended'], ['direct_object_type', 'string']]);
107
98
  expect(trait.requiresDirectObject()).to(be, true);
108
99
  end
109
-
100
+
110
101
  it 'should correctly parse paramters with modifiers'
111
102
  var trait = new SetBuilder.Trait([['string', 'who were'], ['name', 'born'], ['modifier', 'date']]);
112
103
  expect(trait.modifiers().length).to(be, 1);
113
104
  end
114
105
  end
115
-
116
106
  end
117
-
118
-
119
-
107
+
108
+
109
+
120
110
  describe '.Traits'
121
111
  before_each
122
112
  traits = SetBuilder.traits();
123
113
  end
124
-
114
+
125
115
  describe '.length'
126
116
  it 'should have parsed the data structure correctly'
127
117
  expect(traits.length()).to(be, 6);
128
118
  end
129
119
  end
130
-
120
+
131
121
  describe '.find'
132
122
  it 'should get a SetBuilder.Trait object by name'
133
123
  expect(traits.__find('awesome').name()).to(eql, 'awesome');
@@ -137,7 +127,7 @@ describe 'SetBuilder'
137
127
  expect(traits.__find('name').name()).to(eql, 'name');
138
128
  end
139
129
  end
140
-
130
+
141
131
  end
142
132
 
143
133
 
@@ -159,22 +149,22 @@ describe 'SetBuilder'
159
149
  expect(modifiers.operators_for('string')).to(eql, expected_modifiers);
160
150
  end
161
151
  end
162
-
163
152
  end
164
-
153
+
154
+
155
+
165
156
  describe '.Set'
166
-
167
157
  describe '.constraints'
168
158
  it 'should have parsed the correct number of objects'
169
159
  var set = new SetBuilder.Set(set_data);
170
160
  expect(set.constraints().length).to(be, 4);
171
161
  end
172
-
162
+
173
163
  it 'should parse hash-style objects as well as arrays'
174
164
  var set = new SetBuilder.Set(set_data_hash);
175
165
  expect(set.constraints().length).to(be, 4);
176
166
  end
177
-
167
+
178
168
  it 'should consider two sets with identical constraints equal'
179
169
  var set1 = new SetBuilder.Set(set_data);
180
170
  var set2 = new SetBuilder.Set(set_data_hash);
@@ -182,31 +172,30 @@ describe 'SetBuilder'
182
172
  expect(set2.isEqualTo(set1)).to(be, true);
183
173
  end
184
174
  end
185
-
175
+
186
176
  describe '.toString'
187
177
  it 'should generate the natural language description of a simple set'
188
- var simple_set = new SetBuilder.Set([['awesome']]);
178
+ var simple_set = new SetBuilder.Set([{ trait: 'awesome', enums: {'0': 'are'} }]);
189
179
  expect(simple_set.toString()).to(eql, 'who are awesome');
190
180
  end
191
-
181
+
192
182
  it 'should generate the natural language description of a complex set'
193
183
  var set = new SetBuilder.Set(set_data);
194
- var expected_string = 'who are awesome, who have attended McKendree, who died, and whose name is Jerome'
184
+ var expected_string = 'who are awesome, who have attended McKendree, who have died, and whose name is Jerome'
195
185
  expect(set.toString()).to(be, expected_string);
196
186
  end
197
187
 
198
188
  it 'should generate the natural language description of a complex set with negation (NB: nouns are not negated)'
199
189
  var set = new SetBuilder.Set([
200
- ['!awesome'],
201
- ['!attended', 1],
202
- ['!died'],
203
- ['!name', {'is': "Jerome"}]
190
+ { trait: 'awesome', enums: ['are not'] },
191
+ { trait: 'attended', enums: ['have not'], school: 1 },
192
+ { trait: 'died', enums: ['have not'] },
193
+ { trait: 'name', modifiers: [{ operator: 'is', values: ['Jerome'] }] }
204
194
  ]);
205
195
  var expected_string = 'who are not awesome, who have not attended Concordia, who have not died, and whose name is Jerome'
206
196
  expect(set.toString()).to(eql, expected_string);
207
197
  end
208
198
  end
209
-
199
+
210
200
  end
211
201
  end
212
-
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,84 @@
1
+ require "test_helper"
2
+
3
+ class ConstraintTest < ActiveSupport::TestCase
4
+ include SetBuilder
5
+
6
+
7
+ test "constraints find correct modifiers" do
8
+ trait = $friend_traits[:name]
9
+ assert_equal 1, trait.modifiers.length
10
+
11
+ constraint = trait.apply({modifiers: [{ operator: :is, values: ["Jerome"] }]})
12
+ assert_equal 1, constraint.modifiers.length
13
+ assert_kind_of Modifiers::StringPreposition, constraint.modifiers.first
14
+ end
15
+
16
+ test "modifiers should find correct values" do
17
+ trait = $friend_traits[:name]
18
+ constraint = trait.apply({modifiers: [{ operator: :is, values: ["Jerome"] }]})
19
+ modifier = constraint.modifiers.first
20
+ assert_equal :is, modifier.operator
21
+ assert_equal ["Jerome"], modifier.values
22
+ end
23
+
24
+ test "constraint should be valid" do
25
+ trait = $friend_traits[:name]
26
+ constraint = trait.apply({modifiers: [{ operator: :is, values: ["Jerome"] }]})
27
+ assert constraint.valid?
28
+ end
29
+
30
+
31
+
32
+ context "A constraint" do
33
+ should "be invalid if it is missing a direct object" do
34
+ trait = Trait.new('who "attended" :school')
35
+ constraint = trait.apply({})
36
+ assert_match /school is blank/, constraint.errors.join
37
+ end
38
+
39
+ should "be invalid if it is missing an enumeration" do
40
+ trait = Trait.new('who [is|is not] "awesome"')
41
+ constraint = trait.apply({})
42
+ assert_match /should have values for 1 enums/, constraint.errors.join
43
+ end
44
+
45
+ should "be invalid if it supplies an unexpected value for an enumeration" do
46
+ trait = Trait.new('who [is|is not] "awesome"')
47
+ constraint = trait.apply(enums: ["is totally"])
48
+ assert_match /should be 'is' or 'is not'/, constraint.errors.join
49
+ end
50
+
51
+ should "be invalid if it supplies an unexpected value for a modifier's operator" do
52
+ trait = Trait.new('whose "name" <string>')
53
+ constraint = trait.apply(modifiers: [{ operator: "starts_with", values: ["Jer"] }])
54
+ assert_match /should be :contains, :does_not_contain, :begins_with, :does_not_begin_with, :ends_with, :does_not_end_with, :is, or :is_not/, constraint.errors.join
55
+ end
56
+ end
57
+
58
+
59
+
60
+ context "#to_s" do
61
+ should "carry over arbitrary text in the trait definition" do
62
+ trait = Trait.new('who "died", tragically')
63
+ assert_equal "who died, tragically", trait.apply({}).to_s
64
+ end
65
+
66
+ should "interpolate direct objects" do
67
+ trait = Trait.new('who "attended" :school')
68
+ assert_equal "who attended Concordia", trait.apply({school: 1}).to_s
69
+ end
70
+
71
+ should "interpolate modifiers" do
72
+ trait = Trait.new('who was "born" <date>')
73
+ assert_equal "who was born on 2016-01-01", trait.apply({
74
+ modifiers: [{ operator: "on", values: ["2016-01-01"] }] }).to_s
75
+ end
76
+
77
+ should "interpolate enums" do
78
+ trait = Trait.new('who [was|was not] "born" in [Russia|Ukraine]')
79
+ assert_equal "who was born in Ukraine", trait.apply({enums: ["was", "Ukraine"] }).to_s
80
+ end
81
+ end
82
+
83
+
84
+ end
@@ -1,13 +1,23 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class DatePrepositionTest < ActiveSupport::TestCase
4
4
  include SetBuilder::Modifiers
5
-
6
-
5
+
6
+ attr_reader :table
7
+
8
+ setup do
9
+ @table = Arel::Table.new(:people)
10
+ end
11
+
12
+
7
13
  test "should constrain our date queries to A.D." do
8
- modifier = DatePreposition.new({:in_the_last => [Date.today.year, "years"]})
9
- assert_equal "x>='0001-01-01'", modifier.build_conditions_for("x")
14
+ Timecop.freeze do
15
+ time = 5.years.ago
16
+ modifier = DatePreposition.new(operator: :in_the_last, values: [5, "years"])
17
+ assert_equal "\"people\".\"birthday\" >= '#{time}'",
18
+ modifier.build_arel_for(table[:birthday]).to_sql
19
+ end
10
20
  end
11
-
12
-
21
+
22
+
13
23
  end