Skip to content

Commit

Permalink
Merge pull request #3 from coshx/fix/encoding_troubles
Browse files Browse the repository at this point in the history
Fix/encoding troubles
  • Loading branch information
acadet committed Jun 22, 2015
2 parents f2e45f0 + 3bb2e14 commit 29213f7
Show file tree
Hide file tree
Showing 19 changed files with 162 additions and 80 deletions.
6 changes: 4 additions & 2 deletions Caravel.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ Pod::Spec.new do |s|
# summary should be tweet-length, and the description more in depth.
#

version = "0.3.3"

s.name = "Caravel"
s.version = "0.3.2"
s.version = version
s.summary = "A Swift event bus for UIWebView and JS"

s.description = <<-DESC
Expand Down Expand Up @@ -73,7 +75,7 @@ Pod::Spec.new do |s|
# Supports git, hg, bzr, svn and HTTP.
#

s.source = { :git => "https://github.com/coshx/caravel.git", :tag => "v0.3.2" }
s.source = { :git => "https://github.com/coshx/caravel.git", :tag => "v#{version}" }


# ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
- `Int`
- `Double`
- `String`
- `Array`
- `Object`
- `Array` (available as a `NSArray`)
- `Object` (available as a `NSDictionary`)

## Installation

Expand Down
14 changes: 7 additions & 7 deletions caravel-test/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="05f-9A-d0q" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="h11-Jr-oMe" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="-239" y="-480"/>
<point key="canvasLocation" x="-319" y="-1056"/>
</scene>
<!--View Controller-->
<scene sceneID="ufC-wZ-h7g">
Expand Down Expand Up @@ -195,7 +195,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="Z2v-iD-5yN" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="bzb-zR-YuT" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="971" y="181"/>
<point key="canvasLocation" x="1579" y="453"/>
</scene>
<!--Two Bus Controller-->
<scene sceneID="WCS-7T-EvD">
Expand Down Expand Up @@ -244,7 +244,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="rWr-Z7-F2R" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="fzN-nE-3KF" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="538" y="1036"/>
<point key="canvasLocation" x="-86" y="1684"/>
</scene>
<!--Event Name Controller-->
<scene sceneID="ESZ-7I-jb3">
Expand Down Expand Up @@ -293,7 +293,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="Xjb-5n-d2q" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="Qfq-Te-Aqy" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="1256" y="946"/>
<point key="canvasLocation" x="1560" y="1818"/>
</scene>
<!--Two Event Controller-->
<scene sceneID="PpM-Vf-bCh">
Expand Down Expand Up @@ -342,7 +342,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="YPI-Uw-BsQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="f0T-jy-chR" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="-166" y="1130"/>
<point key="canvasLocation" x="-1390" y="1722"/>
</scene>
<!--Initialization Controller-->
<scene sceneID="gwb-lI-Hdz">
Expand Down Expand Up @@ -391,7 +391,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="sgJ-XM-d4b" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="xhC-pK-8CV" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="1285" y="-552"/>
<point key="canvasLocation" x="1829" y="-1104"/>
</scene>
<!--Basic Triggering Controller-->
<scene sceneID="B7P-jf-kp0">
Expand Down Expand Up @@ -440,7 +440,7 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="VRo-xx-F0v" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="gaY-MF-K2P" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="551" y="-552"/>
<point key="canvasLocation" x="575" y="-1128"/>
</scene>
</scenes>
</document>
51 changes: 51 additions & 0 deletions caravel-test/EventDataController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,57 @@ public class EventDataController: UIViewController {
self._raise("Dictionary - bad type")
}
}

bus.register("ComplexArray") { name, data in
if let a = data as? NSArray {
if a.count != 3 {
self._raise("ComplexArray - bad length")
}
if a[0] as! Int != 87 {
self._raise("ComplexArray - bad first element")
}
if let d = a[1] as? NSDictionary {
if d.valueForKey("name") as! String != "Bruce Willis" {
self._raise("ComplexArray - bad second element")
}
} else {
self._raise("ComplexArray - bad typed second element")
}
if a[2] as! String != "left-handed" {
self._raise("ComplexArray - bad third element")
}
} else {
self._raise("ComplexArray - bad type")
}
}

bus.register("ComplexDictionary") { name, data in
if let d = data as? NSDictionary {
if d.valueForKey("name") as! String != "John Malkovich" {
self._raise("ComplexDictionary - bad first pair")
}

if let a = d.valueForKey("movies") as? NSArray {
if a.count != 2 {
self._raise("ComplexDictionary - bad length")
}
if a[0] as! String != "Dangerous Liaisons" {
self._raise("ComplexDictionary - bad first element in array")
}
if a[1] as! String != "Burn after reading" {
self._raise("ComplexDictionary - bad second element in array")
}
} else {
self._raise("ComplexDictionary - bad typed second element")
}

if d.valueForKey("kids") as! Int != 2 {
self._raise("ComplexDictionary - bad third pair")
}
} else {
self._raise("ComplexDictionary - bad type")
}
}
}

_webView.loadRequest(NSURLRequest(URL: NSBundle.mainBundle().URLForResource("event_data", withExtension: "html")!))
Expand Down
2 changes: 2 additions & 0 deletions caravel-test/html/basic_triggering.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Basic triggering</h1>

<p>You should see: <pre>Received From iOS!</pre></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="caravel.min.js"></script>
<script type="text/javascript" src="basic_triggering.js"></script>
2 changes: 2 additions & 0 deletions caravel-test/html/event_name.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Event name</h1>

<p>You should only see <pre>You should see me</pre></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="caravel.min.js"></script>
<script type="text/javascript" src="event_name.js"></script>
2 changes: 2 additions & 0 deletions caravel-test/html/initialization.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Initialization</h1>

<p>You should see <pre>Before</pre><pre>After</pre></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="caravel.min.js"></script>
<script type="text/javascript" src="initialization.js"></script>
2 changes: 2 additions & 0 deletions caravel-test/html/multiple_subscribers.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Multiple subscribers</h1>

<p>You should see: <pre>First!</pre><pre>Second!</pre></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="caravel.min.js"></script>
<script type="text/javascript" src="multiple_subscribers.js"></script>
2 changes: 2 additions & 0 deletions caravel-test/html/two_buses.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Two buses</h1>

<p>You should see <pre>You should see me first and only once</pre><pre>You should see me after and only once</pre></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="caravel.min.js"></script>
<script type="text/javascript" src="two_buses.js"></script>
2 changes: 2 additions & 0 deletions caravel-test/html/two_events.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Two events</h1>

<p>You should only see <pre>You should see me and only me</pre></p>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="caravel.min.js"></script>
<script type="text/javascript" src="two_events.js"></script>
2 changes: 1 addition & 1 deletion caravel-test/js/basic_triggering.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Caravel.getDefault().register("From iOS", function(name, data) {
$('body').append('<p>Received From iOS!');
$('body').append('<p>Received From iOS!</p>');
});

Caravel.getDefault().post("From JS");
50 changes: 49 additions & 1 deletion caravel-test/js/event_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ function ok(name) {
}

function fail(name, data) {
if ((data instanceof Array) || (data instanceof Object)) {
data = JSON.stringify(data);
}
$('body').append('<p>Failed for ' + name + ': received ' + data + '</p>');
}

Expand Down Expand Up @@ -70,9 +73,54 @@ Caravel.getDefault().register("Dictionary", function(name, data) {
}
});

Caravel.getDefault().register("ComplexArray", function(name, data) {
var expectedData = [{name: "Alice", age: 24}, {name: "Bob", age: 23}];
var customFail = function() {
fail(name, data);
};

if (data.length == 2) {
if (data[0].name == expectedData[0].name && data[0].age == expectedData[0].age) {
if (data[1].name == expectedData[1].name && data[1].age == expectedData[1].age) {
ok(name);
} else {
customFail();
}
} else {
customFail();
}
} else {
customFail();
}
});

Caravel.getDefault().register("ComplexDictionary", function(name, data) {
var expectedData = {name: "Cesar", address: { street: "Parrot", city: "Perigueux" }, games: ["Fifa", "Star Wars"]};
var customFail = function() {
fail(name, data);
};

if (data.name == expectedData.name) {
if (data.address.street == expectedData.address.street && data.address.city == expectedData.address.city) {
if (data.length == expectedData.length && data.games[0] == expectedData.games[0] && data.games[1] == expectedData.games[1]) {
ok(name);
} else {
customFail();
}
} else {
customFail();
}
} else {
customFail();
}
});

Caravel.getDefault().post("Int", 987);
Caravel.getDefault().post("Float", 19.89);
Caravel.getDefault().post("Double", 15.15);
Caravel.getDefault().post("String", "Napoleon");
Caravel.getDefault().post("Array", [3, 1, 4]);
Caravel.getDefault().post("Dictionary", { "movie": "Once upon a time in the West", "actor": "Charles Bronson" });
Caravel.getDefault().post("Dictionary", { "movie": "Once upon a time in the West", "actor": "Charles Bronson" });

Caravel.getDefault().post("ComplexArray", [87, {"name": "Bruce Willis"}, "left-handed" ]);
Caravel.getDefault().post("ComplexDictionary", {name: "John Malkovich", movies: ["Dangerous Liaisons", "Burn after reading"], kids: 2});
50 changes: 11 additions & 39 deletions caravel/ArgumentParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,25 @@ import Foundation

/**
* @class ArgumentParser
* @brief Parses JS input to a list of arguments
* @brief Parses JS input to a list of arguments. Expected pattern: busName=*&eventName=*&eventData=*. Data are optional
*/
internal class ArgumentParser {

internal class func parse(input: String) -> [String] {
var outcome = [String]()
var prev: Character?
var buffer = String()
internal class func parse(input: String) -> (busName: String, eventName: String, eventData: String?) {
var queryPairs = input.componentsSeparatedByString("&")
var outcome: (busName: String, eventName: String, eventData: String?) = (busName: "", eventName: "", eventData: nil)

if count(input) == 0 { // No arg
return outcome
}

for current in input {
if current == "@" {
if prev != nil && prev != "\\" {
// Arguments are split using "@" symbol
// Existing "@" have been escaped before
outcome.append(buffer)
buffer = ""
} else if prev != nil && prev == "\\" {
// Escaped "@" symbol
// Let's unescape it
var i = 0, size = count(buffer)
var s = ""

for c in buffer {
if i < size - 1 {
s.append(c)
}
i++
}

buffer = s
buffer.append(current)
}
// A "@" symbol cannot be first as it has been escaped, so no else condition
for p in queryPairs {
var keyValue = p.componentsSeparatedByString("=")
if keyValue[0] == "busName" {
outcome.busName = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
} else if keyValue[0] == "eventName" {
outcome.eventName = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
} else {
buffer.append(current)
outcome.eventData = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
}

prev = current
}

// Add latest buffer
outcome.append(buffer)

return outcome
}
}
24 changes: 10 additions & 14 deletions caravel/Caravel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,20 @@ public class Caravel: NSObject, UIWebViewDelegate {

/**
* Caravel expects the following pattern:
* caravel@bus_name@event_name@extra_arg
* caravel://host.com?busName=*&eventName=*&eventData=*
*
* Followed argument types are supported:
* int, float, double, string
*/
public func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if let lastPathComponent: String = request.URL?.lastPathComponent {

// The last path of the URL needs to contains at least the "caravel" word
if count(lastPathComponent) > count("caravel") && (lastPathComponent as NSString).substringToIndex(count("caravel")) == "caravel" {
var args = ArgumentParser.parse(lastPathComponent)
var busName = args[1]
var eventName = args[2]
if let scheme: String = request.URL?.scheme {
if scheme == "caravel" {
var args = ArgumentParser.parse(request.URL!.query!)

// All buses are notified about that incoming event. Then, they need to investigate first if they
// are potential receivers
if _name == busName {
if eventName == "CaravelInit" { // Reserved event name. Triggers whenReady
if _name == args.busName {
if args.eventName == "CaravelInit" { // Reserved event name. Triggers whenReady
objc_sync_enter(_initializationLock)
_isInitialized = true

Expand All @@ -114,14 +110,14 @@ public class Caravel: NSObject, UIWebViewDelegate {
} else {
var eventData: AnyObject? = nil

if args.count > 3 { // Arg is optional
eventData = DataSerializer.deserialize(args[3])
if let d = args.eventData { // Data are optional
eventData = DataSerializer.deserialize(d)
}

for s in _subscribers {
if s.name == eventName {
if s.name == args.eventName {
dispatch_async(dispatch_get_main_queue()) {
s.callback(eventName, eventData)
s.callback(args.eventName, eventData)
}
}
}
Expand Down
Loading

0 comments on commit 29213f7

Please sign in to comment.