set_builder 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +35 -0
  6. data/Rakefile +14 -0
  7. data/assets/javascripts/array.js +100 -0
  8. data/assets/javascripts/set_builder.js +415 -0
  9. data/init.rb +1 -0
  10. data/install.rb +1 -0
  11. data/lib/set_builder.rb +58 -0
  12. data/lib/set_builder/constraint.rb +67 -0
  13. data/lib/set_builder/modifier.rb +134 -0
  14. data/lib/set_builder/modifier/adverb.rb +11 -0
  15. data/lib/set_builder/modifier/base.rb +105 -0
  16. data/lib/set_builder/modifier/verb.rb +24 -0
  17. data/lib/set_builder/modifier_collection.rb +41 -0
  18. data/lib/set_builder/modifiers.rb +3 -0
  19. data/lib/set_builder/modifiers/date_modifier.rb +83 -0
  20. data/lib/set_builder/modifiers/number_modifier.rb +48 -0
  21. data/lib/set_builder/modifiers/string_modifier.rb +81 -0
  22. data/lib/set_builder/query_builders/string.rb +0 -0
  23. data/lib/set_builder/set.rb +81 -0
  24. data/lib/set_builder/trait.rb +74 -0
  25. data/lib/set_builder/traits.rb +42 -0
  26. data/lib/set_builder/value_map.rb +62 -0
  27. data/lib/set_builder/version.rb +3 -0
  28. data/set_builder.gemspec +25 -0
  29. data/spec/commands/example_command.rb +19 -0
  30. data/spec/dom.html +24 -0
  31. data/spec/lib/images/bg.png +0 -0
  32. data/spec/lib/images/hr.png +0 -0
  33. data/spec/lib/images/loading.gif +0 -0
  34. data/spec/lib/images/sprites.bg.png +0 -0
  35. data/spec/lib/images/sprites.png +0 -0
  36. data/spec/lib/images/vr.png +0 -0
  37. data/spec/lib/jspec.css +149 -0
  38. data/spec/lib/jspec.growl.js +115 -0
  39. data/spec/lib/jspec.jquery.js +88 -0
  40. data/spec/lib/jspec.js +1908 -0
  41. data/spec/lib/jspec.nodejs.js +18 -0
  42. data/spec/lib/jspec.shell.js +39 -0
  43. data/spec/lib/jspec.timers.js +154 -0
  44. data/spec/lib/jspec.xhr.js +210 -0
  45. data/spec/node.js +10 -0
  46. data/spec/rhino.js +10 -0
  47. data/spec/server.html +18 -0
  48. data/spec/server.rb +4 -0
  49. data/spec/unit/array.spec.js +82 -0
  50. data/spec/unit/set_builder.spec.js +166 -0
  51. data/spec/unit/spec.helper.js +0 -0
  52. data/test/date_modifier_test.rb +13 -0
  53. data/test/inflector_test.rb +27 -0
  54. data/test/modifier_test.rb +90 -0
  55. data/test/set_test.rb +96 -0
  56. data/test/test_helper.rb +79 -0
  57. data/test/trait_test.rb +49 -0
  58. data/test/traits_test.rb +41 -0
  59. data/test/value_map_test.rb +30 -0
  60. data/uninstall.rb +1 -0
  61. metadata +191 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ead29825b8e41af3149c07247a660207fa51c442
4
+ data.tar.gz: 04bc422d6ab418fbafa0e50d3ac2d29b529b6fef
5
+ SHA512:
6
+ metadata.gz: 43424db5d5fa2ddaa21007b20299efd01b464b5034b98255ad97fa04ef2df3bdbef6548446b267c3832dbeff630344c35d7bc13577532863a16e323c1309a776
7
+ data.tar.gz: f46edcb206c607d2fa1f1ee8569a6bf0dd30e26f5821a84f84e1eb205ec3ca7ae5e327170f704cfed0b83cd13f289e8695ad03d7cb2808c695713ed443673ba8
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in set_builder.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Bob Lail
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ SetBuilder
2
+ ==========
3
+
4
+ SetBuilder's purpose is to transform _described_ data sets into queries or natural language.
5
+
6
+
7
+ Example
8
+ =======
9
+
10
+ The following set describes a group of people using simple data structures (Arrays, Strings, Symbols, and Hashes):
11
+
12
+ [[:awesome],
13
+ [:attended, "school"],
14
+ [:died, :not],
15
+ [:name, {:is => "Jerome"}]]
16
+
17
+ SetBuilder can render this set in plain English:
18
+
19
+ [Everyone] who is awesome, who attended school, who has not died, and whose name is Jerome.
20
+
21
+ It can also generate a NamedScope on an ActiveRecord model to fetch the people who fit in this set.
22
+
23
+
24
+ Usage
25
+ =====
26
+
27
+
28
+
29
+ Roadmap
30
+ =======
31
+
32
+ Right now SetBuilder uses ActiveRecord::NamedScope::Scope internally, but it shouldn't be hard to refactor it to use DataMapper's composable queries instead.
33
+
34
+
35
+ Copyright (c) 2010 Bob Lail, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ desc 'Run tests.'
5
+ task :default => :test
6
+
7
+ desc 'Run tests.'
8
+ Rake::TestTask.new(:test) do |t|
9
+ t.libs << 'lib'
10
+ t.libs << 'test'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+ require "bundler/gem_tasks"
@@ -0,0 +1,100 @@
1
+ /*
2
+ Extensions to core objects to provide Ruby-like idioms
3
+ ===========================================================
4
+ */
5
+
6
+ if(!Object.keys) {
7
+ Object.keys = function(o) {
8
+ var keys = [];
9
+ for(key in o) {
10
+ keys.push(key);
11
+ }
12
+ return keys;
13
+ }
14
+ }
15
+
16
+
17
+
18
+ //
19
+ // .toSentence
20
+ //
21
+ if(!Array.prototype.toSentence) {
22
+ Array.prototype.toSentence = function() {
23
+ switch(this.length) {
24
+ case 0:
25
+ return '';
26
+ case 1:
27
+ return this[0].toString();
28
+ case 2:
29
+ return this[0].toString() + ' and ' + this[1].toString();
30
+ default:
31
+ return this.slice(0, -1).join(', ') + ', and ' + this[this.length - 1].toString();
32
+ }
33
+ }
34
+ }
35
+
36
+
37
+
38
+ //
39
+ // .dup
40
+ //
41
+ Array.prototype.__dup = function(fn) {
42
+ return this.slice(0);
43
+ }
44
+ if(!Array.prototype.dup) Array.prototype.dup = Array.prototype.__dup;
45
+
46
+
47
+
48
+ //
49
+ // .each
50
+ // Distinct from Prototype's each which catches exceptions (ew!)
51
+ // so that if Prototype defines each, I can still call __each
52
+ //
53
+ Array.prototype.__each = function(fn) {
54
+ for(var i=0, len=this.length; i<len; i++) {
55
+ fn(this[i], i);
56
+ }
57
+ }
58
+ if(!Array.prototype.each) Array.prototype.each = Array.prototype.__each;
59
+
60
+
61
+
62
+ //
63
+ // .collect
64
+ //
65
+ Array.prototype.__collect = function(fn) {
66
+ var new_array = [];
67
+ for(var i=0; i<this.length; i++) {
68
+ new_array.push(fn(this[i]));
69
+ }
70
+ return new_array;
71
+ }
72
+ if(!Array.prototype.collect) Array.prototype.collect = Array.prototype.__collect;
73
+
74
+
75
+
76
+ //
77
+ // .inject
78
+ //
79
+ Array.prototype.__inject = function(memo, fn) {
80
+ for(var i=0; i<this.length; i++) {
81
+ memo = fn(memo, this[i]);
82
+ }
83
+ return memo;
84
+ }
85
+ if(!Array.prototype.inject) Array.prototype.inject = Array.prototype.__inject;
86
+
87
+
88
+
89
+ //
90
+ // .find
91
+ //
92
+ Array.prototype.__find = function(fn) {
93
+ for(var i=0; i<this.length; i++) {
94
+ if(fn(this[i])) {
95
+ return this[i];
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ if(!Array.prototype.find) Array.prototype.find = Array.prototype.__find;
@@ -0,0 +1,415 @@
1
+ var SetBuilder = (function() {
2
+
3
+ var _modifiers;
4
+ var _traits;
5
+ var _value_maps = {};
6
+
7
+ return {
8
+ init: function(traits, modifiers) {
9
+ registerTraits(traits);
10
+ registerModifiers(modifiers);
11
+ },
12
+ registerTraits: function(traits) {
13
+ _traits = new SetBuilder.Traits(traits);
14
+ },
15
+ registerModifiers: function(modifiers) {
16
+ _modifiers = new SetBuilder.Modifiers(modifiers);
17
+ },
18
+ registerValueMap: function(key, map) {
19
+ _value_maps[key] = map;
20
+ },
21
+ registerValueMaps: function(_data) {
22
+ for(key in _data) {
23
+ _value_maps[key] = _data[key];
24
+ }
25
+ },
26
+ traits: function() {
27
+ return _traits;
28
+ },
29
+ modifiers: function() {
30
+ return _modifiers;
31
+ },
32
+ getValueMap: function(key) {
33
+ return _value_maps[key];
34
+ },
35
+ getValue: function(key, value) {
36
+ var match = value.toString(),
37
+ map = SetBuilder.getValueMap(key);
38
+ if(map) {
39
+ var pair = map.__find(function(i) { return (i[0] == match) });
40
+ return pair ? pair[1] : '(unknown)';
41
+ } else {
42
+ return value;
43
+ }
44
+ // map = _value_maps[key];
45
+ // return map ? map[value.toString()] : value;
46
+ },
47
+ getValueMaps: function() {
48
+ return Object.keys(_value_maps);
49
+ }
50
+ }
51
+
52
+ })();
53
+
54
+
55
+
56
+ /*
57
+ Constraint (c.f. /lib/set_builder/constraint.rb)
58
+ ===========================================================
59
+
60
+ a constrained trait
61
+ */
62
+
63
+ SetBuilder.Constraint = function(_trait, args) {
64
+
65
+ var _direct_object;
66
+ if(typeof(_trait) == 'string') {
67
+ _trait = SetBuilder.traits().__find(_trait);
68
+ }
69
+
70
+ args = args.dup();
71
+ if(_trait.requires_direct_object()) _direct_object = args.shift();
72
+ var _modifiers = _trait.modifiers().collect(function(modifier_type) {
73
+ return SetBuilder.modifiers().apply(modifier_type, args.shift());
74
+ });
75
+ var _negative = false;
76
+
77
+
78
+
79
+ // Public methods
80
+
81
+ this.trait = function(val) {
82
+ if(val !== undefined) {
83
+ _trait = val;
84
+ _direct_object = undefined;
85
+ _modifiers = [];
86
+ }
87
+ return _trait;
88
+ }
89
+
90
+ this.direct_object = function(val) {
91
+ if(val !== undefined) {
92
+ _direct_object = val;
93
+ }
94
+ return _direct_object;
95
+ }
96
+
97
+ this.modifiers = function() {
98
+ return _modifiers;
99
+ }
100
+
101
+ this.negate = function(value) {
102
+ _negative = value;
103
+ if(_trait.noun()) _negative = false;
104
+ return this;
105
+ }
106
+
107
+ this.negative = function() {
108
+ return _negative;
109
+ }
110
+
111
+ this.requires_direct_object = function() {
112
+ return _trait.requires_direct_object();
113
+ }
114
+
115
+ this.prefix = function() {
116
+ return _trait.prefix(_negative);
117
+ }
118
+
119
+ this.toString = function(include_prefix) {
120
+ var _description = _trait.toString(include_prefix, _negative);
121
+ if(_direct_object) {
122
+ _description += ' ' + SetBuilder.getValue(_trait.direct_object_type(), _direct_object);
123
+ }
124
+ _modifiers.__each(function(modifier) {
125
+ _description += ' ' + modifier.toString(_negative);
126
+ });
127
+ return _description;
128
+ }
129
+
130
+ };
131
+
132
+
133
+
134
+ /*
135
+ Modifier (c.f. /lib/set_builder/modifier/base.rb)
136
+ ===========================================================
137
+
138
+
139
+ */
140
+
141
+ SetBuilder.Modifier = function(_name, _operator, _values, _params) {
142
+
143
+
144
+
145
+ // Public methods
146
+
147
+ this.name = function() {
148
+ return _name;
149
+ }
150
+
151
+ this.operator = function() {
152
+ return _operator;
153
+ }
154
+
155
+ this.values = function() {
156
+ return _values;
157
+ }
158
+
159
+ this.toString = function(negative) {
160
+ var words = [_operator.replace(/_/, ' ')];
161
+ for(var i=0; i<_values.length; i++) {
162
+ words.push(SetBuilder.getValue(_params[i], _values[i]));
163
+ }
164
+ return words.join(' ');
165
+ }
166
+
167
+ };
168
+
169
+
170
+
171
+ /*
172
+ Modifiers (c.f. /lib/set_builder/modifier.rb)
173
+ ===========================================================
174
+
175
+ [
176
+ [modifier_name, {
177
+ operator: ['argument 1 type', 'argument 2 type'],
178
+ another_operator: ['argument 1 type'],
179
+ yet_another_operator: []
180
+ }]
181
+ ]
182
+ */
183
+
184
+ SetBuilder.Modifiers = function(_modifiers) {
185
+
186
+ var keys = Object.keys(_modifiers);
187
+
188
+ function _operators_for(name) {
189
+ var operators = _modifiers[name];
190
+ if(operators) {
191
+ return operators;
192
+ } else {
193
+ throw ('"' + name.toString() + '" is not a registered modifier.');
194
+ }
195
+ }
196
+
197
+
198
+
199
+ // Public methods
200
+ this.length = function() {
201
+ return keys.length;
202
+ }
203
+
204
+ // Returns the names of the operators allowed for the given modifier
205
+ this.operators_for = function(modifier_type) {
206
+ return Object.keys(_operators_for(modifier_type));
207
+ }
208
+
209
+ // Returns the names of the arguments a given operator anticipates
210
+ this.params_for_operator = function(modifier_type, operator_name) {
211
+ if(!operator_name) throw 'An operator name was not supplied.'
212
+ var params = _operators_for(modifier_type)[operator_name];
213
+ if(params) {
214
+ return params;
215
+ } else {
216
+ throw ('"' + operator_name.toString() + '" is not an operator for the ' + modifier_type + ' modifier.');
217
+ }
218
+ }
219
+
220
+ // Examples of Usage:
221
+ //
222
+ // An operator that takes one argument:
223
+ // apply('date', {'before': ['2012-11-12']})
224
+ //
225
+ // An operator that takes two arguments:
226
+ // apply('date', {'in_the_last': [5, 'days']})
227
+ //
228
+ //
229
+ // `args` is expected to be an object that has one key and one value.
230
+ //
231
+ this.apply = function(modifier_type, args) {
232
+ args = args || {};
233
+ var operator = Object.keys(args)[0];
234
+ if(!operator) throw 'An operator name was not supplied.'
235
+
236
+ var params = this.params_for_operator(modifier_type, operator);
237
+ var values = (args)[operator];
238
+
239
+ if(!(values instanceof Array)) values = [values];
240
+ if(values.length != params.length) {
241
+ throw ('The operator "' + operator.toString() + '" expects ' + params.length + ' arguments but received ' + values.length + '.');
242
+ }
243
+
244
+ return new SetBuilder.Modifier(name, operator, values, params);
245
+ }
246
+
247
+ };
248
+
249
+
250
+
251
+ /*
252
+ Set (c.f. /lib/set_builder/set.rb)
253
+ ===========================================================
254
+
255
+ a set of constrained traits that describe a group
256
+ */
257
+
258
+ SetBuilder.Set = function(_raw_data) {
259
+
260
+ if(!_raw_data) _raw_data = [];
261
+
262
+ var _constraints = [];
263
+ _raw_data.__each(function(line) {
264
+ var trait_name = line[0];
265
+ var negative = false;
266
+ if(trait_name[0] == '!') {
267
+ negative = true;
268
+ trait_name = trait_name.slice(1);
269
+ }
270
+ var trait = SetBuilder.traits().__find(trait_name);
271
+ var args = line.slice(1);
272
+ if(trait) {
273
+ _constraints.push(trait.apply(args).negate(negative));
274
+ } else if(window.console && window.console.log) {
275
+ window.console.log('trait not found with name "' + line[0] + '"');
276
+ }
277
+ });
278
+
279
+
280
+
281
+ // Public methods
282
+
283
+ this.data = function() {
284
+
285
+ // TODO: write the data structure from constraints!
286
+
287
+ }
288
+
289
+ this.constraints = function() {
290
+ return _constraints;
291
+ }
292
+
293
+ this.toString = function() {
294
+ return this.constraints().toSentence();
295
+ }
296
+
297
+ };
298
+
299
+
300
+
301
+ /*
302
+ Trait (c.f. /lib/set_builder/trait/base.rb)
303
+ ===========================================================
304
+
305
+ an individual trait that can be constrained
306
+ */
307
+
308
+ SetBuilder.Trait = function(_raw_data) {
309
+
310
+ // window.console.log('new SetBuilder.Trait()');
311
+ // window.console.log(_raw_data);
312
+ var _name = _raw_data[0];
313
+ var _part_of_speech = _raw_data[1].toString().toLowerCase();
314
+ var _modifiers = _raw_data[2] || []; //.collect(function(modifier_name) {
315
+ // return SetBuilder.Modifiers.__find(modifier_name);
316
+ // });
317
+ var _direct_object_type;
318
+
319
+ if(typeof(_name) != 'string') {
320
+ _direct_object_type = _name[1];
321
+ _name = _name[0];
322
+ }
323
+
324
+
325
+
326
+ // Public methods
327
+
328
+ this.requires_direct_object = function() {
329
+ return !!_direct_object_type;
330
+ }
331
+
332
+ this.direct_object_type = function() {
333
+ return _direct_object_type;
334
+ }
335
+
336
+ this.name = function() {
337
+ return _name;
338
+ }
339
+
340
+ this.noun = function() {
341
+ return (_part_of_speech == 'noun');
342
+ }
343
+
344
+ this.modifiers = function() {
345
+ return _modifiers;
346
+ }
347
+
348
+ this.prefix = function(negative) {
349
+ if(negative === undefined) negative = false;
350
+ switch(_part_of_speech) {
351
+ case 'active':
352
+ return negative ? 'who have not' : 'who';
353
+ case 'perfect':
354
+ return negative ? 'who have not' : 'who have';
355
+ case 'passive':
356
+ return negative ? 'who were not' : 'who were';
357
+ case 'reflexive':
358
+ return negative ? 'who are not' : 'who are';
359
+ case 'noun':
360
+ return 'whose';
361
+ default:
362
+ return undefined;
363
+ }
364
+ }
365
+
366
+ this.toString = function(include_prefix, negative) {
367
+ var prefix = this.prefix(negative);
368
+ if(prefix) { // return an empty string if the prefix is invalid
369
+ return (include_prefix==false) ? this.name() : (prefix + ' ' + this.name());
370
+ } else {
371
+ return '';
372
+ }
373
+ }
374
+
375
+ this.apply = function(args) {
376
+ return new SetBuilder.Constraint(this, args);
377
+ }
378
+
379
+ };
380
+
381
+
382
+
383
+ /*
384
+ Traits (c.f. /lib/set_builder/traits.rb)
385
+ ===========================================================
386
+
387
+ a collection of traits that allows fetching by name
388
+ */
389
+
390
+ SetBuilder.Traits = function(_raw_data) {
391
+
392
+ var _traits = _raw_data.collect(function(line) {
393
+ return new SetBuilder.Trait(line);
394
+ });
395
+
396
+
397
+ // Public methods
398
+
399
+ this.length = function() {
400
+ return _traits.length;
401
+ }
402
+
403
+ this.names = function() {
404
+ return _traits.collect(function(trait) {
405
+ return trait.name();
406
+ });
407
+ }
408
+
409
+ this.__find = function(name) {
410
+ return _traits.__find(function(trait) {
411
+ return (trait.name() == name);
412
+ });
413
+ }
414
+
415
+ };