- Only pass strings between JavaScript and Ruby, encoding in JSON strings if necessary.
- In JavaScript, call Ruby methods with String arguments. JavaScript ints become Ruby Floats, so just use Strings to avoid potential confusion; JSON arguments will probably work and become hashes, but then you'll have to beware of the types of all the nested objects... if I need multiple values then I either supply them as more arguments or I call the Ruby method multiple times.
- In Ruby, check arguments for RubyKObject type. Sometimes arguments don't have the expected String type, so you'll want to convert them:
if (term.class.name == "RubyKObject")
term = term.toString()
end
- In Ruby, return String objects; if necessary, encode in JSON. Here's a simplistic method that works for me:
# takes an argument which is any nesting of String, Array, Hash (and nil)
# return a String holding JSON representation of the argument
def self.strings_arrays_hashes_json(arg)
if (arg == nil)
"null"
elsif (arg.class.name == "String")
result = arg
result = result.gsub("\"","\\\"")
result = result.gsub("\\","\\\\")
result = result.gsub("\/","\\/")
result = result.gsub("\b","\\b")
result = result.gsub("\f","\\f")
result = result.gsub("\n","\\n")
result = result.gsub("\r","\\r")
result = result.gsub("\t","\\t")
"\"" + result + "\""
elsif (arg.class.name == "Array")
recurse = arg.map { |elem| strings_arrays_hashes_json elem }
"[" + recurse.join(", ") + "]"
elsif (arg.class.name == "Hash")
hashes = arg.to_a.map { |key, val|
"\"#{key}\":#{strings_arrays_hashes_json(val)}" }
"{" + hashes.join(", ") + "}"
else
"#{arg}"
end
end
- In JavaScript, cast the results to a string (ie. toString()) and parse out the JSON if necessary (ie. JSON-js). It's crazy, but even an unused toString call can make a difference.
- Thankfully, you can trust nulls and nils; they convert to one another well.
- In JavaScript, call any Ruby methods before playing with the DOM. I've found that, if I have a lot of DOM manipulation, Ruby calls will work up to some point and then WHAM! after that point you get errors or crashes.
BTW, the direct-to-console debugging is your friend; the Ruby puts calls may not get flushed immediately, but this will:
Titanium.API.print("stuff\n");
When you start working this way, you'll notice that you're really pushed into a paradigm where you do simple visual manipulations in the browser as much as possible, but for any substantive changes to data you do a page-submit to pass the values to the same page, then you run your logic during the page initialization and then you rerender the whole page. It's unfortunate, but now I never have troubles. (... at least very few! Just kidding. I haven't had any mysterious Ruby errors or app crashes wherever I take these approaches.)
BTW, every time I hit a glitch, I look more closely at other approaches... but since I figure every tool will have its issues, I'm still sticking with the devil I know. Feel free to ask me later if I'm still sticking to it.
No comments:
Post a Comment