talk 2.0.5 → 2.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/context.rb +1 -1
- data/lib/context_class.rb +6 -0
- data/lib/languages/js/js.rb +81 -0
- data/lib/languages/js/templates/talk.js.erb +860 -0
- data/lib/languages/language.rb +18 -1
- data/lib/languages/objc/objc.rb +0 -13
- data/talk.gemspec +2 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef1157116afc257fd1bfc78676ddc0cb737015f7
|
4
|
+
data.tar.gz: 93d87b8b6b4e8ad6cbd383df6870adf3399e824a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e598d2d1ea1997a9c45cbe1c4989eb390ea4f08df5c1c839379b9fb19e25bcd5d2ea451fa5bb88f9d29096afc6f258f2b6d6103c57eb096c2105ad39f605ec2e
|
7
|
+
data.tar.gz: 7bbaeab38727d136e065c54113792bd7fd3cea40794bb0f0f9e049cb860e1060269a477ec21ac120136a15eb93e9db22b88f23f8d330928a445d37a23467ff60
|
data/Gemfile
CHANGED
data/lib/context.rb
CHANGED
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") %>
|
data/lib/languages/language.rb
CHANGED
@@ -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
|
data/lib/languages/objc/objc.rb
CHANGED
@@ -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
|
-
s.date = '2014-
|
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.
|
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-
|
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
|