Module: Jimmu::Router
- Defined in:
- lib/jimmu.rb
Overview
Resolves request paths to .erb files under views/, following the file-based routing convention described in the Jimmu spec:
views/index.erb -> /
views/about.erb -> /about
views/blog/index.erb -> /blog
views/blog/post.erb -> /blog/post
views/user/[id].erb -> /user/:id
views/post/[category]/[id].erb -> /post/:category/:id
A literal path segment always wins over a [dynamic] one at the
same directory level (so views/user/admin.erb beats
views/user/[id].erb for the request "/user/admin", while any other
value still falls through to the dynamic route).
Directory entries are enumerated directly (Dir.children) rather
than matched with Dir.glob bracket patterns, since glob's [...]
character-class syntax collides with the literal [name] folder
naming convention and is easy to get subtly wrong across relative
vs. absolute paths.
Class Method Summary collapse
-
.match_pattern(pattern, request_path) ⇒ Object
Matches a single registered pattern (e.g. "/room/[name]") against an incoming request path, used for
websocketroutes. - .resolve_dir(base_dir, segments, params) ⇒ Object
-
.resolve_static(public_dir, request_path) ⇒ Object
Returns the on-disk path if
request_pathmaps to a real file under public_dir, else nil. -
.resolve_view(views_dir, request_path) ⇒ Object
Returns [file_path, params] or nil.
- .split_segments(path) ⇒ Object
Class Method Details
.match_pattern(pattern, request_path) ⇒ Object
Matches a single registered pattern (e.g. "/room/[name]") against
an incoming request path, used for websocket routes. Returns a
params Hash on match, or nil.
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 |
# File 'lib/jimmu.rb', line 929 def match_pattern(pattern, request_path) pattern_segments = split_segments(pattern) path_segments = split_segments(request_path) return nil unless pattern_segments.length == path_segments.length params = {} pattern_segments.each_with_index do |seg, i| actual = path_segments[i] if seg.start_with?('[') && seg.end_with?(']') params[seg[1..-2].to_sym] = actual elsif seg != actual return nil end end params end |
.resolve_dir(base_dir, segments, params) ⇒ Object
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
# File 'lib/jimmu.rb', line 950 def resolve_dir(base_dir, segments, params) return nil unless Dir.exist?(base_dir) if segments.empty? idx = File.join(base_dir, 'index.erb') return File.file?(idx) ? [idx, params] : nil end seg = segments[0] rest = segments[1..-1] if rest.empty? exact = File.join(base_dir, "#{seg}.erb") return [exact, params] if File.file?(exact) subdir = File.join(base_dir, seg) if Dir.exist?(subdir) idx = File.join(subdir, 'index.erb') return [idx, params] if File.file?(idx) end else subdir = File.join(base_dir, seg) if Dir.exist?(subdir) result = resolve_dir(subdir, rest, params) return result if result end end resolve_dynamic(base_dir, seg, rest, params) end |
.resolve_static(public_dir, request_path) ⇒ Object
Returns the on-disk path if request_path maps to a real file
under public_dir, else nil. Guards against path traversal.
916 917 918 919 920 921 922 923 924 |
# File 'lib/jimmu.rb', line 916 def resolve_static(public_dir, request_path) return nil if request_path.include?('..') decoded = Jimmu.percent_decode(request_path) return nil if decoded.include?('..') path = File.join(public_dir, decoded) return nil unless path.start_with?(File.(public_dir) + File::SEPARATOR) || File.(path).start_with?(File.(public_dir) + File::SEPARATOR) File.file?(path) ? path : nil end |
.resolve_view(views_dir, request_path) ⇒ Object
Returns [file_path, params] or nil.
909 910 911 912 |
# File 'lib/jimmu.rb', line 909 def resolve_view(views_dir, request_path) segments = split_segments(request_path) resolve_dir(views_dir, segments, {}) end |
.split_segments(path) ⇒ Object
946 947 948 |
# File 'lib/jimmu.rb', line 946 def split_segments(path) path.to_s.split('/').reject(&:empty?) end |