mirror of
https://gitea.invidious.io/iv-org/shard-athena-negotiation.git
synced 2024-08-15 00:53:23 +00:00
Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
|
94cf8e33d9 | ||
|
d821e33839 | ||
|
f6a843890f | ||
|
2b683817c1 | ||
|
80d2019d38 | ||
|
3451002963 | ||
|
3f71823d20 | ||
|
748c63ebd0 | ||
|
14b5e0589e | ||
|
1328425160 | ||
|
67d966e702 | ||
|
74ef3ff387 | ||
|
42c57abcfa | ||
|
090b83b5f0 | ||
|
17d5810179 | ||
|
24d5ab0287 | ||
|
5824495ba7 | ||
|
3982e1b523 | ||
|
c15379251a | ||
|
333abca50d |
15 changed files with 203 additions and 188 deletions
48
.github/workflows/ci.yml
vendored
48
.github/workflows/ci.yml
vendored
|
@ -1,48 +0,0 @@
|
||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
schedule:
|
|
||||||
- cron: '0 21 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_format:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: crystallang/crystal:latest-alpine
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Format
|
|
||||||
run: crystal tool format --check
|
|
||||||
coding_standards:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: crystallang/crystal:latest-alpine
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: shards install
|
|
||||||
- name: Ameba
|
|
||||||
run: ./bin/ameba
|
|
||||||
test_latest:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: crystallang/crystal:latest-alpine
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: shards install
|
|
||||||
- name: Specs
|
|
||||||
run: crystal spec --order random --error-on-warnings
|
|
||||||
test_nightly:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: crystallang/crystal:nightly-alpine
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: shards install
|
|
||||||
- name: Specs
|
|
||||||
run: crystal spec --order random --error-on-warnings
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
/docs/
|
|
||||||
/lib/
|
/lib/
|
||||||
/bin/
|
/bin/
|
||||||
/.shards/
|
/.shards/
|
||||||
|
|
51
CHANGELOG.md
Normal file
51
CHANGELOG.md
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [0.1.5] - 2024-04-09
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Integrate website into monorepo ([#365](https://github.com/athena-framework/athena/pull/365)) (George Dietrich)
|
||||||
|
|
||||||
|
## [0.1.4] - 2023-10-09
|
||||||
|
|
||||||
|
_Administrative release, no functional changes_
|
||||||
|
|
||||||
|
## [0.1.3] - 2023-02-18
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update some links in preparation for Athena Framework `0.18.0` ([#261](https://github.com/athena-framework/athena/pull/261)) (George Dietrich)
|
||||||
|
|
||||||
|
## [0.1.2] - 2022-05-14
|
||||||
|
|
||||||
|
_First release a part of the monorepo._
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `VERSION` constant to `Athena::Negotiation` namespace ([#166](https://github.com/athena-framework/athena/pull/166)) (George Dietrich)
|
||||||
|
- Add getting started documentation to API docs ([#172](https://github.com/athena-framework/athena/pull/172)) (George Dietrich)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Update minimum `crystal` version to `~> 1.4.0` ([#169](https://github.com/athena-framework/athena/pull/169)) (George Dietrich)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Correct the shard version in `README.md` ([#6](https://github.com/athena-framework/negotiation/pull/6)) (syeopite)
|
||||||
|
|
||||||
|
## [0.1.1] - 2021-02-04
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Migrate documentation to [MkDocs](https://mkdocstrings.github.io/crystal/) ([#4](https://github.com/athena-framework/negotiation/pull/4)) (George Dietrich)
|
||||||
|
|
||||||
|
## [0.1.0] - 2020-12-24
|
||||||
|
|
||||||
|
_Initial release._
|
||||||
|
|
||||||
|
[0.1.5]: https://github.com/athena-framework/negotiation/releases/tag/v0.1.5
|
||||||
|
[0.1.4]: https://github.com/athena-framework/negotiation/releases/tag/v0.1.4
|
||||||
|
[0.1.3]: https://github.com/athena-framework/negotiation/releases/tag/v0.1.3
|
||||||
|
[0.1.2]: https://github.com/athena-framework/negotiation/releases/tag/v0.1.2
|
||||||
|
[0.1.1]: https://github.com/athena-framework/negotiation/releases/tag/v0.1.1
|
||||||
|
[0.1.0]: https://github.com/athena-framework/negotiation/releases/tag/v0.1.0
|
3
CONTRIBUTING.md
Normal file
3
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
This repository is a read-only mirror. Please refer the [main Athena repository](https://github.com/athena-framework/athena/blob/master/CONTRIBUTING.md) on how to start contributing.
|
31
README.md
31
README.md
|
@ -1,36 +1,15 @@
|
||||||
# Negotiation
|
# Negotiation
|
||||||
|
|
||||||
[](https://github.com/athena-framework/negotiation/actions?query=workflow%3ACI)
|
[](https://common-changelog.org)
|
||||||
|
[](https://github.com/athena-framework/athena/actions/workflows/ci.yml)
|
||||||
[](https://github.com/athena-framework/negotiation/releases)
|
[](https://github.com/athena-framework/negotiation/releases)
|
||||||
|
|
||||||
Framework agnostic [content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3) library based on [willdurand/Negotiation](https://github.com/willdurand/Negotiation).
|
Framework agnostic [content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3) library based on [willdurand/Negotiation](https://github.com/willdurand/Negotiation).
|
||||||
|
|
||||||
## Installation
|
## Getting Started
|
||||||
|
|
||||||
1. Add the dependency to your `shard.yml`:
|
Checkout the [Documentation](https://athenaframework.org/Negotiation).
|
||||||
|
|
||||||
```yaml
|
|
||||||
dependencies:
|
|
||||||
athena-negotiation:
|
|
||||||
github: athena-framework/negotiation
|
|
||||||
version: ~> 1.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Run `shards install`
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
If using the component on its own, checkout the [API documentation](https://athenaframework.org/Negotiation).
|
|
||||||
If using the component as part of Athena, also checkout the [external documentation](https://athenaframework.org/components/negotiation).
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
1. Fork it (https://github.com/athena-framework/negotiation/fork)
|
Read the general [Contributing Guide](./CONTRIBUTING.md) for information on how to get started.
|
||||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
||||||
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
||||||
4. Push to the branch (`git push origin my-new-feature`)
|
|
||||||
5. Create a new Pull Request
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
- [George Dietrich](https://github.com/blacksmoke16) - creator and maintainer
|
|
||||||
|
|
83
docs/README.md
Normal file
83
docs/README.md
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
The `Athena::Negotiation` component allows an application to support [content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3).
|
||||||
|
The component has no dependencies and is framework agnostic; supporting various negotiators.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
First, install the component by adding the following to your `shard.yml`, then running `shards install`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
athena-negotiation:
|
||||||
|
github: athena-framework/negotiation
|
||||||
|
version: ~> 0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The main type of [Athena::Negotiation][] is [ANG::AbstractNegotiator][] which is used to implement negotiators for each `Accept*` header.
|
||||||
|
`Athena::Negotiation` exposes class level getters for each negotiator; that return a lazily initialized singleton instance.
|
||||||
|
Each negotiator exposes two methods: [ANG::AbstractNegotiator#best][] and [ANG::AbstractNegotiator#ordered_elements][].
|
||||||
|
|
||||||
|
### Media Type
|
||||||
|
|
||||||
|
```crystal
|
||||||
|
negotiator = ANG.negotiator
|
||||||
|
|
||||||
|
accept_header = "text/html, application/xhtml+xml, application/xml;q=0.9"
|
||||||
|
priorities = ["text/html; charset=utf-8", "application/json", "application/xml;q=0.5"]
|
||||||
|
|
||||||
|
accept = negotiator.best(accept_header, priorities).not_nil!
|
||||||
|
|
||||||
|
accept.media_range # => "text/html"
|
||||||
|
accept.parameters # => {"charset" => "utf-8"}
|
||||||
|
```
|
||||||
|
|
||||||
|
The [ANG::Negotiator][] type returns an [ANG::Accept][], or `nil` if negotiating the best media type has failed.
|
||||||
|
|
||||||
|
### Character Set
|
||||||
|
|
||||||
|
```crystal
|
||||||
|
negotiator = ANG.charset_negotiator
|
||||||
|
|
||||||
|
accept_header = "ISO-8859-1, utf-8; q=0.9"
|
||||||
|
priorities = ["iso-8859-1;q=0.3", "utf-8;q=0.9", "utf-16;q=1.0"]
|
||||||
|
|
||||||
|
accept = negotiator.best(accept_header, priorities).not_nil!
|
||||||
|
|
||||||
|
accept.charset # => "utf-8"
|
||||||
|
accept.quality # => 0.9
|
||||||
|
```
|
||||||
|
|
||||||
|
The [ANG::CharsetNegotiator][] type returns an [ANG::AcceptCharset][], or `nil` if negotiating the best character set has failed.
|
||||||
|
|
||||||
|
### Encoding
|
||||||
|
|
||||||
|
```crystal
|
||||||
|
negotiator = ANG.encoding_negotiator
|
||||||
|
|
||||||
|
accept_header = "gzip;q=1.0, identity; q=0.5, *;q=0"
|
||||||
|
priorities = ["gzip", "foo"]
|
||||||
|
|
||||||
|
accept = negotiator.best(accept_header, priorities).not_nil!
|
||||||
|
|
||||||
|
accept.coding # => "gzip"
|
||||||
|
```
|
||||||
|
|
||||||
|
The [ANG::EncodingNegotiator][] type returns an [ANG::AcceptEncoding][], or `nil` if negotiating the best encoding has failed.
|
||||||
|
|
||||||
|
### Language
|
||||||
|
|
||||||
|
```crystal
|
||||||
|
negotiator = ANG.language_negotiator
|
||||||
|
|
||||||
|
accept_header = "en; q=0.1, fr; q=0.4, zh-Hans-CN; q=0.9, de; q=0.2"
|
||||||
|
priorities = ["de", "zh-Hans-CN", "en"]
|
||||||
|
|
||||||
|
accept = negotiator.best(accept_header, priorities).not_nil!
|
||||||
|
|
||||||
|
accept.language # => "zh"
|
||||||
|
accept.region # => "cn"
|
||||||
|
accept.script # => "hans"
|
||||||
|
```
|
||||||
|
|
||||||
|
The [ANG::LanguageNegotiator][] type returns an [ANG::AcceptLanguage][], or `nil` if negotiating the best language has failed.
|
31
mkdocs.yml
Normal file
31
mkdocs.yml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
INHERIT: ../../../mkdocs-common.yml
|
||||||
|
|
||||||
|
site_name: Negotiation
|
||||||
|
site_url: https://athenaframework.org/Negotiation/
|
||||||
|
repo_url: https://github.com/athena-framework/negotiation
|
||||||
|
|
||||||
|
nav:
|
||||||
|
- Introduction: README.md
|
||||||
|
- Back to Manual: project://.
|
||||||
|
- API:
|
||||||
|
- Aliases: aliases.md
|
||||||
|
- Top Level: top_level.md
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- search
|
||||||
|
- section-index
|
||||||
|
- literate-nav
|
||||||
|
- gen-files:
|
||||||
|
scripts:
|
||||||
|
- ../../../gen_doc_stubs.py
|
||||||
|
- mkdocstrings:
|
||||||
|
default_handler: crystal
|
||||||
|
custom_templates: ../../../docs/templates
|
||||||
|
handlers:
|
||||||
|
crystal:
|
||||||
|
crystal_docs_flags:
|
||||||
|
- ./docs/index.cr
|
||||||
|
- ./lib/athena-negotiation/src/athena-negotiation.cr
|
||||||
|
source_locations:
|
||||||
|
lib/athena-negotiation: https://github.com/athena-framework/negotiation/blob/v{shard_version}/{file}#L{line}
|
14
shard.yml
14
shard.yml
|
@ -1,8 +1,8 @@
|
||||||
name: athena-negotiation
|
name: athena-negotiation
|
||||||
|
|
||||||
version: 0.1.1
|
version: 0.1.5
|
||||||
|
|
||||||
crystal: '>= 0.35.0'
|
crystal: ~> 1.4
|
||||||
|
|
||||||
license: MIT
|
license: MIT
|
||||||
|
|
||||||
|
@ -14,12 +14,4 @@ description: |
|
||||||
Framework agnostic content negotiation library.
|
Framework agnostic content negotiation library.
|
||||||
|
|
||||||
authors:
|
authors:
|
||||||
- George Dietrich <george@dietrich.app>
|
- George Dietrich <dev@dietrich.pub>
|
||||||
|
|
||||||
development_dependencies:
|
|
||||||
ameba:
|
|
||||||
github: crystal-ameba/ameba
|
|
||||||
version: ~> 0.13.0
|
|
||||||
athena-spec:
|
|
||||||
github: athena-framework/spec
|
|
||||||
version: ~> 0.2.3
|
|
||||||
|
|
|
@ -71,9 +71,9 @@ struct NegotiatorTest < NegotiatorTestCase
|
||||||
{"image/png, text/plain, audio/ogg", {"baz/asdf"}, nil},
|
{"image/png, text/plain, audio/ogg", {"baz/asdf"}, nil},
|
||||||
{"image/png, text/plain, audio/ogg", {"audio/ogg"}, {"audio/ogg", nil}},
|
{"image/png, text/plain, audio/ogg", {"audio/ogg"}, {"audio/ogg", nil}},
|
||||||
{"image/png, text/plain, audio/ogg", {"YO/SuP"}, nil},
|
{"image/png, text/plain, audio/ogg", {"YO/SuP"}, nil},
|
||||||
{"text/html; charset=UTF-8, application/pdf", {"text/html; charset=UTF-8"}, {"text/html", {"charset" => "UTF-8"}}},
|
{"text/html; charset=utf-8, application/pdf", {"text/html; charset=utf-8"}, {"text/html", {"charset" => "utf-8"}}},
|
||||||
{"text/html; charset=UTF-8, application/pdf", {"text/html"}, nil},
|
{"text/html; charset=utf-8, application/pdf", {"text/html"}, nil},
|
||||||
{"text/html, application/pdf", {"text/html; charset=UTF-8"}, {"text/html", {"charset" => "UTF-8"}}},
|
{"text/html, application/pdf", {"text/html; charset=utf-8"}, {"text/html", {"charset" => "utf-8"}}},
|
||||||
|
|
||||||
# PHP"s PEAR HTTP2 assertions I took from the other lib.
|
# PHP"s PEAR HTTP2 assertions I took from the other lib.
|
||||||
{php_pear_header, {"image/gif", "image/png", "application/xhtml+xml", "application/xml", "text/html", "image/jpeg", "text/plain"}, {"image/png", nil}},
|
{php_pear_header, {"image/gif", "image/png", "application/xhtml+xml", "application/xml", "text/html", "image/jpeg", "text/plain"}, {"image/png", nil}},
|
||||||
|
@ -86,7 +86,7 @@ struct NegotiatorTest < NegotiatorTestCase
|
||||||
{php_pear_header, {"audio/midi"}, {"audio/midi", nil}},
|
{php_pear_header, {"audio/midi"}, {"audio/midi", nil}},
|
||||||
{"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", {"application/rss+xml"}, {"application/rss+xml", nil}},
|
{"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", {"application/rss+xml"}, {"application/rss+xml", nil}},
|
||||||
|
|
||||||
# Case sensitiviy
|
# Case sensitivity
|
||||||
{"text/* ; q=0.3, TEXT/html ;Q=0.7, text/html ; level=1, texT/Html ;leVel = 2 ;q=0.4, */* ; q=0.5", {"text/html; level=2"}, {"text/html", {"level" => "2"}}},
|
{"text/* ; q=0.3, TEXT/html ;Q=0.7, text/html ; level=1, texT/Html ;leVel = 2 ;q=0.4, */* ; q=0.5", {"text/html; level=2"}, {"text/html", {"level" => "2"}}},
|
||||||
{"text/* ; q=0.3, text/html;Q=0.7, text/html ;level=1, text/html; level=2;q=0.4, */*;q=0.5", {"text/HTML; level=3"}, {"text/html", {"level" => "3"}}},
|
{"text/* ; q=0.3, text/html;Q=0.7, text/html ;level=1, text/html; level=2;q=0.4, */*;q=0.5", {"text/HTML; level=3"}, {"text/html", {"level" => "3"}}},
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@ abstract class Athena::Negotiation::AbstractNegotiator(HeaderType)
|
||||||
raise ex if strict
|
raise ex if strict
|
||||||
end
|
end
|
||||||
|
|
||||||
accepted_priorties = priorities.map { |p| HeaderType.new p }
|
accepted_priorities = priorities.map { |p| HeaderType.new p }
|
||||||
|
|
||||||
matches = self.find_matches accepted_headers, accepted_priorties
|
matches = self.find_matches accepted_headers, accepted_priorities
|
||||||
|
|
||||||
specific_matches = matches.reduce({} of Int32 => ANG::AcceptMatch) do |acc, match|
|
specific_matches = matches.reduce({} of Int32 => ANG::AcceptMatch) do |acc, match|
|
||||||
ANG::AcceptMatch.reduce acc, match
|
ANG::AcceptMatch.reduce acc, match
|
||||||
|
@ -38,7 +38,7 @@ abstract class Athena::Negotiation::AbstractNegotiator(HeaderType)
|
||||||
|
|
||||||
match = specific_matches.shift?
|
match = specific_matches.shift?
|
||||||
|
|
||||||
match.nil? ? nil : accepted_priorties[match.index]
|
match.nil? ? nil : accepted_priorities[match.index]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an array of `HeaderType` that the provided *header* allows, ordered so that the `#best` match is first.
|
# Returns an array of `HeaderType` that the provided *header* allows, ordered so that the `#best` match is first.
|
||||||
|
|
|
@ -3,11 +3,11 @@ require "./base_accept"
|
||||||
# Represents an [Accept](https://tools.ietf.org/html/rfc7231#section-5.3.2) header media type.
|
# Represents an [Accept](https://tools.ietf.org/html/rfc7231#section-5.3.2) header media type.
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
# accept = ANG::Accept.new "application/json; q = 0.75; charset = UTF-8"
|
# accept = ANG::Accept.new "application/json; q = 0.75; charset = utf-8"
|
||||||
#
|
#
|
||||||
# accept.header # => "application/json; q = 0.75; charset = UTF-8"
|
# accept.header # => "application/json; q = 0.75; charset = utf-8"
|
||||||
# accept.normalized_header # => "application/json; charset=UTF-8"
|
# accept.normalized_header # => "application/json; charset=utf-8"
|
||||||
# accept.parameters # => {"charset" => "UTF-8"}
|
# accept.parameters # => {"charset" => "utf-8"}
|
||||||
# accept.quality # => 0.75
|
# accept.quality # => 0.75
|
||||||
# accept.type # => "application"
|
# accept.type # => "application"
|
||||||
# accept.sub_type # => "json"
|
# accept.sub_type # => "json"
|
||||||
|
|
|
@ -14,78 +14,9 @@ require "./exceptions/*"
|
||||||
alias ANG = Athena::Negotiation
|
alias ANG = Athena::Negotiation
|
||||||
|
|
||||||
# The `Athena::Negotiation` component allows an application to support [content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3).
|
# The `Athena::Negotiation` component allows an application to support [content negotiation](https://tools.ietf.org/html/rfc7231#section-5.3).
|
||||||
# The component has no dependencies and is framework agnostic; supporting various negotiators.
|
|
||||||
#
|
|
||||||
# ## Usage
|
|
||||||
#
|
|
||||||
# The main type of `Athena::Negotiation` is `ANG::AbstractNegotiator` which is used to implement negotiators for each `Accept*` header.
|
|
||||||
# `Athena::Negotiation` exposes class level getters for each negotiator; that return a lazily initialized singleton instance.
|
|
||||||
# Each negotiator exposes two methods: `ANG::AbstractNegotiator#best` and `ANG::AbstractNegotiator#ordered_elements`.
|
|
||||||
#
|
|
||||||
# ### Media Type
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# negotiator = ANG.negotiator
|
|
||||||
#
|
|
||||||
# accept_header = "text/html, application/xhtml+xml, application/xml;q=0.9"
|
|
||||||
# priorities = ["text/html; charset=UTF-8", "application/json", "application/xml;q=0.5"]
|
|
||||||
#
|
|
||||||
# accept = negotiator.best(accept_header, priorities).not_nil!
|
|
||||||
#
|
|
||||||
# accept.media_range # => "text/html"
|
|
||||||
# accept.parameters # => {"charset" => "UTF-8"}
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
# The `ANG::Negotiator` type returns an `ANG::Accept`, or `nil` if negotiating the best media type has failed.
|
|
||||||
#
|
|
||||||
# ### Character Set
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# negotiator = ANG.charset_negotiator
|
|
||||||
#
|
|
||||||
# accept_header = "ISO-8859-1, UTF-8; q=0.9"
|
|
||||||
# priorities = ["iso-8859-1;q=0.3", "utf-8;q=0.9", "utf-16;q=1.0"]
|
|
||||||
#
|
|
||||||
# accept = negotiator.best(accept_header, priorities).not_nil!
|
|
||||||
#
|
|
||||||
# accept.charset # => "utf-8"
|
|
||||||
# accept.quality # => 0.9
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
# The `ANG::CharsetNegotiator` type returns an `ANG::AcceptCharset`, or `nil` if negotiating the best character set has failed.
|
|
||||||
#
|
|
||||||
# ### Encoding
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# negotiator = ANG.encoding_negotiator
|
|
||||||
#
|
|
||||||
# accept_header = "gzip;q=1.0, identity; q=0.5, *;q=0"
|
|
||||||
# priorities = ["gzip", "foo"]
|
|
||||||
#
|
|
||||||
# accept = negotiator.best(accept_header, priorities).not_nil!
|
|
||||||
#
|
|
||||||
# accept.coding # => "gzip"
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
# The `ANG::EncodingNegotiator` type returns an `ANG::AcceptEncoding`, or `nil` if negotiating the best encoding has failed.
|
|
||||||
#
|
|
||||||
# ### Language
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# negotiator = ANG.language_negotiator
|
|
||||||
#
|
|
||||||
# accept_header = "en; q=0.1, fr; q=0.4, zh-Hans-CN; q=0.9, de; q=0.2"
|
|
||||||
# priorities = ["de", "zh-Hans-CN", "en"]
|
|
||||||
#
|
|
||||||
# accept = negotiator.best(accept_header, priorities).not_nil!
|
|
||||||
#
|
|
||||||
# accept.language # => "zh"
|
|
||||||
# accept.region # => "cn"
|
|
||||||
# accept.script # => "hans"
|
|
||||||
# ```
|
|
||||||
#
|
|
||||||
# The `ANG::LanguageNegotiator` type returns an `ANG::AcceptLanguage`, or `nil` if negotiating the best language has failed.
|
|
||||||
module Athena::Negotiation
|
module Athena::Negotiation
|
||||||
|
VERSION = "0.1.5"
|
||||||
|
|
||||||
# Returns a lazily initialized `ANG::Negotiator` singleton instance.
|
# Returns a lazily initialized `ANG::Negotiator` singleton instance.
|
||||||
class_getter(negotiator) { ANG::Negotiator.new }
|
class_getter(negotiator) { ANG::Negotiator.new }
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ abstract struct Athena::Negotiation::BaseAccept
|
||||||
getter normalized_header : String
|
getter normalized_header : String
|
||||||
|
|
||||||
# Returns any extension parameters included in the header `self` represents.
|
# Returns any extension parameters included in the header `self` represents.
|
||||||
# E.x. `charset=UTF-8` or `version=2`.
|
# E.x. `charset=utf-8` or `version=2`.
|
||||||
getter parameters : Hash(String, String) = Hash(String, String).new
|
getter parameters : Hash(String, String) = Hash(String, String).new
|
||||||
|
|
||||||
# Returns the [quality value](https://tools.ietf.org/html/rfc7231#section-5.3.1) of the header `self` represents.
|
# Returns the [quality value](https://tools.ietf.org/html/rfc7231#section-5.3.1) of the header `self` represents.
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Athena::Negotiation::LanguageNegotiator < Athena::Negotiation::AbstractNeg
|
||||||
base_equal = accept_base.downcase == priority_base.downcase
|
base_equal = accept_base.downcase == priority_base.downcase
|
||||||
sub_equal = accept_sub.try &.downcase == priority_sub.try &.downcase
|
sub_equal = accept_sub.try &.downcase == priority_sub.try &.downcase
|
||||||
|
|
||||||
if ((accept_base == "*" || base_equal) && (accept_sub.nil? || sub_equal))
|
if (accept_base == "*" || base_equal) && (accept_sub.nil? || sub_equal)
|
||||||
score = 10 * (base_equal ? 1 : 0) + (sub_equal ? 1 : 0)
|
score = 10 * (base_equal ? 1 : 0) + (sub_equal ? 1 : 0)
|
||||||
|
|
||||||
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Athena::Negotiation::Negotiator < Athena::Negotiation::AbstractNegotiator(
|
||||||
accept_sub_type = accept.sub_type
|
accept_sub_type = accept.sub_type
|
||||||
priority_sub_type = priority.sub_type
|
priority_sub_type = priority.sub_type
|
||||||
|
|
||||||
intercection = accept.parameters.each_with_object({} of String => String) do |(k, v), params|
|
intersection = accept.parameters.each_with_object({} of String => String) do |(k, v), params|
|
||||||
priority.parameters.tap do |pp|
|
priority.parameters.tap do |pp|
|
||||||
params[k] = v if pp.has_key?(k) && pp[k] == v
|
params[k] = v if pp.has_key?(k) && pp[k] == v
|
||||||
end
|
end
|
||||||
|
@ -21,12 +21,10 @@ class Athena::Negotiation::Negotiator < Athena::Negotiation::AbstractNegotiator(
|
||||||
type_equals = accept_type.downcase == priority_type.downcase
|
type_equals = accept_type.downcase == priority_type.downcase
|
||||||
sub_type_equals = accept_sub_type.downcase == priority_sub_type.downcase
|
sub_type_equals = accept_sub_type.downcase == priority_sub_type.downcase
|
||||||
|
|
||||||
if (
|
if (accept_type == "*" || type_equals) &&
|
||||||
(accept_type == "*" || type_equals) &&
|
|
||||||
(accept_sub_type == "*" || sub_type_equals) &&
|
(accept_sub_type == "*" || sub_type_equals) &&
|
||||||
intercection.size == accept.parameters.size
|
intersection.size == accept.parameters.size
|
||||||
)
|
score = 100 * (type_equals ? 1 : 0) + 10 * (sub_type_equals ? 1 : 0) + intersection.size
|
||||||
score = 100 * (type_equals ? 1 : 0) + 10 * (sub_type_equals ? 1 : 0) + intercection.size
|
|
||||||
|
|
||||||
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
||||||
end
|
end
|
||||||
|
@ -36,22 +34,18 @@ class Athena::Negotiation::Negotiator < Athena::Negotiation::AbstractNegotiator(
|
||||||
accept_sub_type, accept_plus = self.split_sub_type accept_sub_type
|
accept_sub_type, accept_plus = self.split_sub_type accept_sub_type
|
||||||
priority_sub_type, priority_plus = self.split_sub_type priority_sub_type
|
priority_sub_type, priority_plus = self.split_sub_type priority_sub_type
|
||||||
|
|
||||||
if (
|
if !(accept_type == "*" || type_equals) ||
|
||||||
!(accept_type == "*" || type_equals) ||
|
|
||||||
!(accept_sub_type == "*" || priority_sub_type == "*" || accept_plus == "*" || priority_plus == "*")
|
!(accept_sub_type == "*" || priority_sub_type == "*" || accept_plus == "*" || priority_plus == "*")
|
||||||
)
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
sub_type_equals = accept_sub_type.downcase == priority_sub_type.downcase
|
sub_type_equals = accept_sub_type.downcase == priority_sub_type.downcase
|
||||||
plus_equals = accept_plus.downcase == priority_plus.downcase
|
plus_equals = accept_plus.downcase == priority_plus.downcase
|
||||||
|
|
||||||
if (
|
if (accept_sub_type == "*" || priority_sub_type == "*" || sub_type_equals) &&
|
||||||
(accept_sub_type == "*" || priority_sub_type == "*" || sub_type_equals) &&
|
|
||||||
(accept_plus == "*" || priority_plus == '*' || plus_equals) &&
|
(accept_plus == "*" || priority_plus == '*' || plus_equals) &&
|
||||||
intercection.size == accept.parameters.size
|
intersection.size == accept.parameters.size
|
||||||
)
|
score = 100 * (type_equals ? 1 : 0) + 10 * (sub_type_equals ? 1 : 0) + (plus_equals ? 1 : 0) + intersection.size
|
||||||
score = 100 * (type_equals ? 1 : 0) + 10 * (sub_type_equals ? 1 : 0) + (plus_equals ? 1 : 0) + intercection.size
|
|
||||||
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue