class

Analyzer::Groovy::Grails

Inherits Analyzer < FileHelper < Reference < Object

Grails follows a convention-over-configuration layout where each controller class under grails-app/controllers/ exposes its action methods as URL endpoints. The default URL mapping is "/$controller/$action?/$id?(.$format)?", so we surface every action method as /<controller>/<action> (the controller name is the class name with the Controller suffix dropped and the first letter lowercased).

Two action styles are handled:

  • Method form: def show() { ... }
  • Closure form: def show = { ... } (legacy Grails)

When the controller declares static allowedMethods = [save: 'POST', update: ['PUT', 'PATCH']] those restrictions are honored; otherwise actions are emitted as GET (the default Grails dispatch verb when no restriction is set).

UrlMappings.groovy is also scanned for explicit string-based mappings of the form get '/api/users'(controller: 'user', action: 'list') which are surfaced as additional endpoints. It lives under grails-app/conf/ on Grails 1.x/2.x and grails-app/controllers/ on Grails 3+; both locations are handled. Per-verb action = [GET: ..., PUT: ...] dispatch maps and ${name} GString path variables are recognized, while bare-status-code ("404", "500") error mappings are excluded.

Constants

BODY_ARGS_KEY_RE = Regex.union("controller:", "action:", "view:", "uri:")

One precompiled Regex.union scan (PCRE2 JIT) replaces the four OR-ed String#includes? scans that used to gate every verbless paren-form mapping match in emit_mapping_endpoints (runs once per match, so a UrlMappings file with many entries repeats this often). union auto-escapes each literal, so this is exactly equivalent to the OR-chain it replaces.

DEFAULT_METHODS = ["GET"]
HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"] of ::String
RESOURCES_ENDPOINTS = [{suffix: "", method: "GET"}, {suffix: "", method: "POST"}, {suffix: "/:id", method: "GET"}, {suffix: "/:id", method: "PUT"}, {suffix: "/:id", method: "PATCH"}, {suffix: "/:id", method: "DELETE"}]

Endpoints generated by (resources: "name") shortcuts in UrlMappings.groovy. Each tuple is suffix appended to the base URL plus the verb.

RESTFUL_ACTIONS = [{name: "index", method: "GET"}, {name: "show", method: "GET"}, {name: "save", method: "POST"}, {name: "update", method: "PUT"}, {name: "patch", method: "PATCH"}, {name: "delete", method: "DELETE"}]

Actions inherited from RestfulController<T> (Grails REST base).

SCAFFOLD_ACTIONS = [{name: "index", method: "GET"}, {name: "show", method: "GET"}, {name: "create", method: "GET"}, {name: "save", method: "POST"}, {name: "edit", method: "GET"}, {name: "update", method: "PUT"}, {name: "delete", method: "DELETE"}]

Actions added implicitly by static scaffold = X (Grails legacy CRUD scaffolding).

SKIP_ACTION_NAMES = ["beforeInterceptor", "afterInterceptor", "afterView", "allowedMethods", "scaffold", "defaultAction", "errors", "response", "request", "params", "responseFormats", "namespace", "transactional"] of ::String
URL_MAPPINGS_DIR_RE = Regex.union("/grails-app/conf/", "/grails-app/controllers/")

One precompiled Regex.union scan (PCRE2 JIT) replaces the two OR-ed String#includes? scans url_mappings_path? used to run over every candidate path -- Crystal's includes? is not Boyer-Moore accelerated, so a single regex pass is cheaper than two substring scans. union auto-escapes each literal, so this is exactly equivalent to the OR-chain it replaces.

Class methods

tech_name
Source

Instance methods

analyze
Source
tech

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.

Source

Nested types