little_frankie 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE.txt +22 -0
  8. data/Performance.md +65 -0
  9. data/README.md +167 -0
  10. data/Rakefile +1 -0
  11. data/benchmarks/filters/frankie.rb +18 -0
  12. data/benchmarks/filters/sinatra.rb +17 -0
  13. data/benchmarks/helpers/frankie.rb +19 -0
  14. data/benchmarks/helpers/sinatra.rb +18 -0
  15. data/benchmarks/simple/frankie.rb +10 -0
  16. data/benchmarks/simple/sinatra.rb +9 -0
  17. data/benchmarks/url_pattern/frankie.rb +10 -0
  18. data/benchmarks/url_pattern/sinatra.rb +8 -0
  19. data/examples/active_record/.gitignore +1 -0
  20. data/examples/active_record/Gemfile +14 -0
  21. data/examples/active_record/Rakefile +51 -0
  22. data/examples/active_record/config/database.yml +0 -0
  23. data/examples/active_record/database.rb +12 -0
  24. data/examples/active_record/db/migrate/20130606133756_add_shouts.rb +12 -0
  25. data/examples/active_record/models/shout.rb +3 -0
  26. data/examples/active_record/server.rb +43 -0
  27. data/examples/json_api.rb +21 -0
  28. data/examples/templates/server.rb +27 -0
  29. data/examples/templates/views/index.haml +1 -0
  30. data/examples/web_sockets/public/FABridge.js +604 -0
  31. data/examples/web_sockets/public/WebSocketMain.swf +0 -0
  32. data/examples/web_sockets/public/index.html +76 -0
  33. data/examples/web_sockets/public/swfobject.js +4 -0
  34. data/examples/web_sockets/public/web_socket.js +388 -0
  35. data/examples/web_sockets/server.rb +60 -0
  36. data/lib/little_frankie.rb +9 -0
  37. data/lib/little_frankie/app.rb +66 -0
  38. data/lib/little_frankie/class_level_api.rb +40 -0
  39. data/lib/little_frankie/primitives.rb +25 -0
  40. data/lib/little_frankie/request_scope.rb +60 -0
  41. data/lib/little_frankie/route_signature.rb +44 -0
  42. data/lib/little_frankie/version.rb +3 -0
  43. data/little_frankie.gemspec +24 -0
  44. data/spec/app_spec.rb +144 -0
  45. data/spec/class_level_api_spec.rb +39 -0
  46. data/spec/primitives_spec.rb +26 -0
  47. data/spec/request_scope_spec.rb +71 -0
  48. data/spec/spec_helper.rb +42 -0
  49. metadata +138 -0
@@ -0,0 +1,51 @@
1
+ require 'yaml'
2
+ require 'logger'
3
+ MIGRATIONS_DIR = 'db/migrate'
4
+
5
+ namespace :db do
6
+ task :env do
7
+ ENV['RACK_ENV'] ||= 'development'
8
+ DATABASE_ENV = ENV['RACK_ENV']
9
+ require_relative 'database'
10
+ end
11
+
12
+ task :migrate => :env do
13
+ ActiveRecord::Migration.verbose = true
14
+ ActiveRecord::Migrator.migrate MIGRATIONS_DIR, ENV['VERSION'] ? ENV['VERSION'].to_i : nil
15
+ end
16
+
17
+ task :rollback => :env do
18
+ init_connection
19
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
20
+ ActiveRecord::Migrator.rollback MIGRATIONS_DIR, step
21
+ end
22
+
23
+ task :version => :env do
24
+ puts "Current version: #{ActiveRecord::Migrator.current_version}"
25
+ end
26
+
27
+ task :create_migration do
28
+ name = ENV['NAME']
29
+ abort("no NAME specified. use `rake db:create_migration NAME=create_users`") if !name
30
+
31
+ migrations_dir = File.join("db", "migrate")
32
+ version = ENV["VERSION"] || Time.now.utc.strftime("%Y%m%d%H%M%S")
33
+ filename = "#{version}_#{name}.rb"
34
+ migration_name = name.gsub(/_(.)/) { $1.upcase }.gsub(/^(.)/) { $1.upcase }
35
+
36
+ FileUtils.mkdir_p(migrations_dir)
37
+
38
+ open(File.join(migrations_dir, filename), 'w') do |f|
39
+ f << (<<-EOS).gsub(" ", "")
40
+ class #{migration_name} < ActiveRecord::Migration
41
+ def self.up
42
+ end
43
+
44
+ def self.down
45
+ end
46
+ end
47
+ EOS
48
+ end
49
+ end
50
+ end
51
+
File without changes
@@ -0,0 +1,12 @@
1
+ require 'active_record'
2
+
3
+ ENV['RACK_ENV'] ||= 'development'
4
+
5
+ def sqlite_db name
6
+ File.join(File.dirname(__FILE__), "./db/#{name}.sqlite3")
7
+ end
8
+
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => "sqlite3",
11
+ :database => sqlite_db(ENV['RACK_ENV'].to_sym)
12
+ )
@@ -0,0 +1,12 @@
1
+ class AddShouts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :shouts do |t|
4
+ t.string :body
5
+ t.timestamps
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :shouts
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ class Shout < ActiveRecord::Base
2
+ attr_accessible :body
3
+ end
@@ -0,0 +1,43 @@
1
+ #!ruby -I ../../lib -I lib
2
+
3
+ ENV['RACK_ENV'] ||= 'development'
4
+
5
+ require 'rubygems'
6
+ require 'bundler'
7
+ Bundler.setup(:default, ENV['RACK_ENV'].to_sym)
8
+
9
+ require 'frankie'
10
+ require_relative 'database'
11
+
12
+ #Require all models
13
+ Dir[File.dirname(__FILE__) + "/models/*.rb"].each {|file| require file }
14
+ TEMPLATE = DATA.read.freeze
15
+
16
+ class App < Frankie::App
17
+ get '/' do
18
+ shouts = Shout.all.reverse
19
+ ERB.new(TEMPLATE).result(binding)
20
+ end
21
+
22
+ post '/shouts' do
23
+ Shout.create :body => params[:body]
24
+ redirect_to '/'
25
+ end
26
+ end
27
+
28
+ App.run! 9000
29
+
30
+ __END__
31
+ <html>
32
+ <body>
33
+ <form action="/shouts" method="post">
34
+ <input type="text" name="body"></input>
35
+ <input type="submit" value="SHOUT"></input>
36
+ </form>
37
+ <ul>
38
+ <% shouts.each do |shout| %>
39
+ <li><%= shout.body %>
40
+ <% end %>
41
+ </ul>
42
+ </body>
43
+ </html>
@@ -0,0 +1,21 @@
1
+ #!ruby -I ../lib -I lib
2
+ require 'frankie'
3
+ require 'json'
4
+
5
+ #
6
+ # Every response of this app will be automatically converted to json
7
+ #
8
+ class App < Frankie::App
9
+ before { headers 'Content-Type' => 'application/json' }
10
+
11
+ after do
12
+ body = response.raw_body
13
+ response.body = body.to_json if body.respond_to? :to_json
14
+ end
15
+
16
+ get '/' do
17
+ {:some => [:json, :mate!]}
18
+ end
19
+ end
20
+
21
+ App.run! 9000
@@ -0,0 +1,27 @@
1
+ #!ruby -I ../lib -I lib
2
+ require 'frankie'
3
+ require 'sinatra'
4
+ require 'ostruct'
5
+
6
+ module Views
7
+ include ::Sinatra::Templates
8
+
9
+ def settings
10
+ @settings ||= OpenStruct.new :templates => {}
11
+ end
12
+
13
+ def template_cache
14
+ @template_cache = Tilt::Cache.new
15
+ end
16
+ end
17
+
18
+
19
+ class App < Frankie::App
20
+ helpers Views
21
+
22
+ get '/' do
23
+ haml :index
24
+ end
25
+ end
26
+
27
+ App.run!
@@ -0,0 +1 @@
1
+ %h1 Dat HAML!
@@ -0,0 +1,604 @@
1
+ /*
2
+ /*
3
+ Copyright 2006 Adobe Systems Incorporated
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
6
+ to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
15
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
+
17
+ */
18
+
19
+
20
+ /*
21
+ * The Bridge class, responsible for navigating AS instances
22
+ */
23
+ function FABridge(target,bridgeName)
24
+ {
25
+ this.target = target;
26
+ this.remoteTypeCache = {};
27
+ this.remoteInstanceCache = {};
28
+ this.remoteFunctionCache = {};
29
+ this.localFunctionCache = {};
30
+ this.bridgeID = FABridge.nextBridgeID++;
31
+ this.name = bridgeName;
32
+ this.nextLocalFuncID = 0;
33
+ FABridge.instances[this.name] = this;
34
+ FABridge.idMap[this.bridgeID] = this;
35
+
36
+ return this;
37
+ }
38
+
39
+ // type codes for packed values
40
+ FABridge.TYPE_ASINSTANCE = 1;
41
+ FABridge.TYPE_ASFUNCTION = 2;
42
+
43
+ FABridge.TYPE_JSFUNCTION = 3;
44
+ FABridge.TYPE_ANONYMOUS = 4;
45
+
46
+ FABridge.initCallbacks = {};
47
+ FABridge.userTypes = {};
48
+
49
+ FABridge.addToUserTypes = function()
50
+ {
51
+ for (var i = 0; i < arguments.length; i++)
52
+ {
53
+ FABridge.userTypes[arguments[i]] = {
54
+ 'typeName': arguments[i],
55
+ 'enriched': false
56
+ };
57
+ }
58
+ }
59
+
60
+ FABridge.argsToArray = function(args)
61
+ {
62
+ var result = [];
63
+ for (var i = 0; i < args.length; i++)
64
+ {
65
+ result[i] = args[i];
66
+ }
67
+ return result;
68
+ }
69
+
70
+ function instanceFactory(objID)
71
+ {
72
+ this.fb_instance_id = objID;
73
+ return this;
74
+ }
75
+
76
+ function FABridge__invokeJSFunction(args)
77
+ {
78
+ var funcID = args[0];
79
+ var throughArgs = args.concat();//FABridge.argsToArray(arguments);
80
+ throughArgs.shift();
81
+
82
+ var bridge = FABridge.extractBridgeFromID(funcID);
83
+ return bridge.invokeLocalFunction(funcID, throughArgs);
84
+ }
85
+
86
+ FABridge.addInitializationCallback = function(bridgeName, callback)
87
+ {
88
+ var inst = FABridge.instances[bridgeName];
89
+ if (inst != undefined)
90
+ {
91
+ callback.call(inst);
92
+ return;
93
+ }
94
+
95
+ var callbackList = FABridge.initCallbacks[bridgeName];
96
+ if(callbackList == null)
97
+ {
98
+ FABridge.initCallbacks[bridgeName] = callbackList = [];
99
+ }
100
+
101
+ callbackList.push(callback);
102
+ }
103
+
104
+ // updated for changes to SWFObject2
105
+ function FABridge__bridgeInitialized(bridgeName) {
106
+ var objects = document.getElementsByTagName("object");
107
+ var ol = objects.length;
108
+ var activeObjects = [];
109
+ if (ol > 0) {
110
+ for (var i = 0; i < ol; i++) {
111
+ if (typeof objects[i].SetVariable != "undefined") {
112
+ activeObjects[activeObjects.length] = objects[i];
113
+ }
114
+ }
115
+ }
116
+ var embeds = document.getElementsByTagName("embed");
117
+ var el = embeds.length;
118
+ var activeEmbeds = [];
119
+ if (el > 0) {
120
+ for (var j = 0; j < el; j++) {
121
+ if (typeof embeds[j].SetVariable != "undefined") {
122
+ activeEmbeds[activeEmbeds.length] = embeds[j];
123
+ }
124
+ }
125
+ }
126
+ var aol = activeObjects.length;
127
+ var ael = activeEmbeds.length;
128
+ var searchStr = "bridgeName="+ bridgeName;
129
+ if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) {
130
+ FABridge.attachBridge(activeObjects[0], bridgeName);
131
+ }
132
+ else if (ael == 1 && !aol) {
133
+ FABridge.attachBridge(activeEmbeds[0], bridgeName);
134
+ }
135
+ else {
136
+ var flash_found = false;
137
+ if (aol > 1) {
138
+ for (var k = 0; k < aol; k++) {
139
+ var params = activeObjects[k].childNodes;
140
+ for (var l = 0; l < params.length; l++) {
141
+ var param = params[l];
142
+ if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) {
143
+ FABridge.attachBridge(activeObjects[k], bridgeName);
144
+ flash_found = true;
145
+ break;
146
+ }
147
+ }
148
+ if (flash_found) {
149
+ break;
150
+ }
151
+ }
152
+ }
153
+ if (!flash_found && ael > 1) {
154
+ for (var m = 0; m < ael; m++) {
155
+ var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue;
156
+ if (flashVars.indexOf(searchStr) >= 0) {
157
+ FABridge.attachBridge(activeEmbeds[m], bridgeName);
158
+ break;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ return true;
164
+ }
165
+
166
+ // used to track multiple bridge instances, since callbacks from AS are global across the page.
167
+
168
+ FABridge.nextBridgeID = 0;
169
+ FABridge.instances = {};
170
+ FABridge.idMap = {};
171
+ FABridge.refCount = 0;
172
+
173
+ FABridge.extractBridgeFromID = function(id)
174
+ {
175
+ var bridgeID = (id >> 16);
176
+ return FABridge.idMap[bridgeID];
177
+ }
178
+
179
+ FABridge.attachBridge = function(instance, bridgeName)
180
+ {
181
+ var newBridgeInstance = new FABridge(instance, bridgeName);
182
+
183
+ FABridge[bridgeName] = newBridgeInstance;
184
+
185
+ /* FABridge[bridgeName] = function() {
186
+ return newBridgeInstance.root();
187
+ }
188
+ */
189
+ var callbacks = FABridge.initCallbacks[bridgeName];
190
+ if (callbacks == null)
191
+ {
192
+ return;
193
+ }
194
+ for (var i = 0; i < callbacks.length; i++)
195
+ {
196
+ callbacks[i].call(newBridgeInstance);
197
+ }
198
+ delete FABridge.initCallbacks[bridgeName]
199
+ }
200
+
201
+ // some methods can't be proxied. You can use the explicit get,set, and call methods if necessary.
202
+
203
+ FABridge.blockedMethods =
204
+ {
205
+ toString: true,
206
+ get: true,
207
+ set: true,
208
+ call: true
209
+ };
210
+
211
+ FABridge.prototype =
212
+ {
213
+
214
+
215
+ // bootstrapping
216
+
217
+ root: function()
218
+ {
219
+ return this.deserialize(this.target.getRoot());
220
+ },
221
+ //clears all of the AS objects in the cache maps
222
+ releaseASObjects: function()
223
+ {
224
+ return this.target.releaseASObjects();
225
+ },
226
+ //clears a specific object in AS from the type maps
227
+ releaseNamedASObject: function(value)
228
+ {
229
+ if(typeof(value) != "object")
230
+ {
231
+ return false;
232
+ }
233
+ else
234
+ {
235
+ var ret = this.target.releaseNamedASObject(value.fb_instance_id);
236
+ return ret;
237
+ }
238
+ },
239
+ //create a new AS Object
240
+ create: function(className)
241
+ {
242
+ return this.deserialize(this.target.create(className));
243
+ },
244
+
245
+
246
+ // utilities
247
+
248
+ makeID: function(token)
249
+ {
250
+ return (this.bridgeID << 16) + token;
251
+ },
252
+
253
+
254
+ // low level access to the flash object
255
+
256
+ //get a named property from an AS object
257
+ getPropertyFromAS: function(objRef, propName)
258
+ {
259
+ if (FABridge.refCount > 0)
260
+ {
261
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
262
+ }
263
+ else
264
+ {
265
+ FABridge.refCount++;
266
+ retVal = this.target.getPropFromAS(objRef, propName);
267
+ retVal = this.handleError(retVal);
268
+ FABridge.refCount--;
269
+ return retVal;
270
+ }
271
+ },
272
+ //set a named property on an AS object
273
+ setPropertyInAS: function(objRef,propName, value)
274
+ {
275
+ if (FABridge.refCount > 0)
276
+ {
277
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
278
+ }
279
+ else
280
+ {
281
+ FABridge.refCount++;
282
+ retVal = this.target.setPropInAS(objRef,propName, this.serialize(value));
283
+ retVal = this.handleError(retVal);
284
+ FABridge.refCount--;
285
+ return retVal;
286
+ }
287
+ },
288
+
289
+ //call an AS function
290
+ callASFunction: function(funcID, args)
291
+ {
292
+ if (FABridge.refCount > 0)
293
+ {
294
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
295
+ }
296
+ else
297
+ {
298
+ FABridge.refCount++;
299
+ retVal = this.target.invokeASFunction(funcID, this.serialize(args));
300
+ retVal = this.handleError(retVal);
301
+ FABridge.refCount--;
302
+ return retVal;
303
+ }
304
+ },
305
+ //call a method on an AS object
306
+ callASMethod: function(objID, funcName, args)
307
+ {
308
+ if (FABridge.refCount > 0)
309
+ {
310
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
311
+ }
312
+ else
313
+ {
314
+ FABridge.refCount++;
315
+ args = this.serialize(args);
316
+ retVal = this.target.invokeASMethod(objID, funcName, args);
317
+ retVal = this.handleError(retVal);
318
+ FABridge.refCount--;
319
+ return retVal;
320
+ }
321
+ },
322
+
323
+ // responders to remote calls from flash
324
+
325
+ //callback from flash that executes a local JS function
326
+ //used mostly when setting js functions as callbacks on events
327
+ invokeLocalFunction: function(funcID, args)
328
+ {
329
+ var result;
330
+ var func = this.localFunctionCache[funcID];
331
+
332
+ if(func != undefined)
333
+ {
334
+ result = this.serialize(func.apply(null, this.deserialize(args)));
335
+ }
336
+
337
+ return result;
338
+ },
339
+
340
+ // Object Types and Proxies
341
+
342
+ // accepts an object reference, returns a type object matching the obj reference.
343
+ getTypeFromName: function(objTypeName)
344
+ {
345
+ return this.remoteTypeCache[objTypeName];
346
+ },
347
+ //create an AS proxy for the given object ID and type
348
+ createProxy: function(objID, typeName)
349
+ {
350
+ var objType = this.getTypeFromName(typeName);
351
+ instanceFactory.prototype = objType;
352
+ var instance = new instanceFactory(objID);
353
+ this.remoteInstanceCache[objID] = instance;
354
+ return instance;
355
+ },
356
+ //return the proxy associated with the given object ID
357
+ getProxy: function(objID)
358
+ {
359
+ return this.remoteInstanceCache[objID];
360
+ },
361
+
362
+ // accepts a type structure, returns a constructed type
363
+ addTypeDataToCache: function(typeData)
364
+ {
365
+ var newType = new ASProxy(this, typeData.name);
366
+ var accessors = typeData.accessors;
367
+ for (var i = 0; i < accessors.length; i++)
368
+ {
369
+ this.addPropertyToType(newType, accessors[i]);
370
+ }
371
+
372
+ var methods = typeData.methods;
373
+ for (var i = 0; i < methods.length; i++)
374
+ {
375
+ if (FABridge.blockedMethods[methods[i]] == undefined)
376
+ {
377
+ this.addMethodToType(newType, methods[i]);
378
+ }
379
+ }
380
+
381
+
382
+ this.remoteTypeCache[newType.typeName] = newType;
383
+ return newType;
384
+ },
385
+
386
+ //add a property to a typename; used to define the properties that can be called on an AS proxied object
387
+ addPropertyToType: function(ty, propName)
388
+ {
389
+ var c = propName.charAt(0);
390
+ var setterName;
391
+ var getterName;
392
+ if(c >= "a" && c <= "z")
393
+ {
394
+ getterName = "get" + c.toUpperCase() + propName.substr(1);
395
+ setterName = "set" + c.toUpperCase() + propName.substr(1);
396
+ }
397
+ else
398
+ {
399
+ getterName = "get" + propName;
400
+ setterName = "set" + propName;
401
+ }
402
+ ty[setterName] = function(val)
403
+ {
404
+ this.bridge.setPropertyInAS(this.fb_instance_id, propName, val);
405
+ }
406
+ ty[getterName] = function()
407
+ {
408
+ return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
409
+ }
410
+ },
411
+
412
+ //add a method to a typename; used to define the methods that can be callefd on an AS proxied object
413
+ addMethodToType: function(ty, methodName)
414
+ {
415
+ ty[methodName] = function()
416
+ {
417
+ return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments)));
418
+ }
419
+ },
420
+
421
+ // Function Proxies
422
+
423
+ //returns the AS proxy for the specified function ID
424
+ getFunctionProxy: function(funcID)
425
+ {
426
+ var bridge = this;
427
+ if (this.remoteFunctionCache[funcID] == null)
428
+ {
429
+ this.remoteFunctionCache[funcID] = function()
430
+ {
431
+ bridge.callASFunction(funcID, FABridge.argsToArray(arguments));
432
+ }
433
+ }
434
+ return this.remoteFunctionCache[funcID];
435
+ },
436
+
437
+ //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache
438
+ getFunctionID: function(func)
439
+ {
440
+ if (func.__bridge_id__ == undefined)
441
+ {
442
+ func.__bridge_id__ = this.makeID(this.nextLocalFuncID++);
443
+ this.localFunctionCache[func.__bridge_id__] = func;
444
+ }
445
+ return func.__bridge_id__;
446
+ },
447
+
448
+ // serialization / deserialization
449
+
450
+ serialize: function(value)
451
+ {
452
+ var result = {};
453
+
454
+ var t = typeof(value);
455
+ //primitives are kept as such
456
+ if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined)
457
+ {
458
+ result = value;
459
+ }
460
+ else if (value instanceof Array)
461
+ {
462
+ //arrays are serializesd recursively
463
+ result = [];
464
+ for (var i = 0; i < value.length; i++)
465
+ {
466
+ result[i] = this.serialize(value[i]);
467
+ }
468
+ }
469
+ else if (t == "function")
470
+ {
471
+ //js functions are assigned an ID and stored in the local cache
472
+ result.type = FABridge.TYPE_JSFUNCTION;
473
+ result.value = this.getFunctionID(value);
474
+ }
475
+ else if (value instanceof ASProxy)
476
+ {
477
+ result.type = FABridge.TYPE_ASINSTANCE;
478
+ result.value = value.fb_instance_id;
479
+ }
480
+ else
481
+ {
482
+ result.type = FABridge.TYPE_ANONYMOUS;
483
+ result.value = value;
484
+ }
485
+
486
+ return result;
487
+ },
488
+
489
+ //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors
490
+ // the unpacking is done by returning the value on each pachet for objects/arrays
491
+ deserialize: function(packedValue)
492
+ {
493
+
494
+ var result;
495
+
496
+ var t = typeof(packedValue);
497
+ if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined)
498
+ {
499
+ result = this.handleError(packedValue);
500
+ }
501
+ else if (packedValue instanceof Array)
502
+ {
503
+ result = [];
504
+ for (var i = 0; i < packedValue.length; i++)
505
+ {
506
+ result[i] = this.deserialize(packedValue[i]);
507
+ }
508
+ }
509
+ else if (t == "object")
510
+ {
511
+ for(var i = 0; i < packedValue.newTypes.length; i++)
512
+ {
513
+ this.addTypeDataToCache(packedValue.newTypes[i]);
514
+ }
515
+ for (var aRefID in packedValue.newRefs)
516
+ {
517
+ this.createProxy(aRefID, packedValue.newRefs[aRefID]);
518
+ }
519
+ if (packedValue.type == FABridge.TYPE_PRIMITIVE)
520
+ {
521
+ result = packedValue.value;
522
+ }
523
+ else if (packedValue.type == FABridge.TYPE_ASFUNCTION)
524
+ {
525
+ result = this.getFunctionProxy(packedValue.value);
526
+ }
527
+ else if (packedValue.type == FABridge.TYPE_ASINSTANCE)
528
+ {
529
+ result = this.getProxy(packedValue.value);
530
+ }
531
+ else if (packedValue.type == FABridge.TYPE_ANONYMOUS)
532
+ {
533
+ result = packedValue.value;
534
+ }
535
+ }
536
+ return result;
537
+ },
538
+ //increases the reference count for the given object
539
+ addRef: function(obj)
540
+ {
541
+ this.target.incRef(obj.fb_instance_id);
542
+ },
543
+ //decrease the reference count for the given object and release it if needed
544
+ release:function(obj)
545
+ {
546
+ this.target.releaseRef(obj.fb_instance_id);
547
+ },
548
+
549
+ // check the given value for the components of the hard-coded error code : __FLASHERROR
550
+ // used to marshall NPE's into flash
551
+
552
+ handleError: function(value)
553
+ {
554
+ if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0)
555
+ {
556
+ var myErrorMessage = value.split("||");
557
+ if(FABridge.refCount > 0 )
558
+ {
559
+ FABridge.refCount--;
560
+ }
561
+ throw new Error(myErrorMessage[1]);
562
+ return value;
563
+ }
564
+ else
565
+ {
566
+ return value;
567
+ }
568
+ }
569
+ };
570
+
571
+ // The root ASProxy class that facades a flash object
572
+
573
+ ASProxy = function(bridge, typeName)
574
+ {
575
+ this.bridge = bridge;
576
+ this.typeName = typeName;
577
+ return this;
578
+ };
579
+ //methods available on each ASProxy object
580
+ ASProxy.prototype =
581
+ {
582
+ get: function(propName)
583
+ {
584
+ return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
585
+ },
586
+
587
+ set: function(propName, value)
588
+ {
589
+ this.bridge.setPropertyInAS(this.fb_instance_id, propName, value);
590
+ },
591
+
592
+ call: function(funcName, args)
593
+ {
594
+ this.bridge.callASMethod(this.fb_instance_id, funcName, args);
595
+ },
596
+
597
+ addRef: function() {
598
+ this.bridge.addRef(this);
599
+ },
600
+
601
+ release: function() {
602
+ this.bridge.release(this);
603
+ }
604
+ };