meteor-motion 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.repl_history +0 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +166 -0
  7. data/Rakefile +17 -0
  8. data/app/app_delegate.rb +11 -0
  9. data/app/controllers/book_controller.rb +92 -0
  10. data/app/controllers/book_list_controller.rb +105 -0
  11. data/app/controllers/connection_controller.rb +83 -0
  12. data/app/controllers/login_controller.rb +35 -0
  13. data/lib/meteor-motion.rb +12 -0
  14. data/lib/meteor-motion/version.rb +3 -0
  15. data/meteor-motion.gemspec +27 -0
  16. data/motion/adapters/motion_model.rb +61 -0
  17. data/motion/client.rb +179 -0
  18. data/motion/collection.rb +50 -0
  19. data/motion/collections/default.rb +56 -0
  20. data/motion/collections/motion_model.rb +52 -0
  21. data/motion/ddp.rb +161 -0
  22. data/motion/srp/securerandom.rb +248 -0
  23. data/motion/srp/srp.rb +250 -0
  24. data/spec/adapters/motion_model_spec.rb +38 -0
  25. data/spec/client_spec.rb +104 -0
  26. data/spec/collection_spec.rb +63 -0
  27. data/spec/collections/default_spec.rb +46 -0
  28. data/spec/collections/motion_model_spec.rb +69 -0
  29. data/spec/ddp_spec.rb +123 -0
  30. data/spec/server/.meteor/.gitignore +1 -0
  31. data/spec/server/.meteor/packages +9 -0
  32. data/spec/server/.meteor/release +1 -0
  33. data/spec/server/collections/books.js +11 -0
  34. data/spec/server/server/fixtures.js +28 -0
  35. data/spec/server/server/publications.js +3 -0
  36. data/spec/server/smart.json +3 -0
  37. data/vendor/SocketRocket/NSData+SRB64Additions.h +24 -0
  38. data/vendor/SocketRocket/NSData+SRB64Additions.m +39 -0
  39. data/vendor/SocketRocket/SRWebSocket.h +114 -0
  40. data/vendor/SocketRocket/SRWebSocket.m +1757 -0
  41. data/vendor/SocketRocket/SocketRocket-Prefix.pch +27 -0
  42. data/vendor/SocketRocket/SocketRocket.bridgesupport +160 -0
  43. data/vendor/SocketRocket/base64.c +314 -0
  44. data/vendor/SocketRocket/base64.h +34 -0
  45. metadata +190 -0
@@ -0,0 +1,46 @@
1
+ describe MeteorMotion::Collections::Default do
2
+
3
+ describe 'CRUD tasks' do
4
+
5
+ before do
6
+ @coll = MeteorMotion::Collections::Default.new('temp')
7
+ end
8
+
9
+ it 'adds an object to the collection and finds it' do
10
+ @coll.add('abc', {a: 1, b:2})
11
+ @coll.find('abc').should.not.be.equal nil
12
+ end
13
+
14
+ it 'adds the correct fields to the object' do
15
+ @coll.add('abc', {a: 1, b:2})
16
+
17
+ @coll.find('abc')[:a].should.be.equal 1
18
+ @coll.find('abc')[:b].should.be.equal 2
19
+ end
20
+
21
+ it 'updates an objects fields' do
22
+ @coll.add('abc', {a: 1, b:2})
23
+ @coll.find('abc')[:a].should.be.equal 1
24
+
25
+ @coll.update('abc', {a: 2}, nil)
26
+ @coll.find('abc')[:a].should.be.equal 2
27
+ end
28
+
29
+ it 'clears an objects fields' do
30
+ @coll.add('abc', {a: 1, b:2})
31
+ @coll.find('abc')[:a].should.be.equal 1
32
+
33
+ @coll.update('abc', nil, [:a])
34
+ @coll.find('abc')[:a].should.be.equal nil
35
+ end
36
+
37
+ it 'removes an object from the collection' do
38
+ @coll.add('abc', {a: 1, b:2})
39
+
40
+ @coll.remove('abc')
41
+ @coll.find('abc').should.be.equal nil
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,69 @@
1
+ class DummyModel
2
+ include MotionModel::Model
3
+ include MotionModel::ArrayModelAdapter
4
+ include MeteorMotion::Adapters::MotionModel
5
+
6
+
7
+ # Make sure to define :id as String so MotionModel does not create a default int
8
+ #
9
+ columns :id => :string,
10
+ :a => :int,
11
+ :b => :int
12
+ end
13
+
14
+ describe MeteorMotion::Collections::MotionModel do
15
+ describe 'Creation' do
16
+ it 'creates a collection with a compatible class' do
17
+ coll = MeteorMotion::Collections::MotionModel.new(DummyModel)
18
+ coll.should.not.be.equal nil
19
+ coll.name.should.be.equal 'dummymodel'
20
+ end
21
+
22
+ it 'sets a different name when it is provided' do
23
+ coll = MeteorMotion::Collections::MotionModel.new(DummyModel, 'dums')
24
+ coll.should.not.be.equal nil
25
+ coll.name.should.be.equal 'dums'
26
+ end
27
+ end
28
+
29
+
30
+ describe 'CRUD tasks' do
31
+
32
+ before do
33
+ @client = MeteorMotion::Client.new
34
+ @client.connect
35
+ @coll = MeteorMotion::Collections::MotionModel.new(DummyModel)
36
+ end
37
+
38
+ it 'adds an object to the collection and finds it' do
39
+ @coll.add('abc', {a: 1, b:2})
40
+ @coll.find('abc').should.not.be.equal nil
41
+ end
42
+
43
+ it 'adds the correct fields to the object' do
44
+ @coll.add('abc', {a: 1, b:2})
45
+
46
+ @coll.find('abc').a.should.be.equal 1
47
+ @coll.find('abc').b.should.be.equal 2
48
+ end
49
+
50
+ it 'updates an objects fields' do
51
+ @coll.add('abc', {a: 1, b:2})
52
+ @coll.find('abc').a.should.be.equal 1
53
+
54
+ @coll.update('abc', {a: 2}, nil)
55
+ @coll.find('abc').a.should.be.equal 2
56
+ end
57
+
58
+ it 'removes an object from the collection' do
59
+ @coll.add('abc', {a: 1, b:2})
60
+
61
+ wait 1.0 do
62
+ @coll.remove('abc')
63
+ @coll.find('abc').should.be.equal nil
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,123 @@
1
+ describe MeteorMotion::DDP do
2
+ def handle_connect result
3
+ @result = result
4
+ end
5
+
6
+ describe 'connect' do
7
+ def error code, reason, details
8
+ return
9
+ end
10
+
11
+ it 'connects with a valid hostname' do
12
+ ddp = MeteorMotion::DDP.new self
13
+ ddp.connect
14
+
15
+ wait 1.0 do
16
+ ddp.websocket_ready?.should.equal true
17
+ ddp.session.should.not.equal nil
18
+ end
19
+ end
20
+ end
21
+
22
+ describe 'subscriptions' do
23
+
24
+ def error code, reason, details
25
+ if reason != :unknown
26
+ @error_msg = reason
27
+ resume
28
+ end
29
+ end
30
+
31
+ def collections
32
+ return @collections
33
+ end
34
+
35
+ def subscriptions
36
+ return @subscriptions
37
+ end
38
+
39
+ before do
40
+ @ddp = MeteorMotion::DDP.new self
41
+ @ddp.connect
42
+ @collections = {'books' => MeteorMotion::Collections::Default.new('books') }
43
+ @subscriptions = {}
44
+
45
+ wait 1.0 do
46
+ end
47
+ end
48
+
49
+ it 'successfully subscribes to an existing publication' do
50
+ @sub_id = @ddp.sub('books')
51
+ @subscriptions[@sub_id] = {ready: false}
52
+
53
+ wait 1.0 do
54
+ @collections['books'].size.should.equal 3
55
+ @subscriptions[@sub_id][:ready].should.equal true
56
+ end
57
+ end
58
+
59
+
60
+ it 'receives a no-sub message if no matching publication is found' do
61
+ @ddp.sub('posts')
62
+
63
+ wait do
64
+ @error_msg.should.equal "Subscription not found"
65
+ end
66
+ end
67
+
68
+ it 'successfully unsubscribes to an existing publication' do
69
+ @ddp.unsub( @sub_id )
70
+
71
+ wait 1.0 do
72
+ @collections['books'].size.should.equal 0
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+
79
+ describe 'method calls' do
80
+
81
+ def error code, reason, details
82
+ return
83
+ end
84
+
85
+ def handle_method id, type, results
86
+ if results
87
+ @success = results
88
+ end
89
+ end
90
+
91
+ before do
92
+ @ddp = MeteorMotion::DDP.new self
93
+ @ddp.connect
94
+ wait 1.0 do
95
+ end
96
+ end
97
+
98
+ it 'successfully executes an existing remote call without params' do
99
+ @ddp.call('ping')
100
+
101
+ wait 1.0 do
102
+ @success.should.equal 'pong'
103
+ end
104
+ end
105
+
106
+ it 'successfully executes an existing remote call with params' do
107
+ @ddp.call('echo', {message: 'echo'} )
108
+
109
+ wait 1.0 do
110
+ @success.should.equal 'echo'
111
+ end
112
+ end
113
+
114
+ it 'fails when calling a method that does not exist' do
115
+ @ddp.call('someMethod')
116
+
117
+ wait 1.0 do
118
+ @success[:reason].should.be.equal 'Method not found'
119
+ end
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1 @@
1
+ local
@@ -0,0 +1,9 @@
1
+ # Meteor packages used by this project, one per line.
2
+ #
3
+ # 'meteor add' and 'meteor remove' will edit this file for you,
4
+ # but you can also edit it by hand.
5
+
6
+ standard-app-packages
7
+ insecure
8
+ preserve-inputs
9
+ accounts-password
@@ -0,0 +1 @@
1
+ 0.7.0.1
@@ -0,0 +1,11 @@
1
+ Books = new Meteor.Collection('books');
2
+
3
+ Meteor.methods({
4
+ echo: function(message) {
5
+ return message.message;
6
+ },
7
+
8
+ ping: function(message) {
9
+ return 'pong';
10
+ }
11
+ });
@@ -0,0 +1,28 @@
1
+ Books.remove({});
2
+
3
+ Books.insert({
4
+ title: 'Foundation',
5
+ author: 'Isaac Asimov',
6
+ year: '1951'
7
+ });
8
+
9
+ Books.insert({
10
+ title: 'Foundation and Empire',
11
+ author: 'Isaac Asimov',
12
+ year: '1952'
13
+ });
14
+
15
+ Books.insert({
16
+ title: 'Fahrenheit 451',
17
+ author: 'Ray Bradbury',
18
+ year: '1966'
19
+ });
20
+
21
+
22
+ Meteor.users.remove({});
23
+
24
+ Accounts.createUser({
25
+ username: 'user',
26
+ email: 'user@email.com',
27
+ password: 'pass'
28
+ });
@@ -0,0 +1,3 @@
1
+ Meteor.publish('books', function() {
2
+ return Books.find();
3
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "packages": {}
3
+ }
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2012 Square Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #import <Foundation/Foundation.h>
18
+
19
+
20
+ @interface NSData (SRB64Additions)
21
+
22
+ - (NSString *)SR_stringByBase64Encoding;
23
+
24
+ @end
@@ -0,0 +1,39 @@
1
+ //
2
+ // Copyright 2012 Square Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #import "NSData+SRB64Additions.h"
18
+ #import "base64.h"
19
+
20
+
21
+ @implementation NSData (SRB64Additions)
22
+
23
+ - (NSString *)SR_stringByBase64Encoding;
24
+ {
25
+ size_t buffer_size = (([self length] * 3 + 2) / 2);
26
+
27
+ char *buffer = (char *)malloc(buffer_size);
28
+
29
+ int len = b64_ntop([self bytes], [self length], buffer, buffer_size);
30
+
31
+ if (len == -1) {
32
+ free(buffer);
33
+ return nil;
34
+ } else{
35
+ return [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSUTF8StringEncoding freeWhenDone:YES];
36
+ }
37
+ }
38
+
39
+ @end
@@ -0,0 +1,114 @@
1
+ //
2
+ // Copyright 2012 Square Inc.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ #import <Foundation/Foundation.h>
18
+ #import <Security/SecCertificate.h>
19
+
20
+ typedef enum {
21
+ SR_CONNECTING = 0,
22
+ SR_OPEN = 1,
23
+ SR_CLOSING = 2,
24
+ SR_CLOSED = 3,
25
+ } SRReadyState;
26
+
27
+ @class SRWebSocket;
28
+
29
+ extern NSString *const SRWebSocketErrorDomain;
30
+
31
+ #pragma mark - SRWebSocketDelegate
32
+
33
+ @protocol SRWebSocketDelegate;
34
+
35
+ #pragma mark - SRWebSocket
36
+
37
+ @interface SRWebSocket : NSObject <NSStreamDelegate>
38
+
39
+ @property (nonatomic, assign) id <SRWebSocketDelegate> delegate;
40
+
41
+ @property (nonatomic, readonly) SRReadyState readyState;
42
+ @property (nonatomic, readonly, retain) NSURL *url;
43
+
44
+ // This returns the negotiated protocol.
45
+ // It will be nil until after the handshake completes.
46
+ @property (nonatomic, readonly, copy) NSString *protocol;
47
+
48
+ // Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
49
+ - (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
50
+ - (id)initWithURLRequest:(NSURLRequest *)request;
51
+
52
+ // Some helper constructors.
53
+ - (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
54
+ - (id)initWithURL:(NSURL *)url;
55
+
56
+ // Delegate queue will be dispatch_main_queue by default.
57
+ // You cannot set both OperationQueue and dispatch_queue.
58
+ - (void)setDelegateOperationQueue:(NSOperationQueue*) queue;
59
+ - (void)setDelegateDispatchQueue:(dispatch_queue_t) queue;
60
+
61
+ // By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes.
62
+ - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
63
+ - (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
64
+
65
+ // SRWebSockets are intended for one-time-use only. Open should be called once and only once.
66
+ - (void)open;
67
+
68
+ - (void)close;
69
+ - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
70
+
71
+ // Send a UTF8 String or Data.
72
+ - (void)send:(id)data;
73
+
74
+ @end
75
+
76
+ #pragma mark - SRWebSocketDelegate
77
+
78
+ @protocol SRWebSocketDelegate <NSObject>
79
+
80
+ // message will either be an NSString if the server is using text
81
+ // or NSData if the server is using binary.
82
+ - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
83
+
84
+ @optional
85
+
86
+ - (void)webSocketDidOpen:(SRWebSocket *)webSocket;
87
+ - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
88
+ - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
89
+
90
+ @end
91
+
92
+ #pragma mark - NSURLRequest (CertificateAdditions)
93
+
94
+ @interface NSURLRequest (CertificateAdditions)
95
+
96
+ @property (nonatomic, retain, readonly) NSArray *SR_SSLPinnedCertificates;
97
+
98
+ @end
99
+
100
+ #pragma mark - NSMutableURLRequest (CertificateAdditions)
101
+
102
+ @interface NSMutableURLRequest (CertificateAdditions)
103
+
104
+ @property (nonatomic, retain) NSArray *SR_SSLPinnedCertificates;
105
+
106
+ @end
107
+
108
+ #pragma mark - NSRunLoop (SRWebSocket)
109
+
110
+ @interface NSRunLoop (SRWebSocket)
111
+
112
+ + (NSRunLoop *)SR_networkRunLoop;
113
+
114
+ @end