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.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/Rakefile +2 -2
- data/init.rb +1 -1
- data/lib/assets/javascripts/set_builder.js +122 -125
- data/lib/set_builder/constraint.rb +66 -50
- data/lib/set_builder/errors/trait_not_found.rb +3 -0
- data/lib/set_builder/modifier/adverb.rb +4 -4
- data/lib/set_builder/modifier/base.rb +74 -67
- data/lib/set_builder/modifier/verb.rb +1 -16
- data/lib/set_builder/modifier.rb +49 -49
- data/lib/set_builder/modifier_collection.rb +16 -16
- data/lib/set_builder/modifiers/date_preposition.rb +6 -48
- data/lib/set_builder/modifiers/number_preposition.rb +4 -25
- data/lib/set_builder/modifiers/string_preposition.rb +9 -43
- data/lib/set_builder/modifiers.rb +3 -3
- data/lib/set_builder/set.rb +48 -8
- data/lib/set_builder/trait.rb +75 -49
- data/lib/set_builder/traits.rb +13 -4
- data/lib/set_builder/value_map.rb +30 -30
- data/lib/set_builder/version.rb +1 -1
- data/lib/set_builder.rb +8 -7
- data/set_builder.gemspec +4 -2
- data/spec/commands/example_command.rb +2 -2
- data/spec/lib/jspec.css +4 -4
- data/spec/lib/jspec.growl.js +11 -11
- data/spec/lib/jspec.jquery.js +14 -14
- data/spec/lib/jspec.js +210 -210
- data/spec/lib/jspec.nodejs.js +2 -2
- data/spec/lib/jspec.shell.js +11 -11
- data/spec/lib/jspec.timers.js +23 -23
- data/spec/rhino.js +1 -1
- data/spec/server.rb +1 -1
- data/spec/unit/array.spec.js +9 -9
- data/spec/unit/set_builder.spec.js +71 -82
- data/spec/unit/spec.helper.js +1 -0
- data/test/constraint_test.rb +84 -0
- data/test/date_preposition_test.rb +17 -7
- data/test/modifier_test.rb +26 -1
- data/test/set_test.rb +51 -28
- data/test/string_preposition_test.rb +10 -9
- data/test/test_helper.rb +17 -15
- data/test/trait_test.rb +49 -30
- data/test/traits_test.rb +35 -30
- data/test/value_map_test.rb +1 -1
- metadata +37 -15
- data/lib/set_builder/query_builders/string.rb +0 -0
- data/test/inflector_test.rb +0 -27
data/spec/lib/jspec.nodejs.js
CHANGED
data/spec/lib/jspec.shell.js
CHANGED
@@ -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
|
+
})()
|
data/spec/lib/jspec.timers.js
CHANGED
@@ -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
data/spec/server.rb
CHANGED
data/spec/unit/array.spec.js
CHANGED
@@ -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
|
-
[[
|
6
|
-
|
7
|
-
|
8
|
-
[
|
9
|
-
|
10
|
-
|
11
|
-
[
|
12
|
-
|
13
|
-
|
14
|
-
[
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
47
|
-
},
|
48
|
-
'
|
49
|
-
|
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([
|
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
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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
|
-
|
data/spec/unit/spec.helper.js
CHANGED
@@ -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
|
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
|
-
|
9
|
-
|
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
|