Class: Takagi::Router
- Inherits:
-
Object
- Object
- Takagi::Router
- Defined in:
- lib/takagi/router.rb,
lib/takagi/router/route_matcher.rb,
lib/takagi/router/metadata_extractor.rb,
sig/takagi/router.rbs,
sig/takagi/router/route_matcher.rbs,
sig/takagi/router/metadata_extractor.rbs
Direct Known Subclasses
Defined Under Namespace
Classes: MetadataExtractor, RouteContext, RouteEntry, RouteMatcher
Constant Summary collapse
- DEFAULT_CONTENT_FORMAT =
Takagi::CoAP::Registries::ContentFormat::JSON
Class Method Summary collapse
-
.instance ⇒ Router
Global singleton instance for backward compatibility.
-
.reset! ⇒ void
Reset the global instance (for testing).
Instance Method Summary collapse
-
#add_route(method, path, metadata: {}, &block) {|arg0| ... } ⇒ Object
Registers a new route for a given HTTP method and path.
- #all_routes ⇒ Object
- #build_route_entry(method, path, metadata, block) ⇒ Object
-
#configure_core(method, path, &block) ⇒ void
Applies CoRE metadata outside the request cycle.
- #default_interface(method) ⇒ "takagi.observe", ::String
- #default_resource_type(method) ⇒ "core#observable", "core#endpoint"
-
#extract_metadata_from_handler(entry) ⇒ Object
Executes route handler in metadata extraction mode to capture core block attributes Delegates to MetadataExtractor for the actual extraction logic.
- #find_observable(path) ⇒ Object
-
#find_route(method, path) ⇒ Proc, Hash
Finds a registered route for a given method and path.
-
#initialize ⇒ Router
constructor
A new instance of Router.
- #link_format_entries ⇒ Object
-
#match_dynamic_route(method, path) ⇒ Array(RouteEntry, Hash)
Matches dynamic routes that contain parameters (e.g.,
/users/:id) Delegates to RouteMatcher for the actual matching logic. -
#normalize_metadata(method, path, metadata) ⇒ Hash
Normalizes route metadata with sensible defaults for CoRE Link Format.
-
#observable(path, metadata: {}, &block) {|arg0| ... } ⇒ Object
Registers a OBSERVE route.
- #wrap_block(entry) ⇒ nil, untyped
Constructor Details
#initialize ⇒ Router
Returns a new instance of Router.
144 145 146 147 148 149 150 |
# File 'lib/takagi/router.rb', line 144 def initialize @routes = {} @routes_mutex = Mutex.new # Protects route modifications in multithreaded environments @logger = Takagi.logger @route_matcher = RouteMatcher.new(@logger) @metadata_extractor = MetadataExtractor.new(@logger) end |
Class Method Details
.instance ⇒ Router
Global singleton instance for backward compatibility
19 20 21 |
# File 'lib/takagi/router.rb', line 19 def instance @instance ||= new end |
.reset! ⇒ void
This method returns an undefined value.
Reset the global instance (for testing)
26 27 28 29 30 |
# File 'lib/takagi/router.rb', line 26 def reset! @instance = nil # Ensure Takagi::Base fetches a fresh router after reset Takagi::Base.instance_variable_set(:@router, nil) if defined?(Takagi::Base) end |
Instance Method Details
#add_route(method, path, metadata: {}, &block) {|arg0| ... } ⇒ Object
Registers a new route for a given HTTP method and path
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/takagi/router.rb', line 156 def add_route(method, path, metadata: {}, &block) @routes_mutex.synchronize do entry = build_route_entry(method, path, , block) @routes["#{method} #{path}"] = entry @logger.debug "Add new route: #{method} #{path}" # Extract metadata from core blocks inside the handler (entry) if block Takagi::Hooks.emit( :router_route_added, method: method, path: path, entry: entry ) end end |
#all_routes ⇒ Object
193 194 195 |
# File 'lib/takagi/router.rb', line 193 def all_routes @routes.values.map { |entry| "#{entry.method} #{entry.path}" } end |
#build_route_entry(method, path, metadata, block) ⇒ Object
266 267 268 269 270 271 272 273 274 |
# File 'lib/takagi/router.rb', line 266 def build_route_entry(method, path, , block) RouteEntry.new( method: method, path: path, block: block, metadata: (method, path, ), receiver: block&.binding&.receiver ) end |
#configure_core(method, path, &block) ⇒ void
This method returns an undefined value.
Applies CoRE metadata outside the request cycle. Useful for boot time configuration where the DSL block does not have a live request object.
231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/takagi/router.rb', line 231 def configure_core(method, path, &block) return unless block @routes_mutex.synchronize do entry = @routes["#{method} #{path}"] unless entry @logger.warn "configure_core skipped: #{method} #{path} not registered" return end entry.configure_attributes(&block) end end |
#default_interface(method) ⇒ "takagi.observe", ::String
295 296 297 |
# File 'lib/takagi/router.rb', line 295 def default_interface(method) method == 'OBSERVE' ? 'takagi.observe' : "takagi.#{method.downcase}" end |
#default_resource_type(method) ⇒ "core#observable", "core#endpoint"
291 292 293 |
# File 'lib/takagi/router.rb', line 291 def default_resource_type(method) method == 'OBSERVE' ? 'core#observable' : 'core#endpoint' end |
#extract_metadata_from_handler(entry) ⇒ Object
Executes route handler in metadata extraction mode to capture core block attributes Delegates to MetadataExtractor for the actual extraction logic
302 303 304 |
# File 'lib/takagi/router.rb', line 302 def (entry) @metadata_extractor.extract(entry) end |
#find_observable(path) ⇒ Object
197 198 199 |
# File 'lib/takagi/router.rb', line 197 def find_observable(path) @routes.values.find { |entry| entry.method == 'OBSERVE' && entry.path == path } end |
#find_route(method, path) ⇒ Proc, Hash
Finds a registered route for a given method and path
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/takagi/router.rb', line 205 def find_route(method, path) @routes_mutex.synchronize do @logger.debug "Routes: #{@routes.inspect}" @logger.debug "Looking for route: #{method} #{path}" entry = @routes["#{method} #{path}"] params = {} return wrap_block(entry), params if entry @logger.debug '[Debug] Find dynamic route' entry, params = match_dynamic_route(method, path) return wrap_block(entry), params if entry [nil, {}] end end |
#link_format_entries ⇒ Object
223 224 225 226 227 |
# File 'lib/takagi/router.rb', line 223 def link_format_entries @routes_mutex.synchronize do @routes.values.reject { |entry| entry.[:discovery] }.map(&:dup) end end |
#match_dynamic_route(method, path) ⇒ Array(RouteEntry, Hash)
Matches dynamic routes that contain parameters (e.g., /users/:id)
Delegates to RouteMatcher for the actual matching logic
262 263 264 |
# File 'lib/takagi/router.rb', line 262 def match_dynamic_route(method, path) @route_matcher.match(@routes, method, path) end |
#normalize_metadata(method, path, metadata) ⇒ Hash
Normalizes route metadata with sensible defaults for CoRE Link Format
282 283 284 285 286 287 288 289 |
# File 'lib/takagi/router.rb', line 282 def (method, path, ) normalized = ( || {}).transform_keys(&:to_sym) normalized[:rt] ||= default_resource_type(method) normalized[:if] ||= default_interface(method) normalized[:ct] = DEFAULT_CONTENT_FORMAT unless normalized.key?(:ct) normalized[:title] ||= "#{method} #{path}" normalized end |
#observable(path, metadata: {}, &block) {|arg0| ... } ⇒ Object
Registers a OBSERVE route
188 189 190 191 |
# File 'lib/takagi/router.rb', line 188 def observable(path, metadata: {}, &block) = { obs: true, rt: 'core#observable', if: 'takagi.observe' } add_route('OBSERVE', path, metadata: .merge(), &block) end |
#wrap_block(entry) ⇒ nil, untyped
247 248 249 250 251 252 253 254 255 |
# File 'lib/takagi/router.rb', line 247 def wrap_block(entry) block = entry&.block return nil unless block lambda do |req, params = {}| context = RouteContext.new(entry, req, params, entry.receiver) context.run(block) end end |