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.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae95d6f2f3cfb324b760144d8cab1e61fc4b41b5
4
- data.tar.gz: a5f02d71b73862a3251ff48b167a07d3cf1a8b14
3
+ metadata.gz: acd34d467c6aca8cc3c42db795261de035c72c58
4
+ data.tar.gz: 2c08cc3a703c5cc84230cbaa0e047004d4e7f430
5
5
  SHA512:
6
- metadata.gz: f61aa92460102dd67880c0bc3d670f0c5ae5938ab0f83b2bf4f074597ececa1cf6933f9fcf15217d8e06d4913bd4b83192683fd5205d5b57c34aedacacca1932
7
- data.tar.gz: 2803e8640beddb5fb8bbc880a2187af33da4534b98577df9dcde5ef29c7df432b45b886d1f654468d85adb925bb8f7ca5e483051275505ffa9dd385f49585e23
6
+ metadata.gz: d79aec9ff59f398bc844de87cbc9a7946fb43166017d1231c36fc8a1ff267a296a98e88e524d3b01b2c726bd91ed75d4e63833246e32cc6fa25114e038809cb1
7
+ data.tar.gz: d4ba5f0e2dfff5ad5245abd758adcac891c93fe2e0bba30c830e52b7dd63e7749962ed6843dc4f3c4b33b1e7b3a3b33dcb58ceef97312a417cce6abbf8be8962
data/README.md CHANGED
@@ -15,16 +15,16 @@ SetBuilder is a library for:
15
15
 
16
16
  The following Set describes a group of people:
17
17
 
18
- [[:awesome],
19
- [:attended, "school"],
20
- [:died, :not],
21
- [:name, {:is => "Jerome"}]]
18
+ [{ trait: :awesome, choices: ["are"] },
19
+ { trait: :attended, choices: ["have"], school: "school" },
20
+ { trait: :died, choices: ["have not"] },
21
+ { trait: :name, modifiers: [{ operator: :is, values: ["Jerome"] }] }]
22
22
 
23
23
  SetBuilder can render this Set in plain English:
24
24
 
25
- [Everyone] who is awesome, who attended school, who has not died, and whose name is Jerome.
25
+ [Those] who are awesome, who have attended school, who have not died, and whose name is Jerome.
26
26
 
27
- It can also generate a NamedScope on an ActiveRecord model to fetch the people who fit in this set.
27
+ It can also generate an `ActiveRecord::Relation` on an ActiveRecord model to fetch the people who fit in this set.
28
28
 
29
29
 
30
30
  ### Running the tests
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
- require 'rake'
2
- require 'rake/testtask'
1
+ require "rake"
2
+ require "rake/testtask"
3
3
 
4
4
  desc 'Run tests.'
5
5
  task :default => :test
data/init.rb CHANGED
@@ -1 +1 @@
1
- require 'set_builder'
1
+ require "set_builder"
@@ -1,9 +1,9 @@
1
1
  var SetBuilder = (function() {
2
-
2
+
3
3
  var _modifiers;
4
4
  var _traits;
5
5
  var _value_maps = {};
6
-
6
+
7
7
  return {
8
8
  init: function(traits, modifiers) {
9
9
  registerTraits(traits);
@@ -22,7 +22,7 @@ var SetBuilder = (function() {
22
22
  for(key in _data) {
23
23
  _value_maps[key] = _data[key];
24
24
  }
25
- },
25
+ },
26
26
  traits: function() {
27
27
  return _traits;
28
28
  },
@@ -43,7 +43,7 @@ var SetBuilder = (function() {
43
43
  default: return values.slice(0, -1).join(', ') + ', or ' + values[values.length - 1];
44
44
  }
45
45
  }
46
-
46
+
47
47
  var match = value.toString(),
48
48
  map = SetBuilder.getValueMap(key);
49
49
  if(map) {
@@ -57,7 +57,7 @@ var SetBuilder = (function() {
57
57
  return Object.keys(_value_maps);
58
58
  }
59
59
  }
60
-
60
+
61
61
  })();
62
62
 
63
63
 
@@ -65,64 +65,65 @@ var SetBuilder = (function() {
65
65
  /*
66
66
  Constraint (c.f. /lib/set_builder/constraint.rb)
67
67
  ===========================================================
68
-
68
+
69
69
  a constrained trait
70
70
  */
71
71
 
72
- SetBuilder.Constraint = function(_trait, args) {
73
-
74
- var _direct_object;
72
+ SetBuilder.Constraint = function(_trait, params) {
73
+
75
74
  if(typeof(_trait) == 'string') {
76
75
  _trait = SetBuilder.traits().__find(_trait);
77
76
  }
78
77
 
79
- args = args.dup();
80
- if(_trait.requiresDirectObject()) _direct_object = args.shift();
81
- var _modifiers = _trait.modifiers().collect(function(modifier_type) {
82
- return SetBuilder.modifiers().apply(modifier_type, args.shift());
83
- });
84
- var _negative = false;
85
-
86
-
87
-
78
+ var _enums = params.enums || [];
79
+ var _direct_object;
80
+ if(_trait.requiresDirectObject()) {
81
+ _direct_object = params[_trait.directObjectType()];
82
+ }
83
+
84
+ var _modifiers = [];
85
+ for(var i=0, ii=_trait.modifiers().length; i<ii; i++) {
86
+ _modifiers.push(
87
+ SetBuilder.modifiers().apply(
88
+ _trait.modifiers()[i],
89
+ (params.modifiers||[])[i]));
90
+ }
91
+
92
+
93
+
88
94
  // Public methods
89
-
95
+
90
96
  this.trait = function(val) {
91
97
  if(val !== undefined) {
92
98
  _trait = val;
93
99
  _direct_object = undefined;
100
+ _enums = [];
94
101
  _modifiers = [];
95
102
  }
96
103
  return _trait;
97
104
  }
98
-
105
+
99
106
  this.direct_object = function(val) {
100
107
  if(val !== undefined) {
101
108
  _direct_object = val;
102
109
  }
103
110
  return _direct_object;
104
111
  }
105
-
112
+
113
+ this.enums = function() {
114
+ return _enums;
115
+ }
116
+
106
117
  this.modifiers = function() {
107
118
  return _modifiers;
108
119
  }
109
-
110
- this.negate = function(value) {
111
- _negative = value;
112
- if(!_trait.hasNegative()) _negative = false;
113
- return this;
114
- }
115
-
116
- this.negative = function() {
117
- return _negative;
118
- }
119
-
120
+
120
121
  this.requires_direct_object = function() {
121
122
  return _trait.requires_direct_object();
122
123
  }
123
-
124
+
124
125
  this.toString = function() {
125
- var type, text, i = 0;
126
+ var type, text, enum_index = 0, modifier_index = 0;
126
127
  return _trait.tokens().collect(function(token) {
127
128
  type = token[0], text = token[1];
128
129
  switch(type) {
@@ -130,17 +131,17 @@ SetBuilder.Constraint = function(_trait, args) {
130
131
  return text;
131
132
  case 'name':
132
133
  return _trait.name();
133
- case 'negative':
134
- return _negative && text;
134
+ case 'enum':
135
+ return (_enums[enum_index++] || '').toString();
135
136
  case 'direct_object_type':
136
137
  return SetBuilder.getValue(text, _direct_object);
137
138
  case 'modifier':
138
- return _modifiers[i++].toString().replace('_', ' ');
139
+ return (_modifiers[modifier_index++] || '').toString().replace('_', ' ');
139
140
  default:
140
141
  if(console && console.log) console.log('[SetBuilder.Constraint] unknown type: "' + type + '" (text: "' + text + '")');
141
142
  return false;
142
143
  }
143
- }).compact().join(' ');
144
+ }).join('');
144
145
  }
145
146
 
146
147
  };
@@ -155,23 +156,23 @@ SetBuilder.Constraint = function(_trait, args) {
155
156
  */
156
157
 
157
158
  SetBuilder.Modifier = function(_name, _operator, _values, _params) {
158
-
159
-
160
-
159
+
160
+
161
+
161
162
  // Public methods
162
-
163
+
163
164
  this.name = function() {
164
165
  return _name;
165
166
  }
166
-
167
+
167
168
  this.operator = function() {
168
169
  return _operator;
169
170
  }
170
-
171
+
171
172
  this.values = function() {
172
173
  return _values;
173
174
  }
174
-
175
+
175
176
  this.toString = function() {
176
177
  var words = [_operator.replace(/_/, ' ')];
177
178
  for(var i=0; i<_values.length; i++) {
@@ -187,7 +188,7 @@ SetBuilder.Modifier = function(_name, _operator, _values, _params) {
187
188
  /*
188
189
  Modifiers (c.f. /lib/set_builder/modifier.rb)
189
190
  ===========================================================
190
-
191
+
191
192
  [
192
193
  [modifier_name, {
193
194
  operator: ['argument 1 type', 'argument 2 type'],
@@ -198,9 +199,9 @@ SetBuilder.Modifier = function(_name, _operator, _values, _params) {
198
199
  */
199
200
 
200
201
  SetBuilder.Modifiers = function(_modifiers) {
201
-
202
+
202
203
  var keys = Object.keys(_modifiers);
203
-
204
+
204
205
  function _operators_for(name) {
205
206
  var operators = _modifiers[name];
206
207
  if(operators) {
@@ -209,19 +210,19 @@ SetBuilder.Modifiers = function(_modifiers) {
209
210
  throw ('"' + name.toString() + '" is not a registered modifier.');
210
211
  }
211
212
  }
212
-
213
-
214
-
213
+
214
+
215
+
215
216
  // Public methods
216
217
  this.length = function() {
217
218
  return keys.length;
218
219
  }
219
-
220
+
220
221
  // Returns the names of the operators allowed for the given modifier
221
222
  this.operators_for = function(modifier_type) {
222
223
  return Object.keys(_operators_for(modifier_type));
223
224
  }
224
-
225
+
225
226
  // Returns the names of the arguments a given operator anticipates
226
227
  this.params_for_operator = function(modifier_type, operator_name) {
227
228
  if(!operator_name) throw 'An operator name was not supplied.'
@@ -232,31 +233,29 @@ SetBuilder.Modifiers = function(_modifiers) {
232
233
  throw ('"' + operator_name.toString() + '" is not an operator for the ' + modifier_type + ' modifier.');
233
234
  }
234
235
  }
235
-
236
+
236
237
  // Examples of Usage:
237
238
  //
238
239
  // An operator that takes one argument:
239
- // apply('date', {'before': ['2012-11-12']})
240
+ // apply('date', {operator: 'before', values: ['2012-11-12']})
240
241
  //
241
242
  // An operator that takes two arguments:
242
- // apply('date', {'in_the_last': [5, 'days']})
243
- //
244
- //
245
- // `args` is expected to be an object that has one key and one value.
243
+ // apply('date', {operator: 'in_the_last', values: [5, 'days']})
246
244
  //
247
245
  this.apply = function(modifier_type, args) {
248
246
  args = args || {};
249
- var operator = Object.keys(args)[0];
247
+ var operator = args.operator;
250
248
  if(!operator) throw 'An operator name was not supplied.'
251
-
249
+
252
250
  var params = this.params_for_operator(modifier_type, operator);
253
- var values = (args)[operator];
251
+ var values = args.values;
254
252
 
253
+ if(!values) values = [];
255
254
  if(!(values instanceof Array)) values = [values];
256
255
  if(values.length != params.length) {
257
256
  throw ('The operator "' + operator.toString() + '" expects ' + params.length + ' arguments but received ' + values.length + '.');
258
257
  }
259
-
258
+
260
259
  return new SetBuilder.Modifier(name, operator, values, params);
261
260
  }
262
261
 
@@ -267,74 +266,67 @@ SetBuilder.Modifiers = function(_modifiers) {
267
266
  /*
268
267
  Set (c.f. /lib/set_builder/set.rb)
269
268
  ===========================================================
270
-
269
+
271
270
  a set of constrained traits that describe a group
272
271
  */
273
272
 
274
273
  SetBuilder.Set = function(_raw_data) {
275
274
  if(!_raw_data) _raw_data = [];
276
275
  if(_raw_data.constructor !== Array) _raw_data = convertObjectSetToArray(_raw_data);
277
-
276
+
278
277
  var _constraints = [];
279
-
280
- _raw_data.__each(function(line) {
281
- var trait_name = line[0];
282
- var negative = false;
283
-
284
- if(trait_name[0] == '!') {
285
- negative = true;
286
- trait_name = trait_name.slice(1);
287
- }
278
+
279
+ _raw_data.__each(function(params) {
280
+ var trait_name = params.trait;
288
281
  var trait = SetBuilder.traits().__find(trait_name);
289
- var args = line.slice(1);
290
282
  if(trait) {
291
- _constraints.push(trait.apply(args).negate(negative));
283
+ _constraints.push(trait.apply(params));
292
284
  } else if(window.console && window.console.log) {
293
- window.console.log('trait not found with name "' + line[0] + '"');
285
+ window.console.log('trait not found with name "' + trait_name + '"');
294
286
  }
295
287
  });
296
-
297
- function convertObjectSetToArray(data) {
298
- var set = [];
299
-
300
- Object.keys(data).__each(function(key) {
301
- var convertedTrait = [];
302
- var trait = data[key];
303
- convertedTrait.push(trait.negative ? "!" + trait.trait : trait.trait)
304
- if(trait.direct_object) convertedTrait.push(trait.direct_object);
305
- if(trait.modifiers) {
306
- Object.keys(trait.modifiers).__each(function(key) {
307
- var modifier = trait.modifiers[key];
308
- var convertedModifier = {};
309
- convertedModifier[modifier.operator] = modifier.values ? Object.values(modifier.values) : [];
310
- convertedTrait.push(convertedModifier);
288
+
289
+ function convertObjectSetToArray(constraints) {
290
+ return convertHashToArray(constraints).__collect(function(constraint) {
291
+ if(constraint.modifiers) {
292
+ constraint.modifiers = convertHashToArray(constraint.modifiers).__collect(function(modifier) {
293
+ if(modifier.values) {
294
+ modifier.values = convertHashToArray(modifier.values);
295
+ }
296
+ return modifier;
311
297
  });
312
298
  }
313
- set.push(convertedTrait);
299
+ return constraint;
314
300
  });
315
- return set;
316
301
  }
317
-
302
+
303
+ function convertHashToArray(hash) {
304
+ if(hash === Array) return hash;
305
+ return Object.values(hash);
306
+ }
307
+
308
+
309
+
318
310
  // Public methods
319
-
311
+
320
312
  this.data = function() {
321
-
313
+
322
314
  // TODO: write the data structure from constraints!
323
-
315
+
324
316
  }
325
-
317
+
326
318
  this.constraints = function() {
327
319
  return _constraints;
328
320
  }
329
-
321
+
330
322
  this.toString = function() {
331
323
  return this.constraints().toSentence();
332
324
  }
333
-
325
+
334
326
  this.isEqualTo = function(other) {
335
327
  return this.toString() == other.toString();
336
328
  }
337
-
329
+
338
330
  };
339
331
 
340
332
 
@@ -342,14 +334,17 @@ SetBuilder.Set = function(_raw_data) {
342
334
  /*
343
335
  Trait (c.f. /lib/set_builder/trait/base.rb)
344
336
  ===========================================================
345
-
337
+
346
338
  an individual trait that can be constrained
347
339
  */
348
340
 
349
341
  SetBuilder.Trait = function(_tokens) {
350
-
342
+
351
343
  var type, text;
352
- var _name, _modifiers = [], _direct_object_type, _negative;
344
+ var _name,
345
+ _modifiers = [],
346
+ _direct_object_type,
347
+ _enums = [];
353
348
  _tokens.each(function(token) {
354
349
  type = token[0], text = token[1];
355
350
  switch(type) {
@@ -362,35 +357,35 @@ SetBuilder.Trait = function(_tokens) {
362
357
  case 'direct_object_type':
363
358
  _direct_object_type = text;
364
359
  break;
365
- case 'negative':
366
- _negative = text;
360
+ case 'enums':
361
+ _enums.push(text);
367
362
  break;
368
363
  }
369
364
  });
370
-
371
-
365
+
366
+
372
367
  // Public methods
373
-
368
+
374
369
  this.requiresDirectObject = function() {
375
370
  return !!_direct_object_type;
376
371
  }
377
-
378
- this.direct_object_type = function() {
372
+
373
+ this.directObjectType = function() {
379
374
  return _direct_object_type;
380
375
  }
381
-
376
+
382
377
  this.name = function() {
383
378
  return _name;
384
379
  }
385
-
386
- this.hasNegative = function() {
387
- return !!_negative;
380
+
381
+ this.enums = function() {
382
+ return _enums;
388
383
  }
389
-
384
+
390
385
  this.modifiers = function() {
391
386
  return _modifiers;
392
387
  }
393
-
388
+
394
389
  this.tokens = function() {
395
390
  return _tokens;
396
391
  }
@@ -411,24 +406,24 @@ SetBuilder.Trait = function(_tokens) {
411
406
  */
412
407
 
413
408
  SetBuilder.Traits = function(_raw_data) {
414
-
409
+
415
410
  var _traits = _raw_data.collect(function(line) {
416
411
  return new SetBuilder.Trait(line);
417
412
  });
418
-
419
-
413
+
414
+
420
415
  // Public methods
421
-
416
+
422
417
  this.length = function() {
423
418
  return _traits.length;
424
419
  }
425
-
420
+
426
421
  this.names = function() {
427
422
  return _traits.collect(function(trait) {
428
423
  return trait.name();
429
424
  });
430
425
  }
431
-
426
+
432
427
  this.__find = function(name) {
433
428
  return _traits.__find(function(trait) {
434
429
  return (trait.name() == name);
@@ -452,7 +447,7 @@ if(!Object.keys) {
452
447
  for(key in o) {
453
448
  keys.push(key);
454
449
  }
455
- return keys;
450
+ return keys;
456
451
  }
457
452
  }
458
453
 
@@ -568,6 +563,8 @@ Array.prototype.__find = function(fn) {
568
563
  }
569
564
  if(!Array.prototype.find) Array.prototype.find = Array.prototype.__find;
570
565
 
566
+
567
+
571
568
  //
572
569
  // .select
573
570
  //
@@ -1,68 +1,84 @@
1
- require 'set_builder/modifier'
1
+ require "set_builder/modifier"
2
2
 
3
3
 
4
4
  module SetBuilder
5
5
  class Constraint
6
-
7
-
6
+ attr_reader :trait, :params, :direct_object, :enums, :modifiers
7
+ delegate :direct_object_required?,
8
+ :direct_object_type,
9
+ :to => :trait
10
+
11
+
12
+
8
13
  #
9
14
  # Sample constraints:
10
- #
11
- # [:awesome],
12
- # [:attended, "school"],
13
- # [:died],
14
- # [:name, {:is => "Jerome"}]]
15
- #
16
- def initialize(trait, *args, &block)
15
+ #
16
+ # { trait: :awesome }
17
+ # { trait: :attended, school: 2 }
18
+ # { trait: :died, enums: ["have not"] }
19
+ # { trait: :name, modifiers: [{ operator: :is, values: ["Jerome"] }] }
20
+ #
21
+ def initialize(trait, params, &block)
17
22
  @trait, @block = trait, block
18
- @direct_object = args.shift if trait.requires_direct_object?
19
- @modifiers = trait.modifiers.collect {|modifier_type| modifier_type.new(args.shift)}
23
+ @params = params
24
+
25
+ @direct_object = params[direct_object_type] if trait.requires_direct_object?
26
+ @enums = params[:enums] || []
27
+ modifiers = params.fetch(:modifiers, [])
28
+ @modifiers = trait.modifiers.each_with_index.map { |modifier, i|
29
+ modifier.new(modifiers[i] || {}) }
20
30
  end
21
-
22
-
23
-
24
- attr_reader :trait, :direct_object, :modifiers, :negative
25
- alias :negative? :negative
26
-
27
-
28
-
29
- delegate :direct_object_required?,
30
- :direct_object_type,
31
- :to => :trait
32
-
33
-
34
-
31
+
32
+
33
+
35
34
  def valid?
36
- (!direct_object_required? or !direct_object.nil?) and modifiers.all?(&:valid?)
35
+ errors.none?
37
36
  end
38
-
39
-
40
-
41
- def to_s
42
- # p "ValueMap.to_s(#{direct_object_type} (#{direct_object_type.class}), #{direct_object} (#{direct_object.class}))"
43
- @description ||= begin
44
- description = trait.to_s(@negative)
45
- description << " #{ValueMap.to_s(direct_object_type, direct_object)}" if direct_object_required?
46
- description << " #{modifiers.collect{|m| m.to_s(@negative)}.join(" ")}" unless modifiers.empty?
47
- description
37
+
38
+ def errors
39
+ [].tap do |errors|
40
+ errors.push "#{direct_object_type} is blank" if direct_object_required? && direct_object.nil?
41
+ if enums.length != trait.enums.length
42
+ errors.push "should have values for #{trait.enums.length} enums"
43
+ else
44
+ trait.enums.each_with_index do |expected_values, i|
45
+ errors.push "enum ##{i + 1} should be #{expected_values.map { |value| "'#{value}'" }.to_sentence(two_words_connector: " or ", last_word_connector: ", or ")}" unless expected_values.member?(enums[i])
46
+ end
47
+ end
48
+ errors.concat modifiers.flat_map(&:errors)
48
49
  end
49
50
  end
50
-
51
-
52
-
53
- def negate(value)
54
- @negative = value
55
- @negative = false unless trait.negative?
56
- self
51
+
52
+
53
+
54
+ def to_s
55
+ @description ||= stringify(trait.tokens)
57
56
  end
58
-
59
-
60
-
57
+
58
+
59
+
61
60
  def perform(scope)
62
61
  @block.call(self, scope)
63
62
  end
64
-
65
-
66
-
63
+
64
+
65
+
66
+ private
67
+
68
+ def stringify(tokens)
69
+ enum_index = 0
70
+ modifier_index = 0
71
+ tokens.map do |token, value|
72
+ case token
73
+ when :string then value
74
+ when :name then trait.name
75
+ when :enum then enums[enum_index].to_s.tap { enum_index += 1 }
76
+ when :direct_object_type then ValueMap.to_s(value, direct_object)
77
+ when :modifier then modifiers[modifier_index].to_s.tap { modifier_index += 1 }
78
+ else raise NotImplementedError, "Unrecognized token type #{token.inspect}"
79
+ end
80
+ end.join
81
+ end
82
+
67
83
  end
68
84
  end
@@ -0,0 +1,3 @@
1
+ module SetBuilder
2
+ class TraitNotFound < RuntimeError; end
3
+ end