Building a iOS Ruby REPL and Opal for iOS
I'm happy to tell you I just finished the first version of IGJavaScriptConsole, a JavaScript/Ruby REPL for your Objective-C apps!
REPL stands for Read-Eval-Print-Loop. See it in live below:
Why?
Since iOS 7 shipped with JavaScriptCore, I always want to run Ruby on it with
Opal. While it is totally possible to write Opal app as is, its getting harder when the Ruby classes getting interact with native classes -- you
must test it on device/simulator but compile-deploy time is so long and so painful.
While there is a way to connect Safari Web Inspector with JSContext, its not possible for Opal: You have to compile it before it can run on JSContext.
Implementation
That make me think why not build a console myself? Thats the beginning of IGJavaScriptConsole.
Its build on top of following:
- Opal A Ruby to JavaScript compiler. It even come with sprockets extension which lets you bundle the compiled script easily.
- JavaScriptCoreOpalAdditions A thin layer of Objective-C that load and provides native features to Opal.
- jqConsole Web based terminal.
- Ace Web based code editor with syntax highlighting.
- CocoaHTTPServer HTTP and WebSocket server for realtime communication
between iOS and desktop.
Opal on iOS, is it practical?
Absolutely.
When programming Opal you first wrap native JavaScript code with Ruby classes.
When doing it in iOS its no different, just remeber you must expose native Objective-C methods to JavaScript with JSExport protocol first, then wrap them with Ruby code.
// expose Objective-C code to JSContext
@protocol ViewControllerExport <JSExport>
-(void) setGreeting:(NSString*)helloText;
-(NSString*) getGreeting;
@end
// Create javascript object from Objective-C
if (!context[@"App"]) {
context[@"App"] = @{};
}
context[@"App"][@"viewController"] = self;
# wrapping a Objective-C classes
class ViewController
include Native
alias_native :greeting, :getGreeting
alias_native :greeting=, :setGreeting
end
# use the wrapper class
vc = ViewController.new(`App.viewController`)
vc.greeting = "Hi!"
All of those wrapping is boring, but when its done, you can build higher level API or
DSL that dramatically changes how you build apps.
Note you'll not implement the whole app in Ruby with Opal (to do that, use RubyMotion), its best for macro or other dynamic behavior.
If you want to build your own Ruby library for Opal on iOS, check IGHTMLQuery, it wrap everything in Ruby and I think its a pleasure to work with it.
What Next?
- Implement Ruby standard library that is missing on Opal (due to platform limitation) but critical on native app development.
- Something like BubbleWrap might also needed to wrap native class to allow more interaction between Ruby and Objective-C.
- Build great apps and profit!!