intranet-core 1.0.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 +7 -0
- data/README.md +38 -0
- data/lib/core_extensions.rb +12 -0
- data/lib/core_extensions/string.rb +43 -0
- data/lib/core_extensions/tree.rb +84 -0
- data/lib/core_extensions/webrick/httpresponse.rb +22 -0
- data/lib/intranet/abstract_responder.rb +34 -0
- data/lib/intranet/core.rb +125 -0
- data/lib/intranet/core/builder.rb +98 -0
- data/lib/intranet/core/haml_wrapper.rb +60 -0
- data/lib/intranet/core/locales.rb +47 -0
- data/lib/intranet/core/servlet.rb +42 -0
- data/lib/intranet/core/version.rb +8 -0
- data/lib/intranet/logger.rb +38 -0
- data/lib/intranet/resources/haml/http_error.haml +27 -0
- data/lib/intranet/resources/haml/skeleton.haml +52 -0
- data/lib/intranet/resources/haml/title_and_breadcrumb.haml +8 -0
- data/lib/intranet/resources/locales/en.yml +46 -0
- data/lib/intranet/resources/locales/fr.yml +46 -0
- data/lib/intranet/resources/www/background.jpg +0 -0
- data/lib/intranet/resources/www/error.png +0 -0
- data/lib/intranet/resources/www/favicon.ico +0 -0
- data/lib/intranet/resources/www/fonts/SourceSansPro.woff2 +0 -0
- data/lib/intranet/resources/www/nav.js +25 -0
- data/lib/intranet/resources/www/style.css +306 -0
- data/spec/core_extensions/string_spec.rb +135 -0
- data/spec/core_extensions/tree_spec.rb +208 -0
- data/spec/core_extensions/webrick/httpresponse_spec.rb +43 -0
- data/spec/intranet/core/fr.yml +5 -0
- data/spec/intranet/core/haml_wrapper_spec.rb +70 -0
- data/spec/intranet/core/locales_spec.rb +74 -0
- data/spec/intranet/core_spec.rb +403 -0
- data/spec/intranet/logger_spec.rb +129 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/test_responder/responder.rb +42 -0
- data/spec/test_responder/www/style.css +5 -0
- metadata +218 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e210409259e3ae615be11b386d4f59eba6857577
|
4
|
+
data.tar.gz: a971e1e9e6aac78e4ca5fc5503fc47682514a587
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 99566f62fd07cc59ba83f622469b433f2cfea9e099c0d6a14192e8ab00f2fb7857f31c1b18aff1b1a42cc35945334735c28164b868cb90b2d5d2e6175473a705
|
7
|
+
data.tar.gz: 239ded33d2cb26e300ae0b6d7d8b071d84d7d5e205ade2a10c0bf443f599f201aecfb5a6fa7ddaa8523f312782d0e7bc864770da0d51fe1db35bcf2bb922d435
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# intranet-core
|
2
|
+
|
3
|
+
`intranet-core` provides the core component of a generic, highly customizable
|
4
|
+
intranet built around [WEBrick HTTP server](https://rubygems.org/gems/webrick).
|
5
|
+
Each section of the intranet can be provided by a different _module_, which
|
6
|
+
is basically a Webrick servlet in charge of a specific subdirectory of the
|
7
|
+
web server.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### Creating a custom _module_
|
12
|
+
|
13
|
+
You can create a new _module_ by deriving from `Intranet::AbstractResponder`:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'intranet/abstract_responder'
|
17
|
+
|
18
|
+
class MyModule << Intranet::AbstractResponder
|
19
|
+
def initialize(params = {})
|
20
|
+
@params = params
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_page(path, query)
|
24
|
+
# generate HTML for the given path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
### Starting the Intranet
|
30
|
+
|
31
|
+
The Intranet is controlled by the `Intranet::Core` class.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
intranet = Intranet::Core.new
|
35
|
+
module = MyModule.new
|
36
|
+
intranet.register_module(module, 'my_module', __dir__)
|
37
|
+
intranet.start
|
38
|
+
```
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'core_extensions/string'
|
4
|
+
require_relative 'core_extensions/tree'
|
5
|
+
require_relative 'core_extensions/webrick/httpresponse'
|
6
|
+
|
7
|
+
String.include CoreExtensions::String
|
8
|
+
WEBrick::HTTPResponse.include CoreExtensions::WEBrick::HTTPResponse
|
9
|
+
|
10
|
+
# @!visibility protected
|
11
|
+
module CoreExtensions
|
12
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CoreExtensions
|
4
|
+
# @!visibility protected
|
5
|
+
# Extension of Ruby's standard library +String+ class.
|
6
|
+
module String
|
7
|
+
# Replaces all accented characters in a string with their non-accented version.
|
8
|
+
# @return [String]
|
9
|
+
def unaccentize # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
10
|
+
tr('ÀÁÂÃÄÅàáâãäåĀāĂ㥹', 'AAAAAAaaaaaaAaAaAa')
|
11
|
+
.tr('ÇçĆćĈĉĊċČčÐðĎďĐđ', 'CcCcCcCcCcDdDdDd')
|
12
|
+
.tr('ÈÉÊËèéêëĒēĔĕĖėĘęĚě', 'EEEEeeeeEeEeEeEeEe')
|
13
|
+
.tr('ĜĝĞğĠġĢģĤĥĦħ', 'GgGgGgGgHhHh')
|
14
|
+
.tr('ÌÍÎÏìíîïĨĩĪīĬĭĮįİı', 'IIIIiiiiIiIiIiIiIi')
|
15
|
+
.tr('ĴĵĶķĸĹĺĻļĽľĿŀŁł', 'JjKkkLlLlLlLlLl')
|
16
|
+
.tr('ÑñŃńŅņŇňʼnŊŋ', 'NnNnNnNnnNn')
|
17
|
+
.tr('ÒÓÔÕÖØòóôõöøŌōŎŏŐő', 'OOOOOOooooooOoOoOo')
|
18
|
+
.tr('ŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧ', 'RrRrRrSsSsSsSssTtTtTt')
|
19
|
+
.tr('ÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲų', 'UUUUuuuuUuUuUuUuUuUu')
|
20
|
+
.tr('ŴŵÝýÿŶŷŸŹźŻżŽž', 'WwYyyYyYZzZzZz')
|
21
|
+
.gsub(/ß/, 'ss')
|
22
|
+
.gsub(/Æ/, 'AE')
|
23
|
+
.gsub(/æ/, 'ae')
|
24
|
+
.gsub(/Œ/, 'OE')
|
25
|
+
.gsub(/œ/, 'oe')
|
26
|
+
.gsub(/IJ/, 'IJ')
|
27
|
+
.gsub(/ij/, 'ij')
|
28
|
+
end
|
29
|
+
|
30
|
+
# Converts a string to a snake-cased format suitable for URL and/or CSS attributes.
|
31
|
+
# @return [String]
|
32
|
+
def urlize
|
33
|
+
strip.unaccentize.downcase.tr(' \'', '_').delete('^-_a-z0-9')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Tests whether a string is urlize-d, ie. it is only constituted of characters suitable for URL
|
37
|
+
# and/or CSS attributes.
|
38
|
+
# @return [Boolean]
|
39
|
+
def urlized?
|
40
|
+
scan(/[^-_a-z0-9]/).empty?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CoreExtensions
|
4
|
+
# N-ary tree data structure.
|
5
|
+
# Each node of the tree contains an +Object+ (the node value) and can be accessed from its parent
|
6
|
+
# node using an identifier +Object+. A node can be identified uniquely by the succession of
|
7
|
+
# identifiers that lead from the tree root to itself.
|
8
|
+
class Tree
|
9
|
+
# The value of the current tree node.
|
10
|
+
attr_accessor :value
|
11
|
+
|
12
|
+
# The child nodes of the current tree node.
|
13
|
+
# @return [Hash]
|
14
|
+
attr_reader :children_nodes
|
15
|
+
|
16
|
+
# Creates a new tree with a root element and no child nodes.
|
17
|
+
# @param node_value [Object] The value associated to the root element
|
18
|
+
def initialize(node_value = nil)
|
19
|
+
@value = node_value
|
20
|
+
@children_nodes = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Queries
|
24
|
+
|
25
|
+
# Check if the current Tree node has children.
|
26
|
+
def children?
|
27
|
+
!@children_nodes.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Tests whether the current tree node has a specific child.
|
31
|
+
# @param child_id [Object] The unique identifier of the child.
|
32
|
+
# @return [Boolean] True if the child node identified by +child_id+ exists, False otherwise.
|
33
|
+
def child_exists?(child_id)
|
34
|
+
child_node(child_id)
|
35
|
+
true
|
36
|
+
rescue KeyError
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Retrieves the child of the current tree node.
|
41
|
+
# @param child_id [Object] The unique identifier of the child.
|
42
|
+
# @return [Object] The node value of the child identified by +child_id+.
|
43
|
+
# @raise [KeyError] If the child node identified by +child_id+ does not exist.
|
44
|
+
def child_node(child_id)
|
45
|
+
@children_nodes.fetch(child_id)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a hash representation of the current tree node and all its children, recursively
|
49
|
+
# (depth-first).
|
50
|
+
# @param separator [String] The separator to be used between node identifiers.
|
51
|
+
# @return [Hash]
|
52
|
+
def to_h(separator = '/', id_prefix = '')
|
53
|
+
hash = {}
|
54
|
+
id_prefix.empty? ? hash[separator] = @value : hash[id_prefix] = @value
|
55
|
+
@children_nodes.each do |id, node|
|
56
|
+
hash.merge!(node.to_h(separator, id_prefix + separator + id.to_s))
|
57
|
+
end
|
58
|
+
hash
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the string representation of the current tree node and all its children, recursively
|
62
|
+
# (depth-first).
|
63
|
+
# @return [String]
|
64
|
+
def to_s(offset = '')
|
65
|
+
str = offset + 'VALUE: ' + @value.to_s + "\n"
|
66
|
+
@children_nodes.each do |id, node|
|
67
|
+
str += offset + ' * ID: \'' + id.to_s + '\'' + "\n"
|
68
|
+
str += node.to_s(offset + ' ')
|
69
|
+
end
|
70
|
+
str
|
71
|
+
end
|
72
|
+
|
73
|
+
# Retrieves the value associated to a child node of the current tree node, inserting it first if
|
74
|
+
# it does not exist.
|
75
|
+
# @param child_id [Object] The unique identifier for the child node to retrieve or insert.
|
76
|
+
# @param child_value [Object] The value associated to the child node to insert. Ignored if a
|
77
|
+
# child node identified by the given +child_id+ already exists.
|
78
|
+
# @return [Object] The value associated to the child node identified by the given +child_id+.
|
79
|
+
def add_child_node(child_id, child_value = nil)
|
80
|
+
@children_nodes[child_id] = Tree.new(child_value) if @children_nodes[child_id].nil?
|
81
|
+
@children_nodes[child_id]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'htmlentities'
|
4
|
+
require 'webrick'
|
5
|
+
require_relative '../../intranet/core/haml_wrapper'
|
6
|
+
|
7
|
+
module CoreExtensions
|
8
|
+
# @!visibility protected
|
9
|
+
module WEBrick
|
10
|
+
# @!visibility protected
|
11
|
+
# Extension of +WEBrick::HTTPResponse+ to provide the hook
|
12
|
+
# +create_error_page+.
|
13
|
+
module HTTPResponse
|
14
|
+
include Intranet::Core::HamlWrapper
|
15
|
+
|
16
|
+
# Provides custom error pages for common HTTP errors.
|
17
|
+
def create_error_page
|
18
|
+
@body << to_markup('http_error', error: @status)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Intranet
|
4
|
+
# The default implementation and interface of an Intranet module.
|
5
|
+
class AbstractResponder
|
6
|
+
# Destroys the responder instance.
|
7
|
+
# This method gets called when server is shut down.
|
8
|
+
def finalize
|
9
|
+
# nothing to do
|
10
|
+
end
|
11
|
+
|
12
|
+
# Generates the HTML content associated to the given +path+ and +query+.
|
13
|
+
# @param path [String] The requested URI, relative to that module root URI
|
14
|
+
# @param query [Hash] The URI variable/value pairs, if any
|
15
|
+
# @return [Array] The HTTP return code, the MIME type and the answer body.
|
16
|
+
def generate_page(path, query)
|
17
|
+
[404, '', '']
|
18
|
+
end
|
19
|
+
|
20
|
+
# Provides the list of Cascade Style Sheets (CSS) dependencies for this module.
|
21
|
+
# If redefined, this method should probably append dependencies rather than overwriting them.
|
22
|
+
# @return [Array] The list of CSS dependencies, as URL path from server root
|
23
|
+
def css_dependencies
|
24
|
+
['/design/style.css']
|
25
|
+
end
|
26
|
+
|
27
|
+
# Provides the list of Javascript files (JS) dependencies for this module.
|
28
|
+
# If redefined, this method should probably append dependencies rather than overwriting them.
|
29
|
+
# @return [Array] The list of JS dependencies, as URL path from server root
|
30
|
+
def js_dependencies
|
31
|
+
['/design/nav.js']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'webrick'
|
4
|
+
require_relative 'logger'
|
5
|
+
require_relative 'core/locales'
|
6
|
+
require_relative 'core/haml_wrapper'
|
7
|
+
require_relative 'core/builder'
|
8
|
+
require_relative 'core/servlet'
|
9
|
+
require_relative 'core/version'
|
10
|
+
require_relative '../core_extensions'
|
11
|
+
|
12
|
+
# The main Intranet namespace.
|
13
|
+
module Intranet
|
14
|
+
# The core of the Intranet.
|
15
|
+
class Core
|
16
|
+
# The port currently used by the Intranet.
|
17
|
+
# @return [Integer]
|
18
|
+
attr_reader :port
|
19
|
+
|
20
|
+
# Initializes a new Intranet core instance. The first available port will be used, starting at
|
21
|
+
# +preferred_port+. If +preferred_port+ port is 80 and the user has not enough priviledges to
|
22
|
+
# use that port, port 8080 (or one of the following ports) will be used.
|
23
|
+
# @param logger [Object] The logger.
|
24
|
+
# @param preferred_port [Integer] The preferred port for the web server.
|
25
|
+
def initialize(logger, preferred_port = 80)
|
26
|
+
@logger = logger
|
27
|
+
|
28
|
+
# Initialize translation module
|
29
|
+
Intranet::Core::Locales.initialize
|
30
|
+
|
31
|
+
# Initialize HAML wrapper
|
32
|
+
Intranet::Core::HamlWrapper.initialize
|
33
|
+
|
34
|
+
# Instanciate Intranet Builder and register page builders
|
35
|
+
@builder = Intranet::Core::Builder.new(@logger)
|
36
|
+
|
37
|
+
# Instanciate WebRick HTTP server
|
38
|
+
@server = load_http_server(preferred_port)
|
39
|
+
www_dir = File.join(__dir__, 'resources', 'www')
|
40
|
+
mount_default_servlets(www_dir)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Registers a new module to the core. The server must not be running. If +path+ is empty, the
|
44
|
+
# module will be used as Home module. Otherwise, the module will be accessible through the
|
45
|
+
# given +path+ under the web server root.
|
46
|
+
# @param responder [Intranet::AbstractResponder] The module responder instance.
|
47
|
+
# @param path [Array] The path, relative to the web server root, representing the module root
|
48
|
+
# directory. If empty, the responder will be registered as Home responder
|
49
|
+
# (to serve /index.html in particular). Subdirectories are allowed using
|
50
|
+
# an array element for each directory level. Each element must only contain
|
51
|
+
# the following characters: +-_a-z0-9+.
|
52
|
+
# @param resources_dir [String] The path to the directory that contains additional resources
|
53
|
+
# required by the module. This directory should contain three
|
54
|
+
# subdirectories: +haml/+, +locales/+ and +www/+.
|
55
|
+
# @raise [ArgumentError] If one of the element of the +path+ contains invalid characters.
|
56
|
+
# @raise [Errno::EALREADY] If the server is already running.
|
57
|
+
def register_module(responder, path, resources_dir)
|
58
|
+
raise ArgumentError unless path.all?(&:urlized?)
|
59
|
+
raise Errno::EALREADY if @server.status != :Stop
|
60
|
+
|
61
|
+
@builder.register(responder, path)
|
62
|
+
module_add_servlet(path.empty? ? ['home'] : path, resources_dir)
|
63
|
+
module_add_locales(resources_dir)
|
64
|
+
module_add_haml_templates(resources_dir)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Starts the web server.
|
68
|
+
def start
|
69
|
+
@logger.info('Intranet::Core: using locale \'' + I18n.default_locale.to_s + '\'')
|
70
|
+
@logger.info('Intranet::Core: running Intranet version ' + VERSION)
|
71
|
+
# Start serving HTTP requests
|
72
|
+
@server.start
|
73
|
+
end
|
74
|
+
|
75
|
+
# Stops the web server and finalizes all registered module responders.
|
76
|
+
def stop
|
77
|
+
@logger.info('Intranet::Runner: requesting system shutdown...')
|
78
|
+
@server.shutdown
|
79
|
+
@builder.finalize
|
80
|
+
@logger.close
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# See https://github.com/nahi/webrick/blob/master/lib/webrick/accesslog.rb#L69
|
86
|
+
ACCESSLOG_FMT = "%h '%r' -> %s (%b bytes in %Ts)"
|
87
|
+
|
88
|
+
def load_http_server(preferred_port)
|
89
|
+
@port = preferred_port
|
90
|
+
begin
|
91
|
+
WEBrick::HTTPServer.new(Port: @port, Logger: @logger, AccessLog: [[@logger, ACCESSLOG_FMT]])
|
92
|
+
rescue Errno::EACCES # not enough permission to use port 80
|
93
|
+
@port = 8080
|
94
|
+
retry
|
95
|
+
rescue Errno::EADDRINUSE
|
96
|
+
@port += 1
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def mount_default_servlets(www_dir)
|
102
|
+
# Configure handlers for HTTP server
|
103
|
+
# Start serving www/ as HTTP server root "/" using the class WEBrick::HTTPServlet::FileHandler
|
104
|
+
# You can write your own servlet (it must inherit from WEBrick::HTTPServlet::AbstractServlet)
|
105
|
+
# http://ruby-doc.org/stdlib-1.9.3/libdoc/webrick/rdoc/WEBrick/HTTPServlet/AbstractServlet.html
|
106
|
+
# https://www.igvita.com/2007/02/13/building-dynamic-webrick-servers-in-ruby/
|
107
|
+
@server.mount('/design', WEBrick::HTTPServlet::FileHandler, www_dir)
|
108
|
+
@server.mount('/', Intranet::Core::Servlet, @builder)
|
109
|
+
end
|
110
|
+
|
111
|
+
def module_add_servlet(path, resources_dir)
|
112
|
+
@server.mount('/design/' + path.join('/'),
|
113
|
+
WEBrick::HTTPServlet::FileHandler,
|
114
|
+
File.join(resources_dir, 'www'))
|
115
|
+
end
|
116
|
+
|
117
|
+
def module_add_locales(resources_dir)
|
118
|
+
Intranet::Core::Locales.add_path(File.join(resources_dir, 'locales'))
|
119
|
+
end
|
120
|
+
|
121
|
+
def module_add_haml_templates(resources_dir)
|
122
|
+
Intranet::Core::HamlWrapper.add_path(File.join(resources_dir, 'haml'))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'haml_wrapper'
|
4
|
+
require_relative 'version'
|
5
|
+
require_relative '../../core_extensions'
|
6
|
+
|
7
|
+
module Intranet
|
8
|
+
class Core
|
9
|
+
# @!visibility protected
|
10
|
+
# Builder for the Intranet. The builder is in charge of storing registered modules (responders
|
11
|
+
# instances) and to call the appropriate responder according to the received URL.
|
12
|
+
class Builder
|
13
|
+
include HamlWrapper
|
14
|
+
|
15
|
+
# The tree-like structure containing all registered responders (for Haml)
|
16
|
+
# @return [CoreExtensions::Tree]
|
17
|
+
attr_reader :responders
|
18
|
+
|
19
|
+
# Initializes a new builder.
|
20
|
+
# @param logger [Object] The logger.
|
21
|
+
def initialize(logger)
|
22
|
+
@logger = logger
|
23
|
+
@responders = CoreExtensions::Tree.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# Finalizes the builder. Each registered responder is called for +finalize+.
|
27
|
+
def finalize
|
28
|
+
@responders.to_h.each do |path, responder|
|
29
|
+
next if responder.nil?
|
30
|
+
|
31
|
+
@logger.debug('Intranet::Builder: finalize responder at \'' + path + '\'')
|
32
|
+
responder.finalize
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Processes the given URL path and query. The corresponding responder is called to get the
|
37
|
+
# page content. If no responder can handle the request, HTTP error 404 is returned. If the
|
38
|
+
# responder returns a partial HTML content (HTTP error 206), it is assumed to be the page
|
39
|
+
# body and integrated into the Intranet template.
|
40
|
+
# @param path [String] The requested path, relative to the web server root. This path is
|
41
|
+
# supposed secured and normalized (no '../' in particular).
|
42
|
+
# @param query [Hash] The content of the GET parameters of the URL.
|
43
|
+
# @return [Array] The HTTP return code, the MIME type and the answer body.
|
44
|
+
def do_get(path, query = {})
|
45
|
+
resp, responder_path = get_responder(path)
|
46
|
+
status, mime_type, body = resp.generate_page(responder_path, query)
|
47
|
+
|
48
|
+
# Generate header and footer when partial content is returned by the responder
|
49
|
+
if status == 206 && mime_type == 'text/html'
|
50
|
+
body = to_markup('skeleton', is_home: path == '/index.html', body: body,
|
51
|
+
css: resp.css_dependencies, js: resp.js_dependencies)
|
52
|
+
status = 200
|
53
|
+
end
|
54
|
+
[status, mime_type, body]
|
55
|
+
rescue KeyError, NoMethodError
|
56
|
+
[404, '', '']
|
57
|
+
end
|
58
|
+
|
59
|
+
# Registers a new responder. If a responder is already registered with the same path, the new
|
60
|
+
# one overrides the old one.
|
61
|
+
# @param responder [Intranet::AbstractResponder] The responder instance of the module.
|
62
|
+
# @param path [Array] The path, relative to the web server root, representing the module root
|
63
|
+
# directory. If empty, the responder will be registered as Home responder
|
64
|
+
# (to serve /index.html in particular). Subdirectories are allowed using
|
65
|
+
# an array element for each directory level.
|
66
|
+
# @raise [ArgumentError] If one of the element of the +path+ contains invalid characters.
|
67
|
+
def register(responder, path = [])
|
68
|
+
raise ArgumentError unless path.all?(&:urlized?)
|
69
|
+
|
70
|
+
current_node = @responders
|
71
|
+
path.each do |part|
|
72
|
+
next if part.empty? || part == '.'
|
73
|
+
|
74
|
+
current_node = current_node.add_child_node(part)
|
75
|
+
end
|
76
|
+
current_node.value = responder
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Get the responder instance associated with the given path.
|
82
|
+
# @param path [String] The absolute URL path.
|
83
|
+
# @return [Array] The responder instance (possibly nil) and the remaining of the URL path that
|
84
|
+
# has not been parsed.
|
85
|
+
def get_responder(path)
|
86
|
+
current_treenode = @responders
|
87
|
+
relative_path = path[1..-1].split('/').delete_if do |part|
|
88
|
+
if current_treenode.child_exists?(part)
|
89
|
+
current_treenode = current_treenode.child_node(part)
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
[current_treenode.value, '/' + relative_path.join('/')]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|