talk 2.0.5 → 2.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f1f1b965faec105c8139b2c31c25093ad3f7a07d
4
- data.tar.gz: 65ad8dfa35eca34ccf71e9348760e42fb68cd639
3
+ metadata.gz: ef1157116afc257fd1bfc78676ddc0cb737015f7
4
+ data.tar.gz: 93d87b8b6b4e8ad6cbd383df6870adf3399e824a
5
5
  SHA512:
6
- metadata.gz: 09583344d986efe5ff4d06b71c54dabcbee808d27586dd623a79d5c1451ce3e4f4e967a7096286fdbc7f9df77fe47e6e718359b402509b11cadf7191a5df8831
7
- data.tar.gz: e4501266f0041de42d2c9b4556a04a98645318b850b68d2c9cc031413d5f4fb0bc838ad1a749430d86c006c8bdafa387c81055fa1564c37dcdc273f48449ab1b
6
+ metadata.gz: e598d2d1ea1997a9c45cbe1c4989eb390ea4f08df5c1c839379b9fb19e25bcd5d2ea451fa5bb88f9d29096afc6f258f2b6d6103c57eb096c2105ad39f605ec2e
7
+ data.tar.gz: 7bbaeab38727d136e065c54113792bd7fd3cea40794bb0f0f9e049cb860e1060269a477ec21ac120136a15eb93e9db22b88f23f8d330928a445d37a23467ff60
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem 'trollop'
4
4
  gem 'json'
5
+ gem 'uglifier'
5
6
 
6
7
  group :test do
7
8
  gem 'cucumber'
data/lib/context.rb CHANGED
@@ -18,7 +18,7 @@ module Talk
18
18
 
19
19
  ## Parser interface
20
20
 
21
- def parse(word, file, line)
21
+ def parse(word, file=nil, line=nil)
22
22
  @property_words.push word
23
23
  end
24
24
 
data/lib/context_class.rb CHANGED
@@ -185,6 +185,12 @@ module Talk
185
185
 
186
186
  add_tag_singular(name) unless params[:multi]
187
187
  add_tag_required(name) if params[:required]
188
+ postprocess(lambda do |c|
189
+ return if c.has_key? name
190
+ tag = c.start_tag(name, c.file, c.line)
191
+ tag.parse(params[:default])
192
+ c.end_tag(tag)
193
+ end) if params[:default]
188
194
  end
189
195
 
190
196
  def add_tag_singular(name)
@@ -0,0 +1,81 @@
1
+ require 'uglifier'
2
+
3
+ def make_source
4
+ @prefix = common_class_prefix if meta(:namespace) == "true"
5
+ transform = meta(:minify) ? lambda { |source| Uglifier.compile(source)} : nil
6
+ generate_template("talk.js", "talk.js.erb", transform)
7
+ end
8
+
9
+ def autogenerated_warning
10
+ <<-AUTOGEN_DONE
11
+ // Autogenerated from Talk
12
+ // Please do not edit this file directly. Instead, modify the underlying .talk files.
13
+ AUTOGEN_DONE
14
+ end
15
+
16
+ def comment_block(tag, indent_level=0)
17
+ lines = []
18
+ indent = "\t" * indent_level
19
+ lines.push(indent + "/*")
20
+ lines.push(wrap_text_to_width(tag[:description], 80, indent + " * ")) unless tag[:description].nil?
21
+ lines.push(indent + " * ")
22
+ lines.push(indent + " * " + definition_reference(tag))
23
+ lines.push(indent + " */")
24
+
25
+ lines.join("\n")
26
+ end
27
+
28
+ def definition_reference(tag)
29
+ "@talkFile #{tag[:__meta][:file]}:#{tag[:__meta][:line]}"
30
+ end
31
+
32
+ def class_line(cls)
33
+ @rendered ||= Set.new
34
+ out = []
35
+
36
+ return nil unless cls[:implement]
37
+ return nil if cls[:name] == rootclass
38
+ return nil if @rendered.include? cls
39
+ @rendered.add(cls)
40
+ out << class_line(class_named(cls[:inherits])) unless cls[:inherits].nil?
41
+ out << comment_block(cls)
42
+ out << "// " + cls[:name]
43
+
44
+ fields = {}
45
+ cls[:field].each do |field|
46
+ mapped = mapped_name(cls[:name], field[:name], :field)
47
+ fields[mapped] = {typeStack:field[:type]}
48
+ fields[mapped][:canonicalName] = field[:name] unless mapped == field[:name]
49
+ end
50
+
51
+ out << "TalkObject.addClass('#{cls[:name]}', #{fields.to_json}, #{truncated_name(superclass(cls))});"
52
+ out.join("\n")
53
+ end
54
+
55
+ def protocol_line(proto)
56
+ methods = proto[:method].map { |m| m[:name] }
57
+ out = []
58
+ out << comment_block(proto)
59
+ out << "TalkObject.addProtocol('#{proto[:name]}', #{methods.to_json});"
60
+ out.join("\n")
61
+ end
62
+
63
+ def glossary_line(glossary)
64
+ terms = {}
65
+ glossary[:term].each { |term| terms[term[:name]] = term[:value] }
66
+
67
+ out = []
68
+ out << comment_block(glossary)
69
+ out << "TalkObject.addGlossary('#{glossary[:name]}', #{terms.to_json});"
70
+ out.join("\n")
71
+ end
72
+
73
+ def enumeration_line(enumeration)
74
+ constants = {}
75
+ enumeration[:constant].each { |constant| constants[constant[:name]] = constant[:value] }
76
+
77
+ out = []
78
+ out << comment_block(enumeration)
79
+ out << "TalkObject.addEnumeration('#{enumeration[:name]}', #{constants.to_json});"
80
+ out.join("\n")
81
+ end
@@ -0,0 +1,860 @@
1
+ <%= autogenerated_warning %>
2
+ /*********************************************************************************
3
+ * TalkObject
4
+ *
5
+ * This module defines the constructor and methods for accessing TalkObjects
6
+ */
7
+
8
+ "use strict";
9
+
10
+ /**
11
+ * TalkObject - variable definition
12
+ *
13
+ * Takes an object and if found loads object
14
+ */
15
+
16
+ var TalkObject = function(obj)
17
+ {
18
+ this.__definition = { __class: { type: "string" } };
19
+ if(obj) this.loadFromObject(obj);
20
+ };
21
+
22
+ /**
23
+ * TalkObject vars, et-al
24
+ */
25
+ TalkObject.glossaries = {};
26
+ TalkObject.shortglossaries = {};
27
+ TalkObject.enumerations = {};
28
+ TalkObject.shortenumerations = {};
29
+ TalkObject.allConstants = {};
30
+ TalkObject.validators = {};
31
+ TalkObject.protocols = {};
32
+ TalkObject.methods = {};
33
+ TalkObject.prototype.__class = "TalkObject";
34
+ TalkObject.classes = { "TalkObject":TalkObject };
35
+ TalkObject.shortclasses = { "TalkObject":TalkObject };
36
+
37
+ /**
38
+ * TalkValidationError - Creates an error message on validation error
39
+ */
40
+ TalkObject.TalkValidationError = function(message)
41
+ {
42
+
43
+ this.name = "TalkValidationError";
44
+ this.message = message || "Error validating Talk object";
45
+ };
46
+
47
+ TalkObject.TalkValidationError.prototype = new Error();
48
+ TalkObject.TalkValidationError.prototype.constructor = TalkObject.TalkValidationError;
49
+ TalkObject.TalkValidationError.makeError = function(cls, key, param, msg)
50
+ {
51
+ var errString = "Invalid value " + cls.__class + "." + key +
52
+ (param ? ("=" + JSON.stringify(param) + ": ") : " - ") + msg;
53
+ if((typeof logger != 'undefined') && logger) logger.debug(errString);
54
+ return new TalkObject.TalkValidationError(errString);
55
+ };
56
+
57
+
58
+ /**
59
+ * TalkImplementationError - Creates an error message on implementation error
60
+ * (which shouldn't happen in production code)
61
+ */
62
+ TalkObject.TalkImplementationError = function(message) {
63
+ //#JSCOVERAGE_IF 0
64
+ // We shouldn't have this happen in production.
65
+ this.name = "TalkImplementationError";
66
+ this.message = message || "Error validating Talk object";
67
+ //#JSCOVERAGE_ENDIF
68
+ };
69
+
70
+ TalkObject.TalkImplementationError.prototype= new Error();
71
+ TalkObject.TalkImplementationError.prototype.constructor = TalkObject.TalkImplementationError;
72
+ TalkObject.TalkImplementationError.makeError = function(cls, key, msg)
73
+ {
74
+ //#JSCOVERAGE_IF 0
75
+ // This should not happen in production.
76
+ var errString = "Invalid server implementation of " + cls.__class + "."
77
+ + key + ": " + msg;
78
+ if((typeof logger != 'undefined') && logger) logger.error(errString);
79
+ return new TalkObject.TalkImplementationError(errString);
80
+ //#JSCOVERAGE_ENDIF
81
+ };
82
+
83
+ /**
84
+ * __validateString - augment the TalkObject with validation of strings
85
+ */
86
+ TalkObject.prototype.__validateString = function(key, param, unsigned, size)
87
+ {
88
+ var def = this.__definition[key];
89
+ if(typeof(param) != 'string') { // Make sure it a string type
90
+ throw TalkObject.TalkValidationError.makeError(
91
+ this, key, param, "Expected to be a string");
92
+ }
93
+
94
+ // Check against pattern matching
95
+ if(def.regex && !param.match(new RegExp(def.regex))) {
96
+ throw TalkObject.TalkValidationError.makeError(
97
+ this, key, param, "Expected to match pattern: " + def.regex);
98
+ }
99
+
100
+ // Check over our constraints if they exist
101
+ if(def.constraints) {
102
+ var found = false;
103
+ for(var constraintIdx in def.constraints)
104
+ {
105
+ var constraint = def.constraints[constraintIdx];
106
+ var glossary = TalkObject.glossary(constraint);
107
+ if(!glossary) {
108
+ /* The constraint references a non-existent glossary. This is an issue
109
+ ** in our Talk renderer. This shouldn't happen. */
110
+ //#JSCOVERAGE_IF 0
111
+ var errMsg = "Constrains on undefined glossary " + constraint;
112
+ throw TalkObject.TalkImplementationError.makeError( this, key, errMsg);
113
+ //#JSCOVERAGE_ENDIF
114
+ }
115
+
116
+ for(var i = 0; i < glossary.__values.length; i++)
117
+ {
118
+ if(glossary.__values[i] == param) {
119
+ found = true;
120
+ break;
121
+ }
122
+ }
123
+ }
124
+
125
+ if(!found) {
126
+ var errMsg = "Expected to be in at least one of glossaries "
127
+ + def.constraints.join(", ");
128
+ throw TalkObject.TalkValidationError.makeError(this, key, param, errMsg);
129
+ }
130
+ }
131
+
132
+ return param;
133
+ };
134
+
135
+
136
+ /**
137
+ * __validateInteger - augment the TalkObject with validation of Integer
138
+ */
139
+ TalkObject.prototype.__validateInteger = function(key, param, unsigned, size)
140
+ {
141
+ var range = {};
142
+ var def = this.__definition[key];
143
+
144
+ // Validate number
145
+ if(typeof(param) != 'number')
146
+ {
147
+ var errMsg = "Expected " + key + " to be a number";
148
+ throw TalkObject.TalkValidationError.makeError(this, key, param, errMsg);
149
+ }
150
+
151
+ // compute the ranges for validation checking
152
+ if(unsigned)
153
+ {
154
+ range.min = 0;
155
+ range.max = Math.pow(2, size);
156
+ } else {
157
+ range.min = -Math.pow(2, size-1);
158
+ range.max = Math.pow(2, size-1)-1;
159
+ }
160
+
161
+ if(def.minValue !== undefined && def.minValue !== null)
162
+ {
163
+ range.min = Math.max(def.minVlaue, range.min);
164
+ }
165
+
166
+ if(def.maxValue !== undefined && def.maxValue !== null)
167
+ {
168
+ range.max = Math.min(def.maxValue, range.max);
169
+ }
170
+
171
+ // check for constraints
172
+ if(def.constraints) {
173
+ var found = false;
174
+ for(var constraintIdx in def.constraints)
175
+ {
176
+ var constraint = def.constraints[constraintIdx];
177
+ var enumeration = TalkObject.enumeration(constraint);
178
+ if(!enumeration)
179
+ {
180
+ //#JSCOVERAGE_IF 0
181
+ /* The constraint references a non-existent enumeration. This is an
182
+ ** issue in our Talk renderer. This shouldn't happen. */
183
+ var errMsg = "Constrains on undefined enumeration " + constraint;
184
+ throw TalkObject.TalkImplementationError.makeError(this, key, errMsg);
185
+ //#JSCOVERAGE_ENDIF
186
+ }
187
+
188
+ for(var i = 0; i < enumeration.__values.length; i++)
189
+ {
190
+ if(enumeration.__values[i] == param)
191
+ {
192
+ found = true;
193
+ break;
194
+ }
195
+ }
196
+ }
197
+
198
+ if(!found)
199
+ {
200
+ var errMsg = "Expected to be in " + def.constraints.join(", ");
201
+ throw TalkObject.TalkValidationError.makeError(this, key, param, errMsg);
202
+ }
203
+ }
204
+
205
+ if(param < range.min)
206
+ {
207
+ throw TalkObject.TalkValidationError.makeError( this, key, param, "Expected >= " + range.min);
208
+ }
209
+
210
+ if(param > range.max)
211
+ {
212
+ throw TalkObject.TalkValidationError.makeError(this, key, param, "Expected <= " + range.max);
213
+ }
214
+
215
+ if(param != Math.floor(param))
216
+ {
217
+ throw TalkObject.TalkValidationError.makeError( this, key, param, "Expected integer");
218
+ }
219
+
220
+ return param;
221
+ };
222
+
223
+ /**
224
+ * __validateReal - augment the TalkObject with validation of Real
225
+ */
226
+ TalkObject.prototype.__validateReal = function(key, param)
227
+ {
228
+ var def = this.__definition[key];
229
+ if(typeof(param) != 'number') return "Expected numeric value for " + key;
230
+ if(def.minValue !== undefined && def.minValue !== null && param < def.minValue)
231
+ {
232
+ throw TalkObject.TalkValidationError.makeError(this, key, param, "Expected >= " + def.minValue);
233
+ }
234
+ if(def.maxValue !== undefined && def.maxValue !== null && param > def.maxValue)
235
+ {
236
+ throw TalkObject.TalkValidationError.makeError(this, key, param, "Expected <= " + def.maxValue);
237
+ }
238
+
239
+ return param;
240
+ };
241
+
242
+ /**
243
+ * __validateBool - augment the TalkObject with validation of Boolean
244
+ */
245
+ TalkObject.prototype.__validateBool = function(key, param)
246
+ {
247
+ if(typeof(param) != 'boolean' && typeof(param) != 'number')
248
+ {
249
+ throw TalkObject.TalkValidationError.makeError(this, key, param, "Expected boolean");
250
+ }
251
+ return param;
252
+ };
253
+
254
+ /**
255
+ * __validateObject - augment the TalkObject with validation of Object
256
+ */
257
+ TalkObject.prototype.__validateObject = function(key, param)
258
+ {
259
+ return param;
260
+ };
261
+
262
+ /**
263
+ * __validateTalkObject - augment the TalkObject with validation of TalkObject
264
+ */
265
+ TalkObject.prototype.__validateTalkObject = function(key, param, type)
266
+ {
267
+ var talkClass;
268
+ if(param && '__class' in param)
269
+ {
270
+ talkClass = TalkObject.classNamed(param.__class);
271
+ if(!TalkObject.isSubclass(param.__class, type))
272
+ {
273
+ throw TalkObject.TalkValidationError.makeError( this, key, param,
274
+ "Expected a subclass of " + type);
275
+ }
276
+ if(!talkClass)
277
+ {
278
+ throw TalkObject.TalkValidationError.makeError( this, key, param,
279
+ "Value has unknown class " + param.__class);
280
+ }
281
+ } else {
282
+ talkClass = TalkObject.classNamed(type);
283
+ if(!talkClass)
284
+ {
285
+ throw TalkObject.TalkImplementationError.makeError( this, key, param,
286
+ "Implementation specifies " + "unknown class " + type);
287
+ }
288
+ }
289
+
290
+ var instance = new talkClass(param);
291
+ instance.loadFromObject(param);
292
+ return instance;
293
+ };
294
+
295
+ /**
296
+ * __validateTypeStack - augment the TalkObject with validation of TypeStack
297
+ */
298
+ TalkObject.prototype.__validateTypeStack = function(key, param, typeStack)
299
+ {
300
+ var def = this.__definition[key];
301
+ var type = typeStack[typeStack.length-1];
302
+ var isBase = typeStack.length == 1;
303
+ typeStack = typeStack.slice(0, def.typeStack.length-1);
304
+
305
+ if(param === undefined || param === null) {
306
+ if(def.required && def.typeStack.length-1 == typeStack.length)
307
+ {
308
+ throw TalkObject.TalkValidationError.makeError( this, key, param, "Field is required");
309
+ }
310
+
311
+ return param;
312
+ }
313
+
314
+ if(isBase)
315
+ {
316
+ if(type == '[]' || type == '{}')
317
+ {
318
+ //#JSCOVERAGE_IF 0
319
+ // Implementation has a bad type stack. This shouldn't happen.
320
+ throw TalkObject.TalkImplementationError.makeError( this, key,
321
+ "Nonsense field definition; expected individual, got " + type);
322
+ //#JSCOVERAGE_ENDIF
323
+ }
324
+
325
+ var val;
326
+ var intMatch = type.match(/^(u)?int([0-9]+)$/);
327
+
328
+ if(intMatch)
329
+ {
330
+ val = this.__validateInteger(key, param, intMatch[1] == 'u', intMatch[2]);
331
+ } else if(type == 'string') {
332
+ val = this.__validateString(key, param);
333
+ } else if(type == 'real') {
334
+ val = this.__validateReal(key, param);
335
+ } else if(type == 'bool') {
336
+ val = this.__validateBool(key, param);
337
+ } else if(type == 'talkobject') {
338
+ if(!param.__class)
339
+ {
340
+ throw new TalkObject.TalkValidationError.makeError( this, key, param,
341
+ "Expected explicit class identification in generic field.");
342
+ }
343
+ val = this.__validateTalkObject(key, param, "TalkObject");
344
+ } else if(TalkObject.classNamed(type)) {
345
+ val = this.__validateTalkObject(key, param, type);
346
+ if(val && !val.__class)
347
+ {
348
+ val.__class = type;
349
+ }
350
+ } else if(type == 'object') {
351
+ val = this.__validateObject(key, param);
352
+ } else {
353
+ throw TalkObject.TalkImplementationError.makeError( this, key, "Unrecognized type " + type);
354
+ }
355
+
356
+ return val;
357
+ } else {
358
+ // This must be a collection type, '[]' for array, '{}' for dict
359
+ if(typeof(param) != 'object' || !('constructor' in param)) {
360
+ throw TalkObject.TalkValidationError.makeError( this, key, param,
361
+ "Expected a " + type + " collection");
362
+ }
363
+
364
+ if(type == '[]')
365
+ {
366
+ if(param.constructor != Array) return undefined;
367
+ var validatedArray = [];
368
+ for(var i = 0; i < param.length; i++)
369
+ {
370
+ var v = this.__validateTypeStack(key, param[i], typeStack);
371
+ if(v === undefined)
372
+ {
373
+ return undefined;
374
+ }
375
+ validatedArray.push(v);
376
+ }
377
+ return validatedArray;
378
+ } else if(type == '{}') {
379
+ if(param.constructor != Object) return undefined;
380
+ var validatedDict = {};
381
+ for(var k in param)
382
+ {
383
+ var v = this.__validateTypeStack(key, param[k], typeStack);
384
+ if(v === undefined) return undefined;
385
+ validatedDict[k] = v;
386
+ }
387
+ return validatedDict;
388
+ } else {
389
+ //#JSCOVERAGE_IF 0
390
+ // Implementation has a bad type stack. This shouldn't happen.
391
+ throw TalkObject.TalkImplementationError.makeError( this, key, param,
392
+ "Nonsense definition; expected collection, got " + type);
393
+ //#JSCOVERAGE_ENDIF
394
+ }
395
+ }
396
+ };
397
+
398
+
399
+
400
+ /**
401
+ * __validateParameter - augment the TalkObject with validation of Parameter
402
+ */
403
+ TalkObject.prototype.__validateParameter = function(key, param)
404
+ {
405
+ var def = this.__definition[key];
406
+ if(!("typeStack" in def))
407
+ {
408
+ //#JSCOVERAGE_IF 0
409
+ throw TalkObject.TalkImplementationError.makeError( this, key,
410
+ "Nonsense field definition; expected typeStack");
411
+ //#JSCOVERAGE_ENDIF
412
+ }
413
+
414
+ return this.__validateTypeStack(key, param, def.typeStack);
415
+ };
416
+
417
+ /**
418
+ * __validate - augment the TalkObject with validation
419
+ */
420
+ TalkObject.prototype.__validate = function(throwError) {
421
+ try {
422
+ for(var key in this.__definition)
423
+ {
424
+ this.__validateParameter(key, this[key]);
425
+ if(TalkObject.validators[this.__class] &&
426
+ TalkObject.validators[this.__class][key])
427
+ {
428
+ var err = TalkObject.validators[this.__class][key](this, key);
429
+ if(err)
430
+ {
431
+ //#JSCOVERAGE_IF 0
432
+ throw TalkObject.TalkImplementationError.makeError( this, key, param, err);
433
+ //#JSCOVERAGE_ENDIF
434
+ }
435
+ }
436
+ }
437
+ return true;
438
+ } catch(err) {
439
+ if(throwError) throw err;
440
+ return false;
441
+ }
442
+ };
443
+
444
+
445
+ /**
446
+ * instantiate - simple instantiation function will make numbers 0, booleans false and all else null
447
+ */
448
+ TalkObject.prototype.instantiate = function() {
449
+ try {
450
+ for(var def in this.__definition)
451
+ {
452
+ if( "typeStack" in def )
453
+ {
454
+ var type = def.typeStack[def.typeStack.length-1];
455
+ var isBase = def.typeStack.length == 1;
456
+ var val;
457
+ if(isBase)
458
+ {
459
+ var intMatch = type.match(/^(u)?int([0-9]+)$/);
460
+
461
+ if(intMatch) { val = 0; }
462
+ else if(type == 'real') { val = 0; }
463
+ else if(type == 'bool') { val = false; }
464
+ // else if(type == 'string') { val = null; }
465
+ else { val = null; }
466
+ return val;
467
+ } else val = null;
468
+ this[key]=val;
469
+ }
470
+ }
471
+ return true;
472
+ } catch(err) {
473
+ return false;
474
+ }
475
+ };
476
+
477
+
478
+ /**
479
+ * loadFromObject - augment the TalkObject with loadFromObject which returns a validated object
480
+ */
481
+ TalkObject.prototype.loadFromObject = function(obj, strict)
482
+ {
483
+ var validatedData = {};
484
+ for(var key in obj)
485
+ {
486
+ if(key == "__class" || key == "constructor") continue;
487
+ if(!(key in this.__definition))
488
+ {
489
+ if(strict)
490
+ {
491
+ throw new TalkObject.TalkValidationError( this, key, obj[key],
492
+ "Attempted to instantiate in strict mode with unsupported field");
493
+ }
494
+ } else {
495
+ validatedData[key] = this.__validateParameter(key, obj[key], strict);
496
+ }
497
+ }
498
+
499
+ for(var key in validatedData)
500
+ {
501
+ this[key] = validatedData[key];
502
+ }
503
+
504
+ // Run the validation check to make sure required fields are set.
505
+ this.__validate(true);
506
+ var keys = [];
507
+ for(var k in this)
508
+ {
509
+ keys.push(k + " (" + typeof(this[k]) + ")");
510
+ }
511
+
512
+ /* If we got __class from the prototype, it won't automatically show in
513
+ ** JSON.stringify. This statement seems to be a no-op, but it actually
514
+ ** fixes that issue. */
515
+ this["__class"] = this.__class;
516
+
517
+ return this;
518
+ };
519
+
520
+ /**
521
+ * set - a javascript setter for a value in the object
522
+ */
523
+ TalkObject.prototype.set = function(key, value)
524
+ {
525
+ if(value === undefined && typeof(key) == "object")
526
+ {
527
+ // Alternative usage; caller supplies key-value pairs to set.
528
+ for(var k in key)
529
+ {
530
+ if(!this.set(k, key[k])) return false;
531
+ }
532
+ }
533
+
534
+ this[key] = this.__validateParameter(key, value, true);
535
+ return true;
536
+ };
537
+
538
+ /**
539
+ * get - a javascript getter for a value in the object
540
+ */
541
+ TalkObject.prototype.get = function(key)
542
+ {
543
+ if(!(key in this.__definition))
544
+ {
545
+ throw TalkObject.TalkValidationError.makeError(
546
+ this, key, null, "not a valid field");
547
+ }
548
+ return this[key] ? this[key] : null;
549
+ };
550
+
551
+
552
+ /**
553
+ * __objectify - not really sure what this does it looks like a deep copy
554
+ */
555
+ TalkObject.prototype.__objectify = function(impliedClass)
556
+ {
557
+ for(var key in this)
558
+ {
559
+ if(key.match(/^__/))
560
+ {
561
+ // Anything that starts with __ is internal use only; disregard it.
562
+ continue;
563
+ } else if(this[key] === null || this[key] === undefined) {
564
+ // null values pass through.
565
+ obj[key] = null;
566
+ } else if(typeof(this[key]) == 'function'){
567
+ // Objectifying functions makes no sense, so don't do that!
568
+ continue;
569
+ } else if(typeof(this[key]) == 'object' && "__objectify" in this[key]) {
570
+ // Talk objects need to have recursive objectification
571
+ var def = this.__definition[key];
572
+ obj[key] = this[key].__objectify(def.type);
573
+ } else {
574
+ // Primitives can be assigned directly.
575
+ obj[key] = this[key];
576
+ }
577
+ }
578
+
579
+ if(TalkObject.shortName(impliedClass) != TalkObject.shortName(this.__class))
580
+ {
581
+ obj.__class = this.__class;
582
+ }
583
+
584
+ return obj;
585
+ };
586
+
587
+ /**
588
+ * shortName - returns short name of object
589
+ */
590
+ TalkObject.shortName = function(className)
591
+ {
592
+ var comps = className.split(".");
593
+ var s = comps[comps.length-1];
594
+ return s;
595
+ };
596
+
597
+ /**
598
+ * shortName - returns the class object for a name. If not strict will look for shortnames
599
+ * as well as canonical
600
+ */
601
+ TalkObject.classNamed = function(className, strict)
602
+ {
603
+ if(TalkObject.classes[className]) return TalkObject.classes[className];
604
+ if(strict) return undefined;
605
+ return TalkObject.shortclasses[className];
606
+ };
607
+
608
+ /**
609
+ * addClass - This is what the talk generator created javascript calls for each generated class
610
+ */
611
+ TalkObject.addClass = function(className, definition, superclassName)
612
+ {
613
+ if(!superclassName) superclassName = "TalkObject";
614
+ var superclass = TalkObject.classNamed(superclassName);
615
+ if(!superclass)
616
+ {
617
+ //#JSCOVERAGE_IF 0
618
+ if((typeof logger != 'undefined') && logger) logger.error("Implementation error: No superclass '"
619
+ + superclassName + "' for class '" + className + "'");
620
+ return undefined;
621
+ //#JSCOVERAGE_ENDIF
622
+ }
623
+
624
+ var cls = function(obj)
625
+ {
626
+ if(obj) this.loadFromObject(obj);
627
+ else this.instantiate();
628
+ };
629
+
630
+ cls.prototype = new superclass();
631
+ cls.prototype.constructor = cls;
632
+ cls.prototype.__super = superclass;
633
+ cls.prototype.__class = className;
634
+ cls.prototype.__definition = {};
635
+
636
+ for(var k in superclass.prototype.__definition) {
637
+ cls.prototype.__definition[k] = superclass.prototype.__definition[k];
638
+ }
639
+
640
+ for(var k in definition)
641
+ {
642
+ cls.prototype.__definition[k] = definition[k];
643
+ }
644
+
645
+ TalkObject.classes[className] = cls;
646
+ TalkObject.shortclasses[TalkObject.shortName(className)] = cls;
647
+
648
+ return cls;
649
+ };
650
+
651
+ /**
652
+ * setValidator - Setup a validator on a fieldname
653
+ */
654
+ TalkObject.setValidator = function(className, fieldName, validator)
655
+ {
656
+ var cls = TalkObject.classNamed(className);
657
+ if(!(cls.prototype.__class in TalkObject.validators))
658
+ {
659
+ TalkObject.validators[cls.prototype.__class] = {};
660
+ }
661
+
662
+ TalkObject.validators[cls.prototype.__class][fieldName] = validator;
663
+ };
664
+
665
+ /**
666
+ * instance - get an instance of a className from obj
667
+ */
668
+ TalkObject.instance = function(className, obj, strict, throwError)
669
+ {
670
+ var cls = TalkObject.classNamed(className, strict);
671
+ if(!cls)
672
+ {
673
+ //#JSCOVERAGE_IF 0
674
+ if((typeof logger != 'undefined') && logger) logger.trace("Cannot create instance of unknown class " + className
675
+ + " (strict = " + (strict ? "yes" : "no") + ")");
676
+ return undefined;
677
+ //#JSCOVERAGE_ENDIF
678
+ }
679
+
680
+ try {
681
+ var instance = new cls(obj);
682
+ return instance;
683
+ } catch(err) {
684
+ if(throwError) throw err;
685
+ return undefined;
686
+ }
687
+ };
688
+
689
+ /**
690
+ * isSubclass - returns true if subclassName is subclass of superclassName
691
+ */
692
+ TalkObject.isSubclass = function(subclassName, superclassName)
693
+ {
694
+ var c = TalkObject.classNamed(subclassName);
695
+ var s = TalkObject.classNamed(superclassName);
696
+ while(c && c != s)
697
+ {
698
+ c = c.prototype.__super;
699
+ }
700
+
701
+ return c != undefined;
702
+ };
703
+
704
+ /**
705
+ * glossary - returns a glossary lookup
706
+ */
707
+ TalkObject.glossary = function(glossaryName, strict)
708
+ {
709
+ var r=undefined;
710
+ if(TalkObject.glossaries[glossaryName]) {
711
+ r = TalkObject.glossaries[glossaryName];
712
+ } else if(strict) {
713
+ r = undefined;
714
+ } else if(TalkObject.shortglossaries[glossaryName]) {
715
+ r = TalkObject.shortglossaries[glossaryName];
716
+ }
717
+
718
+ if(!r)
719
+ {
720
+ //#JSCOVERAGE_IF 0
721
+ if((typeof logger != 'undefined') && logger) logger.error("Undefined glossary: " + glossaryName + " (strict: "
722
+ + (strict ? "yes" : "no") + ")");
723
+ //#JSCOVERAGE_ENDIF
724
+ }
725
+
726
+ return r;
727
+ };
728
+
729
+ /**
730
+ * enumeration - returns an enumeration lookup
731
+ */
732
+ TalkObject.enumeration = function(enumeration, strict)
733
+ {
734
+ var r = undefined;
735
+ if(TalkObject.enumerations[enumeration]) {
736
+ r = TalkObject.enumerations[enumeration];
737
+ } else if(strict) {
738
+ r = undefined;
739
+ } else if(TalkObject.shortenumerations[enumeration]) {
740
+ r = TalkObject.shortenumerations[enumeration];
741
+ }
742
+
743
+ if(!r)
744
+ {
745
+ //#JSCOVERAGE_IF 0
746
+ if((typeof logger != 'undefined') && logger) logger.error("Undefined enumeration: " + enumeration + " (strict: "
747
+ + (strict ? "yes" : "no") + ")");
748
+ //#JSCOVERAGE_ENDIF
749
+ }
750
+ return r;
751
+ };
752
+
753
+ /**
754
+ * constantFromSource - generic function which can be called for eitehr glossary or enumeration
755
+ * epending on the parameters passed in
756
+ */
757
+ TalkObject.constantFromSource = function(container, constant, source, strict)
758
+ {
759
+ var r;
760
+ r = source(container, strict);
761
+ if(!r) r = source(container, strict);
762
+ if(!r) return undefined;
763
+ return r[constant];
764
+ };
765
+
766
+ /**
767
+ * constant - return a constant looking in both glossary and enumerations
768
+ */
769
+ TalkObject.constant = function(container, constant, strict)
770
+ {
771
+ var r = undefined;
772
+ if(constant == undefined)
773
+ {
774
+ r = TalkObject.allConstants[container];
775
+ } else {
776
+ r = TalkObject.constantFromSource(container, constant, TalkObject.glossary, strict)
777
+ || TalkObject.constantFromSource(container, constant, TalkObject.enumeration, strict);
778
+ }
779
+
780
+ if(r === undefined)
781
+ {
782
+ var constantName = container;
783
+ var caller = callerid();
784
+ if(constant) constantName += "."+constant;
785
+ if((typeof logger != 'undefined') && logger) logger.error("Undefined constant: " + constantName + " (strict: "
786
+ + (strict ? "yes" : "no") + ", " + caller.shortFile + ":" + caller.line + ")");
787
+ }
788
+
789
+ return r;
790
+ };
791
+
792
+ /**
793
+ * protocol - return a protocol object
794
+ */
795
+ TalkObject.protocol = function(protocol)
796
+ {
797
+ return TalkObject.protocols[protocol];
798
+ };
799
+
800
+
801
+ /**
802
+ * addGlossary - This is what the talk generator created javascript calls for each generated glossary
803
+ */
804
+ TalkObject.addGlossary = function(glossaryName, glossary)
805
+ {
806
+ var newGloss = { '__values':[] };
807
+ for(var k in glossary)
808
+ {
809
+ var v = glossary[k];
810
+ newGloss.__values.push(v);
811
+ newGloss[k] = v;
812
+ TalkObject.allConstants[k] = v;
813
+ }
814
+
815
+ TalkObject.glossaries[glossaryName] = newGloss;
816
+ TalkObject.shortglossaries[TalkObject.shortName(glossaryName)] = newGloss;
817
+ return newGloss;
818
+ };
819
+
820
+ /**
821
+ * addEnumeration - This is what the talk generator created javascript calls for each generated enumeration
822
+ */
823
+ TalkObject.addEnumeration = function(enumerationName, enumeration)
824
+ {
825
+ var newEnum = { '__values':[] };
826
+ for(var k in enumeration)
827
+ {
828
+ var v = enumeration[k];
829
+ newEnum.__values.push(v);
830
+ newEnum[k] = v;
831
+ TalkObject.allConstants[k] = v;
832
+ }
833
+
834
+ var shortName = TalkObject.shortName(enumerationName);
835
+ TalkObject.enumerations[enumerationName] = newEnum;
836
+ TalkObject.shortenumerations[shortName] = newEnum;
837
+ return newEnum;
838
+ };
839
+
840
+ /**
841
+ * addProtocol - This is what the talk generator created javascript calls for each generated protocol
842
+ */
843
+ TalkObject.addProtocol = function(protocolName, protocol)
844
+ {
845
+ for(var method in protocol )
846
+ TalkObject.methods[protocolName + "." + method] = method;
847
+ TalkObject.protocols[protocolName] = protocol;
848
+ };
849
+
850
+ TalkObject.method = function(protocolName, method)
851
+ {
852
+ var key = protocolName + "." + method;
853
+ if( key in TalkObject.methods ) return TalkObject.methods[key];
854
+
855
+ };
856
+
857
+ <%= (@base[:class].map { |cls| class_line(cls) }).compact.join("\n") %>
858
+ <%= (@base[:protocol].map { |proto| protocol_line(proto) }).compact.join("\n") %>
859
+ <%= (@base[:glossary].map { |glossary| glossary_line(glossary) }).compact.join("\n") %>
860
+ <%= (@base[:enumeration].map { |enumeration| enumeration_line(enumeration) }).compact.join("\n") %>
@@ -126,12 +126,13 @@ module Talk
126
126
  @target[:destination]
127
127
  end
128
128
 
129
- def generate_template(output_file, template_file=nil)
129
+ def generate_template(output_file, template_file=nil, transform=nil)
130
130
  template_file ||= output_file + ".erb"
131
131
  template_contents = IO.read(File.join(self.path, "templates", template_file))
132
132
  erb = ERB.new(template_contents)
133
133
  erb.filename = template_file
134
134
  source = erb.result(binding)
135
+ source = transform.call(source) unless transform.nil?
135
136
  filename = File.join(@output_path, output_file)
136
137
  write(filename, source)
137
138
  source
@@ -197,5 +198,21 @@ module Talk
197
198
  name = name[:name] if name.is_a? Hash
198
199
  name.split('.').last
199
200
  end
201
+
202
+ def mapped_name(container_name, object_name, type, name_key=:name)
203
+ return object_name if @target[:map].nil? or @target[:map].empty?
204
+
205
+ object_name = object_name[:name] if object_name.is_a? Hash
206
+ container_name = container_name[:name] if container_name.is_a? Hash
207
+ container_name = truncated_name(container_name)
208
+
209
+ @target[:map].each do |map|
210
+ matches = (map[:type] == type.to_s && map[:class_name] == container_name && map[:field_name] == object_name)
211
+ return map[:new_field_name] if matches
212
+ end
213
+
214
+ object_name
215
+ end
216
+
200
217
  end
201
218
  end
@@ -59,19 +59,6 @@ def definition_reference(tag)
59
59
  "@talkFile #{tag[:__meta][:file]}:#{tag[:__meta][:line]}"
60
60
  end
61
61
 
62
- def mapped_name(container_name, object_name, type, name_key=:name)
63
- object_name = object_name[:name] if object_name.is_a? Hash
64
- container_name = container_name[:name] if container_name.is_a? Hash
65
- container_name = truncated_name(container_name)
66
-
67
- @target[:map].each do |map|
68
- matches = (map[:type] == type.to_s && map[:class_name] == container_name && map[:field_name] == object_name)
69
- return map[:new_field_name] if matches
70
- end
71
-
72
- object_name
73
- end
74
-
75
62
  def assist_line(field)
76
63
  return nil if field[:type].length <= 1
77
64
  elements = []
data/talk.gemspec CHANGED
@@ -1,8 +1,8 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'talk'
3
3
  s.executables << 'talk'
4
- s.version = '2.0.5'
5
- s.date = '2014-05-30'
4
+ s.version = '2.0.6'
5
+ s.date = '2014-06-04'
6
6
  s.summary = "Compile-to-source protocol contract specification language"
7
7
  s.description = "A lightweight language for specifying protocol contracts. Compiles to source in Java, Javascript, ObjC and Ruby."
8
8
  s.authors = ["Jonas Acres"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: talk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.5
4
+ version: 2.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Acres
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-30 00:00:00.000000000 Z
11
+ date: 2014-06-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A lightweight language for specifying protocol contracts. Compiles to
14
14
  source in Java, Javascript, ObjC and Ruby.
@@ -62,6 +62,8 @@ files:
62
62
  - lib/languages/java/templates/class.java.erb
63
63
  - lib/languages/java/templates/enumeration.java.erb
64
64
  - lib/languages/java/templates/glossary.java.erb
65
+ - lib/languages/js/js.rb
66
+ - lib/languages/js/templates/talk.js.erb
65
67
  - lib/languages/language.rb
66
68
  - lib/languages/objc/objc.rb
67
69
  - lib/languages/objc/templates/TalkClasses.h.erb