angelo 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1ed1fe692f13d99357085f5cdb4ac8a05f8158f
4
- data.tar.gz: 8fce9323f6e7c1ccdf7aba3507f6618c7fcd5364
3
+ metadata.gz: 3c515e055a1dbd1a233df60640c31b82866edf6a
4
+ data.tar.gz: 617d5e38dec4a3ea40c27dc16eb094081f7b6b8f
5
5
  SHA512:
6
- metadata.gz: 442a22ca6c5b0992956be8c12dcfebd7b307613b56b6f8972c06ea9f08069ef5be1e9d7be9e77596daa855fe26f74bc10b58531001c240e68d403be4957faa5f
7
- data.tar.gz: db87f3ebc41b1bf8923fc36d05728a7825686d63caa27f4ba5dffba578fba2d266e975265856524441eab55d3aa6b7ba2fd9bfa50ee6812a841555979d60bf2d
6
+ metadata.gz: 51acea14b590f1ed28b8017c2b9d88b953a77f24ee5c1784e6681d1d0521487faf7c18d228d99a9f3bd98b0b168c6f69d4e58e95d0b6463738053c35282433d1
7
+ data.tar.gz: 95de633d4b58ffeb51c4f43f03ce09bdae4f68191bf6e0cd278d9c1a77204907ed64ef3ab6cca2371698b98ae6818fe9b431503da77a1671890fbf8eb0957faf
data/.travis.yml CHANGED
@@ -2,4 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - "1.9.3"
4
4
  - "2.0.0"
5
- script: bundle exec rspec
5
+ - "2.1.1"
6
+ script: rake
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  changelog
2
2
  =========
3
3
 
4
+ ### 0.1.8 6 may 2014
5
+
6
+ * leave RSpec for Minitest
7
+ * fix for Reel::Connection::StateError -> Reel::StateError
8
+ * rename "socket" route definition to "websocket"
9
+
4
10
  ### 0.1.7 17 apr 2014
5
11
 
6
12
  * reel 0.5.0 support (Reel::Server -> Reel::Server::HTTP)
data/Gemfile CHANGED
@@ -5,13 +5,7 @@ gem 'tilt'
5
5
  gem 'mime-types'
6
6
  gem 'websocket-driver'
7
7
 
8
- platform :rbx do
9
- gem 'rubysl-cgi'
10
- gem 'rubysl-erb'
11
- gem 'rubysl-prettyprint'
12
- end
13
-
14
- platform :ruby_20 do
8
+ platform :ruby_20, :ruby_21 do
15
9
  gem 'mustermann'
16
10
  end
17
11
 
@@ -28,6 +22,5 @@ end
28
22
 
29
23
  group :test do
30
24
  gem 'httpclient'
31
- gem 'rspec'
32
- gem 'rspec-pride'
25
+ gem 'minitest'
33
26
  end
data/README.md CHANGED
@@ -5,18 +5,163 @@ Angelo
5
5
 
6
6
  A [Sinatra](https://github.com/sinatra/sinatra)-esque DSL for [Reel](https://github.com/celluloid/reel).
7
7
 
8
- ### Notes/Features
8
+ ### tl;dr
9
9
 
10
- * "easy" websocket support via `socket '/path' do |s|` route handler
11
- * "easy" websocket stashing via `websockets` helper
12
- * "easy" event handling via `async` helpers
10
+ * websocket support via `websocket('/path'){|s| ... }` route builder
11
+ * contextual websocket stashing via `websockets` helper
12
+ * `task` handling via `async` and `future` helpers
13
13
  * no rack
14
14
  * optional tilt/erb support
15
15
  * optional mustermann support
16
16
 
17
+ ### What is Angelo?
18
+
19
+ Just like Sinatra, Angelo gives you an expressive DSL for creating web applications. There are some
20
+ notable differences, but the basics remain the same. It mostly follows the subclass style of Sinatra:
21
+ you must define a subclass of `Angelo::Base` but also `.run` on that class for the service to start.
22
+ In addition, and perhaps more importantly, **Angelo is built upon Reel, which is, in turn, built upon
23
+ Celluloid::IO and gives you a reactor with evented IO in Ruby!**
24
+
25
+ Note: There currently is no "standalone" capability where one can define route handlers at the top level.
26
+
27
+ Things will feel very familiar to anyone experienced with Sinatra. Inside the subclass, you can define
28
+ route handlers denoted by HTTP verb and path. Unlike Sinatra, the only acceptable return value from a
29
+ route block is the body of the response in full. Chunked response support was recently added to Reel,
30
+ and look for that support in Angelo soon.
31
+
32
+ There is also [Mustermann](#mustermann) support for full-on, Sinatra-like path
33
+ matching and params.
34
+
35
+ ### Websockets!
36
+
37
+ One of the main motivations for Angelo was the ability to define websocket handlers with ease. Through
38
+ the addition of a `websocket` route builder and a `websockets` helper, Angelo attempts to make it easy
39
+ for you to build real-time web applications.
40
+
41
+ ##### Route Builder
42
+
43
+ The `websocket` route builder accepts a path and a block, and passes the actual websocket to the block
44
+ as the only argument. This socket is an instance of Reel's
45
+ [WebSocket](https://github.com/celluloid/reel/blob/master/lib/reel/websocket.rb) class, and, as such,
46
+ responds to methods like `on_message` and `on_close`. A service-wide `on_pong` handler (defined at the
47
+ class-level of the Angelo app) is available to customize the behavior when a pong frame comes back from
48
+ a connected websocket client.
49
+
50
+ ##### `websockets` helper
51
+
52
+ Angelo includes a "stash" helper for connected websockets. One can `<<` a websocket into `websockets`
53
+ from inside a websocket handler block. These can "later" be iterated over so one can do things like
54
+ emit a message on every connected websocket when the service receives a POST request.
55
+
56
+ The `websockets` helper also includes a context ability, so you can stash connected websocket clients
57
+ into different "sections".
58
+
59
+ ##### Example!
60
+
61
+ Here is an example of the `websocket` route builder, the `websockets` helper, and the context feature:
62
+
63
+ ```ruby
64
+ require 'angelo'
65
+
66
+ class Foo < Angelo::Base
67
+
68
+ websocket '/' do |ws|
69
+ websockets << ws
70
+ end
71
+
72
+ websocket '/bar' do |ws|
73
+ websockets[:bar] << ws
74
+ end
75
+
76
+ post '/' do
77
+ websockets.each {|ws| ws.write params[:foo]}
78
+ end
79
+
80
+ post '/bar' do
81
+ websockets[:bar].each {|ws| ws.write params[:bar]}
82
+ end
83
+
84
+ end
85
+
86
+ Foo.run
87
+ ```
88
+
89
+ In this case, any clients that connected to a websocket at the path '/' would be stashed in the
90
+ default websockets array; clients that connected to '/bar' would be stashed into the `:bar` section.
91
+
92
+ Each "section" can accessed with a familiar, `Hash`-like syntax, and can be iterated over with
93
+ a `.each` block.
94
+
95
+ When a `POST /` with a 'foo' param is received, any value is messaged out to any '/' connected
96
+ websockets. When a `POST /bar` with a 'bar' param is received, any value is messaged out to all
97
+ websockets that connected to '/bar'.
98
+
99
+ ### Tasks + Async / Future
100
+
101
+ Angelo is built on Reel and Celluloid::IO, giving your web application class the ability to define
102
+ "tasks" and call them from route handler blocks in an `async` or `future` style.
103
+
104
+ ##### `task` builder
105
+
106
+ You can define a task on the reactor using the `task` class method and giving it a symbol and a
107
+ block. The block can take arguments that you can pass later, with `async` or `future`.
108
+
109
+ ```ruby
110
+ # defining a task on the reactor called `:in_sec` which will sleep for
111
+ # given number of seconds, then return the given message.
112
+ #
113
+ task :in_sec do |sec, msg|
114
+ sleep sec.to_i
115
+ msg
116
+ end
117
+ ```
118
+
119
+ ##### `async` helper
120
+
121
+ This helper is directly analogous to the Celluoid method of the same name. Once tasks are defined,
122
+ you can call them with this helper method, passing the symbol of the task name and any arguments.
123
+ The task will run on the reactor, asynchronously, and return immediately.
124
+
125
+ ```ruby
126
+ get '/' do
127
+ # run the task defined above asynchronously, return immediately
128
+ #
129
+ async :in_sec, params[:sec], params[:msg]
130
+
131
+ # NOTE: params[:msg] is discarded, the return value of tasks called with `async` is nil.
132
+
133
+ # return this response body while the task is still running
134
+ # assuming params[:sec] is > 0
135
+ #
136
+ 'hi'
137
+ end
138
+ ```
139
+
140
+ ##### `future` helper
141
+
142
+ Just like `async`, this comes from Celluloid as well. It behaves exactly like `async`, with the
143
+ notable exception of returing a "future" object that you can call `#value` on later to retreive
144
+ the return value of the task. Once `#value` is called, things will "block" until the task is
145
+ finished.
146
+
147
+ ```ruby
148
+ get '/' do
149
+ # run the task defined above asynchronously, return immediately
150
+ #
151
+ f = future :in_sec, params[:sec], params[:msg]
152
+
153
+ # now, block until the task is finished and return the task's value
154
+ # as a response body
155
+ #
156
+ f.value
157
+ end
158
+ ```
159
+
160
+ ### WORK LEFT TO DO
161
+
17
162
  Lots of work left to do!
18
163
 
19
- ### Quick example
164
+ ### Full-ish example
20
165
 
21
166
  ```ruby
22
167
  require 'angelo'
@@ -25,18 +170,28 @@ require 'angelo/mustermann'
25
170
  class Foo < Angelo::Base
26
171
  include Angelo::Mustermann
27
172
 
173
+ # just some constants to use in routes later...
174
+ #
28
175
  TEST = {foo: "bar", baz: 123, bat: false}.to_json
29
-
30
176
  HEART = '<3'
177
+
178
+ # a flag to know if the :heart task is running
179
+ #
31
180
  @@hearting = false
32
181
 
182
+ # you can define instance methods, just like Sinatra!
183
+ #
33
184
  def pong; 'pong'; end
34
185
  def foo; params[:foo]; end
35
186
 
187
+ # standard HTTP GET handler
188
+ #
36
189
  get '/ping' do
37
190
  pong
38
191
  end
39
192
 
193
+ # standard HTTP POST handler
194
+ #
40
195
  post '/foo' do
41
196
  foo
42
197
  end
@@ -45,12 +200,19 @@ class Foo < Angelo::Base
45
200
  params.to_json
46
201
  end
47
202
 
203
+ # emit the TEST JSON value on all :emit_test websockets
204
+ # return the params posted as JSON
205
+ #
48
206
  post '/emit' do
49
207
  websockets[:emit_test].each {|ws| ws.write TEST}
50
208
  params.to_json
51
209
  end
52
210
 
53
- socket '/ws' do |ws|
211
+ # handle websocket requests at '/ws'
212
+ # stash them in the :emit_test context
213
+ # write 6 messages to the websocket whenever a message is received
214
+ #
215
+ websocket '/ws' do |ws|
54
216
  websockets[:emit_test] << ws
55
217
  ws.on_message do |msg|
56
218
  5.times { ws.write TEST }
@@ -58,19 +220,24 @@ class Foo < Angelo::Base
58
220
  end
59
221
  end
60
222
 
223
+ # emit the TEST JSON value on all :other websockets
224
+ #
61
225
  post '/other' do
62
226
  websockets[:other].each {|ws| ws.write TEST}
227
+ ''
63
228
  end
64
229
 
65
- socket '/other/ws' do |ws|
230
+ # stash '/other/ws' connected websockets in the :other context
231
+ #
232
+ websocket '/other/ws' do |ws|
66
233
  websockets[:other] << ws
67
234
  end
68
235
 
69
- socket '/hearts' do |ws|
236
+ websocket '/hearts' do |ws|
70
237
 
71
- # this is a call to Base#async, actually calling
238
+ # this is a call to Base#async, actually calling
72
239
  # the reactor to start the task
73
- #
240
+ #
74
241
  async :hearts unless @@hearting
75
242
 
76
243
  websockets[:hearts] << ws
@@ -87,12 +254,15 @@ class Foo < Angelo::Base
87
254
  post '/in/:sec/sec/:msg' do
88
255
 
89
256
  # this is a call to Base#future, telling the reactor
90
- # do this thing and we'' want the value eventually
257
+ # do this thing and we'll want the value eventually
91
258
  #
92
259
  f = future :in_sec params[:sec], params[:msg]
93
260
  f.value
94
261
  end
95
262
 
263
+ # define a task on the reactor that sleeps for the given number of
264
+ # seconds and returns the given message
265
+ #
96
266
  task :in_sec do |sec, msg|
97
267
  sleep sec.to_i
98
268
  msg
@@ -155,8 +325,6 @@ class Foo < Angelo::Base
155
325
  end
156
326
  ```
157
327
 
158
- NOTE: this always sets the Mustermann object's `type` to `:sinatra`
159
-
160
328
  ### Contributing
161
329
 
162
330
  YES, HAVE SOME
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.pattern = ENV['TEST_PATTERN'] || "test/**/*_spec.rb"
5
+ end
6
+
7
+ task :default => :test
data/lib/angelo/base.rb CHANGED
@@ -74,7 +74,7 @@ module Angelo
74
74
  end
75
75
  end
76
76
 
77
- def socket path, &block
77
+ def websocket path, &block
78
78
  routes[:socket][path] = WebsocketResponder.new &block
79
79
  end
80
80
 
@@ -1,7 +1,7 @@
1
1
  require 'websocket/driver'
2
2
 
3
3
  module Angelo
4
- module RSpec
4
+ module Minitest
5
5
 
6
6
  module Helpers
7
7
 
@@ -61,16 +61,16 @@ module Angelo
61
61
  end
62
62
  end
63
63
 
64
- def last_response_should_be_html body = ''
65
- last_response.status.should eq 200
66
- last_response.body.should eq body
67
- last_response.headers['Content-Type'].split(';').should include HTML_TYPE
64
+ def last_response_must_be_html body = ''
65
+ last_response.status.must_equal 200
66
+ last_response.body.must_equal body
67
+ last_response.headers['Content-Type'].split(';').must_include HTML_TYPE
68
68
  end
69
69
 
70
- def last_response_should_be_json obj = {}
71
- last_response.status.should eq 200
72
- JSON.parse(last_response.body).should eq obj
73
- last_response.headers['Content-Type'].split(';').should include JSON_TYPE
70
+ def last_response_must_be_json obj = {}
71
+ last_response.status.must_equal 200
72
+ JSON.parse(last_response.body).must_equal obj
73
+ last_response.headers['Content-Type'].split(';').must_include JSON_TYPE
74
74
  end
75
75
 
76
76
  end
@@ -28,9 +28,9 @@ module Angelo
28
28
  end
29
29
  end
30
30
 
31
- def socket path, &block
31
+ def websocket path, &block
32
32
  path = ::Mustermann.new path
33
- routes[:socket][path] = WebsocketResponder.new &block
33
+ super path, &block
34
34
  end
35
35
 
36
36
  def routes
@@ -42,7 +42,7 @@ module Angelo
42
42
  ::STDERR.puts e.backtrace
43
43
  begin
44
44
  @connection.close
45
- rescue Reel::Connection::StateError => rcse
45
+ rescue Reel::StateError => rcse
46
46
  close_websocket
47
47
  end
48
48
  end
@@ -1,3 +1,3 @@
1
1
  module Angelo
2
- VERSION = '0.1.7'
2
+ VERSION = '0.1.8'
3
3
  end
@@ -42,7 +42,7 @@ locals :bar - bat
42
42
  </body>
43
43
  </html>
44
44
  HTML
45
- last_response_should_be_html expected
45
+ last_response_must_be_html expected
46
46
  end
47
47
 
48
48
  it 'renders templates without layout' do
@@ -51,7 +51,7 @@ HTML
51
51
  foo - asdf
52
52
  locals :bar - bat
53
53
  HTML
54
- last_response_should_be_html expected
54
+ last_response_must_be_html expected
55
55
  end
56
56
 
57
57
  end
@@ -30,13 +30,13 @@ if RUBY_VERSION =~ /^2\./
30
30
  it 'matches via mustermann routes objects' do
31
31
  path = '/some/things/are_good'
32
32
  get path
33
- last_response_should_be_json mm_pattern.params(path)
33
+ last_response_must_be_json mm_pattern.params(path)
34
34
  end
35
35
 
36
36
  it 'overrides query string params' do
37
37
  path = '/some/things/are_good'
38
38
  get path, foo: 'other', bar: 'are_bad'
39
- last_response_should_be_json mm_pattern.params(path)
39
+ last_response_must_be_json mm_pattern.params(path)
40
40
  end
41
41
 
42
42
  it 'overrides post body params' do
@@ -44,14 +44,14 @@ if RUBY_VERSION =~ /^2\./
44
44
  headers = {Angelo::CONTENT_TYPE_HEADER_KEY => Angelo::JSON_TYPE}
45
45
  [:post, :put].each do |m|
46
46
  __send__ m, path, {foo: 'other', bar: 'are_bad'}.to_json, headers
47
- last_response_should_be_json mm_pattern.params(path)
47
+ last_response_must_be_json mm_pattern.params(path)
48
48
  end
49
49
  end
50
50
 
51
51
  it '404s correctly for not found routes' do
52
52
  path = '/bad/monkey'
53
53
  get path
54
- last_response.status.should eq 404
54
+ last_response.status.must_equal 404
55
55
  end
56
56
 
57
57
  end
@@ -87,7 +87,7 @@ locals :bar - alpaca
87
87
  </body>
88
88
  </html>
89
89
  HTML
90
- last_response_should_be_html expected
90
+ last_response_must_be_html expected
91
91
  end
92
92
 
93
93
  end
@@ -43,21 +43,21 @@ describe Angelo::ParamsParser do
43
43
  let(:parser) { ParamsTester.new }
44
44
 
45
45
  it 'parses query string params in the normal, non-racked-up, way' do
46
- parser.parse_formencoded(get_params).should eq params_s
46
+ parser.parse_formencoded(get_params).must_equal params_s
47
47
  end
48
48
 
49
49
  it 'parses formencoded POST bodies in the normal, non-racked-up, way' do
50
50
  parser.form_encoded = true
51
51
  parser.json = false
52
52
  parser.body = get_params
53
- parser.parse_post_body.should eq params_s
53
+ parser.parse_post_body.must_equal params_s
54
54
  end
55
55
 
56
56
  it 'parses JSON POST bodies params' do
57
57
  parser.form_encoded = false
58
58
  parser.json = true
59
59
  parser.body = json_params
60
- parser.parse_post_body.should eq post_params
60
+ parser.parse_post_body.must_equal post_params
61
61
  end
62
62
 
63
63
  it 'should override query string with JSON POST bodies params' do
@@ -65,7 +65,7 @@ describe Angelo::ParamsParser do
65
65
  parser.json = true
66
66
  parser.query_string = get_params
67
67
  parser.body = json_params
68
- parser.parse_post_body.should eq post_params
68
+ parser.parse_post_body.must_equal post_params
69
69
  end
70
70
 
71
71
  it 'does not parse POST bodies if no Content-Type' do
@@ -73,8 +73,8 @@ describe Angelo::ParamsParser do
73
73
  parser.json = false
74
74
  parser.query_string = get_params
75
75
  parser.body = nil
76
- parser.parse_post_body.should eq params_s
77
- parser.parse_query_string.should eq params_s
76
+ parser.parse_post_body.must_equal params_s
77
+ parser.parse_query_string.must_equal params_s
78
78
  end
79
79
 
80
80
  end
@@ -0,0 +1,72 @@
1
+ require_relative '../spec_helper'
2
+ require 'openssl'
3
+
4
+ describe Angelo::Server do
5
+
6
+ describe 'serving static files' do
7
+
8
+ let(:css_etag) do
9
+ fs = File::Stat.new File.join(TEST_APP_ROOT, 'public', 'test.css')
10
+ OpenSSL::Digest::SHA.hexdigest fs.ino.to_s + fs.size.to_s + fs.mtime.to_s
11
+ end
12
+
13
+ define_app do
14
+
15
+ @root = TEST_APP_ROOT
16
+
17
+ get '/test.html' do
18
+ 'you should not see this'
19
+ end
20
+
21
+ end
22
+
23
+ it 'serves static files for gets' do
24
+ get '/test.css'
25
+ last_response.status.must_equal 200
26
+ last_response.headers['Content-Type'].must_equal 'text/css'
27
+ last_response.headers['Content-Disposition'].must_equal 'attachment; filename=test.css'
28
+ last_response.headers['Content-Length'].must_equal '116'
29
+ last_response.headers['Etag'].must_equal css_etag
30
+ last_response.body.length.must_equal 116
31
+ last_response.body.must_equal File.read(File.join TEST_APP_ROOT, 'public', 'test.css')
32
+ end
33
+
34
+ it 'serves headers for static files on head' do
35
+ head '/test.css'
36
+ last_response.status.must_equal 200
37
+ last_response.headers['Content-Type'].must_equal 'text/css'
38
+ last_response.headers['Content-Disposition'].must_equal 'attachment; filename=test.css'
39
+ last_response.headers['Content-Length'].must_equal '116'
40
+ last_response.headers['Etag'].must_equal css_etag
41
+ last_response.body.length.must_equal 0
42
+ end
43
+
44
+ it 'serves static file over route' do
45
+ get '/test.html'
46
+ last_response.status.must_equal 200
47
+ last_response.headers['Content-Type'].must_equal 'text/html'
48
+ last_response.headers['Content-Disposition'].must_equal 'attachment; filename=test.html'
49
+ last_response.body.must_equal File.read(File.join TEST_APP_ROOT, 'public', 'test.html')
50
+ end
51
+
52
+ it 'not modifieds when if-none-match matched etag' do
53
+ get '/test.css', {}, {'If-None-Match' => css_etag}
54
+ last_response.status.must_equal 304
55
+ end
56
+
57
+ it 'serves proper content-types' do
58
+ { 'test.js' => 'application/javascript',
59
+ 'test.html' => 'text/html',
60
+ 'test.css' => 'text/css',
61
+ 'what.png' => 'image/png' }.each do |k,v|
62
+
63
+ get "/#{k}"
64
+ last_response.status.must_equal 200
65
+ last_response.headers['Content-Type'].must_equal v
66
+
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -32,7 +32,7 @@ describe Angelo::WebsocketResponder do
32
32
  describe 'basics' do
33
33
 
34
34
  define_app do
35
- socket '/' do |ws|
35
+ websocket '/' do |ws|
36
36
  while msg = ws.read do
37
37
  ws.write msg
38
38
  end
@@ -44,7 +44,7 @@ describe Angelo::WebsocketResponder do
44
44
  latch = CountDownLatch.new 500
45
45
 
46
46
  wsh.on_message = ->(e) {
47
- expect(e.data).to match(/hi there \d/)
47
+ assert_match /hi there \d/, e.data
48
48
  latch.count_down
49
49
  }
50
50
 
@@ -72,7 +72,7 @@ describe Angelo::WebsocketResponder do
72
72
  Reactor.testers[:wshs] = Array.new(CONCURRENCY).map do
73
73
  wsh = socket '/'
74
74
  wsh.on_message = ->(e) {
75
- expect(e.data).to match(/hi there \d/)
75
+ assert_match /hi there \d/, e.data
76
76
  latch.count_down
77
77
  }
78
78
  wsh.init
@@ -118,7 +118,7 @@ describe Angelo::WebsocketResponder do
118
118
  end
119
119
  end
120
120
 
121
- socket '/concur' do |ws|
121
+ websocket '/concur' do |ws|
122
122
  websockets << ws
123
123
  end
124
124
 
@@ -129,7 +129,7 @@ describe Angelo::WebsocketResponder do
129
129
  latch = CountDownLatch.new CONCURRENCY * Angelo::HTTPABLE.length
130
130
 
131
131
  expectation = ->(e){
132
- expect(e.data).to match(/from http (#{Angelo::HTTPABLE.map(&:to_s).join('|')})/)
132
+ assert_match /from http (#{Angelo::HTTPABLE.map(&:to_s).join('|')})/, e.data
133
133
  }
134
134
 
135
135
  socket_wait_for '/concur', latch, expectation do
@@ -143,7 +143,7 @@ describe Angelo::WebsocketResponder do
143
143
 
144
144
  describe 'helper contexts' do
145
145
  let(:obj){ {'foo' => 'bar'} }
146
- let(:wait_for_block){ ->(e){ expect(JSON.parse(e.data)).to eq(obj) }}
146
+ let(:wait_for_block){ ->(e){ assert_equal obj, JSON.parse(e.data) }}
147
147
 
148
148
  define_app do
149
149
 
@@ -152,7 +152,7 @@ describe Angelo::WebsocketResponder do
152
152
  ''
153
153
  end
154
154
 
155
- socket '/' do |ws|
155
+ websocket '/' do |ws|
156
156
  websockets << ws
157
157
  while msg = ws.read do
158
158
  ws.write msg.to_json
@@ -164,7 +164,7 @@ describe Angelo::WebsocketResponder do
164
164
  ''
165
165
  end
166
166
 
167
- socket '/one' do |ws|
167
+ websocket '/one' do |ws|
168
168
  websockets[:one] << ws
169
169
  while msg = ws.read do
170
170
  ws.write msg.to_json
@@ -176,7 +176,7 @@ describe Angelo::WebsocketResponder do
176
176
  ''
177
177
  end
178
178
 
179
- socket '/other' do |ws|
179
+ websocket '/other' do |ws|
180
180
  websockets[:other] << ws
181
181
  while msg = ws.read do
182
182
  ws.write msg.to_json
@@ -2,12 +2,13 @@ require_relative './spec_helper'
2
2
 
3
3
  describe Angelo::Base do
4
4
 
5
- let :obj do
5
+ def obj
6
6
  {'foo' => 'bar', 'bar' => 123.4567890123456, 'bat' => true}
7
7
  end
8
- let(:obj_s) {
8
+
9
+ def obj_s
9
10
  obj.keys.reduce({}){|h,k| h[k] = obj[k].to_s; h}
10
- }
11
+ end
11
12
 
12
13
  describe 'the basics' do
13
14
 
@@ -35,24 +36,24 @@ describe Angelo::Base do
35
36
  it 'responds to http requests properly' do
36
37
  Angelo::HTTPABLE.each do |m|
37
38
  __send__ m, '/'
38
- last_response_should_be_html m.to_s
39
+ last_response_must_be_html m.to_s
39
40
  end
40
41
  end
41
42
 
42
43
  it 'responds to get requests with json properly' do
43
44
  get '/json', obj
44
- last_response_should_be_json obj_s
45
+ last_response_must_be_json obj_s
45
46
  end
46
47
 
47
48
  it 'responds to post requests with json properly' do
48
49
  post '/json', obj.to_json, {'Content-Type' => Angelo::JSON_TYPE}
49
- last_response_should_be_json obj
50
+ last_response_must_be_json obj
50
51
  end
51
52
 
52
53
  it 'redirects' do
53
54
  get '/redirect'
54
- expect(last_response.status).to eq(301)
55
- expect(last_response.headers['Location']).to eq('/')
55
+ last_response.status.must_equal 301
56
+ last_response.headers['Location'].must_equal '/'
56
57
  end
57
58
 
58
59
  end
@@ -77,11 +78,11 @@ describe Angelo::Base do
77
78
  it 'runs before filters before routes' do
78
79
 
79
80
  get '/before', obj
80
- last_response_should_be_json obj_s
81
+ last_response_must_be_json obj_s
81
82
 
82
83
  [:post, :put].each do |m|
83
84
  __send__ m, '/before', obj.to_json, {Angelo::CONTENT_TYPE_HEADER_KEY => Angelo::JSON_TYPE}
84
- last_response_should_be_json obj
85
+ last_response_must_be_json obj
85
86
  end
86
87
 
87
88
  end
@@ -115,8 +116,8 @@ describe Angelo::Base do
115
116
  b = [4, 12, 28, 60]
116
117
  Angelo::HTTPABLE.each_with_index do |m,i|
117
118
  __send__ m, '/after', obj
118
- last_response_should_be_html a[i]
119
- invoked.should eq b[i]
119
+ last_response_must_be_html a[i]
120
+ invoked.must_equal b[i]
120
121
  end
121
122
  end
122
123
 
@@ -138,16 +139,16 @@ describe Angelo::Base do
138
139
 
139
140
  it 'sets headers for a response' do
140
141
  put '/incr'
141
- expect(last_response.headers['X-Http-Angelo-Server']).to eq('catbutt')
142
+ last_response.headers['X-Http-Angelo-Server'].must_equal 'catbutt'
142
143
  end
143
144
 
144
145
  it 'does not carry headers over responses' do
145
146
  headers_count = 0
146
147
  put '/incr'
147
- expect(last_response.headers['X-Http-Angelo-Server']).to eq('catbutt')
148
+ last_response.headers['X-Http-Angelo-Server'].must_equal 'catbutt'
148
149
 
149
150
  put '/incr'
150
- expect(last_response.headers['X-Http-Angelo-Server']).to be_nil
151
+ last_response.headers['X-Http-Angelo-Server'].must_be_nil
151
152
  end
152
153
 
153
154
  end
@@ -190,35 +191,35 @@ describe Angelo::Base do
190
191
  it 'sets html content type for current route' do
191
192
  Angelo::HTTPABLE.each do |m|
192
193
  __send__ m, '/html'
193
- last_response_should_be_html '<html><body>hi</body></html>'
194
+ last_response_must_be_html '<html><body>hi</body></html>'
194
195
  end
195
196
  end
196
197
 
197
198
  it 'sets json content type for current route and to_jsons hashes' do
198
199
  Angelo::HTTPABLE.each do |m|
199
200
  __send__ m, '/json'
200
- last_response_should_be_json 'hi' => 'there'
201
+ last_response_must_be_json 'hi' => 'there'
201
202
  end
202
203
  end
203
204
 
204
205
  it 'does not to_json strings' do
205
206
  Angelo::HTTPABLE.each do |m|
206
207
  __send__ m, '/json_s'
207
- last_response_should_be_json 'woo' => 'woo'
208
+ last_response_must_be_json 'woo' => 'woo'
208
209
  end
209
210
  end
210
211
 
211
212
  it '500s on html hashes' do
212
213
  Angelo::HTTPABLE.each do |m|
213
214
  __send__ m, '/bad_html_h'
214
- last_response.status.should eq 500
215
+ last_response.status.must_equal 500
215
216
  end
216
217
  end
217
218
 
218
219
  it '500s on bad json strings' do
219
220
  Angelo::HTTPABLE.each do |m|
220
221
  __send__ m, '/bad_json_s'
221
- last_response.status.should eq 500
222
+ last_response.status.must_equal 500
222
223
  end
223
224
  end
224
225
 
@@ -240,7 +241,7 @@ describe Angelo::Base do
240
241
  it 'sets default content type' do
241
242
  Angelo::HTTPABLE.each do |m|
242
243
  __send__ m, '/html'
243
- last_response_should_be_html '<html><body>hi</body></html>'
244
+ last_response_must_be_html '<html><body>hi</body></html>'
244
245
  end
245
246
  end
246
247
 
@@ -260,7 +261,7 @@ describe Angelo::Base do
260
261
  it 'sets default content type' do
261
262
  Angelo::HTTPABLE.each do |m|
262
263
  __send__ m, '/json'
263
- last_response_should_be_json 'hi' => 'there'
264
+ last_response_must_be_json 'hi' => 'there'
264
265
  end
265
266
  end
266
267
  end
@@ -284,7 +285,7 @@ describe Angelo::Base do
284
285
  it 'sets html content type for current route when default is set json' do
285
286
  Angelo::HTTPABLE.each do |m|
286
287
  __send__ m, '/json'
287
- last_response_should_be_json 'hi' => 'there'
288
+ last_response_must_be_json 'hi' => 'there'
288
289
  end
289
290
  end
290
291
 
@@ -305,7 +306,7 @@ describe Angelo::Base do
305
306
  it 'sets json content type for current route when default is set html' do
306
307
  Angelo::HTTPABLE.each do |m|
307
308
  __send__ m, '/html'
308
- last_response_should_be_html '<html><body>hi</body></html>'
309
+ last_response_must_be_html '<html><body>hi</body></html>'
309
310
  end
310
311
  end
311
312
 
@@ -330,17 +331,17 @@ describe Angelo::Base do
330
331
 
331
332
  it 'parses formencoded body when content-type is formencoded' do
332
333
  post '/json', obj, {'Content-Type' => Angelo::FORM_TYPE}
333
- last_response_should_be_json obj_s
334
+ last_response_must_be_json obj_s
334
335
  end
335
336
 
336
337
  it 'does not parse JSON body when content-type is formencoded' do
337
338
  post '/json', obj.to_json, {'Content-Type' => Angelo::FORM_TYPE}
338
- last_response.status.should eq 400
339
+ last_response.status.must_equal 400
339
340
  end
340
341
 
341
342
  it 'does not parse body when request content-type not set' do
342
343
  post '/json', obj, {'Content-Type' => ''}
343
- last_response_should_be_json({})
344
+ last_response_must_be_json({})
344
345
  end
345
346
 
346
347
  end
@@ -375,7 +376,7 @@ describe Angelo::Base do
375
376
  }
376
377
 
377
378
  get '/rh', ps, hs
378
- last_response_should_be_json 'values' => hs.values
379
+ last_response_must_be_json 'values' => hs.values
379
380
  end
380
381
 
381
382
  end
@@ -1,11 +1,13 @@
1
- $:.unshift File.expand_path '../../../lib', __FILE__
1
+ $:.unshift File.expand_path '../../lib', __FILE__
2
2
 
3
3
  require 'bundler'
4
4
  Bundler.require :default, :development, :test
5
+ require 'minitest/pride'
6
+ require 'minitest/autorun'
5
7
  require 'angelo'
6
- require 'angelo/rspec/helpers'
8
+ require 'angelo/minitest/helpers'
7
9
  Celluloid.logger.level = ::Logger::ERROR
8
- include Angelo::RSpec::Helpers
10
+ include Angelo::Minitest::Helpers
9
11
 
10
12
  TEST_APP_ROOT = File.expand_path '../test_app_root', __FILE__
11
13
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: angelo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenichi Nakamura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-17 00:00:00.000000000 Z
11
+ date: 2014-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: reel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mime-types
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  description: A Sinatra-esque DSL for Reel
@@ -45,36 +45,37 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - .gitignore
49
- - .travis.yml
48
+ - ".gitignore"
49
+ - ".travis.yml"
50
50
  - CHANGELOG.md
51
51
  - Gemfile
52
52
  - LICENSE
53
53
  - README.md
54
+ - Rakefile
54
55
  - angelo.gemspec
55
56
  - lib/angelo.rb
56
57
  - lib/angelo/base.rb
58
+ - lib/angelo/minitest/helpers.rb
57
59
  - lib/angelo/mustermann.rb
58
60
  - lib/angelo/params_parser.rb
59
61
  - lib/angelo/responder.rb
60
62
  - lib/angelo/responder/websocket.rb
61
- - lib/angelo/rspec/helpers.rb
62
63
  - lib/angelo/server.rb
63
64
  - lib/angelo/tilt/erb.rb
64
65
  - lib/angelo/version.rb
65
- - spec/angelo/erb_spec.rb
66
- - spec/angelo/mustermann_spec.rb
67
- - spec/angelo/params_spec.rb
68
- - spec/angelo/static_spec.rb
69
- - spec/angelo/websocket_spec.rb
70
- - spec/angelo_spec.rb
71
- - spec/spec_helper.rb
72
- - spec/test_app_root/public/test.css
73
- - spec/test_app_root/public/test.html
74
- - spec/test_app_root/public/test.js
75
- - spec/test_app_root/public/what.png
76
- - spec/test_app_root/views/index.html.erb
77
- - spec/test_app_root/views/layout.html.erb
66
+ - test/angelo/erb_spec.rb
67
+ - test/angelo/mustermann_spec.rb
68
+ - test/angelo/params_spec.rb
69
+ - test/angelo/static_spec.rb
70
+ - test/angelo/websocket_spec.rb
71
+ - test/angelo_spec.rb
72
+ - test/spec_helper.rb
73
+ - test/test_app_root/public/test.css
74
+ - test/test_app_root/public/test.html
75
+ - test/test_app_root/public/test.js
76
+ - test/test_app_root/public/what.png
77
+ - test/test_app_root/views/index.html.erb
78
+ - test/test_app_root/views/layout.html.erb
78
79
  homepage: https://github.com/kenichi/angelo
79
80
  licenses:
80
81
  - apache
@@ -85,31 +86,18 @@ require_paths:
85
86
  - lib
86
87
  required_ruby_version: !ruby/object:Gem::Requirement
87
88
  requirements:
88
- - - '>='
89
+ - - ">="
89
90
  - !ruby/object:Gem::Version
90
91
  version: '0'
91
92
  required_rubygems_version: !ruby/object:Gem::Requirement
92
93
  requirements:
93
- - - '>='
94
+ - - ">="
94
95
  - !ruby/object:Gem::Version
95
96
  version: '0'
96
97
  requirements: []
97
98
  rubyforge_project:
98
- rubygems_version: 2.0.14
99
+ rubygems_version: 2.2.2
99
100
  signing_key:
100
101
  specification_version: 4
101
102
  summary: A Sinatra-esque DSL for Reel
102
- test_files:
103
- - spec/angelo/erb_spec.rb
104
- - spec/angelo/mustermann_spec.rb
105
- - spec/angelo/params_spec.rb
106
- - spec/angelo/static_spec.rb
107
- - spec/angelo/websocket_spec.rb
108
- - spec/angelo_spec.rb
109
- - spec/spec_helper.rb
110
- - spec/test_app_root/public/test.css
111
- - spec/test_app_root/public/test.html
112
- - spec/test_app_root/public/test.js
113
- - spec/test_app_root/public/what.png
114
- - spec/test_app_root/views/index.html.erb
115
- - spec/test_app_root/views/layout.html.erb
103
+ test_files: []
@@ -1,72 +0,0 @@
1
- require_relative '../spec_helper'
2
- require 'openssl'
3
-
4
- describe Angelo::Server do
5
-
6
- describe 'serving static files' do
7
-
8
- let(:test_css_etag) do
9
- fs = File::Stat.new File.join(TEST_APP_ROOT, 'public', 'test.css')
10
- OpenSSL::Digest::SHA.hexdigest fs.ino.to_s + fs.size.to_s + fs.mtime.to_s
11
- end
12
-
13
- define_app do
14
-
15
- @root = TEST_APP_ROOT
16
-
17
- get '/test.html' do
18
- 'you should not see this'
19
- end
20
-
21
- end
22
-
23
- it 'serves static files for gets' do
24
- get '/test.css'
25
- expect(last_response.status).to be(200)
26
- expect(last_response.headers['Content-Type']).to eq('text/css')
27
- expect(last_response.headers['Content-Disposition']).to eq('attachment; filename=test.css')
28
- expect(last_response.headers['Content-Length']).to eq('116')
29
- expect(last_response.headers['Etag']).to eq(test_css_etag)
30
- expect(last_response.body.length).to be(116)
31
- expect(last_response.body).to eq(File.read(File.join TEST_APP_ROOT, 'public', 'test.css'))
32
- end
33
-
34
- it 'serves headers for static files on head' do
35
- head '/test.css'
36
- expect(last_response.status).to be(200)
37
- expect(last_response.headers['Content-Type']).to eq('text/css')
38
- expect(last_response.headers['Content-Disposition']).to eq('attachment; filename=test.css')
39
- expect(last_response.headers['Content-Length']).to eq('116')
40
- expect(last_response.headers['Etag']).to eq(test_css_etag)
41
- expect(last_response.body.length).to be(0)
42
- end
43
-
44
- it 'serves static file over route' do
45
- get '/test.html'
46
- expect(last_response.status).to be(200)
47
- expect(last_response.headers['Content-Type']).to eq('text/html')
48
- expect(last_response.headers['Content-Disposition']).to eq('attachment; filename=test.html')
49
- expect(last_response.body).to eq(File.read(File.join TEST_APP_ROOT, 'public', 'test.html'))
50
- end
51
-
52
- it 'not modifieds when if-none-match matched etag' do
53
- get '/test.css', {}, {'If-None-Match' => test_css_etag}
54
- expect(last_response.status).to be(304)
55
- end
56
-
57
- it 'serves proper content-types' do
58
- { 'test.js' => 'application/javascript',
59
- 'test.html' => 'text/html',
60
- 'test.css' => 'text/css',
61
- 'what.png' => 'image/png' }.each do |k,v|
62
-
63
- get "/#{k}"
64
- expect(last_response.status).to be(200)
65
- expect(last_response.headers['Content-Type']).to eq(v)
66
-
67
- end
68
- end
69
-
70
- end
71
-
72
- end