webmachine 1.6.0 → 2.0.0.beta

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +2 -5
  4. data/documentation/adapters.md +2 -11
  5. data/examples/debugger.rb +5 -3
  6. data/examples/logging.rb +2 -2
  7. data/examples/webrick.rb +2 -2
  8. data/lib/webmachine/adapter.rb +0 -3
  9. data/lib/webmachine/adapters/lazy_request_body.rb +1 -1
  10. data/lib/webmachine/adapters/rack.rb +38 -34
  11. data/lib/webmachine/adapters/rack_mapped.rb +1 -2
  12. data/lib/webmachine/adapters/webrick.rb +11 -12
  13. data/lib/webmachine/adapters.rb +0 -2
  14. data/lib/webmachine/application.rb +2 -2
  15. data/lib/webmachine/chunked_body.rb +1 -1
  16. data/lib/webmachine/configuration.rb +1 -1
  17. data/lib/webmachine/constants.rb +12 -12
  18. data/lib/webmachine/cookie.rb +20 -18
  19. data/lib/webmachine/decision/conneg.rb +24 -24
  20. data/lib/webmachine/decision/falsey.rb +0 -1
  21. data/lib/webmachine/decision/flow.rb +19 -20
  22. data/lib/webmachine/decision/fsm.rb +4 -4
  23. data/lib/webmachine/decision/helpers.rb +21 -21
  24. data/lib/webmachine/dispatcher/route.rb +28 -28
  25. data/lib/webmachine/dispatcher.rb +3 -2
  26. data/lib/webmachine/errors.rb +7 -8
  27. data/lib/webmachine/etags.rb +2 -1
  28. data/lib/webmachine/header_negotiation.rb +5 -6
  29. data/lib/webmachine/headers.rb +5 -5
  30. data/lib/webmachine/media_type.rb +5 -5
  31. data/lib/webmachine/quoted_string.rb +3 -3
  32. data/lib/webmachine/request.rb +7 -10
  33. data/lib/webmachine/rescueable_exception.rb +3 -3
  34. data/lib/webmachine/resource/authentication.rb +3 -4
  35. data/lib/webmachine/resource/callbacks.rb +3 -3
  36. data/lib/webmachine/resource/encodings.rb +3 -9
  37. data/lib/webmachine/resource.rb +1 -1
  38. data/lib/webmachine/response.rb +7 -9
  39. data/lib/webmachine/spec/adapter_lint.rb +67 -69
  40. data/lib/webmachine/spec/test_resource.rb +22 -22
  41. data/lib/webmachine/streaming/encoder.rb +3 -2
  42. data/lib/webmachine/streaming/io_encoder.rb +4 -3
  43. data/lib/webmachine/trace/fsm.rb +25 -18
  44. data/lib/webmachine/trace/resource_proxy.rb +10 -9
  45. data/lib/webmachine/trace/static/http-headers-status-v3.png +0 -0
  46. data/lib/webmachine/trace/trace_resource.rb +22 -24
  47. data/lib/webmachine/trace.rb +7 -6
  48. data/lib/webmachine/translation.rb +3 -3
  49. data/lib/webmachine/version.rb +1 -1
  50. metadata +52 -86
  51. data/.gitignore +0 -31
  52. data/Gemfile +0 -46
  53. data/Guardfile +0 -11
  54. data/RELEASING.md +0 -21
  55. data/Rakefile +0 -44
  56. data/lib/webmachine/adapters/httpkit.rb +0 -74
  57. data/lib/webmachine/adapters/reel.rb +0 -113
  58. data/memory_test.rb +0 -37
  59. data/spec/spec_helper.rb +0 -56
  60. data/spec/webmachine/adapter_spec.rb +0 -39
  61. data/spec/webmachine/adapters/httpkit_spec.rb +0 -10
  62. data/spec/webmachine/adapters/rack_mapped_spec.rb +0 -71
  63. data/spec/webmachine/adapters/rack_spec.rb +0 -62
  64. data/spec/webmachine/adapters/reel_spec.rb +0 -76
  65. data/spec/webmachine/adapters/webrick_spec.rb +0 -12
  66. data/spec/webmachine/application_spec.rb +0 -74
  67. data/spec/webmachine/chunked_body_spec.rb +0 -30
  68. data/spec/webmachine/configuration_spec.rb +0 -27
  69. data/spec/webmachine/cookie_spec.rb +0 -99
  70. data/spec/webmachine/decision/conneg_spec.rb +0 -166
  71. data/spec/webmachine/decision/falsey_spec.rb +0 -8
  72. data/spec/webmachine/decision/flow_spec.rb +0 -1148
  73. data/spec/webmachine/decision/fsm_spec.rb +0 -163
  74. data/spec/webmachine/decision/helpers_spec.rb +0 -216
  75. data/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb +0 -22
  76. data/spec/webmachine/dispatcher/route_spec.rb +0 -248
  77. data/spec/webmachine/dispatcher_spec.rb +0 -104
  78. data/spec/webmachine/errors_spec.rb +0 -13
  79. data/spec/webmachine/etags_spec.rb +0 -75
  80. data/spec/webmachine/events_spec.rb +0 -58
  81. data/spec/webmachine/headers_spec.rb +0 -99
  82. data/spec/webmachine/media_type_spec.rb +0 -85
  83. data/spec/webmachine/request_spec.rb +0 -273
  84. data/spec/webmachine/rescueable_exception_spec.rb +0 -15
  85. data/spec/webmachine/resource/authentication_spec.rb +0 -68
  86. data/spec/webmachine/response_spec.rb +0 -51
  87. data/spec/webmachine/trace/fsm_spec.rb +0 -37
  88. data/spec/webmachine/trace/resource_proxy_spec.rb +0 -34
  89. data/spec/webmachine/trace/trace_store_spec.rb +0 -29
  90. data/spec/webmachine/trace_spec.rb +0 -17
  91. data/webmachine.gemspec +0 -25
@@ -1,104 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Webmachine::Dispatcher do
4
- let(:dispatcher) { Webmachine.application.dispatcher }
5
- let(:request) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/"), Webmachine::Headers["accept" => "*/*"], "") }
6
- let(:request2) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/hello/bob.html"), Webmachine::Headers["accept" => "*/*"], "") }
7
- let(:response) { Webmachine::Response.new }
8
- let(:resource) do
9
- Class.new(Webmachine::Resource) do
10
- def to_html; "hello world!"; end
11
- end
12
- end
13
- let(:resource2) do
14
- Class.new(Webmachine::Resource) do
15
- def to_html; "goodbye, cruel world"; end
16
- end
17
- end
18
- let(:resource3) do
19
- Class.new(Webmachine::Resource) do
20
- def to_html
21
- name, format = request.path_info[:captures]
22
- "Hello #{name} with #{format}"
23
- end
24
- end
25
- end
26
- let(:fsm){ double }
27
-
28
- before { dispatcher.reset }
29
-
30
- it "should add routes from a block" do
31
- _resource = resource
32
- expect(Webmachine.routes do
33
- add [:*], _resource
34
- end).to eq(Webmachine)
35
- expect(dispatcher.routes.size).to eq(1)
36
- end
37
-
38
- it "should add routes" do
39
- expect {
40
- dispatcher.add_route [:*], resource
41
- }.to_not raise_error
42
- end
43
-
44
- it "should have add_route return the newly created route" do
45
- route = dispatcher.add_route [:*], resource
46
- expect(route).to be_instance_of Webmachine::Dispatcher::Route
47
- end
48
-
49
- it "should route to the proper resource" do
50
- dispatcher.add_route ["goodbye"], resource2
51
- dispatcher.add_route [:*], resource
52
- expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource), request, response).and_return(fsm)
53
- expect(fsm).to receive(:run)
54
- dispatcher.dispatch(request, response)
55
- end
56
- it "should handle regex path segments in route definition" do
57
- dispatcher.add_route ["hello", /(.*)\.(.*)/], resource3
58
- expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource3), request2, response).and_return(fsm)
59
- expect(fsm).to receive(:run)
60
- dispatcher.dispatch(request2, response)
61
- end
62
-
63
- it "should apply route to request before creating the resource" do
64
- route = dispatcher.add_route [:*], resource
65
- applied = false
66
-
67
- expect(route).to receive(:apply) { applied = true }
68
- expect(resource).to(receive(:new) do
69
- expect(applied).to be(true)
70
- resource2.new(request, response)
71
- end)
72
-
73
- dispatcher.dispatch(request, response)
74
- end
75
-
76
- it "should add routes with guards" do
77
- dispatcher.add [], lambda {|req| req.method == "POST" }, resource
78
- dispatcher.add [:*], resource2 do |req|
79
- !req.query.empty?
80
- end
81
- request.uri.query = "?foo=bar"
82
- expect(dispatcher.routes.size).to eq(2)
83
- expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource2), request, response).and_return(fsm)
84
- expect(fsm).to receive(:run)
85
- dispatcher.dispatch(request, response)
86
- end
87
-
88
- it "should respond with a valid resource for a 404" do
89
- dispatcher.dispatch(request, response)
90
- expect(response.code).to eq(404)
91
- expect(response.body).to_not be_empty
92
- expect(response.headers).to have_key('Content-Length')
93
- expect(response.headers).to have_key('Date')
94
- end
95
-
96
- it "should respond with a valid resource for a 404 with a custom Accept header" do
97
- request.headers['Accept'] = "application/json"
98
- dispatcher.dispatch(request, response)
99
- expect(response.code).to eq(404)
100
- expect(response.body).to_not be_empty
101
- expect(response.headers).to have_key('Content-Length')
102
- expect(response.headers).to have_key('Date')
103
- end
104
- end
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Webmachine errors" do
4
- describe ".render_error" do
5
- it "sets the given response code on the response object" do
6
- req = double('request', :method => 'GET').as_null_object
7
- res = Webmachine::Response.new
8
-
9
- Webmachine.render_error(404, req, res)
10
- expect(res.code).to eq(404)
11
- end
12
- end
13
- end
@@ -1,75 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Webmachine::ETag do
4
- let(:etag_str){ '"deadbeef12345678"' }
5
- let(:etag) { described_class.new etag_str }
6
-
7
- subject { etag }
8
-
9
- it { is_expected.to eq(etag_str) }
10
- it { is_expected.to be_kind_of(described_class) }
11
- its(:to_s) { should == '"deadbeef12345678"' }
12
- its(:etag) { should == '"deadbeef12345678"' }
13
- it { is_expected.to eq(described_class.new(etag_str.dup)) }
14
-
15
- context "when the original etag is unquoted" do
16
- let(:etag_str) { 'deadbeef12345678' }
17
-
18
- it { is_expected.to eq(etag_str) }
19
- its(:to_s) { should == '"deadbeef12345678"' }
20
- its(:etag) { should == '"deadbeef12345678"' }
21
- it { is_expected.to eq(described_class.new(etag_str.dup)) }
22
- end
23
-
24
- context "when the original etag contains unbalanced quotes" do
25
- let(:etag_str) { 'deadbeef"12345678' }
26
-
27
- it { is_expected.to eq(etag_str) }
28
- its(:to_s) { should == '"deadbeef\\"12345678"' }
29
- its(:etag) { should == '"deadbeef\\"12345678"' }
30
- it { is_expected.to eq(described_class.new(etag_str.dup)) }
31
- end
32
- end
33
-
34
- describe Webmachine::WeakETag do
35
- let(:strong_etag){ '"deadbeef12345678"' }
36
- let(:weak_etag) { described_class.new strong_etag }
37
-
38
- subject { weak_etag }
39
-
40
- it { is_expected.to eq(strong_etag) }
41
- it { is_expected.to be_kind_of(described_class) }
42
- its(:to_s) { should == 'W/"deadbeef12345678"' }
43
- its(:etag) { should == '"deadbeef12345678"' }
44
- it { is_expected.to eq(described_class.new(strong_etag.dup)) }
45
-
46
- context "when the original etag is unquoted" do
47
- let(:strong_etag) { 'deadbeef12345678' }
48
-
49
- it { is_expected.to eq(strong_etag) }
50
- it { is_expected.to be_kind_of(described_class) }
51
- its(:to_s) { should == 'W/"deadbeef12345678"' }
52
- its(:etag) { should == '"deadbeef12345678"' }
53
- it { is_expected.to eq(described_class.new(strong_etag.dup)) }
54
- end
55
-
56
- context "when the original etag contains unbalanced quotes" do
57
- let(:strong_etag) { 'deadbeef"12345678' }
58
-
59
- it { is_expected.to eq(strong_etag) }
60
- it { is_expected.to be_kind_of(described_class) }
61
- its(:to_s) { should == 'W/"deadbeef\\"12345678"' }
62
- its(:etag) { should == '"deadbeef\\"12345678"' }
63
- it { is_expected.to eq(described_class.new(strong_etag.dup)) }
64
- end
65
-
66
- context "when the original etag is already a weak tag" do
67
- let(:strong_etag) { 'W/"deadbeef12345678"' }
68
-
69
- it { is_expected.to eq(strong_etag) }
70
- it { is_expected.to be_kind_of(described_class) }
71
- its(:to_s) { should == 'W/"deadbeef12345678"' }
72
- its(:etag) { should == '"deadbeef12345678"' }
73
- it { is_expected.to eq(described_class.new(strong_etag.dup)) }
74
- end
75
- end
@@ -1,58 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Webmachine::Events do
4
- describe ".backend" do
5
- it "defaults to AS::Notifications" do
6
- expect(described_class.backend).to be(AS::Notifications)
7
- end
8
- end
9
-
10
- describe ".publish" do
11
- it "calls the backend" do
12
- expect(described_class.backend).to receive(:publish).with('test.event', 1, 'two')
13
- described_class.publish('test.event', 1, 'two')
14
- end
15
- end
16
-
17
- describe ".instrument" do
18
- it "calls the backend" do
19
- expect(described_class.backend).to receive(:instrument).with(
20
- 'test.event', {}
21
- ).and_yield
22
-
23
- described_class.instrument('test.event') { }
24
- end
25
- end
26
-
27
- describe ".subscribe" do
28
- it "calls the backend" do
29
- expect(described_class.backend).to receive(:subscribe).with(
30
- 'test.event'
31
- ).and_yield
32
-
33
- described_class.subscribe('test.event') { }
34
- end
35
- end
36
-
37
- describe ".subscribed" do
38
- it "calls the backend" do
39
- callback = Proc.new { }
40
-
41
- expect(described_class.backend).to receive(:subscribed).with(
42
- callback, 'test.event'
43
- ).and_yield
44
-
45
- described_class.subscribed(callback, 'test.event') { }
46
- end
47
- end
48
-
49
- describe ".unsubscribe" do
50
- it "calls the backend" do
51
- subscriber = described_class.subscribe('test.event') { }
52
-
53
- expect(described_class.backend).to receive(:unsubscribe).with(subscriber)
54
-
55
- described_class.unsubscribe(subscriber)
56
- end
57
- end
58
- end
@@ -1,99 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Webmachine::Headers do
4
- it "should set and access values insensitive to case" do
5
- subject['Content-TYPE'] = "text/plain"
6
- expect(subject['CONTENT-TYPE']).to eq('text/plain')
7
- expect(subject.delete('CoNtEnT-tYpE')).to eq('text/plain')
8
- end
9
-
10
- describe "#from_cgi" do
11
- it "should understand the Content-Length header" do
12
- headers = described_class.from_cgi("CONTENT_LENGTH" => 14)
13
- expect(headers["content-length"]).to eq(14)
14
- end
15
- end
16
-
17
- describe ".[]" do
18
- context "Webmachine::Headers['Content-Type', 'application/json']" do
19
- it "creates a hash with lowercase keys" do
20
- headers = described_class[
21
- 'Content-Type', 'application/json',
22
- 'Accept', 'application/json'
23
- ]
24
-
25
- expect(headers.to_hash).to eq({
26
- 'content-type' => 'application/json',
27
- 'accept' => 'application/json'
28
- })
29
- end
30
- end
31
-
32
- context "Webmachine::Headers[[['Content-Type', 'application/json']]]" do
33
- it "creates a hash with lowercase keys" do
34
- headers = described_class[
35
- [
36
- ['Content-Type', 'application/json'],
37
- ['Accept', 'application/json']
38
- ]
39
- ]
40
-
41
- expect(headers.to_hash).to eq({
42
- 'content-type' => 'application/json',
43
- 'accept' => 'application/json'
44
- })
45
- end
46
- end
47
-
48
- context "Webmachine::Headers['Content-Type' => 'application/json']" do
49
- it "creates a hash with lowercase keys" do
50
- headers = described_class[
51
- 'Content-Type' => 'application/json',
52
- 'Accept' => 'application/json'
53
- ]
54
-
55
- expect(headers.to_hash).to eq({
56
- 'content-type' => 'application/json',
57
- 'accept' => 'application/json'
58
- })
59
- end
60
- end
61
- end
62
-
63
- describe "#fetch" do
64
- subject { described_class['Content-Type' => 'application/json'] }
65
-
66
- it "returns the value for the given key" do
67
- expect(subject.fetch('conTent-tYpe')).to eq('application/json')
68
- end
69
-
70
- context "acessing a missing key" do
71
- it "raises an IndexError" do
72
- expect { subject.fetch('accept') }.to raise_error(IndexError)
73
- end
74
-
75
- context "and a default value given" do
76
- it "returns the default value if the key does not exist" do
77
- expect(subject.fetch('accept', 'text/html')).to eq('text/html')
78
- end
79
- end
80
-
81
- context "and a block given" do
82
- it "passes the value to the block and returns the block's result" do
83
- expect(subject.fetch('access') {|k| "#{k} not found"}).to eq('access not found')
84
- end
85
- end
86
- end
87
- end
88
-
89
- context "filtering with #grep" do
90
- subject { described_class["content-type" => "text/plain", "etag" => '"abcdef1234567890"'] }
91
- it "should filter keys by the given pattern" do
92
- expect(subject.grep(/content/i)).to include("content-type")
93
- end
94
-
95
- it "should return a Headers instance" do
96
- expect(subject.grep(/etag/i)).to be_instance_of(described_class)
97
- end
98
- end
99
- end
@@ -1,85 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Webmachine::MediaType do
4
- let(:raw_type){ "application/xml;charset=UTF-8" }
5
- subject { described_class.new("application/xml", {"charset" => "UTF-8"}) }
6
-
7
- context "equivalence" do
8
- it { is_expected.to eq(raw_type) }
9
- it { is_expected.to eq(described_class.parse(raw_type)) }
10
- end
11
-
12
- context "when it is the wildcard type" do
13
- subject { described_class.new("*/*") }
14
- it { is_expected.to be_matches_all }
15
- end
16
-
17
- context "parsing a type" do
18
- it "should return MediaTypes untouched" do
19
- expect(described_class.parse(subject)).to equal(subject)
20
- end
21
-
22
- it "should parse a String" do
23
- type = described_class.parse(raw_type)
24
- expect(type).to be_kind_of(described_class)
25
- expect(type.type).to eq("application/xml")
26
- expect(type.params).to eq({"charset" => "UTF-8"})
27
- end
28
-
29
- it "should parse a type/params pair" do
30
- type = described_class.parse(["application/xml", {"charset" => "UTF-8"}])
31
- expect(type).to be_kind_of(described_class)
32
- expect(type.type).to eq("application/xml")
33
- expect(type.params).to eq({"charset" => "UTF-8"})
34
- end
35
-
36
- it "should parse a type/params pair where the type has some params in the string" do
37
- type = described_class.parse(["application/xml;version=1", {"charset" => "UTF-8"}])
38
- expect(type).to be_kind_of(described_class)
39
- expect(type.type).to eq("application/xml")
40
- expect(type.params).to eq({"charset" => "UTF-8", "version" => "1"})
41
- end
42
-
43
- it "should parse a type/params pair with params and whitespace in the string" do
44
- type = described_class.parse(["multipart/form-data; boundary=----------------------------2c46a7bec2b9", {"charset" => "UTF-8"}])
45
- expect(type).to be_kind_of(described_class)
46
- expect(type.type).to eq("multipart/form-data")
47
- expect(type.params).to eq({"boundary" => "----------------------------2c46a7bec2b9", "charset" => "UTF-8"})
48
- end
49
-
50
- it "should parse a type/params pair where type has single-token params" do
51
- type = described_class.parse(["text/html;q=1;rdfa", {"charset" => "UTF-8"}])
52
- expect(type).to be_kind_of(described_class)
53
- expect(type.type).to eq("text/html")
54
- expect(type.params).to eq({"q" => "1", "rdfa" => "", "charset" => "UTF-8"})
55
- end
56
-
57
- it "should raise an error when given an invalid type/params pair" do
58
- expect {
59
- described_class.parse([false, "blah"])
60
- }.to raise_error(ArgumentError)
61
- end
62
- end
63
-
64
- describe "matching a requested type" do
65
- it { is_expected.to be_exact_match("application/xml;charset=UTF-8") }
66
- it { is_expected.to be_exact_match("application/*;charset=UTF-8") }
67
- it { is_expected.to be_exact_match("*/*;charset=UTF-8") }
68
- it { is_expected.to be_exact_match("*;charset=UTF-8") }
69
- it { is_expected.not_to be_exact_match("text/xml") }
70
- it { is_expected.not_to be_exact_match("application/xml") }
71
- it { is_expected.not_to be_exact_match("application/xml;version=1") }
72
-
73
- it { is_expected.to be_type_matches("application/xml") }
74
- it { is_expected.to be_type_matches("application/*") }
75
- it { is_expected.to be_type_matches("*/*") }
76
- it { is_expected.to be_type_matches("*") }
77
- it { is_expected.not_to be_type_matches("text/xml") }
78
- it { is_expected.not_to be_type_matches("text/*") }
79
-
80
- it { is_expected.to be_params_match({}) }
81
- it { is_expected.to be_params_match({"charset" => "UTF-8"}) }
82
- it { is_expected.not_to be_params_match({"charset" => "Windows-1252"}) }
83
- it { is_expected.not_to be_params_match({"version" => "3"}) }
84
- end
85
- end