class Analyzer::Lua::Lor

Overview

lor (https://github.com/sumory/lor) is an Express-style web framework for Lua on top of OpenResty. Routes are declared on the application or on a router instance:

local app = lor() app:get("/", handler) -- direct app route

local userRouter = lor:Router() userRouter:get("/find/:id", handler) -- router route app:use("/user", userRouter()) -- mount router under a prefix

The mount prefix is what makes lor routes hard to read in isolation: a route file declares userRouter:get("/find/:id", …) and a different file (router.lua) mounts it with app:use("/user", userRouter()), so the real URL is /user/find/:id. userRouter in the mounting file is bound to require("app.routes.user"), so we resolve that require to the route file and prefix every route the file declares. Prefixes compose transitively for nested mounts.

Path params use Express :name syntax, which already matches noir's URL convention. Verbs come from lor's supported set (get/post/put/delete/patch/ head/options/trace and the catch-all all).

Defined in:

analyzer/analyzers/lua/lor.cr

Constant Summary

ALL_VERBS = ["GET", "POST", "PUT", "DELETE", "PATCH"] of ::String

app:all(...) matches every method; surface the common five (the same fallback set the Lapis app:match analyzer uses).

APP_VAR_RE = /(?:^|[^A-Za-z0-9_.])(?:local\s+)?([A-Za-z_]\w*)\s*=\s*lor\s*\(\s*\)/

local app = lor() — the application object.

REQUIRE_RE = /(?:^|[^A-Za-z0-9_.])(?:local\s+)?([A-Za-z_]\w*)\s*=\s*require\s*\(?\s*(['"])([^'"]+)\2/

local userRouter = require("app.routes.user") — module binding.

ROUTER_VAR_RE = /(?:^|[^A-Za-z0-9_.])(?:local\s+)?([A-Za-z_]\w*)\s*=\s*lor\s*[:.]\s*[Rr]outer\s*\(/

local userRouter = lor:Router() — a router instance.

USE_MOUNT_RE = /\b([A-Za-z_]\w*)\s*[:.]\s*use\s*\(\s*(['"])([^'"]*)\2\s*,\s*([A-Za-z_]\w*)\s*\(/

app:use("/prefix", userRouter()) — mount a sub-router under a prefix. The second arg must be a bare-variable call (name(...)); a function literal or table second arg is middleware, not a router mount.

USE_RECEIVER_RE = /\b([A-Za-z_]\w*)\s*[:.]\s*use\s*\(/

Any <var>:use( — used purely to flag a variable as an app/router receiver (lor's App/Router both expose :use; redis/db/cache never do).

Class Method Summary

Instance Method Summary

Instance methods inherited from class Analyzer

analyze analyze, base_path : String base_path, base_paths : Array(String) base_paths, base_relative_path(path : String) : String base_relative_path, callees_needed? : Bool callees_needed?, content_matches?(content : String, markers : Regex) : Bool content_matches?, http_header_name(name : String) : String | Nil http_header_name, line_number_for_index(content : String, char_index : Int32) : Int32 line_number_for_index, logger : NoirLogger logger, parallel_analyze(files : Array(String), &block : String -> Nil) parallel_analyze, read_file_content(path : String) : String read_file_content, result : Array(Endpoint) result, tech : String tech, unique_params(params : Array(Param)) : Array(Param) unique_params, url : String url, web_root_path(path : String, markers : Array(String)) : String web_root_path

Constructor methods inherited from class Analyzer

new(options : Hash(String, YAML::Any)) new

Macros inherited from class Analyzer

analyzer_for(tech) analyzer_for

Instance methods inherited from module FileHelper

all_files : Array(String) all_files, get_files_by_basename(basename : String) : Array(String) get_files_by_basename, get_files_by_extension(extension : String) : Array(String) get_files_by_extension, get_files_by_extensions(extensions : Array(String)) : Array(String) get_files_by_extensions, get_files_by_prefix(prefix : String) : Array(String) get_files_by_prefix, get_files_by_prefix_and_extension(prefix : String, extension : String) : Array(String) get_files_by_prefix_and_extension, get_files_by_relative_path(relative_path : String, root : String = "") : Array(String) get_files_by_relative_path, get_public_dir_files(base_path : String, folder : String) : Array(String) get_public_dir_files, get_public_files(base_path : String, anchors : Array(String) = ["shard.yml", "Gemfile"]) : Array(String) get_public_files, walked_path(expanded : String) : String walked_path

Class Method Detail

def self.tech_name : String #

[View source]

Instance Method Detail

def analyze #

[View source]
def tech : String #

Instance-side view of the same declaration. The per-file rescues live on this base class, which has no way to name the analyzer that is running inside them, so a skipped file could not be attributed to a tech. Deriving it from analyzer_for keeps the name written exactly once.


[View source]