set_builder 2.0.0.beta2 → 2.0.0.beta3
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.
- 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
|