utopia 1.9.11 → 2.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 +4 -4
- data/.codeclimate.yml +3 -2
- data/.gitignore +4 -1
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/.yardopts +2 -0
- data/Gemfile +8 -1
- data/README.md +2 -2
- data/Rakefile +10 -10
- data/benchmarks/call_vs_check.rb +36 -0
- data/benchmarks/const_vs_hash.rb +33 -0
- data/documentation/Gemfile +5 -0
- data/documentation/Guardfile +20 -0
- data/documentation/config.ru +6 -13
- data/documentation/config/puma.rb +20 -0
- data/documentation/pages/_editor.xnode +64 -0
- data/documentation/pages/_heading.xnode +2 -2
- data/documentation/pages/_page.xnode +1 -2
- data/documentation/pages/errors/exception.xnode +3 -3
- data/documentation/pages/errors/file-not-found.xnode +3 -3
- data/documentation/pages/wiki/bower-integration/content.md +1 -1
- data/documentation/pages/wiki/content.md +6 -8
- data/documentation/pages/wiki/controller.rb +3 -3
- data/documentation/pages/wiki/edit.xnode +7 -19
- data/documentation/pages/wiki/middleware/content/content.md +4 -10
- data/documentation/pages/wiki/{controller → middleware/controller}/actions/content.md +0 -0
- data/documentation/pages/wiki/{controller → middleware/controller}/links.yaml +0 -0
- data/documentation/pages/wiki/{controller → middleware/controller}/rewrite/content.md +3 -3
- data/documentation/pages/wiki/show.xnode +4 -6
- data/documentation/pages/wiki/updating-utopia/content.md +55 -0
- data/documentation/pages/wiki/your-first-page/content.md +5 -3
- data/documentation/public/materials +1 -0
- data/lib/utopia.rb +3 -4
- data/lib/utopia/command.rb +4 -284
- data/lib/utopia/command/server.rb +115 -0
- data/lib/utopia/command/setup.rb +78 -0
- data/lib/utopia/command/site.rb +183 -0
- data/lib/utopia/content.rb +83 -59
- data/lib/utopia/content/{transaction.rb → document.rb} +116 -110
- data/lib/utopia/content/link.rb +7 -2
- data/lib/utopia/content/links.rb +2 -1
- data/lib/utopia/content/markup.rb +7 -2
- data/lib/utopia/{tags/deferred.rb → content/namespace.rb} +25 -6
- data/lib/utopia/content/node.rb +74 -76
- data/lib/utopia/content/response.rb +22 -3
- data/lib/utopia/content/tags.rb +66 -0
- data/lib/utopia/controller.rb +10 -18
- data/lib/utopia/controller/actions.rb +10 -0
- data/lib/utopia/controller/base.rb +2 -1
- data/lib/utopia/controller/respond.rb +1 -1
- data/lib/utopia/controller/rewrite.rb +8 -4
- data/lib/utopia/exceptions.rb +1 -0
- data/lib/utopia/exceptions/handler.rb +7 -2
- data/lib/utopia/exceptions/mailer.rb +33 -12
- data/lib/utopia/{tags/node.rb → extensions/array_split.rb} +11 -9
- data/lib/utopia/{tags/environment.rb → extensions/date_comparisons.rb} +24 -14
- data/lib/utopia/http.rb +2 -0
- data/lib/utopia/locale.rb +1 -0
- data/lib/utopia/localization.rb +37 -28
- data/lib/utopia/logger.rb +1 -0
- data/lib/utopia/logger/compact_formatter.rb +1 -0
- data/lib/utopia/middleware.rb +11 -1
- data/lib/utopia/path.rb +1 -0
- data/lib/utopia/path/matcher.rb +14 -2
- data/lib/utopia/redirection.rb +13 -16
- data/lib/utopia/session.rb +14 -6
- data/lib/utopia/setup.rb +3 -1
- data/lib/utopia/static.rb +11 -12
- data/lib/utopia/version.rb +1 -1
- data/setup/server/git/hooks/post-receive +0 -4
- data/setup/site/.gitignore +9 -0
- data/setup/site/.rspec +1 -0
- data/setup/site/Gemfile +4 -0
- data/setup/site/Guardfile +17 -0
- data/setup/site/Rakefile +2 -2
- data/setup/site/config.ru +5 -12
- data/setup/site/pages/_heading.xnode +2 -2
- data/setup/site/pages/_page.xnode +1 -1
- data/setup/site/pages/errors/exception.xnode +3 -3
- data/setup/site/pages/errors/file-not-found.xnode +3 -3
- data/setup/site/pages/welcome/index.xnode +3 -3
- data/setup/site/public/_static/site.css +4 -0
- data/setup/site/spec/spec_helper.rb +29 -0
- data/setup/site/tasks/deploy.rake +13 -0
- data/setup/site/tasks/development.rake +34 -0
- data/setup/site/tasks/environment.rake +17 -0
- data/spec/mock_node.rb +15 -0
- data/spec/spec_helper.rb +29 -0
- data/{lib/utopia/extensions/date.rb → spec/utopia/content/document_spec.rb} +31 -21
- data/spec/utopia/content/markup_spec.rb +2 -2
- data/spec/utopia/content/{tag_spec.rb → namespace_spec.rb} +17 -10
- data/spec/utopia/content/tags_spec.rb +80 -0
- data/spec/utopia/content_spec.rb +1 -1
- data/spec/utopia/content_spec.ru +1 -6
- data/spec/utopia/content_spec/_heading.xnode +1 -1
- data/spec/utopia/content_spec/content/test-partial.xnode +1 -1
- data/spec/utopia/content_spec/index.xnode +1 -1
- data/spec/utopia/controller/middleware_spec.ru +1 -3
- data/spec/utopia/controller/respond_spec.rb +2 -22
- data/spec/utopia/controller/respond_spec.ru +1 -5
- data/spec/utopia/controller/respond_spec/errors/file-not-found.xnode +7 -6
- data/spec/utopia/exceptions/handler_spec.ru +1 -2
- data/spec/utopia/exceptions/mailer_spec.ru +1 -2
- data/spec/utopia/extensions_spec.rb +2 -2
- data/spec/utopia/localization_spec.ru +1 -2
- data/spec/utopia/performance_spec.rb +2 -6
- data/spec/utopia/performance_spec/config.ru +5 -12
- data/spec/utopia/performance_spec/pages/_heading.xnode +2 -2
- data/spec/utopia/performance_spec/pages/_page.xnode +1 -1
- data/spec/utopia/performance_spec/pages/errors/exception.xnode +3 -3
- data/spec/utopia/performance_spec/pages/errors/file-not-found.xnode +3 -3
- data/spec/utopia/performance_spec/pages/welcome/index.xnode +3 -3
- data/spec/utopia/setup_spec.rb +79 -15
- data/utopia.gemspec +3 -3
- metadata +41 -27
- data/.simplecov +0 -9
- data/documentation/pages/welcome/index.xnode +0 -41
- data/lib/utopia/content/tag.rb +0 -90
- data/lib/utopia/extensions/array.rb +0 -29
- data/lib/utopia/tags/override.rb +0 -33
- data/setup/site/.simplecov +0 -9
- data/setup/site/tasks/test.rake +0 -10
- data/setup/site/tasks/utopia.rake +0 -41
- data/spec/utopia/controller/respond_spec/rewrite/controller.rb +0 -12
data/lib/utopia/exceptions.rb
CHANGED
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
module Utopia
|
|
22
22
|
module Exceptions
|
|
23
|
-
#
|
|
23
|
+
# A middleware which catches exceptions and performs an internal redirect.
|
|
24
24
|
class Handler
|
|
25
|
+
# @param location [String] Peform an internal redirect to this location when an exception is raised.
|
|
25
26
|
def initialize(app, location = '/errors/exception')
|
|
26
27
|
@app = app
|
|
27
28
|
|
|
@@ -29,6 +30,8 @@ module Utopia
|
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
def freeze
|
|
33
|
+
return self if frozen?
|
|
34
|
+
|
|
32
35
|
@location.freeze
|
|
33
36
|
|
|
34
37
|
super
|
|
@@ -74,7 +77,9 @@ module Utopia
|
|
|
74
77
|
end
|
|
75
78
|
end
|
|
76
79
|
|
|
77
|
-
private
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def write_exception_to_stream(stream, env, exception, include_backtrace = false)
|
|
78
83
|
buffer = []
|
|
79
84
|
|
|
80
85
|
buffer << "While requesting resource #{env[Rack::PATH_INFO].inspect}, a fatal error occurred:"
|
|
@@ -23,7 +23,7 @@ require 'mail'
|
|
|
23
23
|
|
|
24
24
|
module Utopia
|
|
25
25
|
module Exceptions
|
|
26
|
-
#
|
|
26
|
+
# A middleware which catches all exceptions raised from the app it wraps and sends a useful email with the exception, stacktrace, and contents of the environment.
|
|
27
27
|
class Mailer
|
|
28
28
|
# A basic local non-authenticated SMTP server.
|
|
29
29
|
LOCAL_SMTP = [:smtp, {
|
|
@@ -32,17 +32,36 @@ module Utopia
|
|
|
32
32
|
:enable_starttls_auto => false
|
|
33
33
|
}]
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
DEFAULT_FROM = (ENV['USER'] || 'rack') + "@localhost"
|
|
36
|
+
DEFAULT_SUBJECT = '%{exception} [PID %{pid} : %{cwd}]'
|
|
37
|
+
|
|
38
|
+
# @param to [String] The address to email error reports to.
|
|
39
|
+
# @param from [String] The from address for error reports.
|
|
40
|
+
# @param subject [String] The subject template which can access attributes defined by `#attributes_for`.
|
|
41
|
+
# @param delivery_method [Object] The delivery method as required by the mail gem.
|
|
42
|
+
# @param dump_environment [Boolean] Attach `env` as `environment.yaml` to the error report.
|
|
43
|
+
def initialize(app, to: "postmaster", from: DEFAULT_FROM, subject: DEFAULT_SUBJECT, delivery_method: LOCAL_SMTP, dump_environment: false)
|
|
36
44
|
@app = app
|
|
37
45
|
|
|
38
|
-
@to =
|
|
39
|
-
@from =
|
|
40
|
-
@subject =
|
|
41
|
-
@delivery_method =
|
|
46
|
+
@to = to
|
|
47
|
+
@from = from
|
|
48
|
+
@subject = subject
|
|
49
|
+
@delivery_method = delivery_method
|
|
50
|
+
@dump_environment = dump_environment
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def freeze
|
|
54
|
+
return self if frozen?
|
|
55
|
+
|
|
56
|
+
@to.freeze
|
|
57
|
+
@from.freeze
|
|
58
|
+
@subject.freeze
|
|
59
|
+
@delivery_method.freeze
|
|
60
|
+
@dump_environment.freeze
|
|
42
61
|
|
|
43
|
-
|
|
62
|
+
super
|
|
44
63
|
end
|
|
45
|
-
|
|
64
|
+
|
|
46
65
|
def call(env)
|
|
47
66
|
begin
|
|
48
67
|
return @app.call(env)
|
|
@@ -100,17 +119,19 @@ module Utopia
|
|
|
100
119
|
return io.string
|
|
101
120
|
end
|
|
102
121
|
|
|
103
|
-
def
|
|
104
|
-
|
|
122
|
+
def attributes_for(exception, env)
|
|
123
|
+
{
|
|
105
124
|
exception: exception.class.name,
|
|
106
125
|
pid: $$,
|
|
107
126
|
cwd: Dir.getwd,
|
|
108
127
|
}
|
|
109
|
-
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def generate_mail(exception, env)
|
|
110
131
|
mail = Mail.new(
|
|
111
132
|
:from => @from,
|
|
112
133
|
:to => @to,
|
|
113
|
-
:subject => @subject %
|
|
134
|
+
:subject => @subject % attributes_for(exception, env)
|
|
114
135
|
)
|
|
115
136
|
|
|
116
137
|
mail.text_part = Mail::Part.new
|
|
@@ -19,15 +19,17 @@
|
|
|
19
19
|
# THE SOFTWARE.
|
|
20
20
|
|
|
21
21
|
module Utopia
|
|
22
|
-
module
|
|
23
|
-
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
module Extensions
|
|
23
|
+
module ArraySplit
|
|
24
|
+
def split_at(*args, &block)
|
|
25
|
+
if middle = index(*args, &block)
|
|
26
|
+
[self[0...middle], self[middle], self[middle+1..-1]]
|
|
27
|
+
else
|
|
28
|
+
[[], nil, []]
|
|
29
|
+
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
::Array.prepend(ArraySplit)
|
|
32
34
|
end
|
|
33
|
-
end
|
|
35
|
+
end
|
|
@@ -18,24 +18,34 @@
|
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
19
|
# THE SOFTWARE.
|
|
20
20
|
|
|
21
|
+
require 'date'
|
|
22
|
+
|
|
21
23
|
module Utopia
|
|
22
|
-
module
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
module Extensions
|
|
25
|
+
# Provides comparison operator extensions.
|
|
26
|
+
module TimeDateComparison
|
|
27
|
+
def <=>(other)
|
|
28
|
+
if Date === other or DateTime === other
|
|
29
|
+
self.to_datetime <=> other
|
|
30
|
+
else
|
|
31
|
+
super
|
|
32
|
+
end
|
|
30
33
|
end
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
::Time.prepend(TimeDateComparison)
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
# Provides comparison operator extensions.
|
|
39
|
+
module DateTimeComparison
|
|
40
|
+
def <=>(other)
|
|
41
|
+
if Time === other
|
|
42
|
+
self.to_datetime <=> other.to_datetime
|
|
43
|
+
else
|
|
44
|
+
super
|
|
37
45
|
end
|
|
38
46
|
end
|
|
39
47
|
end
|
|
48
|
+
|
|
49
|
+
::Date.prepend(DateTimeComparison)
|
|
40
50
|
end
|
|
41
|
-
end
|
|
51
|
+
end
|
data/lib/utopia/http.rb
CHANGED
data/lib/utopia/locale.rb
CHANGED
data/lib/utopia/localization.rb
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
require_relative 'middleware'
|
|
22
22
|
|
|
23
23
|
module Utopia
|
|
24
|
-
#
|
|
24
|
+
# A middleware which attempts to find localized content.
|
|
25
25
|
class Localization
|
|
26
26
|
# A wrapper to provide easy access to locale related data in the request.
|
|
27
27
|
class Wrapper
|
|
@@ -59,38 +59,42 @@ module Utopia
|
|
|
59
59
|
LOCALIZATION_KEY = 'utopia.localization'.freeze
|
|
60
60
|
CURRENT_LOCALE_KEY = 'utopia.localization.current_locale'.freeze
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
# @param locales [Array<String>] An array of all supported locales.
|
|
63
|
+
# @param default_locale [String] The default locale if none is provided.
|
|
64
|
+
# @param default_locales [String] The locales to try in order if none is provided.
|
|
65
|
+
# @param hosts [Hash<Pattern, String>] Specify a mapping of the HTTP_HOST header to a given locale.
|
|
66
|
+
# @param ignore [Array<Pattern>] A list of patterns matched against PATH_INFO which will not be localized.
|
|
67
|
+
def initialize(app, locales:, default_locale: nil, default_locales: nil, hosts: {}, ignore: [], **options)
|
|
65
68
|
@app = app
|
|
66
69
|
|
|
67
|
-
@all_locales = HTTP::Accept::Languages::Locales.new(
|
|
70
|
+
@all_locales = HTTP::Accept::Languages::Locales.new(locales)
|
|
68
71
|
|
|
69
|
-
# Locales here are represented as an array of strings, e.g. ['en', 'ja', 'cn', 'de'].
|
|
70
|
-
unless @default_locales =
|
|
72
|
+
# Locales here are represented as an array of strings, e.g. ['en', 'ja', 'cn', 'de'] and are used in order if no locale is specified by the user.
|
|
73
|
+
unless @default_locales = default_locales
|
|
71
74
|
# We append nil, i.e. no localization.
|
|
72
75
|
@default_locales = @all_locales.names + [nil]
|
|
73
76
|
end
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
@default_locales.unshift(default_locale)
|
|
77
|
-
else
|
|
78
|
-
@default_locale = @default_locales.first
|
|
79
|
-
end
|
|
78
|
+
@default_locale = default_locale || @default_locales.first
|
|
80
79
|
|
|
81
|
-
@
|
|
80
|
+
unless @default_locales.include? @default_locale
|
|
81
|
+
@default_locales.unshift(@default_locale)
|
|
82
|
+
end
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
# Select a localization based on a request host name:
|
|
85
|
+
@hosts = hosts
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
@ignore = ignore || options[:nonlocalized]
|
|
86
88
|
end
|
|
87
89
|
|
|
88
90
|
def freeze
|
|
91
|
+
return self if frozen?
|
|
92
|
+
|
|
89
93
|
@all_locales.freeze
|
|
90
94
|
@default_locales.freeze
|
|
91
95
|
@default_locale.freeze
|
|
92
96
|
@hosts.freeze
|
|
93
|
-
@
|
|
97
|
+
@ignore.freeze
|
|
94
98
|
|
|
95
99
|
super
|
|
96
100
|
end
|
|
@@ -104,7 +108,7 @@ module Utopia
|
|
|
104
108
|
# Keep track of what locales have been tried:
|
|
105
109
|
locales = Set.new
|
|
106
110
|
|
|
107
|
-
host_preferred_locales(env)
|
|
111
|
+
host_preferred_locales(env) do |locale|
|
|
108
112
|
yield env.merge(CURRENT_LOCALE_KEY => locale) if locales.add? locale
|
|
109
113
|
end
|
|
110
114
|
|
|
@@ -124,16 +128,13 @@ module Utopia
|
|
|
124
128
|
end
|
|
125
129
|
end
|
|
126
130
|
|
|
127
|
-
HTTP_HOST = 'HTTP_HOST'.freeze
|
|
128
|
-
|
|
129
131
|
def host_preferred_locales(env)
|
|
130
132
|
http_host = env[Rack::HTTP_HOST]
|
|
131
133
|
|
|
132
|
-
#
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
matching_hosts.flat_map{|host_pattern, locale| locale}
|
|
134
|
+
# Yield all hosts which match the incoming http_host:
|
|
135
|
+
@hosts.each do |pattern, locale|
|
|
136
|
+
yield locale if http_host[pattern]
|
|
137
|
+
end
|
|
137
138
|
end
|
|
138
139
|
|
|
139
140
|
def request_preferred_locale(env)
|
|
@@ -163,10 +164,18 @@ module Utopia
|
|
|
163
164
|
return []
|
|
164
165
|
end
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
SAFE_METHODS = ['GET', 'HEAD']
|
|
168
|
+
|
|
169
|
+
def localized?(env)
|
|
170
|
+
# Only SAFE_METHODS can be localized:
|
|
171
|
+
request_method = env[Rack::REQUEST_METHOD]
|
|
172
|
+
return false unless SAFE_METHODS.include?(request_method)
|
|
173
|
+
|
|
174
|
+
# Ignore requests which match the ignored paths:
|
|
167
175
|
path_info = env[Rack::PATH_INFO]
|
|
176
|
+
return false if @ignore.any? { |pattern| path_info[pattern] != nil }
|
|
168
177
|
|
|
169
|
-
|
|
178
|
+
return true
|
|
170
179
|
end
|
|
171
180
|
|
|
172
181
|
# Set the Vary: header on the response to indicate that this response should include the header in the cache key.
|
|
@@ -190,8 +199,8 @@ module Utopia
|
|
|
190
199
|
end
|
|
191
200
|
|
|
192
201
|
def call(env)
|
|
193
|
-
# Pass the request through
|
|
194
|
-
return @app.call(env)
|
|
202
|
+
# Pass the request through if it shouldn't be localized:
|
|
203
|
+
return @app.call(env) unless localized?(env)
|
|
195
204
|
|
|
196
205
|
env[LOCALIZATION_KEY] = self
|
|
197
206
|
|
data/lib/utopia/logger.rb
CHANGED
data/lib/utopia/middleware.rb
CHANGED
|
@@ -24,12 +24,22 @@ require_relative 'http'
|
|
|
24
24
|
require_relative 'path'
|
|
25
25
|
|
|
26
26
|
module Utopia
|
|
27
|
+
# The default pages path for {Utopia::Content} middleware.
|
|
27
28
|
PAGES_PATH = 'pages'.freeze
|
|
28
29
|
|
|
29
|
-
# This is used for shared controller variables which get consumed by the content middleware
|
|
30
|
+
# This is used for shared controller variables which get consumed by the content middleware.
|
|
30
31
|
VARIABLES_KEY = 'utopia.variables'.freeze
|
|
31
32
|
|
|
33
|
+
# The default root directory for middleware to operate within, e.g. the web-site directory. Convention over configuration.
|
|
34
|
+
# @param subdirectory [String] Appended to the default root to make a more specific path.
|
|
35
|
+
# @param pwd [String] The working directory for the current site.
|
|
32
36
|
def self.default_root(subdirectory = PAGES_PATH, pwd = Dir.pwd)
|
|
33
37
|
File.expand_path(subdirectory, pwd)
|
|
34
38
|
end
|
|
39
|
+
|
|
40
|
+
# The same as {default_root} but returns an instance of {Path}.
|
|
41
|
+
# @return [Path] The path as requested.
|
|
42
|
+
def self.default_path(*args)
|
|
43
|
+
Path[default_root(*args)]
|
|
44
|
+
end
|
|
35
45
|
end
|
data/lib/utopia/path.rb
CHANGED
data/lib/utopia/path/matcher.rb
CHANGED
|
@@ -22,14 +22,23 @@ require_relative '../path'
|
|
|
22
22
|
|
|
23
23
|
module Utopia
|
|
24
24
|
class Path
|
|
25
|
+
# Performs structured, efficient, matches against {Path} instances. Supports regular expressions, type-casts and constants.
|
|
26
|
+
# @example
|
|
27
|
+
# path = Utopia::Path['users/20/edit']
|
|
28
|
+
# matcher = Utopia::Path::Matcher[users: /users/, id: Integer, action: String]
|
|
29
|
+
# match_data = matcher.match(path)
|
|
25
30
|
class Matcher
|
|
31
|
+
# The result of matching against a {Path}.
|
|
26
32
|
class MatchData
|
|
27
33
|
def initialize(named_parts, post_match)
|
|
28
34
|
@named_parts = named_parts
|
|
29
35
|
@post_match = Path[post_match]
|
|
30
36
|
end
|
|
31
37
|
|
|
38
|
+
# Matched components by name.
|
|
32
39
|
attr :named_parts
|
|
40
|
+
|
|
41
|
+
# Any remaining part past the end of the explicitly matched components.
|
|
33
42
|
attr :post_match
|
|
34
43
|
|
|
35
44
|
def [] key
|
|
@@ -41,7 +50,7 @@ module Utopia
|
|
|
41
50
|
end
|
|
42
51
|
end
|
|
43
52
|
|
|
44
|
-
# patterns
|
|
53
|
+
# @param patterns [Hash<Symbol,Pattern>] An ordered list of things to match.
|
|
45
54
|
def initialize(patterns = [])
|
|
46
55
|
@patterns = patterns
|
|
47
56
|
end
|
|
@@ -64,14 +73,16 @@ module Utopia
|
|
|
64
73
|
return nil
|
|
65
74
|
end
|
|
66
75
|
|
|
67
|
-
# This is a path prefix matching algorithm. The pattern is an array of String, Symbol, Regexp, or nil. The
|
|
76
|
+
# This is a path prefix matching algorithm. The pattern is an array of String, Symbol, Regexp, or nil. The path is an array of String.
|
|
68
77
|
def match(path)
|
|
69
78
|
components = path.to_a
|
|
70
79
|
|
|
80
|
+
# Can't possibly match if not enough components:
|
|
71
81
|
return nil if components.size < @patterns.size
|
|
72
82
|
|
|
73
83
|
named_parts = {}
|
|
74
84
|
|
|
85
|
+
# Try to match each component against the pattern:
|
|
75
86
|
@patterns.each_with_index do |(key, pattern), index|
|
|
76
87
|
component = components[index]
|
|
77
88
|
|
|
@@ -83,6 +94,7 @@ module Utopia
|
|
|
83
94
|
if result = pattern.match(component)
|
|
84
95
|
named_parts[key] = result
|
|
85
96
|
else
|
|
97
|
+
# Couldn't match:
|
|
86
98
|
return nil
|
|
87
99
|
end
|
|
88
100
|
else
|