zero 0.1.0

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.
Files changed (65) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +14 -0
  5. data/Gemfile.lock +59 -0
  6. data/Guardfile +15 -0
  7. data/README.md +60 -0
  8. data/Thorfile +6 -0
  9. data/lib/zero.rb +7 -0
  10. data/lib/zero/controller.rb +46 -0
  11. data/lib/zero/rack_request.rb +44 -0
  12. data/lib/zero/renderer.rb +139 -0
  13. data/lib/zero/request.rb +100 -0
  14. data/lib/zero/request/accept.rb +28 -0
  15. data/lib/zero/request/accept_type.rb +58 -0
  16. data/lib/zero/request/client.rb +31 -0
  17. data/lib/zero/request/parameter.rb +101 -0
  18. data/lib/zero/request/server.rb +41 -0
  19. data/lib/zero/response.rb +80 -0
  20. data/lib/zero/router.rb +63 -0
  21. data/lib/zero/version.rb +3 -0
  22. data/spec/fixtures/templates/index.html.erb +1 -0
  23. data/spec/fixtures/templates/index.json.erb +1 -0
  24. data/spec/spec_helper.rb +65 -0
  25. data/spec/unit/controller/call_spec.rb +22 -0
  26. data/spec/unit/controller/renderer_spec.rb +11 -0
  27. data/spec/unit/renderer/read_template_path_spec.rb +53 -0
  28. data/spec/unit/renderer/render_spec.rb +50 -0
  29. data/spec/unit/renderer/template_path.rb +8 -0
  30. data/spec/unit/renderer/type_map_spec.rb +9 -0
  31. data/spec/unit/request/accept/encoding_spec.rb +9 -0
  32. data/spec/unit/request/accept/language_spec.rb +9 -0
  33. data/spec/unit/request/accept/types_spec.rb +9 -0
  34. data/spec/unit/request/accept_spec.rb +7 -0
  35. data/spec/unit/request/accepttype/each_spec.rb +10 -0
  36. data/spec/unit/request/accepttype/preferred_spec.rb +35 -0
  37. data/spec/unit/request/client/address_spec.rb +9 -0
  38. data/spec/unit/request/client/hostname_spec.rb +9 -0
  39. data/spec/unit/request/client/user_agent_spec.rb +9 -0
  40. data/spec/unit/request/client_spec.rb +8 -0
  41. data/spec/unit/request/content_type_spec.rb +16 -0
  42. data/spec/unit/request/create_spec.rb +21 -0
  43. data/spec/unit/request/delete_spec.rb +15 -0
  44. data/spec/unit/request/get_spec.rb +15 -0
  45. data/spec/unit/request/head_spec.rb +15 -0
  46. data/spec/unit/request/method_spec.rb +8 -0
  47. data/spec/unit/request/parameter/[]_spec.rb +56 -0
  48. data/spec/unit/request/parameter/custom_spec.rb +18 -0
  49. data/spec/unit/request/parameter/initialize_spec.rb +12 -0
  50. data/spec/unit/request/parameter/payload_spec.rb +33 -0
  51. data/spec/unit/request/parameter/query_spec.rb +25 -0
  52. data/spec/unit/request/params_spec.rb +8 -0
  53. data/spec/unit/request/patch_spec.rb +15 -0
  54. data/spec/unit/request/path_spec.rb +9 -0
  55. data/spec/unit/request/post_spec.rb +15 -0
  56. data/spec/unit/request/put_spec.rb +15 -0
  57. data/spec/unit/request/server/hostname_spec.rb +9 -0
  58. data/spec/unit/request/server/port_spec.rb +7 -0
  59. data/spec/unit/request/server/protocol_spec.rb +9 -0
  60. data/spec/unit/request/server/software_spec.rb +9 -0
  61. data/spec/unit/request/server_spec.rb +8 -0
  62. data/spec/unit/response/response_spec.rb +146 -0
  63. data/spec/unit/router/call_spec.rb +55 -0
  64. data/zero.gemspec +27 -0
  65. metadata +345 -0
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Controller, '.call' do
4
+ subject { SpecController.call(env) }
5
+ let(:env) { EnvGenerator.get('/foo') }
6
+
7
+ it "returns a response" do
8
+ subject.should be_respond_to(:to_a)
9
+ end
10
+
11
+ it "returns an object with the first element being a status" do
12
+ subject[0].should be_kind_of(Numeric)
13
+ end
14
+
15
+ it "does not modify an existing request" do
16
+ r = Zero::Request.new(env)
17
+ r.params['foo'] = 'bar'
18
+ subject
19
+ r = Zero::Request.create(env)
20
+ expect(r.params['foo']).to eq('bar')
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Controller, '#renderer' do
4
+ subject { Zero::Controller }
5
+ let(:renderer) { Object.new }
6
+
7
+ it 'returns the set renderer' do
8
+ subject.renderer = renderer
9
+ expect(subject.new(Object.new).renderer).to be(renderer)
10
+ end
11
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Renderer, 'read_template_path!' do
4
+ subject { Zero::Renderer.new(template_path, type_map) }
5
+ let(:template_path) { 'foo' }
6
+ let(:file_list) { ['foo/welcome/index.html.erb'] }
7
+
8
+ before :each do
9
+ subject.stub(:search_files).and_return(file_list)
10
+ end
11
+
12
+ shared_examples_for 'a template loader' do
13
+ it 'creates a template tree' do
14
+ subject.read_template_path!
15
+ subject.templates['welcome/index'].should eq(result)
16
+ end
17
+ end
18
+
19
+ context 'without mapping' do
20
+ let(:type_map) { {} }
21
+ let(:result) { { 'html' => 'foo/welcome/index.html.erb' } }
22
+
23
+ it_behaves_like 'a template loader'
24
+ end
25
+
26
+ context 'with a single mapping' do
27
+ let(:type_map) { {'html' => 'text/html' } }
28
+ let(:result) { { 'text/html' => 'foo/welcome/index.html.erb' } }
29
+
30
+ it_behaves_like 'a template loader'
31
+ end
32
+
33
+ context 'with multiple mappings' do
34
+ let(:type_map) { {'html' => ['text/html', 'text/xml'] } }
35
+ let(:result) { {
36
+ 'text/html' => 'foo/welcome/index.html.erb',
37
+ 'text/xml' => 'foo/welcome/index.html.erb'
38
+ } }
39
+
40
+ it_behaves_like 'a template loader'
41
+ end
42
+
43
+ context 'with default template' do
44
+ let(:file_list) {['foo/welcome/index.erb']}
45
+ let(:type_map) { {'default' => ['text/html', 'text/xml'] } }
46
+ let(:result) { {
47
+ 'text/html' => 'foo/welcome/index.erb',
48
+ 'text/xml' => 'foo/welcome/index.erb'
49
+ } }
50
+
51
+ it_behaves_like 'a template loader'
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Renderer, '#render' do
4
+ subject { Zero::Renderer.new(template_path, type_map) }
5
+ let(:template_path) { 'spec/fixtures/templates' }
6
+ let(:file_list) { ['./foo/welcome/index.html.erb'] }
7
+ let(:type_map) {{
8
+ 'html' => ['text/html', 'text/xml', '*/*'],
9
+ 'json' => ['application/json', 'plain/text']
10
+ }}
11
+ let(:html_types) { ['text/html'] }
12
+ let(:json_types) { ['application/json'] }
13
+ let(:foo_types) { ['foo/bar', 'bar/foo'] }
14
+ let(:binding) { SpecTemplateContext.new('foo') }
15
+
16
+ before :each do
17
+ subject.read_template_path!
18
+ end
19
+
20
+ it 'returns a tilt template' do
21
+ subject.render('index', html_types, binding).should be_kind_of(String)
22
+ end
23
+
24
+ it 'renders html content' do
25
+ subject.render('index', html_types, binding).should match('success')
26
+ end
27
+
28
+ it 'returns a tilt template for different types' do
29
+ subject.render('index', json_types, binding).should be_kind_of(String)
30
+ end
31
+
32
+ it 'renders json content' do
33
+ subject.render('index', json_types, binding).should match("{text: 'success'}")
34
+ end
35
+
36
+ it 'returns an ArgumentError, if given template does not exist' do
37
+ expect {
38
+ subject.render('foobar', html_types, binding)
39
+ }.to raise_error(ArgumentError, "No template found for 'foobar'!")
40
+ end
41
+
42
+ it 'returns an ArgumentError, if no template fits types' do
43
+ expect {
44
+ subject.render('index', foo_types, binding)
45
+ }.to raise_error(
46
+ ArgumentError,
47
+ "No template found for any of this types #{foo_types.join ', '}!"
48
+ )
49
+ end
50
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Renderer, '#template_path' do
4
+ subject { Zero::Renderer.new(template_path) }
5
+ let(:template_path) { 'foo' }
6
+
7
+ its(:type_map) { should be(template_path) }
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Renderer, '#type_map' do
4
+ subject { Zero::Renderer.new(template_path, type_map) }
5
+ let(:template_path) { 'foo' }
6
+ let(:type_map) { {'html' => ['text/html']} }
7
+
8
+ its(:type_map) { should be(type_map) }
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Accept, '#encoding' do
4
+ subject { Zero::Request::Accept.new(env) }
5
+ let(:encoding) { 'en_US' }
6
+ let(:env) { EnvGenerator.get('/foo', {'HTTP_ACCEPT_ENCODING' => encoding}) }
7
+
8
+ its(:encoding) { should be_an_instance_of(Zero::Request::AcceptType) }
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Accept, '#language' do
4
+ subject { Zero::Request::Accept.new(env) }
5
+ let(:language) { 'en_US' }
6
+ let(:env) { EnvGenerator.get('/foo', {'HTTP_ACCEPT_LANGUAGE' => language}) }
7
+
8
+ its(:language) { should be_an_instance_of(Zero::Request::AcceptType) }
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Accept, '#types' do
4
+ subject { Zero::Request::Accept.new(env) }
5
+ let(:media_types) { 'text/html' }
6
+ let(:env) { EnvGenerator.get('/foo', {'HTTP_ACCEPT' => media_types}) }
7
+
8
+ its(:types) { should be_an_instance_of(Zero::Request::AcceptType) }
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#accept' do
4
+ subject { Zero::Request.new(env) }
5
+ let(:env) { EnvGenerator.get('/foo') }
6
+ its(:accept) { should be_an_instance_of(Zero::Request::Accept) }
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::AcceptType, '#each' do
4
+ subject { Zero::Request::AcceptType.new(types) }
5
+ let(:html) { 'text/html' }
6
+ let(:json) { 'application/json' }
7
+ let(:types) { [html, json].join(',') }
8
+
9
+ specify { expect {|b| subject.each(&b) }.to yield_successive_args(html, json) }
10
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::AcceptType, '#preferred' do
4
+ subject { Zero::Request::AcceptType }
5
+ let(:html) { 'text/html' }
6
+ let(:json) { 'application/json' }
7
+ let(:foo) { 'text/foo' }
8
+ let(:lower_quality) { foo + ';q=0.5' }
9
+ let(:default) { '*/*;q=0.1' }
10
+ let(:simple_accept) { [html, json].join(',') }
11
+ let(:quality_accept) { [html, lower_quality, default].join(',') }
12
+ let(:random_accept) { [lower_quality, default, html].join(',') }
13
+ let(:lower_accept) { [lower_quality, default].join(',') }
14
+
15
+ context 'without mapping' do
16
+ it { subject.new(html).preferred.should == html }
17
+ it { subject.new(json).preferred.should == json }
18
+ it { subject.new(simple_accept).preferred.should == html }
19
+ it { subject.new(quality_accept).preferred.should == html }
20
+ it { subject.new(random_accept).preferred.should == html }
21
+ it { subject.new(lower_accept).preferred.should == foo }
22
+ end
23
+
24
+ # context 'with mapping' do
25
+ # before :all do
26
+ # Zero::Request::Accept.map = {'text/html' => 'html'}
27
+ # end
28
+ #
29
+ # after :all do
30
+ # Zero::Request::Accept.map = {}
31
+ # end
32
+ #
33
+ # it { subject.new(html).preferred.should == 'html' }
34
+ # end
35
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Client, '#address' do
4
+ subject { Zero::Request::Client.new(env) }
5
+ let(:address) { '127.0.0.1' }
6
+ let(:env) { {'REMOTE_ADDR' => address} }
7
+
8
+ its(:address) { should == address }
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Client, '#hostname' do
4
+ subject { Zero::Request::Client.new(env) }
5
+ let(:hostname) { 'foo.bar' }
6
+ let(:env) { {'REMOTE_HOST' => hostname} }
7
+
8
+ its(:hostname) { should == hostname }
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Client, '#user_agent' do
4
+ subject { Zero::Request::Client.new(env) }
5
+ let(:user_agent) { 'Mozilla (dummy agent)' }
6
+ let(:env) { {'HTTP_USER_AGENT' => user_agent} }
7
+
8
+ its(:user_agent) { should == user_agent }
9
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#client' do
4
+ subject { Zero::Request.new(env) }
5
+ let(:env) { EnvGenerator.get('/foo') }
6
+
7
+ its(:client) { should be_an_instance_of(Zero::Request::Client) }
8
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#content_type' do
4
+ subject { Zero::Request.new(env) }
5
+
6
+ context 'returns nil with no content type' do
7
+ let(:env) { EnvGenerator.get('/foo') }
8
+ its('content_type') { should be(nil) }
9
+ end
10
+
11
+ context 'returns the set content type' do
12
+ let(:content_type) { 'bogus/type' }
13
+ let(:env) { EnvGenerator.post('/foo', {'CONTENT_TYPE' => content_type}) }
14
+ its('content_type') { should be(content_type) }
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '.create' do
4
+ subject { Zero::Request.new(env) }
5
+
6
+ context "with a fresh environment" do
7
+ let(:env) { EnvGenerator.get('/foo') }
8
+ it "creates an instance of Zero::Request" do
9
+ Zero::Request.create(env).should be_an_instance_of(Zero::Request)
10
+ end
11
+ end
12
+
13
+ context "with an already used environment" do
14
+ let(:env) { EnvGenerator.get('/foo') }
15
+ let(:new_env) { subject.env }
16
+
17
+ it "returns an already build request" do
18
+ Zero::Request.create(new_env).should be(subject)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#delete?' do
4
+ subject { Zero::Request.new(env) }
5
+
6
+ context "with a delete request" do
7
+ let(:env) { EnvGenerator.delete('/foo') }
8
+ its(:delete?) { should be(true) }
9
+ end
10
+
11
+ context "with a get request" do
12
+ let(:env) { EnvGenerator.get('/foo') }
13
+ its(:delete?) { should be(false) }
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#get?' do
4
+ subject { Zero::Request.new(env) }
5
+
6
+ context "with a get request" do
7
+ let(:env) { EnvGenerator.get('/foo') }
8
+ its(:get?) { should be(true) }
9
+ end
10
+
11
+ context "with a post request" do
12
+ let(:env) { EnvGenerator.post('/foo') }
13
+ its(:get?) { should be(false) }
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#head?' do
4
+ subject { Zero::Request.new(env) }
5
+
6
+ context "with a head request" do
7
+ let(:env) { EnvGenerator.head('/foo') }
8
+ its(:head?) { should be(true) }
9
+ end
10
+
11
+ context "with a get request" do
12
+ let(:env) { EnvGenerator.get('/foo') }
13
+ its(:head?) { should be(false) }
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request, '#method' do
4
+ subject { Zero::Request.new(env) }
5
+ let(:env) { EnvGenerator.get('/foo') }
6
+
7
+ its(:method) { should == :get }
8
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Zero::Request::Parameter, '#[]' do
4
+ subject { Zero::Request::Parameter.new(env) }
5
+
6
+ context 'without parameters' do
7
+ let(:env) { EnvGenerator.get('/foo') }
8
+
9
+ it 'returns the custom parameter' do
10
+ subject['foo'] = 'bar'
11
+ expect(subject['foo']).to eq('bar')
12
+ end
13
+ end
14
+
15
+ context 'with query parameters' do
16
+ let(:env) { EnvGenerator.get('/foo?foo=bar') }
17
+
18
+ it 'returns the query parameter' do
19
+ expect(subject['foo']).to eq('bar')
20
+ end
21
+
22
+ it 'returns the custom parameter' do
23
+ subject['foo'] = 'baz'
24
+ expect(subject['foo']).to eq('baz')
25
+ end
26
+ end
27
+
28
+ context 'with payload parameters' do
29
+ let(:env) do
30
+ EnvGenerator.post('/foo', {
31
+ :input => 'foo=bar', 'CONTENT_TYPE' => 'multipart/form-data'
32
+ })
33
+ end
34
+
35
+ it 'returns the payload value' do
36
+ expect(subject['foo']).to eq('bar')
37
+ end
38
+
39
+ it 'returns the custom parameter' do
40
+ subject['foo'] = 'baz'
41
+ expect(subject['foo']).to eq('baz')
42
+ end
43
+ end
44
+
45
+ context 'with query and payload parameters' do
46
+ let(:env) do
47
+ EnvGenerator.post('/foo?foo=baz', {
48
+ :input => 'foo=bar', 'CONTENT_TYPE' => 'multipart/form-data'
49
+ })
50
+ end
51
+
52
+ it 'returns the payload parameter' do
53
+ expect(subject['foo']).to eq('bar')
54
+ end
55
+ end
56
+ end