simple-httpd 0.3.0 → 0.3.1
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
- data/.rubocop.yml +7 -0
- data/Gemfile +3 -1
- data/VERSION +1 -1
- data/bin/simple-httpd +1 -3
- data/examples/ex1.services/ex1_service_module.rb +8 -0
- data/examples/ex1/root.rb +4 -0
- data/examples/ex1/spec.rb +7 -0
- data/examples/ex2/info.rb +5 -3
- data/examples/ex3/example_service.rb +3 -2
- data/lib/simple/httpd.rb +37 -28
- data/lib/simple/httpd/base_controller.rb +6 -0
- data/lib/simple/httpd/base_controller/build_url.rb +1 -1
- data/lib/simple/httpd/base_controller/debug.rb +2 -0
- data/lib/simple/httpd/base_controller/error_handling.rb +21 -38
- data/lib/simple/httpd/base_controller/json.rb +2 -31
- data/lib/simple/httpd/base_controller/request.rb +23 -0
- data/lib/simple/httpd/base_controller/result.rb +19 -0
- data/lib/simple/httpd/cli.rb +71 -30
- data/lib/simple/httpd/helpers.rb +35 -3
- data/lib/simple/httpd/mount.rb +66 -0
- data/lib/simple/httpd/rack/dynamic_mount.rb +52 -32
- data/lib/simple/httpd/rack/static_mount.rb +20 -14
- data/lib/simple/httpd/route.rb +79 -0
- data/lib/simple/httpd/server.rb +28 -16
- data/lib/simple/httpd/service_adapter.rb +108 -0
- data/simple-httpd.gemspec +2 -1
- data/spec/simple/httpd/base_controller/httpd_cors_spec.rb +8 -3
- data/spec/simple/httpd/base_controller/httpd_url_building_spec.rb +17 -0
- data/spec/simple/httpd/helpers_spec.rb +25 -8
- data/spec/simple/httpd/loading_helpers_spec.rb +15 -0
- data/spec/simple/httpd/rspec_httpd_spec.rb +25 -9
- data/spec/simple/httpd/services/service_explicit_spec.rb +0 -5
- data/spec/simple/httpd/services/sideloading_spec.rb +9 -0
- data/spec/spec_helper.rb +2 -3
- metadata +31 -12
- data/examples/services/example_service.rb +0 -25
- data/lib/simple/httpd/mount_spec.rb +0 -106
- data/lib/simple/httpd/service.rb +0 -70
- data/lib/simple/service.rb +0 -69
- data/lib/simple/service/action.rb +0 -78
- data/lib/simple/service/context.rb +0 -46
- data/spec/simple/httpd/services/service_spec.rb +0 -34
data/lib/simple/httpd/cli.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
2
|
-
|
3
1
|
module Simple
|
4
2
|
class Httpd
|
5
3
|
class << self
|
@@ -11,9 +9,13 @@ end
|
|
11
9
|
module Simple::Httpd::CLI
|
12
10
|
include Simple::CLI
|
13
11
|
|
12
|
+
def logger
|
13
|
+
::Simple::CLI.logger
|
14
|
+
end
|
15
|
+
|
14
16
|
# Runs a simple httpd server
|
15
17
|
#
|
16
|
-
# A
|
18
|
+
# A mount is either the location of a directory, which would then be mounted
|
17
19
|
# at the "/" HTTP location, or a directory followed by a colon and where to mount
|
18
20
|
# the directory.
|
19
21
|
#
|
@@ -22,7 +24,9 @@ module Simple::Httpd::CLI
|
|
22
24
|
#
|
23
25
|
# Examples:
|
24
26
|
#
|
25
|
-
# simple-httpd
|
27
|
+
# PORT=8080 simple-httpd start httpd/root --service=src/to/service.rb \
|
28
|
+
# MyService:/
|
29
|
+
# httpd/assets:assets
|
26
30
|
#
|
27
31
|
# serves the content of ./httpd/root on http://0.0.0.0/ and the content of httpd/assets
|
28
32
|
# on http://0.0.0.0/assets.
|
@@ -30,7 +34,8 @@ module Simple::Httpd::CLI
|
|
30
34
|
# Options:
|
31
35
|
#
|
32
36
|
# --environment=ENV ... the environment setting, which adjusts configuration.
|
33
|
-
# --services=<path>,<path> ... load these ruby
|
37
|
+
# --services=<path>,<path> ... load these ruby files or directories during startup. This
|
38
|
+
# can be used to define service objects.
|
34
39
|
#
|
35
40
|
# simple-httpd respects the HOST and PORT environment values to determine the interface
|
36
41
|
# and port to listen to. Default values are "127.0.0.1" and 8181.
|
@@ -40,40 +45,76 @@ module Simple::Httpd::CLI
|
|
40
45
|
# - a mount_point <tt>[ mount_point, path ]</tt>, e.g. <tt>[ "path/to/root", "/"]</tt>
|
41
46
|
# - a string denoting a mount_point, e.g. "path/to/root:/")
|
42
47
|
# - a string denoting a "/" mount_point (e.g. "path", which is shorthand for "path:/")
|
43
|
-
def
|
44
|
-
|
48
|
+
def start(*mounts, environment: "development", services: nil)
|
49
|
+
host = ENV["HOST"] || "127.0.0.1"
|
50
|
+
port = Integer(ENV["PORT"] || 8181)
|
45
51
|
|
46
|
-
|
52
|
+
prepare_environment!(environment: environment)
|
53
|
+
|
54
|
+
app = build_app!(mounts: mounts, services: services)
|
55
|
+
logger.info "start to listen on #{mounts.inspect}"
|
56
|
+
::Simple::Httpd.listen!(app, environment: environment,
|
57
|
+
host: host,
|
58
|
+
port: port)
|
59
|
+
end
|
47
60
|
|
48
|
-
|
61
|
+
def routes(*mounts, environment: "development", services: nil)
|
62
|
+
prepare_environment!(environment: environment)
|
63
|
+
app = build_app!(mounts: mounts, services: services)
|
64
|
+
routes = app.route_descriptions
|
49
65
|
|
50
|
-
|
51
|
-
|
66
|
+
logger.info "Found #{routes.count} routes"
|
67
|
+
|
68
|
+
max_verb_len = routes.map(&:verb).map(&:length).max
|
69
|
+
max_path_len = routes.map(&:path).map(&:length).max
|
70
|
+
|
71
|
+
routes.
|
72
|
+
sort_by { |route| [route.path, route.verb] }.
|
73
|
+
each { |route|
|
74
|
+
puts format("%#{max_verb_len}s %-#{max_path_len}s %s", route.verb, route.path, route.source_location_str)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def prepare_environment!(environment:)
|
81
|
+
::Simple::Httpd.env = environment
|
82
|
+
start_simplecov if environment == "test"
|
52
83
|
|
53
84
|
# late loading simple/httpd, for simplecov support
|
54
85
|
require "simple/httpd"
|
55
|
-
|
56
|
-
|
57
|
-
services&.split(",")&.each do |service_path|
|
58
|
-
paths = if Dir.exist?(service_path)
|
59
|
-
Dir.glob("#{service_path}/**/*.rb").sort
|
60
|
-
else
|
61
|
-
[service_path]
|
62
|
-
end
|
63
|
-
|
64
|
-
paths.each do |path|
|
65
|
-
logger.info "Loading service(s) from #{helpers.shorten_path path}"
|
66
|
-
load path
|
67
|
-
end
|
68
|
-
end
|
86
|
+
end
|
69
87
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
def build_app!(mounts:, services:)
|
89
|
+
mounts << "." if mounts.empty?
|
90
|
+
logger.info "building server on #{mounts.inspect}"
|
91
|
+
|
92
|
+
load_services! services if services
|
93
|
+
app = ::Simple::Httpd.build(*mounts)
|
94
|
+
app.rack # builds the rack application
|
95
|
+
app
|
74
96
|
end
|
75
97
|
|
76
|
-
|
98
|
+
def load_services!(paths)
|
99
|
+
expect! paths => String
|
100
|
+
|
101
|
+
resolve_service_path(paths).each do |path|
|
102
|
+
logger.info "Loading service(s) from #{::Simple::Httpd::Helpers.shorten_path path}"
|
103
|
+
load path
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def resolve_service_path(paths)
|
108
|
+
# each service_path either denotes the path to a file or to a directory
|
109
|
+
# of files.
|
110
|
+
paths.split(",").each_with_object([]) do |service_path, ary|
|
111
|
+
if Dir.exist?(service_path)
|
112
|
+
ary.concat Dir.glob("#{service_path}/**/*.rb").sort
|
113
|
+
else
|
114
|
+
ary << service_path
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
77
118
|
|
78
119
|
def stderr_logger
|
79
120
|
logger = ::Logger.new STDERR
|
data/lib/simple/httpd/helpers.rb
CHANGED
@@ -37,8 +37,10 @@ module Simple::Httpd::Helpers
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# instance_eval zero or more paths in the context of obj
|
40
|
-
def instance_eval_paths(obj,
|
41
|
-
|
40
|
+
def instance_eval_paths(obj, paths:)
|
41
|
+
return obj unless paths
|
42
|
+
|
43
|
+
Array(paths).each do |path|
|
42
44
|
# STDERR.puts "Loading #{path}"
|
43
45
|
obj.instance_eval File.read(path), path, 1
|
44
46
|
end
|
@@ -46,9 +48,39 @@ module Simple::Httpd::Helpers
|
|
46
48
|
end
|
47
49
|
|
48
50
|
# subclass a klass with an optional description
|
49
|
-
def subclass(klass, description: nil)
|
51
|
+
def subclass(klass, paths: nil, description: nil)
|
52
|
+
raise "Missing description" unless description
|
53
|
+
|
50
54
|
subclass = Class.new(klass)
|
51
55
|
subclass.define_method(:inspect) { description } if description
|
56
|
+
instance_eval_paths subclass, paths: paths if paths
|
52
57
|
subclass
|
53
58
|
end
|
59
|
+
|
60
|
+
def filter_stacktrace_entry?(line)
|
61
|
+
return true if line =~ /\.rvm\b/
|
62
|
+
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
# Receives a stacktrace (like, for example, from Kernel#callers or
|
67
|
+
# from Exception#backtrace), and removes all lines that point to
|
68
|
+
# ".rvm". It also removes the working directory from the file paths.
|
69
|
+
#
|
70
|
+
# returns the cleaned array
|
71
|
+
def filtered_stacktrace(stacktrace, count: 20)
|
72
|
+
lines = []
|
73
|
+
|
74
|
+
stacktrace[0..count].inject(false) do |filtered_last_line, line|
|
75
|
+
if filter_stacktrace_entry?(line)
|
76
|
+
lines << "... (lines removed) ..." unless filtered_last_line
|
77
|
+
true
|
78
|
+
else
|
79
|
+
lines << shorten_path(line)
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
lines
|
85
|
+
end
|
54
86
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "simple-service"
|
2
|
+
require_relative "./rack"
|
3
|
+
|
4
|
+
module Simple::Httpd::Mount
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def build(arg, at:)
|
8
|
+
if at
|
9
|
+
entity, mount_point = arg, at
|
10
|
+
else
|
11
|
+
# The regexp below uses negative lookbehind and negative lookahead to
|
12
|
+
# only match single colons, but not double (or more) colons. See
|
13
|
+
# `ri Regexp` for details.
|
14
|
+
entity, mount_point = *arg.split(/(?<!:):(?!:)/, 2)
|
15
|
+
end
|
16
|
+
|
17
|
+
mount_point = normalize_and_verify_mount_point(mount_point)
|
18
|
+
|
19
|
+
PathMount.build(mount_point, path: entity) ||
|
20
|
+
raise(ArgumentError, "#{mount_point}: don't know how to mount #{entity.inspect}")
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def normalize_and_verify_mount_point(mount_point)
|
26
|
+
mount_point ||= "/" # fall back to "/"
|
27
|
+
mount_point = File.join("/", mount_point) # make sure we start at "/"
|
28
|
+
|
29
|
+
canary_url = "http://0.0.0.0#{mount_point}" # verify mount_point: can it be used to build a URL?
|
30
|
+
URI.parse canary_url
|
31
|
+
|
32
|
+
mount_point
|
33
|
+
end
|
34
|
+
|
35
|
+
class PathMount
|
36
|
+
Rack = ::Simple::Httpd::Rack
|
37
|
+
|
38
|
+
attr_reader :path, :mount_point
|
39
|
+
|
40
|
+
def self.build(mount_point, path:)
|
41
|
+
path = path.gsub(/\/$/, "") # remove trailing "/"
|
42
|
+
|
43
|
+
raise ArgumentError, "You probably don't want to mount your root directory, check mount" if path == ""
|
44
|
+
return unless Dir.exist?(path)
|
45
|
+
|
46
|
+
new(mount_point, path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(mount_point, path)
|
50
|
+
@mount_point, @path = mount_point, path
|
51
|
+
end
|
52
|
+
|
53
|
+
def route_descriptions
|
54
|
+
build_rack_apps.inject([]) do |ary, app|
|
55
|
+
ary.concat app.route_descriptions
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_rack_apps
|
60
|
+
dynamic_mount = Rack::DynamicMount.build(mount_point, path)
|
61
|
+
static_mount = Rack::StaticMount.build(mount_point, path)
|
62
|
+
|
63
|
+
[dynamic_mount, static_mount].compact
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -7,12 +7,13 @@ class Simple::Httpd::Rack::DynamicMount
|
|
7
7
|
H = ::Simple::Httpd::Helpers
|
8
8
|
Rack = ::Simple::Httpd::Rack
|
9
9
|
|
10
|
-
|
11
|
-
expect! path => String
|
10
|
+
extend Forwardable
|
12
11
|
|
13
|
-
|
12
|
+
delegate :call => :@rack_app # rubocop:disable Style/HashSyntax
|
14
13
|
|
15
|
-
|
14
|
+
def self.build(mount_point, path)
|
15
|
+
expect! path => String
|
16
|
+
new(mount_point, path)
|
16
17
|
end
|
17
18
|
|
18
19
|
attr_reader :path
|
@@ -20,47 +21,66 @@ class Simple::Httpd::Rack::DynamicMount
|
|
20
21
|
|
21
22
|
def initialize(mount_point, path)
|
22
23
|
@mount_point = mount_point
|
23
|
-
@path = path
|
24
|
+
@path = path.gsub(/\/\z/, "") # remove trailing "/"
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
setup_paths!
|
27
|
+
load_service_files!
|
28
|
+
@root_controller = build_root_controller # also loads helpers
|
29
|
+
@url_map = build_url_map
|
28
30
|
|
29
|
-
|
30
|
-
@root_controller = build_root_controller(helper_paths)
|
31
|
+
@rack_app = ::Rack::URLMap.new(@url_map)
|
31
32
|
end
|
32
33
|
|
33
|
-
#
|
34
|
-
|
35
|
-
@controller_paths.sort.each_with_object({}) do |absolute_path, url_map|
|
36
|
-
relative_path = absolute_path[(path.length)..-1]
|
34
|
+
# RouteDescriptions are being built during build_url_map
|
35
|
+
include ::Simple::Httpd::RouteDescriptions
|
37
36
|
|
38
|
-
|
39
|
-
controller_class = load_controller absolute_path
|
37
|
+
private
|
40
38
|
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
def logger
|
40
|
+
::Simple::Httpd.logger
|
41
|
+
end
|
44
42
|
|
45
|
-
|
46
|
-
|
43
|
+
def setup_paths!
|
44
|
+
@source_paths = Dir.glob("#{path}/**/*.rb")
|
45
|
+
@helper_paths, @controller_paths = @source_paths.partition { |str| /_helper(s?)\.rb$/ =~ str }
|
46
|
+
|
47
|
+
logger.info "#{path}: found #{@source_paths.count} sources, #{@helper_paths.count} helpers"
|
48
|
+
end
|
47
49
|
|
48
|
-
|
50
|
+
def load_service_files!
|
51
|
+
return if path == "." # i.e. mounting current directory
|
52
|
+
|
53
|
+
service_path = "#{path}.services"
|
54
|
+
service_files = Dir.glob("#{service_path}/**/*.rb")
|
55
|
+
return if service_files.empty?
|
56
|
+
|
57
|
+
logger.info "#{service_path}: loading #{service_files.count} service file(s)"
|
58
|
+
service_files.sort.each do |path|
|
59
|
+
logger.debug "Loading service file #{path.inspect}"
|
60
|
+
load path
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
52
64
|
# wraps all helpers into a Simple::Httpd::BaseController subclass
|
53
|
-
def build_root_controller
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
H.instance_eval_paths klass, *helper_paths.sort
|
58
|
-
klass
|
65
|
+
def build_root_controller
|
66
|
+
H.subclass ::Simple::Httpd::BaseController,
|
67
|
+
paths: @helper_paths.sort,
|
68
|
+
description: "root controller at #{path} w/#{@helper_paths.count} helpers"
|
59
69
|
end
|
60
70
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
71
|
+
def build_url_map
|
72
|
+
@controller_paths.sort.each_with_object({}) do |absolute_path, hsh|
|
73
|
+
relative_path = absolute_path[(path.length)..-1]
|
74
|
+
|
75
|
+
relative_mount_point = relative_path == "/root.rb" ? "/" : relative_path.gsub(/\.rb$/, "")
|
76
|
+
controller_class = H.subclass @root_controller, description: "controller at #{absolute_path}", paths: absolute_path
|
77
|
+
|
78
|
+
controller_class.route_descriptions.each do |route|
|
79
|
+
route = route.prefix(@mount_point, relative_mount_point)
|
80
|
+
describe_route! route
|
81
|
+
end
|
82
|
+
|
83
|
+
hsh.update relative_mount_point => controller_class
|
84
|
+
end
|
65
85
|
end
|
66
86
|
end
|
@@ -1,48 +1,54 @@
|
|
1
1
|
# A simple file server middleware
|
2
2
|
class Simple::Httpd::Rack::StaticMount
|
3
|
+
H = ::Simple::Httpd::Helpers
|
3
4
|
Rack = ::Simple::Httpd::Rack
|
4
5
|
|
5
6
|
EXTENSIONS = %w(.txt .md .js .css .png .jpeg .jpg)
|
7
|
+
GLOB_PATTERN = "**/*.{#{EXTENSIONS.map { |s| s[1..-1] }.join(",")}}"
|
6
8
|
|
7
9
|
def self.build(mount_point, path)
|
8
|
-
static_files =
|
10
|
+
static_files = Dir.chdir(path) { Dir.glob(GLOB_PATTERN) }
|
11
|
+
|
9
12
|
return nil if static_files.empty?
|
10
13
|
|
11
14
|
::Simple::Httpd.logger.info do
|
12
15
|
"#{mount_point}: serving #{static_files.count} static file(s)"
|
13
16
|
end
|
14
17
|
|
15
|
-
new(path, static_files)
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.static_files(path)
|
19
|
-
Dir.chdir(path) do
|
20
|
-
pattern = "**/*{" + EXTENSIONS.join(",") + "}"
|
21
|
-
Dir.glob(pattern)
|
22
|
-
end
|
18
|
+
new(mount_point, path, static_files)
|
23
19
|
end
|
24
20
|
|
25
21
|
attr_reader :mount_point, :path
|
26
22
|
|
27
|
-
|
23
|
+
private
|
24
|
+
|
25
|
+
def initialize(mount_point, path, static_files)
|
26
|
+
@mount_point = mount_point
|
28
27
|
@path = path
|
29
28
|
@static_files = Set.new(static_files)
|
29
|
+
@file_server = ::Rack::File.new(path)
|
30
|
+
|
31
|
+
describe_route! verb: "GET",
|
32
|
+
path: File.join(mount_point, GLOB_PATTERN),
|
33
|
+
source_location: File.join(H.shorten_path(path), GLOB_PATTERN)
|
30
34
|
end
|
31
35
|
|
36
|
+
include ::Simple::Httpd::RouteDescriptions
|
37
|
+
|
38
|
+
public
|
39
|
+
|
32
40
|
def call(env)
|
33
41
|
request_path = env["PATH_INFO"]
|
34
42
|
if serve_file?(request_path)
|
35
43
|
file_path = request_path[1..-1]
|
36
44
|
env["PATH_INFO"] = file_path
|
37
|
-
file_server.call(env)
|
45
|
+
@file_server.call(env)
|
38
46
|
else
|
39
47
|
Rack.error 404, "No such file"
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
43
|
-
|
44
|
-
@file_server ||= ::Rack::File.new(path)
|
45
|
-
end
|
51
|
+
private
|
46
52
|
|
47
53
|
def serve_file?(request_path)
|
48
54
|
@static_files.include?(request_path[1..-1])
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Simple::Httpd::Route
|
2
|
+
H = ::Simple::Httpd::Helpers
|
3
|
+
SELF = self
|
4
|
+
|
5
|
+
attr_reader :verb, :path, :source_location
|
6
|
+
|
7
|
+
def self.build(route)
|
8
|
+
expect! route => [
|
9
|
+
::Simple::Httpd::Route,
|
10
|
+
{
|
11
|
+
verb: %w(GET POST PUT DELETE HEAD OPTIONS),
|
12
|
+
path: String,
|
13
|
+
source_location: [nil, Array, String]
|
14
|
+
}
|
15
|
+
]
|
16
|
+
|
17
|
+
return route if route.is_a?(self)
|
18
|
+
|
19
|
+
::Simple::Httpd::Route.new(*route.values_at(:verb, :path, :source_location))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def initialize(verb, path, source_location)
|
25
|
+
@verb = verb
|
26
|
+
@path = path
|
27
|
+
@source_location = source_location
|
28
|
+
end
|
29
|
+
|
30
|
+
public
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
parts = [verb, path, source_location_str]
|
34
|
+
parts.compact.join " "
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
"<#{SELF.name}: #{self}>"
|
39
|
+
end
|
40
|
+
|
41
|
+
def prefix(*prefixes)
|
42
|
+
SELF.new(verb, File.join(*prefixes, path), source_location)
|
43
|
+
end
|
44
|
+
|
45
|
+
def source_location_str
|
46
|
+
case source_location
|
47
|
+
when Array
|
48
|
+
path, lineno = *source_location
|
49
|
+
path = H.shorten_path(path)
|
50
|
+
"#{path}:#{lineno}"
|
51
|
+
when String, nil
|
52
|
+
source_location
|
53
|
+
else
|
54
|
+
source_location.inspect
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module Simple::Httpd::RouteDescriptions
|
60
|
+
# returns a list of route desc entries.
|
61
|
+
#
|
62
|
+
# When building a simple-httpd application we also collect all routes defined
|
63
|
+
# via get, put, etc., including their source location (which, for example,
|
64
|
+
# might point to a service's method or to a controller source file).
|
65
|
+
#
|
66
|
+
# (see <tt>Simple::Httpd::Route</tt>).
|
67
|
+
def route_descriptions
|
68
|
+
@route_descriptions ||= []
|
69
|
+
end
|
70
|
+
|
71
|
+
# Adds a route description.
|
72
|
+
#
|
73
|
+
# The argument must either be a Route, or an argument acceptable to Route.build.
|
74
|
+
#
|
75
|
+
# (see <tt>Simple::Httpd::Route</tt>).
|
76
|
+
def describe_route!(route)
|
77
|
+
route_descriptions << ::Simple::Httpd::Route.build(route)
|
78
|
+
end
|
79
|
+
end
|