xenon 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- metadata +13 -145
- data/.codeclimate.yml +0 -18
- data/.gitignore +0 -25
- data/.rspec +0 -3
- data/.travis.yml +0 -6
- data/Gemfile +0 -13
- data/Guardfile +0 -16
- data/LICENSE +0 -22
- data/README.md +0 -86
- data/Rakefile +0 -8
- data/examples/hello_world/config.ru +0 -3
- data/examples/hello_world/hello_world.rb +0 -17
- data/lib/xenon.rb +0 -253
- data/lib/xenon/auth.rb +0 -63
- data/lib/xenon/errors.rb +0 -5
- data/lib/xenon/etag.rb +0 -48
- data/lib/xenon/headers.rb +0 -112
- data/lib/xenon/headers/accept.rb +0 -34
- data/lib/xenon/headers/accept_charset.rb +0 -59
- data/lib/xenon/headers/accept_encoding.rb +0 -63
- data/lib/xenon/headers/accept_language.rb +0 -59
- data/lib/xenon/headers/authorization.rb +0 -50
- data/lib/xenon/headers/cache_control.rb +0 -56
- data/lib/xenon/headers/content_type.rb +0 -23
- data/lib/xenon/headers/if_match.rb +0 -53
- data/lib/xenon/headers/if_modified_since.rb +0 -22
- data/lib/xenon/headers/if_none_match.rb +0 -53
- data/lib/xenon/headers/if_range.rb +0 -45
- data/lib/xenon/headers/if_unmodified_since.rb +0 -22
- data/lib/xenon/headers/user_agent.rb +0 -65
- data/lib/xenon/headers/www_authenticate.rb +0 -70
- data/lib/xenon/media_type.rb +0 -162
- data/lib/xenon/parsers/basic_rules.rb +0 -86
- data/lib/xenon/parsers/header_rules.rb +0 -60
- data/lib/xenon/parsers/media_type.rb +0 -53
- data/lib/xenon/quoted_string.rb +0 -20
- data/lib/xenon/routing/directives.rb +0 -14
- data/lib/xenon/routing/header_directives.rb +0 -32
- data/lib/xenon/routing/method_directives.rb +0 -26
- data/lib/xenon/routing/param_directives.rb +0 -22
- data/lib/xenon/routing/path_directives.rb +0 -37
- data/lib/xenon/routing/route_directives.rb +0 -51
- data/lib/xenon/routing/security_directives.rb +0 -20
- data/lib/xenon/version.rb +0 -3
- data/spec/spec_helper.rb +0 -94
- data/spec/xenon/etag_spec.rb +0 -19
- data/spec/xenon/headers/accept_charset_spec.rb +0 -31
- data/spec/xenon/headers/accept_encoding_spec.rb +0 -40
- data/spec/xenon/headers/accept_language_spec.rb +0 -33
- data/spec/xenon/headers/accept_spec.rb +0 -54
- data/spec/xenon/headers/authorization_spec.rb +0 -47
- data/spec/xenon/headers/cache_control_spec.rb +0 -64
- data/spec/xenon/headers/if_match_spec.rb +0 -73
- data/spec/xenon/headers/if_modified_since_spec.rb +0 -19
- data/spec/xenon/headers/if_none_match_spec.rb +0 -79
- data/spec/xenon/headers/if_range_spec.rb +0 -45
- data/spec/xenon/headers/if_unmodified_since_spec.rb +0 -19
- data/spec/xenon/headers/user_agent_spec.rb +0 -67
- data/spec/xenon/headers/www_authenticate_spec.rb +0 -43
- data/spec/xenon/media_type_spec.rb +0 -267
- data/xenon.gemspec +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 667df7004abbed158847a2aba0f15151db579d8f
|
4
|
+
data.tar.gz: d3088dfa5b57e422c80bd682bf77dba901e8e6ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ec395fab860a41762f82b91aac705618e8a487ce38466db91a94731405157a231ccbf55abf9861b7fd4efbd6222b5d1377bfaeb9f6bd562dc0eabec1f9dd134
|
7
|
+
data.tar.gz: addd9426fde2c16ed7fbd073f9da3dd409288bf61722e74743cf9c7703f26c65c08d2b016ed8b48e4451e1993908e78595b0c8fe986629ac1cf0a0513d25183f
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xenon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Beech
|
@@ -11,156 +11,40 @@ cert_chain: []
|
|
11
11
|
date: 2015-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: xenon-http
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.0.4
|
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
|
-
version:
|
26
|
+
version: 0.0.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: xenon-routing
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.0.4
|
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
|
-
version:
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rack
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.6'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.6'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: bundler
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.10'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.10'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rake
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '10.4'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '10.4'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rspec
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '3.3'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '3.3'
|
40
|
+
version: 0.0.4
|
97
41
|
description: Provides a model for the HTTP protocol and a tree-based routing syntax.
|
98
42
|
email:
|
99
43
|
- greg@gregbeech.com
|
100
44
|
executables: []
|
101
45
|
extensions: []
|
102
46
|
extra_rdoc_files: []
|
103
|
-
files:
|
104
|
-
- ".codeclimate.yml"
|
105
|
-
- ".gitignore"
|
106
|
-
- ".rspec"
|
107
|
-
- ".travis.yml"
|
108
|
-
- Gemfile
|
109
|
-
- Guardfile
|
110
|
-
- LICENSE
|
111
|
-
- README.md
|
112
|
-
- Rakefile
|
113
|
-
- examples/hello_world/config.ru
|
114
|
-
- examples/hello_world/hello_world.rb
|
115
|
-
- lib/xenon.rb
|
116
|
-
- lib/xenon/auth.rb
|
117
|
-
- lib/xenon/errors.rb
|
118
|
-
- lib/xenon/etag.rb
|
119
|
-
- lib/xenon/headers.rb
|
120
|
-
- lib/xenon/headers/accept.rb
|
121
|
-
- lib/xenon/headers/accept_charset.rb
|
122
|
-
- lib/xenon/headers/accept_encoding.rb
|
123
|
-
- lib/xenon/headers/accept_language.rb
|
124
|
-
- lib/xenon/headers/authorization.rb
|
125
|
-
- lib/xenon/headers/cache_control.rb
|
126
|
-
- lib/xenon/headers/content_type.rb
|
127
|
-
- lib/xenon/headers/if_match.rb
|
128
|
-
- lib/xenon/headers/if_modified_since.rb
|
129
|
-
- lib/xenon/headers/if_none_match.rb
|
130
|
-
- lib/xenon/headers/if_range.rb
|
131
|
-
- lib/xenon/headers/if_unmodified_since.rb
|
132
|
-
- lib/xenon/headers/user_agent.rb
|
133
|
-
- lib/xenon/headers/www_authenticate.rb
|
134
|
-
- lib/xenon/media_type.rb
|
135
|
-
- lib/xenon/parsers/basic_rules.rb
|
136
|
-
- lib/xenon/parsers/header_rules.rb
|
137
|
-
- lib/xenon/parsers/media_type.rb
|
138
|
-
- lib/xenon/quoted_string.rb
|
139
|
-
- lib/xenon/routing/directives.rb
|
140
|
-
- lib/xenon/routing/header_directives.rb
|
141
|
-
- lib/xenon/routing/method_directives.rb
|
142
|
-
- lib/xenon/routing/param_directives.rb
|
143
|
-
- lib/xenon/routing/path_directives.rb
|
144
|
-
- lib/xenon/routing/route_directives.rb
|
145
|
-
- lib/xenon/routing/security_directives.rb
|
146
|
-
- lib/xenon/version.rb
|
147
|
-
- spec/spec_helper.rb
|
148
|
-
- spec/xenon/etag_spec.rb
|
149
|
-
- spec/xenon/headers/accept_charset_spec.rb
|
150
|
-
- spec/xenon/headers/accept_encoding_spec.rb
|
151
|
-
- spec/xenon/headers/accept_language_spec.rb
|
152
|
-
- spec/xenon/headers/accept_spec.rb
|
153
|
-
- spec/xenon/headers/authorization_spec.rb
|
154
|
-
- spec/xenon/headers/cache_control_spec.rb
|
155
|
-
- spec/xenon/headers/if_match_spec.rb
|
156
|
-
- spec/xenon/headers/if_modified_since_spec.rb
|
157
|
-
- spec/xenon/headers/if_none_match_spec.rb
|
158
|
-
- spec/xenon/headers/if_range_spec.rb
|
159
|
-
- spec/xenon/headers/if_unmodified_since_spec.rb
|
160
|
-
- spec/xenon/headers/user_agent_spec.rb
|
161
|
-
- spec/xenon/headers/www_authenticate_spec.rb
|
162
|
-
- spec/xenon/media_type_spec.rb
|
163
|
-
- xenon.gemspec
|
47
|
+
files: []
|
164
48
|
homepage: https://github.com/gregbeech/xenon
|
165
49
|
licenses:
|
166
50
|
- MIT
|
@@ -185,21 +69,5 @@ rubygems_version: 2.4.8
|
|
185
69
|
signing_key:
|
186
70
|
specification_version: 4
|
187
71
|
summary: An HTTP framework for building RESTful APIs.
|
188
|
-
test_files:
|
189
|
-
- spec/spec_helper.rb
|
190
|
-
- spec/xenon/etag_spec.rb
|
191
|
-
- spec/xenon/headers/accept_charset_spec.rb
|
192
|
-
- spec/xenon/headers/accept_encoding_spec.rb
|
193
|
-
- spec/xenon/headers/accept_language_spec.rb
|
194
|
-
- spec/xenon/headers/accept_spec.rb
|
195
|
-
- spec/xenon/headers/authorization_spec.rb
|
196
|
-
- spec/xenon/headers/cache_control_spec.rb
|
197
|
-
- spec/xenon/headers/if_match_spec.rb
|
198
|
-
- spec/xenon/headers/if_modified_since_spec.rb
|
199
|
-
- spec/xenon/headers/if_none_match_spec.rb
|
200
|
-
- spec/xenon/headers/if_range_spec.rb
|
201
|
-
- spec/xenon/headers/if_unmodified_since_spec.rb
|
202
|
-
- spec/xenon/headers/user_agent_spec.rb
|
203
|
-
- spec/xenon/headers/www_authenticate_spec.rb
|
204
|
-
- spec/xenon/media_type_spec.rb
|
72
|
+
test_files: []
|
205
73
|
has_rdoc:
|
data/.codeclimate.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# For more details, see here:
|
2
|
-
# http://docs.codeclimate.com/article/289-configuring-your-repository-via-codeclimate-yml#platform
|
3
|
-
|
4
|
-
# For a list of all available engines, see here:
|
5
|
-
# http://docs.codeclimate.com/article/296-engines-available-engines
|
6
|
-
|
7
|
-
engines:
|
8
|
-
rubocop:
|
9
|
-
enabled: true
|
10
|
-
|
11
|
-
ratings:
|
12
|
-
paths:
|
13
|
-
- lib/**/*
|
14
|
-
|
15
|
-
exclude_paths:
|
16
|
-
- examples/**/*
|
17
|
-
- spec/**/*
|
18
|
-
- vendor/**/*
|
data/.gitignore
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
.ruby-version
|
4
|
-
.ruby-gemset
|
5
|
-
Gemfile.lock
|
6
|
-
/.config
|
7
|
-
/coverage/
|
8
|
-
/InstalledFiles
|
9
|
-
/pkg/
|
10
|
-
/spec/reports/
|
11
|
-
/test/tmp/
|
12
|
-
/test/version_tmp/
|
13
|
-
/tmp/
|
14
|
-
|
15
|
-
## Documentation cache and generated files:
|
16
|
-
/.yardoc/
|
17
|
-
/_yardoc/
|
18
|
-
/doc/
|
19
|
-
/rdoc/
|
20
|
-
|
21
|
-
## Environment normalisation:
|
22
|
-
/.bundle/
|
23
|
-
/lib/bundler/man/
|
24
|
-
.ruby-gemset
|
25
|
-
.ruby-version
|
data/.rspec
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Guardfile
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
clearing :on
|
2
|
-
|
3
|
-
guard :rspec, cmd: "bundle exec rspec" do
|
4
|
-
require "guard/rspec/dsl"
|
5
|
-
dsl = Guard::RSpec::Dsl.new(self)
|
6
|
-
|
7
|
-
# RSpec files
|
8
|
-
rspec = dsl.rspec
|
9
|
-
watch(rspec.spec_helper) { rspec.spec_dir }
|
10
|
-
watch(rspec.spec_support) { rspec.spec_dir }
|
11
|
-
watch(rspec.spec_files)
|
12
|
-
|
13
|
-
# Ruby files
|
14
|
-
ruby = dsl.ruby
|
15
|
-
dsl.watch_spec_files_for(ruby.lib_files)
|
16
|
-
end
|
data/LICENSE
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
The MIT License (MIT)
|
2
|
-
|
3
|
-
Copyright (c) 2015 Greg Beech
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
22
|
-
|
data/README.md
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
# Xenon
|
2
|
-
|
3
|
-
[![Gem Version][fury-badge]][fury] [![Build Status][travis-badge]][travis] [![Code Climate][cc-badge]][cc] [![Test Coverage][ccc-badge]][ccc] [![YARD Docs][docs-badge]][docs]
|
4
|
-
|
5
|
-
An HTTP framework for building RESTful APIs, inspired by [Spray][spray].
|
6
|
-
|
7
|
-
At the moment I probably wouldn't use this gem for anything you actually depend on because it's _very_ early in its lifecycle. However, this is a flavour of what's in here.
|
8
|
-
|
9
|
-
## HTTP Model
|
10
|
-
|
11
|
-
A set of model objects for the HTTP protocol which can parse and format the strings you typically get into proper objects you can work with. At the moment this covers key things like media types and the most common headers, but it will expand to cover the whole protocol. You can use the model by itself without any other parts of the library.
|
12
|
-
|
13
|
-
This is how things tend to look:
|
14
|
-
|
15
|
-
```ruby
|
16
|
-
accept = Xenon::Headers::Accept.parse('application/json, application/*; q=0.5')
|
17
|
-
accept.media_ranges.first.media_type.json? #=> true
|
18
|
-
accept.media_ranges.last.q #=> 0.5
|
19
|
-
# etc.
|
20
|
-
```
|
21
|
-
|
22
|
-
## Routing
|
23
|
-
|
24
|
-
A tree-based routing approach based on Spray, giving you great flexibility in building APIs and without the need to write extensions, helpers, etc. because everything is a directive and you extend it by simply writing directives! This is highly unstable and in flux at the moment.
|
25
|
-
|
26
|
-
This is the kind of syntax I'm aiming for which _sort of_ works, but needs a load of changes to allow composition so what's there now is really just a proof of concept of the basic syntax rather than anything close to useful.
|
27
|
-
|
28
|
-
```ruby
|
29
|
-
path_prefix 'users' do
|
30
|
-
path_end do
|
31
|
-
get do
|
32
|
-
complete 200, User.all
|
33
|
-
end
|
34
|
-
post do
|
35
|
-
body as: User do |user|
|
36
|
-
user.save!
|
37
|
-
respond_with_header 'Location' => "/users/#{user.id}" do
|
38
|
-
complete 201, user
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
path /[0-9]+/ do |user_id|
|
44
|
-
get do
|
45
|
-
complete 200, User.get_by_id(user_id)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
```
|
50
|
-
|
51
|
-
Of course, it'll do all the things you'd expect like support content negotiation properly and return the correct status codes when paths or methods aren't found.
|
52
|
-
|
53
|
-
## Installation
|
54
|
-
|
55
|
-
Add this line to your application's Gemfile:
|
56
|
-
|
57
|
-
gem 'xenon'
|
58
|
-
|
59
|
-
And then execute:
|
60
|
-
|
61
|
-
$ bundle
|
62
|
-
|
63
|
-
Or install it yourself as:
|
64
|
-
|
65
|
-
$ gem install xenon
|
66
|
-
|
67
|
-
## Contributing
|
68
|
-
|
69
|
-
1. Fork it ( https://github.com/gregbeech/xenon/fork )
|
70
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
71
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
72
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
73
|
-
5. Create a new Pull Request
|
74
|
-
|
75
|
-
|
76
|
-
[fury]: http://badge.fury.io/rb/xenon "Xenon at Rubygems"
|
77
|
-
[fury-badge]: https://badge.fury.io/rb/xenon.svg "Gem Version"
|
78
|
-
[travis]: https://travis-ci.org/gregbeech/xenon "Xenon at Travis CI"
|
79
|
-
[travis-badge]: https://travis-ci.org/gregbeech/xenon.svg "Build Status"
|
80
|
-
[cc]: https://codeclimate.com/github/gregbeech/xenon "Xenon Quality at Code Climate"
|
81
|
-
[cc-badge]: https://codeclimate.com/github/gregbeech/xenon/badges/gpa.svg "Code Quality"
|
82
|
-
[ccc]: https://codeclimate.com/github/gregbeech/xenon/coverage "Xenon Coverage at Code Climate"
|
83
|
-
[ccc-badge]: https://codeclimate.com/github/gregbeech/xenon/badges/coverage.svg "Code Coverage"
|
84
|
-
[docs]: http://www.rubydoc.info/github/gregbeech/xenon "YARD Docs"
|
85
|
-
[docs-badge]: http://img.shields.io/badge/yard-docs-blue.svg "YARD Docs"
|
86
|
-
[spray]: http://spray.io/ "spray"
|
data/Rakefile
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'xenon'
|
2
|
-
|
3
|
-
class HelloWorld < Xenon::API
|
4
|
-
authenticator = Xenon::BasicAuth.new realm: 'hello world' do |credentials|
|
5
|
-
credentials.username # should actually auth here!
|
6
|
-
end
|
7
|
-
|
8
|
-
path '/' do
|
9
|
-
get do
|
10
|
-
authenticate(authenticator) do |user|
|
11
|
-
params :greeting do |greeting|
|
12
|
-
complete :ok, { greeting => user }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/xenon.rb
DELETED
@@ -1,253 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'rack'
|
3
|
-
require 'active_support/core_ext/string'
|
4
|
-
require 'xenon/headers'
|
5
|
-
require 'xenon/routing/directives'
|
6
|
-
require 'xenon/version'
|
7
|
-
|
8
|
-
module Xenon
|
9
|
-
|
10
|
-
class Rejection
|
11
|
-
attr_reader :reason, :info
|
12
|
-
|
13
|
-
def initialize(reason, info = {})
|
14
|
-
@reason = reason
|
15
|
-
@info = info
|
16
|
-
end
|
17
|
-
|
18
|
-
def [](name)
|
19
|
-
@info[name]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Request
|
24
|
-
attr_accessor :unmatched_path
|
25
|
-
|
26
|
-
def initialize(rack_req)
|
27
|
-
@rack_req = rack_req
|
28
|
-
@unmatched_path = rack_req.path.freeze
|
29
|
-
end
|
30
|
-
|
31
|
-
def request_method
|
32
|
-
@rack_req.request_method.downcase.to_sym
|
33
|
-
end
|
34
|
-
|
35
|
-
def form_hash
|
36
|
-
@form_hash ||= @rack_req.POST.with_indifferent_access.freeze
|
37
|
-
end
|
38
|
-
|
39
|
-
def param_hash
|
40
|
-
puts "GET = #{@rack_req.GET.inspect}"
|
41
|
-
@param_hash ||= @rack_req.GET.with_indifferent_access.freeze
|
42
|
-
end
|
43
|
-
|
44
|
-
def header(name)
|
45
|
-
snake_name = name.to_s.tr('-', '_')
|
46
|
-
value = @rack_req.env['HTTP_' + snake_name.upcase]
|
47
|
-
return nil if value.nil?
|
48
|
-
|
49
|
-
klass = Xenon::Headers.header_class(name)
|
50
|
-
klass ? klass.parse(value) : Xenon::Headers::Raw.new(name, value)
|
51
|
-
end
|
52
|
-
|
53
|
-
def copy(changes = {})
|
54
|
-
r = dup
|
55
|
-
changes.each { |k, v| r.instance_variable_set("@#{k}", v.freeze) }
|
56
|
-
r
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class Response
|
61
|
-
attr_reader :status, :headers, :body
|
62
|
-
|
63
|
-
def initialize
|
64
|
-
@headers = Headers.new
|
65
|
-
@complete = false
|
66
|
-
freeze
|
67
|
-
end
|
68
|
-
|
69
|
-
def complete?
|
70
|
-
@complete
|
71
|
-
end
|
72
|
-
|
73
|
-
def copy(changes = {})
|
74
|
-
r = dup
|
75
|
-
changes.each { |k, v| r.instance_variable_set("@#{k}", v) }
|
76
|
-
r.freeze
|
77
|
-
end
|
78
|
-
|
79
|
-
def freeze
|
80
|
-
@headers.freeze
|
81
|
-
@body.freeze
|
82
|
-
super
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class Context
|
87
|
-
attr_accessor :request, :response, :rejections
|
88
|
-
|
89
|
-
def initialize(request, response)
|
90
|
-
@request = request
|
91
|
-
@response = response
|
92
|
-
@rejections = []
|
93
|
-
end
|
94
|
-
|
95
|
-
def branch
|
96
|
-
original_request = @request
|
97
|
-
original_response = @response
|
98
|
-
yield
|
99
|
-
ensure
|
100
|
-
@request = original_request
|
101
|
-
@response = original_response unless @response.complete?
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class JsonMarshaller
|
106
|
-
def media_type
|
107
|
-
MediaType::JSON
|
108
|
-
end
|
109
|
-
|
110
|
-
def content_type
|
111
|
-
media_type.with_charset(Encoding::UTF_8)
|
112
|
-
end
|
113
|
-
|
114
|
-
def marshal_to?(media_range)
|
115
|
-
media_range =~ media_type
|
116
|
-
end
|
117
|
-
|
118
|
-
def marshal(obj)
|
119
|
-
[obj.to_json]
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
class XmlMarshaller
|
124
|
-
def media_type
|
125
|
-
MediaType::XML
|
126
|
-
end
|
127
|
-
|
128
|
-
def content_type
|
129
|
-
media_type.with_charset(Encoding::UTF_8)
|
130
|
-
end
|
131
|
-
|
132
|
-
def marshal_to?(media_range)
|
133
|
-
media_range =~ media_type
|
134
|
-
end
|
135
|
-
|
136
|
-
def marshal(obj)
|
137
|
-
raise "#{obj.class} does not support #to_xml" unless obj.respond_to?(:to_xml)
|
138
|
-
[obj.to_xml]
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
class API
|
143
|
-
include Xenon::Routing::Directives
|
144
|
-
|
145
|
-
DEFAULT_MARSHALLERS = [JsonMarshaller.new]
|
146
|
-
|
147
|
-
class << self
|
148
|
-
def marshallers(*marshallers)
|
149
|
-
@marshallers = marshallers unless marshallers.nil? || marshallers.empty?
|
150
|
-
(@marshallers.nil? || @marshallers.empty?) ? DEFAULT_MARSHALLERS : @marshallers
|
151
|
-
end
|
152
|
-
|
153
|
-
def select_marshaller(media_ranges)
|
154
|
-
weighted = marshallers.sort_by do |m|
|
155
|
-
media_range = media_ranges.find { |mr| m.marshal_to?(mr) }
|
156
|
-
media_range ? media_range.q : 0.0
|
157
|
-
end
|
158
|
-
weighted.last
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
attr_reader :context
|
163
|
-
|
164
|
-
class << self
|
165
|
-
def routes
|
166
|
-
@routes ||= []
|
167
|
-
end
|
168
|
-
|
169
|
-
def method_missing(name, *args, &block)
|
170
|
-
if instance_methods.include?(name)
|
171
|
-
routes << [name, args, block]
|
172
|
-
else
|
173
|
-
super
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def call(env)
|
179
|
-
dup.call!(env)
|
180
|
-
end
|
181
|
-
|
182
|
-
def call!(env)
|
183
|
-
@context = Context.new(Request.new(Rack::Request.new(env)), Response.new)
|
184
|
-
|
185
|
-
accept = @context.request.header('Accept')
|
186
|
-
marshaller = accept ? self.class.select_marshaller(accept.media_ranges) : self.class.marshallers.first
|
187
|
-
|
188
|
-
catch (:complete) do
|
189
|
-
begin
|
190
|
-
if marshaller.nil?
|
191
|
-
@context.rejections << Rejection.new(:accept, { supported: self.class.marshallers.map(&:media_type) })
|
192
|
-
else
|
193
|
-
self.class.routes.each do |route|
|
194
|
-
name, args, block = route
|
195
|
-
route_block = proc { instance_eval(&block) }
|
196
|
-
send(name, *args, &route_block)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
handle_rejections(@context.rejections)
|
200
|
-
rescue => e
|
201
|
-
handle_error(e)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
marshaller ||= self.class.marshallers.first
|
206
|
-
resp = @context.response.copy(
|
207
|
-
headers: @context.response.headers.set(Headers::ContentType.new(marshaller.content_type)),
|
208
|
-
body: marshaller.marshal(@context.response.body))
|
209
|
-
[resp.status, resp.headers.map { |h| [h.name, h.to_s] }.to_h, resp.body]
|
210
|
-
end
|
211
|
-
|
212
|
-
def handle_error(e)
|
213
|
-
puts "handle_error: #{e.class}: #{e}\n #{e.backtrace.join("\n ")}"
|
214
|
-
case e
|
215
|
-
when ParseError
|
216
|
-
fail 400, e.message
|
217
|
-
else
|
218
|
-
fail 500, e.message # TODO: Only if verbose errors configured
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
def handle_rejections(rejections)
|
223
|
-
puts "handle_rejections: #{rejections}"
|
224
|
-
if rejections.empty?
|
225
|
-
fail 404
|
226
|
-
else
|
227
|
-
rejection = rejections.first
|
228
|
-
case rejection.reason
|
229
|
-
when :accept
|
230
|
-
fail 406, "Supported media types: #{rejection[:supported].join(", ")}"
|
231
|
-
when :header
|
232
|
-
fail 400, "Missing required header: #{rejection[:required]}"
|
233
|
-
when :method
|
234
|
-
supported = rejections.take_while { |r| r.reason == :method }.map { |r| r[:supported].upcase }
|
235
|
-
fail 405, "Supported methods: #{supported.join(", ")}"
|
236
|
-
when :unauthorized
|
237
|
-
if rejection[:scheme]
|
238
|
-
challenge = Headers::Challenge.new(rejection[:scheme], rejection.info.except(:scheme))
|
239
|
-
respond_with_header Headers::WWWAuthenticate.new(challenge) do
|
240
|
-
fail 401
|
241
|
-
end
|
242
|
-
else
|
243
|
-
fail 401
|
244
|
-
end
|
245
|
-
else
|
246
|
-
fail 500
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
end
|