elevate 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ describe Elevate::Dispatcher do
2
+ DELAY = 0.2
3
+
4
+ before do
5
+ @dispatcher = Elevate::Dispatcher.new
6
+ end
7
+
8
+ describe "#on_started=" do
9
+ before do
10
+ @dispatcher.on_started = lambda { @thread = NSThread.currentThread }
11
+ end
12
+
13
+ after do
14
+ @thread = nil
15
+ end
16
+
17
+ it "invokes the callback on the main thread" do
18
+ wait DELAY do
19
+ @thread.should == NSThread.currentThread
20
+ end
21
+ end
22
+
23
+ it "does not invoke the callback immediately" do
24
+ @thread.should.be.nil
25
+ end
26
+ end
27
+
28
+ describe "#on_finished=" do
29
+ before do
30
+ @dispatcher.on_finished = lambda { @thread = NSThread.currentThread }
31
+ @dispatcher.invoke_finished_callback()
32
+ end
33
+
34
+ it "invokes the callback on the main thread" do
35
+ wait DELAY do
36
+ @thread.should == NSThread.currentThread
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ describe Elevate::DSL do
2
+ describe "#on_started" do
3
+ it "stores the provided block" do
4
+ i = Elevate::DSL.new do
5
+ on_started { |operation| puts 'hi' }
6
+ end
7
+
8
+ i.started_callback.should.not.be.nil
9
+ end
10
+ end
11
+
12
+ describe "#on_completed" do
13
+ it "stores the passed block" do
14
+ i = Elevate::DSL.new do
15
+ on_completed { |o| puts 'hi' }
16
+ end
17
+
18
+ i.finished_callback.should.not.be.nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ class Target
2
+ attr_reader :called
3
+ attr_reader :io_coordinator
4
+ attr_accessor :exception
5
+ attr_accessor :result
6
+
7
+ def initialize
8
+ @called = 0
9
+ @result = true
10
+ end
11
+
12
+ def execute
13
+ @io_coordinator = Thread.current[:io_coordinator]
14
+
15
+ @called += 1
16
+
17
+ if @exception
18
+ raise @exception
19
+ end
20
+
21
+ @result
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ describe Elevate::HTTP::HTTPClient do
2
+ extend WebStub::SpecHelpers
3
+
4
+ before do
5
+ disable_network_access!
6
+
7
+ @base_url = "http://www.example.com"
8
+ @path = "/resource/action"
9
+ @url = @base_url + @path
10
+
11
+ @client = Elevate::HTTP::HTTPClient.new(@base_url)
12
+ end
13
+
14
+ it "issues requests to the complete URL" do
15
+ stub_request(:get, @url).to_return(status_code: 201)
16
+
17
+ @client.get(@path).status_code.should == 201
18
+ end
19
+
20
+ it "appends query parameters to the URL" do
21
+ stub_request(:get, @url + "?q=help&page=2").to_return(json: { result: 0 })
22
+
23
+ @client.get(@path, q: "help", page: 2).body.should == { "result" => 0 }
24
+ end
25
+
26
+ it "decodes JSON responses" do
27
+ result = { "int" => 42, "string" => "hi", "dict" => { "boolean" => true }, "array" => [1,2,3] }
28
+ stub_request(:get, @url).to_return(json: result)
29
+
30
+ @client.get(@path).body.should == result
31
+ end
32
+
33
+ it "encodes JSON bodies" do
34
+ stub_request(:post, @url).
35
+ with(json: { string: "hello", array: [1,2,3] }).
36
+ to_return(json: { result: true })
37
+
38
+ @client.post(@path, { string: "hello", array: [1,2,3] }).body.should == { "result" => true }
39
+ end
40
+ end
@@ -0,0 +1,103 @@
1
+ describe Elevate::HTTP::HTTPRequest do
2
+ extend WebStub::SpecHelpers
3
+
4
+ before do
5
+ disable_network_access!
6
+ end
7
+
8
+ before do
9
+ @url = "http://www.example.com/"
10
+ @body = "hello"
11
+ end
12
+
13
+ it "requires a valid HTTP method" do
14
+ lambda { Elevate::HTTP::HTTPRequest.new(:invalid, @url) }.should.raise(ArgumentError)
15
+ end
16
+
17
+ it "requires a URL starting with http" do
18
+ lambda { Elevate::HTTP::HTTPRequest.new(:get, "asdf") }.should.raise(ArgumentError)
19
+ end
20
+
21
+ it "requires the body to be an instance of NSData" do
22
+ lambda { Elevate::HTTP::HTTPRequest.new(:get, @url, body: @body) }.should.raise(ArgumentError)
23
+ end
24
+
25
+ describe "fulfilling a GET request" do
26
+ before do
27
+ stub_request(:get, @url).
28
+ to_return(body: @body, headers: {"Content-Type" => "text/plain"}, status_code: 201)
29
+
30
+ @request = Elevate::HTTP::HTTPRequest.new(:get, @url)
31
+ @response = @request.response
32
+ end
33
+
34
+ it "response has the correct status code" do
35
+ @response.status_code.should == 201
36
+ end
37
+
38
+ it "response has the right body" do
39
+ NSString.alloc.initWithData(@response.body, encoding:NSUTF8StringEncoding).should == @body
40
+ end
41
+
42
+ it "response has the correct headers" do
43
+ @response.headers.should == { "Content-Type" => "text/plain" }
44
+ end
45
+
46
+ it "response has no errors" do
47
+ @response.error.should.be.nil
48
+ end
49
+ end
50
+
51
+ describe "fulfilling a GET request with headers" do
52
+ before do
53
+ stub_request(:get, @url).with(headers: { "API-Token" => "abc123" }).to_return(body: @body)
54
+
55
+ @request = Elevate::HTTP::HTTPRequest.new(:get, @url, headers: {})
56
+ @response = @request.response
57
+ end
58
+
59
+ it "includes the headers in the request" do
60
+ @response.body.should.not.be.nil
61
+ end
62
+ end
63
+
64
+ describe "fulfilling a POST request with a body" do
65
+ before do
66
+ stub_request(:post, @url).with(body: @body).to_return(body: @body)
67
+ end
68
+
69
+ it "sends the body as part of the request" do
70
+ request = Elevate::HTTP::HTTPRequest.new(:post, @url, body: @body.dataUsingEncoding(NSUTF8StringEncoding))
71
+ response = request.response
72
+
73
+ NSString.alloc.initWithData(response.body, encoding:NSUTF8StringEncoding).should == @body
74
+ end
75
+ end
76
+
77
+ describe "cancelling a request" do
78
+ before do
79
+ stub_request(:get, @url).to_return(body: @body, delay: 1.0)
80
+ end
81
+
82
+ it "aborts the request" do
83
+ start = Time.now
84
+
85
+ request = Elevate::HTTP::HTTPRequest.new(:get, @url)
86
+ request.start()
87
+ request.cancel()
88
+
89
+ response = request.response # simulate blocking
90
+ finish = Time.now
91
+
92
+ (finish - start).should < 1.0
93
+ end
94
+
95
+ it "sets the response to nil" do
96
+ request = Elevate::HTTP::HTTPRequest.new(:get, @url)
97
+ request.start()
98
+ request.cancel()
99
+
100
+ request.response.should.be.nil
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,44 @@
1
+ describe Elevate::IOCoordinator do
2
+ before do
3
+ @coordinator = Elevate::IOCoordinator.new
4
+ end
5
+
6
+ it "is not cancelled" do
7
+ @coordinator.should.not.be.cancelled
8
+ end
9
+
10
+ describe "#install" do
11
+ it "stores the coordinator in a thread-local variable" do
12
+ @coordinator.install()
13
+
14
+ Thread.current[:io_coordinator].should == @coordinator
15
+ end
16
+ end
17
+
18
+ [:signal_blocked, :signal_unblocked].each do |method|
19
+ describe method.to_s do
20
+ describe "when IO has not been cancelled" do
21
+ it "does not raise CancelledError" do
22
+ lambda { @coordinator.send(method, 42) }.should.not.raise
23
+ end
24
+ end
25
+
26
+ describe "when IO was cancelled" do
27
+ it "raises CancelledError" do
28
+ @coordinator.cancel()
29
+
30
+ lambda { @coordinator.send(method, "hello") }.should.raise(Elevate::CancelledError)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#uninstall" do
37
+ it "removes the coordinator from a thread-local variable" do
38
+ @coordinator.install()
39
+ @coordinator.uninstall()
40
+
41
+ Thread.current[:io_coordinator].should.be.nil
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,133 @@
1
+ describe Elevate::ElevateOperation do
2
+ before do
3
+ @target = Target.new
4
+ @operation = Elevate::ElevateOperation.alloc.initWithTarget(@target)
5
+ @queue = NSOperationQueue.alloc.init
6
+ end
7
+
8
+ after do
9
+ @queue.waitUntilAllOperationsAreFinished()
10
+ end
11
+
12
+ it "subclasses NSOperation" do
13
+ @operation.class.ancestors.should.include NSOperation
14
+ end
15
+
16
+ describe "#on_finished" do
17
+ it "invokes it after #on_started" do
18
+ @lock = NSLock.alloc.init
19
+ @value = []
20
+
21
+ @operation.on_started = lambda do
22
+ @lock.lock()
23
+ if @value == []
24
+ @value << 1
25
+ end
26
+ @lock.unlock()
27
+ end
28
+
29
+ @operation.on_finished = lambda do
30
+ @lock.lock()
31
+ if @value == [1]
32
+ @value << 2
33
+ end
34
+ @lock.unlock()
35
+
36
+ resume
37
+ end
38
+
39
+ @queue.addOperation(@operation)
40
+
41
+ wait_max 1.0 do
42
+ @lock.lock()
43
+ @value.should == [1,2]
44
+ @lock.unlock()
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "#exception" do
50
+ describe "when no exception is raised" do
51
+ it "returns nil" do
52
+ @queue.addOperation(@operation)
53
+ @operation.waitUntilFinished()
54
+
55
+ @operation.exception.should.be.nil
56
+ end
57
+ end
58
+
59
+ describe "when an exception is raised" do
60
+ it "returns the exception" do
61
+ @target.exception = IndexError.new
62
+
63
+ @queue.addOperation(@operation)
64
+ @operation.waitUntilFinished()
65
+
66
+ @operation.exception.should == @target.exception
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#main" do
72
+ describe "when the operation has not been run" do
73
+ it "invokes the target" do
74
+ @queue.addOperation(@operation)
75
+ @operation.waitUntilFinished()
76
+
77
+ @target.called.should == 1
78
+ end
79
+ end
80
+
81
+ describe "when the operation has been cancelled prior to starting" do
82
+ it "does not invoke the target" do
83
+ @operation.cancel()
84
+
85
+ @queue.addOperation(@operation)
86
+ @operation.waitUntilFinished()
87
+
88
+ @target.called.should == 0
89
+ end
90
+ end
91
+
92
+ describe "when the operation is running" do
93
+ it "allows IO to be cancelled" do
94
+ @queue.addOperation(@operation)
95
+ @operation.waitUntilFinished()
96
+
97
+ @target.io_coordinator.should.not.be.nil
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "#result" do
103
+ before do
104
+ @target.result = 42
105
+ end
106
+
107
+ describe "before starting the operation" do
108
+ it "returns nil" do
109
+ @operation.result.should.be.nil
110
+ end
111
+ end
112
+
113
+ describe "when the operation has been cancelled" do
114
+ it "returns nil" do
115
+ @operation.cancel()
116
+
117
+ @queue.addOperation(@operation)
118
+ @operation.waitUntilFinished()
119
+
120
+ @operation.result.should.be.nil
121
+ end
122
+ end
123
+
124
+ describe "when the operation has finished" do
125
+ it "returns the result of the target's #execute method" do
126
+ @queue.addOperation(@operation)
127
+ @operation.waitUntilFinished()
128
+
129
+ @operation.result.should == 42
130
+ end
131
+ end
132
+ end
133
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elevate
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Green
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: guard-motion
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.1.1
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.1.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: rb-fsevent
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.1
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: webstub
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.3.3
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.3.3
78
+ description: Distill the essence of your RubyMotion app
79
+ email:
80
+ - mattgreenrocks@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .rvmrc
87
+ - Gemfile
88
+ - Gemfile.lock
89
+ - Guardfile
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - app/app_delegate.rb
94
+ - elevate.gemspec
95
+ - lib/elevate.rb
96
+ - lib/elevate/api.rb
97
+ - lib/elevate/callback.rb
98
+ - lib/elevate/dispatcher.rb
99
+ - lib/elevate/dsl.rb
100
+ - lib/elevate/http/base64.rb
101
+ - lib/elevate/http/http_client.rb
102
+ - lib/elevate/http/request.rb
103
+ - lib/elevate/http/response.rb
104
+ - lib/elevate/http/uri.rb
105
+ - lib/elevate/io_coordinator.rb
106
+ - lib/elevate/operation.rb
107
+ - lib/elevate/promise.rb
108
+ - lib/elevate/version.rb
109
+ - spec/api_spec.rb
110
+ - spec/callback_spec.rb
111
+ - spec/dispatcher_spec.rb
112
+ - spec/dsl_spec.rb
113
+ - spec/helpers/target.rb
114
+ - spec/http/http_client_spec.rb
115
+ - spec/http/http_request_spec.rb
116
+ - spec/io_coordinator_spec.rb
117
+ - spec/operation_spec.rb
118
+ homepage: http://github.com/mattgreen/elevate
119
+ licenses: []
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ segments:
131
+ - 0
132
+ hash: 1532692712045252370
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ segments:
140
+ - 0
141
+ hash: 1532692712045252370
142
+ requirements: []
143
+ rubyforge_project:
144
+ rubygems_version: 1.8.24
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: Distill the essence of your RubyMotion app
148
+ test_files:
149
+ - spec/api_spec.rb
150
+ - spec/callback_spec.rb
151
+ - spec/dispatcher_spec.rb
152
+ - spec/dsl_spec.rb
153
+ - spec/helpers/target.rb
154
+ - spec/http/http_client_spec.rb
155
+ - spec/http/http_request_spec.rb
156
+ - spec/io_coordinator_spec.rb
157
+ - spec/operation_spec.rb