angelo 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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