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 +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
|