lively 0.20.0 → 0.22.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/getting-started.md +10 -15
- data/lib/lively/application.rb +23 -42
- data/lib/lively/hello_world.rb +1 -5
- data/lib/lively/page.rb +14 -13
- data/lib/lively/page.xrb +1 -1
- data/lib/lively/pages/index.rb +2 -2
- data/lib/lively/resolver.rb +5 -8
- data/lib/lively/router.rb +108 -89
- data/lib/lively/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +5 -5
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15152c7881657de7dd4fa32fc683e7ebe4a03d4bc0f4607d012d4c759893f5c9
|
|
4
|
+
data.tar.gz: 8920462124226fb11f45ae5bfcaebcbe8b31c498ac5747f37e5519824559cda5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3aecbe697281e791829fa34fe243d872c024603bf549d192911c7acde336e9e50fc3460fbdef7935c7aeb9fa533de7bbcda9c500bff141e78bf7acbfb22beb48
|
|
7
|
+
data.tar.gz: fe65914d211265582cfb6e3d5ad1d84bf61f752900dcc758b1ac4be71502a98c7d8f7d29675bc14761f4e2297c145e13189477685a1553c2ac8d2196be98fc94
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/context/getting-started.md
CHANGED
|
@@ -82,7 +82,7 @@ class GameState
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
class GameView < Live::View
|
|
85
|
-
def initialize(id
|
|
85
|
+
def initialize(id, data, game_state: nil)
|
|
86
86
|
super(id, data)
|
|
87
87
|
@game_state = game_state
|
|
88
88
|
end
|
|
@@ -117,29 +117,24 @@ class Application < Lively::Application
|
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
def configure_routes(router)
|
|
120
|
-
super
|
|
121
|
-
|
|
122
120
|
router.get("/") do
|
|
123
|
-
|
|
121
|
+
body = resolver.root(DisplayView)
|
|
122
|
+
Lively::Pages::Index.new(title: title, body: body).call
|
|
124
123
|
end
|
|
125
124
|
|
|
126
|
-
router.get("/control") do
|
|
127
|
-
|
|
125
|
+
router.get("/control") do
|
|
126
|
+
body = resolver.root(ControlView)
|
|
127
|
+
Lively::Pages::Index.new(title: title, body: body).call
|
|
128
128
|
end
|
|
129
129
|
end
|
|
130
|
-
|
|
131
|
-
private
|
|
132
|
-
|
|
133
|
-
def render(body)
|
|
134
|
-
page = Lively::Pages::Index.new(title: "My App", body: body)
|
|
135
|
-
Protocol::HTTP::Response[200, [], [page.call]]
|
|
136
|
-
end
|
|
137
130
|
end
|
|
138
131
|
```
|
|
139
132
|
|
|
140
|
-
|
|
133
|
+
`allowed_views` defines the view classes the shared resolver may construct. Each matched route constructs its root view using the shared resolver, wraps that concrete body in a page, and invokes `Page#call` to produce the response. This keeps view construction lazy without making the page body itself callable. Lively installs its `/live` WebSocket route independently, so overriding `configure_routes` does not remove it.
|
|
134
|
+
|
|
135
|
+
Routes match exact paths and may accept one or more HTTP methods. Handlers receive the original request and can parse query parameters when needed. Routes without an explicit method accept every method.
|
|
141
136
|
|
|
142
|
-
Requests which do not match a route are passed to the application's delegate.
|
|
137
|
+
Requests which do not match a route are passed to the application's delegate. Applications that need custom fallback behavior can supply an appropriate delegate when they are constructed.
|
|
143
138
|
|
|
144
139
|
## Live Reloading
|
|
145
140
|
|
data/lib/lively/application.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Lively
|
|
|
23
23
|
#
|
|
24
24
|
# Use {.[]} to create a simple application class for a single view, optionally
|
|
25
25
|
# with shared state. For more complex applications, subclass and override
|
|
26
|
-
# {#allowed_views}, {#state}, and {#configure_routes}.
|
|
26
|
+
# {#allowed_views}, {#state}, and {#configure_routes} to route requests to pages.
|
|
27
27
|
class Application < Protocol::HTTP::Middleware
|
|
28
28
|
VIEWS = [HelloWorld].freeze
|
|
29
29
|
STATE = {}.freeze
|
|
@@ -31,7 +31,7 @@ module Lively
|
|
|
31
31
|
# Create a new application class configured for a specific Live view tag,
|
|
32
32
|
# optionally with shared state that is passed to all views.
|
|
33
33
|
#
|
|
34
|
-
# @parameter tag [Class] The Live view class to
|
|
34
|
+
# @parameter tag [Class] The Live view class to render at the root route.
|
|
35
35
|
# @parameter state [Hash] Shared state to pass to all views as keyword arguments.
|
|
36
36
|
# @returns [Class] A new application class configured for the specified tag.
|
|
37
37
|
def self.[](*tags, **state)
|
|
@@ -43,15 +43,6 @@ module Lively
|
|
|
43
43
|
return klass
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
# Initialize a new Lively application.
|
|
47
|
-
# @parameter delegate [Protocol::HTTP::Middleware] The next middleware in the chain.
|
|
48
|
-
def initialize(delegate)
|
|
49
|
-
super(delegate)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# @attribute [Protocol::HTTP::Middleware] The delegate middleware for request handling.
|
|
53
|
-
attr :delegate
|
|
54
|
-
|
|
55
46
|
# The shared state for this application, passed to all views via the resolver.
|
|
56
47
|
# Override this in subclasses to provide custom state.
|
|
57
48
|
# @returns [Hash] Key-value pairs passed as keyword arguments to view constructors.
|
|
@@ -87,43 +78,23 @@ module Lively
|
|
|
87
78
|
self.class.name
|
|
88
79
|
end
|
|
89
80
|
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
|
|
93
|
-
self.allowed_views.first.new(**self.state)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Create the index page for this application.
|
|
97
|
-
# @returns [Pages::Index] A new index page instance.
|
|
98
|
-
def index
|
|
99
|
-
Pages::Index.new(title: self.title, body: self.body)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Handle a standard HTTP request which did not match a configured route.
|
|
103
|
-
# @parameter request [Protocol::HTTP::Request] The incoming HTTP request.
|
|
104
|
-
# @returns [Protocol::HTTP::Response] The delegate response.
|
|
105
|
-
def handle(request)
|
|
106
|
-
return delegate.call(request)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Add the standard application routes to the given router.
|
|
110
|
-
# Override this method and call `super` to add application-specific routes.
|
|
111
|
-
# @parameter router [Router] The router to configure.
|
|
81
|
+
# Add application routes to the given router.
|
|
82
|
+
# Override this method to map paths to views or other handlers.
|
|
83
|
+
# @parameter router [Router::Builder] The router to configure.
|
|
112
84
|
def configure_routes(router)
|
|
113
85
|
router.get("/") do
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
router.route("/live") do |request|
|
|
118
|
-
Async::WebSocket::Adapters::HTTP.open(request, &self.method(:live)) || Protocol::HTTP::Response[400]
|
|
86
|
+
view_class = self.allowed_views.first
|
|
87
|
+
body = self.resolver.root(view_class) if view_class
|
|
88
|
+
Pages::Index.new(title: self.title, body: body).call
|
|
119
89
|
end
|
|
120
90
|
end
|
|
121
91
|
|
|
122
|
-
# The router for this application. Unmatched requests are
|
|
123
|
-
#
|
|
92
|
+
# The router for this application. Unmatched requests are passed to the
|
|
93
|
+
# application delegate.
|
|
124
94
|
# @returns [Router] The configured router.
|
|
125
95
|
def router
|
|
126
|
-
@router ||= Router.
|
|
96
|
+
@router ||= Router.build(delegate) do |router|
|
|
97
|
+
configure_system_routes(router)
|
|
127
98
|
configure_routes(router)
|
|
128
99
|
end
|
|
129
100
|
end
|
|
@@ -132,7 +103,17 @@ module Lively
|
|
|
132
103
|
# @parameter request [Protocol::HTTP::Request] The incoming HTTP request.
|
|
133
104
|
# @returns [Protocol::HTTP::Response] The appropriate response for the request.
|
|
134
105
|
def call(request)
|
|
135
|
-
return router.call(request)
|
|
106
|
+
return router.call(request)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# Add framework-owned routes to the given router.
|
|
112
|
+
# @parameter router [Router::Builder] The router to configure.
|
|
113
|
+
def configure_system_routes(router)
|
|
114
|
+
router.route("/live") do |request|
|
|
115
|
+
Async::WebSocket::Adapters::HTTP.open(request, &self.method(:live)) || Protocol::HTTP::Response[400]
|
|
116
|
+
end
|
|
136
117
|
end
|
|
137
118
|
end
|
|
138
119
|
end
|
data/lib/lively/hello_world.rb
CHANGED
data/lib/lively/page.rb
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# Copyright, 2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "json"
|
|
7
|
+
require "protocol/http/response"
|
|
7
8
|
require "xrb/markup"
|
|
8
9
|
require "xrb/tag"
|
|
9
10
|
require "xrb/template"
|
|
@@ -11,15 +12,15 @@ require "xrb/template"
|
|
|
11
12
|
module Lively
|
|
12
13
|
# Represents a complete HTML document.
|
|
13
14
|
#
|
|
14
|
-
# A page combines
|
|
15
|
-
# JavaScript modules, and body attributes required to present it.
|
|
16
|
-
#
|
|
15
|
+
# A page combines a renderable body with the stylesheets, import map,
|
|
16
|
+
# JavaScript modules, and body attributes required to present it.
|
|
17
|
+
# Pages render complete HTTP responses after a route has selected their content.
|
|
17
18
|
class Page
|
|
18
19
|
TEMPLATE = XRB::Template.load_file(File.expand_path("page.xrb", __dir__))
|
|
19
20
|
|
|
20
21
|
# Initialize a new page.
|
|
21
22
|
# @parameter title [String] The document title.
|
|
22
|
-
# @parameter body [Object | Nil] The document body.
|
|
23
|
+
# @parameter body [Object | Nil] The renderable document body.
|
|
23
24
|
# @parameter icon [String | Nil] The favicon URL.
|
|
24
25
|
# @parameter stylesheets [Array(String | Hash)] Stylesheets in document order. Hash entries specify link attributes.
|
|
25
26
|
# @parameter imports [Hash] JavaScript import map entries.
|
|
@@ -39,7 +40,7 @@ module Lively
|
|
|
39
40
|
# @attribute [String] The document title.
|
|
40
41
|
attr :title
|
|
41
42
|
|
|
42
|
-
# @attribute [Object | Nil] The document body.
|
|
43
|
+
# @attribute [Object | Nil] The renderable document body.
|
|
43
44
|
attr :body
|
|
44
45
|
|
|
45
46
|
# @attribute [String | Nil] The favicon URL.
|
|
@@ -79,12 +80,6 @@ module Lively
|
|
|
79
80
|
XRB::Tag.closed("link", {rel: "stylesheet", type: "text/css"}.merge(attributes))
|
|
80
81
|
end
|
|
81
82
|
|
|
82
|
-
# The rendered body content.
|
|
83
|
-
# @returns [Object]
|
|
84
|
-
def body_content
|
|
85
|
-
@body&.to_html || "No body specified!"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
83
|
# The serialized JavaScript import map.
|
|
89
84
|
# @returns [XRB::MarkupString]
|
|
90
85
|
def import_map
|
|
@@ -94,10 +89,16 @@ module Lively
|
|
|
94
89
|
XRB::MarkupString.raw(json)
|
|
95
90
|
end
|
|
96
91
|
|
|
97
|
-
# Render this page to
|
|
92
|
+
# Render this page to an HTML string.
|
|
98
93
|
# @returns [String]
|
|
99
|
-
def
|
|
94
|
+
def to_html
|
|
100
95
|
@template.to_string(self)
|
|
101
96
|
end
|
|
97
|
+
|
|
98
|
+
# Render this page as an HTTP response.
|
|
99
|
+
# @returns [Protocol::HTTP::Response] A successful HTML response.
|
|
100
|
+
def call
|
|
101
|
+
Protocol::HTTP::Response[200, {"content-type" => "text/html; charset=utf-8"}, [to_html]]
|
|
102
|
+
end
|
|
102
103
|
end
|
|
103
104
|
end
|
data/lib/lively/page.xrb
CHANGED
data/lib/lively/pages/index.rb
CHANGED
|
@@ -29,7 +29,7 @@ module Lively
|
|
|
29
29
|
|
|
30
30
|
# Initialize a new index page.
|
|
31
31
|
# @parameter title [String] The title of the page.
|
|
32
|
-
# @parameter body [Object] The
|
|
32
|
+
# @parameter body [Object | Nil] The renderable document body.
|
|
33
33
|
def initialize(title: "Lively", body: nil)
|
|
34
34
|
super(
|
|
35
35
|
title: title,
|
|
@@ -37,7 +37,7 @@ module Lively
|
|
|
37
37
|
icon: ICON,
|
|
38
38
|
stylesheets: STYLESHEETS,
|
|
39
39
|
imports: IMPORTS,
|
|
40
|
-
modules: MODULES
|
|
40
|
+
modules: MODULES
|
|
41
41
|
)
|
|
42
42
|
end
|
|
43
43
|
end
|
data/lib/lively/resolver.rb
CHANGED
|
@@ -21,14 +21,11 @@ module Lively
|
|
|
21
21
|
# @attribute [Hash] The shared state passed to view constructors.
|
|
22
22
|
attr :state
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if klass = @allowed[data[:class]]
|
|
30
|
-
return klass.new(id, data, **@state)
|
|
31
|
-
end
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# Construct a view with shared application state.
|
|
27
|
+
def make(view_class, id, data, **options)
|
|
28
|
+
super(view_class, id, data, **@state, **options)
|
|
32
29
|
end
|
|
33
30
|
end
|
|
34
31
|
end
|
data/lib/lively/router.rb
CHANGED
|
@@ -3,136 +3,155 @@
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
4
|
# Copyright, 2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
require "protocol/http"
|
|
6
|
+
require "protocol/http/middleware"
|
|
7
7
|
require "protocol/url"
|
|
8
8
|
|
|
9
9
|
module Lively
|
|
10
10
|
# Dispatches HTTP requests to handlers using exact path and method matches.
|
|
11
11
|
#
|
|
12
12
|
# Request targets are parsed with {Protocol::URL::Reference}. Handlers receive
|
|
13
|
-
# the original request
|
|
14
|
-
class Router
|
|
15
|
-
EMPTY_PARAMETERS = {}.freeze
|
|
13
|
+
# the original request.
|
|
14
|
+
class Router < Protocol::HTTP::Middleware
|
|
16
15
|
ANY_METHOD = nil
|
|
17
|
-
private_constant :
|
|
16
|
+
private_constant :ANY_METHOD
|
|
18
17
|
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
# Builds an immutable route table.
|
|
19
|
+
class Builder
|
|
20
|
+
# Initialize a route builder.
|
|
21
|
+
def initialize
|
|
22
|
+
@routes = {}
|
|
23
|
+
end
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
# A frozen snapshot of the configured routes.
|
|
26
|
+
# @returns [Hash] The route table.
|
|
27
|
+
def routes
|
|
28
|
+
@routes.transform_values do |handlers|
|
|
29
|
+
handlers.dup.freeze
|
|
30
|
+
end.freeze
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Add a route.
|
|
34
|
+
#
|
|
35
|
+
# When `methods` is omitted, the handler accepts every HTTP method. Otherwise,
|
|
36
|
+
# it may be a single method or an array of methods.
|
|
37
|
+
#
|
|
38
|
+
# @parameter path [String] The absolute path to match.
|
|
39
|
+
# @parameter handler [Interface(:call) | Nil] A callable route handler.
|
|
40
|
+
# @parameter methods [String | Symbol | Array(String | Symbol) | Nil] The accepted HTTP methods.
|
|
41
|
+
# @yields {|request| ...} The route handler.
|
|
42
|
+
# @parameter request [Protocol::HTTP::Request] The original request.
|
|
43
|
+
# @returns [Builder] The builder.
|
|
44
|
+
def route(path, handler = nil, methods: nil, &block)
|
|
45
|
+
raise ArgumentError, "Provide a route handler or block, not both!" if handler && block
|
|
46
|
+
handler ||= block
|
|
47
|
+
raise ArgumentError, "A route handler is required!" unless handler
|
|
48
|
+
|
|
49
|
+
path = route_path(path)
|
|
50
|
+
methods = route_methods(methods)
|
|
51
|
+
handlers = (@routes[path] ||= {})
|
|
52
|
+
|
|
53
|
+
methods.each do |method|
|
|
54
|
+
if handlers.key?(method)
|
|
55
|
+
raise ArgumentError, "Route already defined for #{method || "any method"} #{path}!"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
handlers[method] = handler
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
return self
|
|
62
|
+
end
|
|
40
63
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
Protocol::HTTP::Methods.each do |name, method|
|
|
65
|
+
# Add a route for this HTTP method.
|
|
66
|
+
# @parameter path [String] The absolute path to match.
|
|
67
|
+
# @yields {|request| ...} The route handler.
|
|
68
|
+
# @returns [Builder] The builder.
|
|
69
|
+
define_method(name) do |path, handler = nil, &block|
|
|
70
|
+
route(path, handler, methods: method, &block)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
44
75
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
76
|
+
def route_path(path)
|
|
77
|
+
url = Protocol::URL[path]
|
|
78
|
+
|
|
79
|
+
unless url && !url.is_a?(Protocol::URL::Absolute)
|
|
80
|
+
raise ArgumentError, "Route must be an absolute path: #{path.inspect}!"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
reference = Protocol::URL::Reference[url]
|
|
84
|
+
|
|
85
|
+
unless reference.path.absolute?
|
|
86
|
+
raise ArgumentError, "Route must be an absolute path: #{path.inspect}!"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if reference.query? || reference.fragment?
|
|
90
|
+
raise ArgumentError, "Route path cannot include a query or fragment: #{path.inspect}!"
|
|
48
91
|
end
|
|
49
92
|
|
|
50
|
-
|
|
93
|
+
return reference.path.freeze
|
|
51
94
|
end
|
|
52
95
|
|
|
53
|
-
|
|
96
|
+
def route_methods(methods)
|
|
97
|
+
return [ANY_METHOD] unless methods
|
|
98
|
+
|
|
99
|
+
methods = Array(methods)
|
|
100
|
+
raise ArgumentError, "At least one HTTP method is required!" if methods.empty?
|
|
101
|
+
|
|
102
|
+
return methods.map do |method|
|
|
103
|
+
raise ArgumentError, "HTTP method cannot be nil!" unless method
|
|
104
|
+
|
|
105
|
+
method.to_s.upcase
|
|
106
|
+
end.uniq
|
|
107
|
+
end
|
|
54
108
|
end
|
|
55
109
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
110
|
+
# Build and configure a frozen router.
|
|
111
|
+
# @parameter delegate [Protocol::HTTP::Middleware] The middleware for unmatched requests.
|
|
112
|
+
# @yields {|builder| ...} Configures the routes.
|
|
113
|
+
# @parameter builder [Builder] The route builder.
|
|
114
|
+
# @returns [Router] The configured router.
|
|
115
|
+
def self.build(delegate = Protocol::HTTP::Middleware::NotFound)
|
|
116
|
+
builder = Builder.new
|
|
117
|
+
yield builder
|
|
118
|
+
|
|
119
|
+
return new(delegate, builder.routes).freeze
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Initialize a router.
|
|
123
|
+
# @parameter delegate [Protocol::HTTP::Middleware] The middleware for unmatched requests.
|
|
124
|
+
# @parameter routes [Hash] The frozen route table.
|
|
125
|
+
def initialize(delegate, routes)
|
|
126
|
+
super(delegate)
|
|
127
|
+
@routes = routes
|
|
64
128
|
end
|
|
65
129
|
|
|
66
130
|
# Dispatch a request to a matching route.
|
|
67
131
|
# @parameter request [Protocol::HTTP::Request] The request to dispatch.
|
|
68
|
-
# @returns [Protocol::HTTP::Response
|
|
132
|
+
# @returns [Protocol::HTTP::Response] The handler, error, or delegate response.
|
|
69
133
|
def call(request)
|
|
70
134
|
reference = parse_reference(request.path)
|
|
71
135
|
return Protocol::HTTP::Response[400] unless reference
|
|
72
136
|
|
|
73
|
-
unless handlers = @routes[reference.path]
|
|
74
|
-
return nil
|
|
75
|
-
end
|
|
137
|
+
return super unless handlers = @routes[reference.path]
|
|
76
138
|
|
|
77
139
|
unless handler = handlers[request.method] || handlers[ANY_METHOD]
|
|
78
140
|
allowed_methods = handlers.keys.compact.sort.join(", ")
|
|
79
141
|
return Protocol::HTTP::Response[405, [["allow", allowed_methods]]]
|
|
80
142
|
end
|
|
81
143
|
|
|
82
|
-
|
|
83
|
-
return Protocol::HTTP::Response[400] unless parameters
|
|
84
|
-
|
|
85
|
-
return handler.call(request, parameters)
|
|
144
|
+
return handler.call(request)
|
|
86
145
|
end
|
|
87
146
|
|
|
88
147
|
private
|
|
89
148
|
|
|
90
|
-
def route_path(path)
|
|
91
|
-
url = Protocol::URL[path]
|
|
92
|
-
|
|
93
|
-
unless url && !url.is_a?(Protocol::URL::Absolute)
|
|
94
|
-
raise ArgumentError, "Route must be an absolute path: #{path.inspect}!"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
reference = Protocol::URL::Reference[url]
|
|
98
|
-
|
|
99
|
-
unless reference.path.absolute?
|
|
100
|
-
raise ArgumentError, "Route must be an absolute path: #{path.inspect}!"
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
if reference.query? || reference.fragment?
|
|
104
|
-
raise ArgumentError, "Route path cannot include a query or fragment: #{path.inspect}!"
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
return reference.path.freeze
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def route_methods(methods)
|
|
111
|
-
return [ANY_METHOD] unless methods
|
|
112
|
-
|
|
113
|
-
methods = Array(methods)
|
|
114
|
-
raise ArgumentError, "At least one HTTP method is required!" if methods.empty?
|
|
115
|
-
|
|
116
|
-
return methods.map do |method|
|
|
117
|
-
raise ArgumentError, "HTTP method cannot be nil!" unless method
|
|
118
|
-
|
|
119
|
-
method.to_s.upcase
|
|
120
|
-
end.uniq
|
|
121
|
-
end
|
|
122
|
-
|
|
123
149
|
def parse_reference(path)
|
|
124
150
|
reference = Protocol::URL::Reference[path]
|
|
125
151
|
return if reference&.fragment?
|
|
126
152
|
|
|
127
153
|
return reference
|
|
128
|
-
rescue ArgumentError
|
|
129
|
-
nil
|
|
130
154
|
end
|
|
131
155
|
|
|
132
|
-
def parse_query(reference)
|
|
133
|
-
reference.parse_query! || EMPTY_PARAMETERS
|
|
134
|
-
rescue ArgumentError
|
|
135
|
-
nil
|
|
136
|
-
end
|
|
137
156
|
end
|
|
138
157
|
end
|
data/lib/lively/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lively
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -114,28 +114,28 @@ dependencies:
|
|
|
114
114
|
requirements:
|
|
115
115
|
- - "~>"
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: '0.
|
|
117
|
+
version: '0.19'
|
|
118
118
|
type: :runtime
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '0.
|
|
124
|
+
version: '0.19'
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: protocol-url
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
128
128
|
requirements:
|
|
129
129
|
- - "~>"
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: '0.
|
|
131
|
+
version: '0.19'
|
|
132
132
|
type: :runtime
|
|
133
133
|
prerelease: false
|
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
|
136
136
|
- - "~>"
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
|
-
version: '0.
|
|
138
|
+
version: '0.19'
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
140
|
name: xrb
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
metadata.gz.sig
CHANGED
|
Binary file
|