forked from soveran/cuba
-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add match_hook_args plugin, similar to match_hooks but support matche…
…rs and block args as hook arguments
- Loading branch information
1 parent
91ab4f7
commit 44a7e0e
Showing
5 changed files
with
189 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# frozen-string-literal: true | ||
|
||
# | ||
class Roda | ||
module RodaPlugins | ||
# The match_hook_args plugin adds hooks that are called upon a successful match | ||
# by any of the matchers. It is similar to the match_hook plugin, but it allows | ||
# for passing the matchers and block arguments for each match method. | ||
# | ||
# plugin :match_hook_args | ||
# | ||
# add_match_hook do |matchers, block_args| | ||
# logger.debug("matchers: #{matchers.inspect}. #{block_args.inspect} yielded.") | ||
# end | ||
# | ||
# # Term is an implicit matcher used for terminating matches, and | ||
# # will be included in the array of matchers yielded to match block | ||
# # if a terminating match is used. | ||
# term = self.class::RodaRequest::TERM | ||
# | ||
# route do |r| | ||
# r.root do | ||
# # matchers: nil, block_args: nil | ||
# end | ||
# | ||
# r.on 'a', ['b', 'c'], Integer |segment, id| | ||
# # for a request for /a/b/1: | ||
# # matchers: ['a', ['b', 'c'], Integer], block_args: ['b', 1] | ||
# end | ||
# | ||
# r.get 'd' |segment, id| | ||
# # for a request for /d | ||
# # matchers: ['d', term], block_args: [] | ||
# end | ||
# end | ||
module MatchHookArgs | ||
def self.configure(app) | ||
app.opts[:match_hook_args] ||= [] | ||
end | ||
|
||
module ClassMethods | ||
# Freeze the array of hook methods when freezing the app | ||
def freeze | ||
opts[:match_hook_args].freeze | ||
super | ||
end | ||
|
||
# Add a match hook that will be called with matchers and block args. | ||
def add_match_hook(&block) | ||
opts[:match_hook_args] << define_roda_method("match_hook_args", :any, &block) | ||
|
||
if opts[:match_hook_args].length == 1 | ||
class_eval("alias _match_hook_args #{opts[:match_hook_args].first}", __FILE__, __LINE__) | ||
else | ||
class_eval("def _match_hook_args(v, a); #{opts[:match_hook_args].map{|m| "#{m}(v, a)"}.join(';')} end", __FILE__, __LINE__) | ||
end | ||
|
||
public :_match_hook_args | ||
|
||
nil | ||
end | ||
end | ||
|
||
module InstanceMethods | ||
# Default empty method if no match hooks are defined. | ||
def _match_hook_args(matchers, block_args) | ||
end | ||
end | ||
|
||
module RequestMethods | ||
private | ||
|
||
# Call the match hook with matchers and block args if yielding to the block before yielding to the block. | ||
def if_match(v) | ||
super do |*a| | ||
scope._match_hook_args(v, a) | ||
yield(*a) | ||
end | ||
end | ||
|
||
# Call the match hook with nil matchers and blocks before yielding to the block | ||
def always | ||
scope._match_hook_args(nil, nil) | ||
super | ||
end | ||
end | ||
end | ||
|
||
register_plugin :match_hook_args, MatchHookArgs | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
require_relative "../spec_helper" | ||
|
||
describe "match_hook_args plugin" do | ||
it "yields matchers and block args to match hooks" do | ||
matches = [] | ||
app(:bare) do | ||
plugin :match_hook_args | ||
add_match_hook do |matchers, block_args| | ||
matches << [matchers, block_args, request.matched_path, request.remaining_path] | ||
end | ||
route do |r| | ||
r.on "foo" do | ||
r.on "bar" do | ||
r.get "baz" do | ||
"fbb" | ||
end | ||
"fb" | ||
end | ||
"f" | ||
end | ||
|
||
r.get "bar" do | ||
"b" | ||
end | ||
|
||
r.get "baz", Integer do |id| | ||
"b-#{id}" | ||
end | ||
|
||
r.root do | ||
"r" | ||
end | ||
|
||
"n" | ||
end | ||
end | ||
|
||
term = app::RodaRequest::TERM | ||
|
||
body("/foo").must_equal 'f' | ||
matches.must_equal [[%w"foo", [], "/foo", ""]] | ||
|
||
matches.clear | ||
body("/foo/bar").must_equal 'fb' | ||
matches.must_equal [[%w"foo", [], "/foo", "/bar"], [%w"bar", [], "/foo/bar", ""]] | ||
|
||
matches.clear | ||
body("/foo/bar/baz").must_equal 'fbb' | ||
matches.must_equal [[%w"foo", [], "/foo", "/bar/baz"], [%w"bar", [], "/foo/bar", "/baz"], [["baz", term], [], "/foo/bar/baz", ""]] | ||
|
||
matches.clear | ||
body("/bar").must_equal 'b' | ||
matches.must_equal [[["bar", term], [], "/bar", ""]] | ||
|
||
matches.clear | ||
body("/baz/1").must_equal 'b-1' | ||
matches.must_equal [[["baz", Integer, term], [1], "/baz/1", ""]] | ||
|
||
matches.clear | ||
body.must_equal 'r' | ||
matches.must_equal [[nil, nil, "", "/"]] | ||
|
||
matches.clear | ||
body('/x').must_equal 'n' | ||
matches.must_be_empty | ||
|
||
matches.clear | ||
body("/foo/baz").must_equal 'f' | ||
matches.must_equal [[%w"foo", [], "/foo", "/baz"]] | ||
|
||
matches.clear | ||
body("/foo/bar/bar").must_equal 'fb' | ||
matches.must_equal [[%w"foo", [], "/foo", "/bar/bar"], [%w"bar", [], "/foo/bar", "/bar"]] | ||
|
||
app.add_match_hook{|_,_|matches << :x } | ||
|
||
matches.clear | ||
body("/foo/bar/baz").must_equal 'fbb' | ||
matches.must_equal [[%w"foo", [], "/foo", "/bar/baz"], :x, [%w"bar", [], "/foo/bar", "/baz"], :x, [["baz", term], [], "/foo/bar/baz", ""], :x] | ||
|
||
app.freeze | ||
|
||
matches.clear | ||
body("/foo/bar/baz").must_equal 'fbb' | ||
matches.must_equal [[%w"foo", [], "/foo", "/bar/baz"], :x, [%w"bar", [], "/foo/bar", "/baz"], :x, [["baz", term], [], "/foo/bar/baz", ""], :x] | ||
|
||
app.opts[:match_hook_args].must_be :frozen? | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters