diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 626786e9..6d02c1d0 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -2032,6 +2032,12 @@ YAML: - .rviz - .yaml +Zephir: + type: programming + lexer: PHP + color: "#118f9e" + primary_extension: .zep + eC: type: programming search_term: ec diff --git a/lib/linguist/samples.json b/lib/linguist/samples.json index 9864f7a1..5ed874d7 100644 --- a/lib/linguist/samples.json +++ b/lib/linguist/samples.json @@ -6,6 +6,9 @@ "Agda": [ ".agda" ], + "Alloy": [ + ".als" + ], "Apex": [ ".cls" ], @@ -449,6 +452,9 @@ ".sh", ".zsh" ], + "ShellSession": [ + ".sh-session" + ], "Shen": [ ".shen" ], @@ -537,6 +543,9 @@ ], "YAML": [ ".yml" + ], + "Zephir": [ + ".zep" ] }, "interpreters": { @@ -600,8 +609,8 @@ ".gemrc" ] }, - "tokens_total": 525524, - "languages_total": 635, + "tokens_total": 527926, + "languages_total": 643, "tokens": { "ABAP": { "*/**": 1, @@ -920,6 +929,241 @@ "zero": 1, "Nat": 1 }, + "Alloy": { + "module": 3, + "examples/systems/file_system": 1, + "abstract": 2, + "sig": 20, + "Object": 10, + "{": 54, + "}": 60, + "Name": 2, + "File": 1, + "extends": 10, + "some": 3, + "d": 3, + "Dir": 8, + "|": 19, + "this": 14, + "in": 19, + "d.entries.contents": 1, + "entries": 3, + "set": 10, + "DirEntry": 2, + "parent": 3, + "lone": 6, + "this.": 4, + "@contents.": 1, + "@entries": 1, + "all": 16, + "e1": 2, + "e2": 2, + "e1.name": 1, + "e2.name": 1, + "@parent": 2, + "Root": 5, + "one": 8, + "no": 8, + "Cur": 1, + "name": 1, + "contents": 2, + "pred": 16, + "OneParent_buggyVersion": 2, + "-": 41, + "d.parent": 2, + "OneParent_correctVersion": 2, + "(": 12, + "&&": 2, + "contents.d": 1, + ")": 9, + "NoDirAliases": 3, + "o": 1, + "o.": 1, + "check": 6, + "for": 7, + "expect": 6, + "examples/systems/marksweepgc": 1, + "Node": 10, + "HeapState": 5, + "left": 3, + "right": 1, + "marked": 1, + "freeList": 1, + "clearMarks": 1, + "[": 82, + "hs": 16, + ".marked": 3, + ".right": 4, + "hs.right": 3, + "fun": 1, + "reachable": 1, + "n": 5, + "]": 80, + "+": 14, + "n.": 1, + "hs.left": 2, + "mark": 1, + "from": 2, + "hs.reachable": 1, + "setFreeList": 1, + ".freeList.*": 3, + ".left": 5, + "hs.marked": 1, + "GC": 1, + "root": 5, + "assert": 3, + "Soundness1": 2, + "h": 9, + "live": 3, + "h.reachable": 1, + "h.right": 1, + "Soundness2": 2, + ".reachable": 2, + "h.GC": 1, + ".freeList": 1, + "Completeness": 1, + "examples/systems/views": 1, + "open": 2, + "util/ordering": 1, + "State": 16, + "as": 2, + "so": 1, + "util/relation": 1, + "rel": 1, + "Ref": 19, + "t": 16, + "b": 13, + "v": 25, + "views": 2, + "when": 1, + "is": 1, + "view": 2, + "of": 3, + "type": 1, + "backing": 1, + "dirty": 3, + "contains": 1, + "refs": 7, + "that": 1, + "have": 1, + "been": 1, + "invalidated": 1, + "obj": 1, + "ViewType": 8, + "anyviews": 2, + "visualization": 1, + "ViewType.views": 1, + "Map": 2, + "keys": 3, + "map": 2, + "s": 6, + "Ref.map": 1, + "s.refs": 3, + "MapRef": 4, + "fact": 4, + "State.obj": 3, + "Iterator": 2, + "done": 3, + "lastRef": 2, + "IteratorRef": 5, + "Set": 2, + "elts": 2, + "SetRef": 5, + "KeySetView": 6, + "State.views": 1, + "IteratorView": 3, + "s.views": 2, + "handle": 1, + "possibility": 1, + "modifying": 1, + "an": 1, + "object": 1, + "and": 1, + "its": 1, + "at": 1, + "once": 1, + "*": 1, + "should": 1, + "we": 1, + "limit": 1, + "frame": 1, + "conds": 1, + "to": 1, + "non": 1, + "*/": 1, + "modifies": 5, + "pre": 15, + "post": 14, + "rs": 4, + "let": 5, + "vr": 1, + "pre.views": 8, + "mods": 3, + "rs.*vr": 1, + "r": 3, + "pre.refs": 6, + "pre.obj": 10, + "post.obj": 7, + "viewFrame": 4, + "post.dirty": 1, + "pre.dirty": 1, + "allocates": 5, + "&": 3, + "post.refs": 1, + ".map": 3, + ".elts": 3, + "dom": 1, + "<:>": 1, + "setRefs": 1, + "MapRef.put": 1, + "k": 5, + "none": 4, + "post.views": 4, + "SetRef.iterator": 1, + "iterRef": 4, + "i": 7, + "i.left": 3, + "i.done": 1, + "i.lastRef": 1, + "IteratorRef.remove": 1, + ".lastRef": 2, + "IteratorRef.next": 1, + "ref": 3, + "IteratorRef.hasNext": 1, + "s.obj": 1, + "zippishOK": 2, + "ks": 6, + "vs": 6, + "m": 4, + "ki": 2, + "vi": 2, + "s0": 4, + "so/first": 1, + "s1": 4, + "so/next": 7, + "s2": 6, + "s3": 4, + "s4": 4, + "s5": 4, + "s6": 4, + "s7": 2, + "precondition": 2, + "s0.dirty": 1, + "ks.iterator": 1, + "vs.iterator": 1, + "ki.hasNext": 1, + "vi.hasNext": 1, + "ki.this/next": 1, + "vi.this/next": 1, + "m.put": 1, + "ki.remove": 1, + "vi.remove": 1, + "State.dirty": 1, + "ViewType.pre.views": 2, + "but": 1, + "#s.obj": 1, + "<": 1 + }, "ApacheConf": { "ServerSignature": 1, "Off": 1, @@ -48819,6 +49063,151 @@ "foodforthought.jpg": 1, "name##*fo": 1 }, + "ShellSession": { + "echo": 2, + "FOOBAR": 2, + "Hello": 2, + "World": 2, + "gem": 4, + "install": 4, + "nokogiri": 6, + "...": 4, + "Building": 2, + "native": 2, + "extensions.": 2, + "This": 4, + "could": 2, + "take": 2, + "a": 4, + "while...": 2, + "checking": 1, + "for": 4, + "libxml/parser.h...": 1, + "***": 2, + "extconf.rb": 1, + "failed": 1, + "Could": 2, + "not": 2, + "create": 1, + "Makefile": 1, + "due": 1, + "to": 3, + "some": 1, + "reason": 2, + "probably": 1, + "lack": 1, + "of": 2, + "necessary": 1, + "libraries": 1, + "and/or": 1, + "headers.": 1, + "Check": 1, + "the": 2, + "mkmf.log": 1, + "file": 1, + "more": 1, + "details.": 1, + "You": 1, + "may": 1, + "need": 1, + "configuration": 1, + "options.": 1, + "brew": 2, + "tap": 2, + "homebrew/dupes": 1, + "Cloning": 1, + "into": 1, + "remote": 3, + "Counting": 1, + "objects": 3, + "done.": 4, + "Compressing": 1, + "%": 5, + "(": 6, + "/591": 1, + ")": 6, + "Total": 1, + "delta": 2, + "reused": 1, + "Receiving": 1, + "/1034": 1, + "KiB": 1, + "|": 1, + "bytes/s": 1, + "Resolving": 1, + "deltas": 1, + "/560": 1, + "Checking": 1, + "connectivity...": 1, + "done": 1, + "Warning": 1, + "homebrew/dupes/lsof": 1, + "over": 1, + "mxcl/master/lsof": 1, + "Tapped": 1, + "formula": 4, + "apple": 1, + "-": 12, + "gcc42": 1, + "Downloading": 1, + "http": 2, + "//r.research.att.com/tools/gcc": 1, + "darwin11.pkg": 1, + "########################################################################": 1, + "Caveats": 1, + "NOTE": 1, + "provides": 1, + "components": 1, + "that": 1, + "were": 1, + "removed": 1, + "from": 3, + "XCode": 2, + "in": 2, + "release.": 1, + "There": 1, + "is": 2, + "no": 1, + "this": 1, + "if": 1, + "you": 1, + "are": 1, + "using": 1, + "version": 1, + "prior": 1, + "contains": 1, + "compilers": 2, + "built": 2, + "Apple": 1, + "s": 1, + "GCC": 1, + "sources": 1, + "build": 1, + "available": 1, + "//opensource.apple.com/tarballs/gcc": 1, + "All": 1, + "have": 1, + "suffix.": 1, + "A": 1, + "GFortran": 1, + "compiler": 1, + "also": 1, + "included.": 1, + "Summary": 1, + "/usr/local/Cellar/apple": 1, + "gcc42/4.2.1": 1, + "files": 1, + "M": 1, + "seconds": 1, + "v": 1, + "Fetching": 1, + "Successfully": 1, + "installed": 2, + "Installing": 2, + "ri": 1, + "documentation": 2, + "RDoc": 1 + }, "Shen": { "*": 47, "graph.shen": 1, @@ -54312,11 +54701,163 @@ "GMT": 1, "recorded_with": 1, "VCR": 1 + }, + "Zephir": { + "%": 10, + "{": 56, + "#define": 1, + "MAX_FACTOR": 3, + "}": 50, + "namespace": 3, + "Test": 2, + ";": 86, + "#include": 1, + "static": 1, + "long": 3, + "fibonacci": 4, + "(": 55, + "n": 5, + ")": 53, + "if": 39, + "<": 1, + "return": 25, + "else": 11, + "-": 25, + "+": 5, + "class": 2, + "Cblock": 1, + "public": 22, + "function": 22, + "testCblock1": 1, + "int": 3, + "a": 6, + "testCblock2": 1, + "Router": 1, + "Route": 1, + "protected": 9, + "_pattern": 3, + "_compiledPattern": 3, + "_paths": 3, + "_methods": 5, + "_hostname": 3, + "_converters": 3, + "_id": 2, + "_name": 3, + "_beforeMatch": 3, + "__construct": 1, + "pattern": 37, + "paths": 7, + "null": 11, + "httpMethods": 6, + "this": 28, + "reConfigure": 2, + "let": 51, + "compilePattern": 2, + "var": 4, + "idPattern": 6, + "memstr": 10, + "str_replace": 6, + ".": 5, + "via": 1, + "extractNamedParams": 2, + "string": 6, + "char": 1, + "ch": 27, + "tmp": 4, + "matches": 5, + "boolean": 1, + "notValid": 5, + "false": 3, + "cursor": 4, + "cursorVar": 5, + "marker": 4, + "bracketCount": 7, + "parenthesesCount": 5, + "foundPattern": 6, + "intermediate": 4, + "numberMatches": 4, + "route": 12, + "item": 7, + "variable": 5, + "regexp": 7, + "strlen": 1, + "<=>": 5, + "0": 9, + "for": 4, + "in": 4, + "1": 3, + "substr": 3, + "break": 9, + "&&": 6, + "z": 2, + "Z": 2, + "true": 2, + "<='9')>": 1, + "_": 1, + "2": 2, + "continue": 1, + "[": 14, + "]": 14, + "moduleName": 5, + "controllerName": 7, + "actionName": 4, + "parts": 9, + "routePaths": 5, + "realClassName": 1, + "namespaceName": 1, + "pcrePattern": 4, + "compiledPattern": 4, + "extracted": 4, + "typeof": 2, + "throw": 1, + "new": 1, + "Exception": 1, + "explode": 1, + "switch": 1, + "count": 1, + "case": 3, + "controller": 1, + "action": 1, + "array": 1, + "The": 1, + "contains": 1, + "invalid": 1, + "#": 1, + "array_merge": 1, + "//Update": 1, + "the": 1, + "s": 1, + "name": 5, + "*": 2, + "@return": 1, + "*/": 1, + "getName": 1, + "setName": 1, + "beforeMatch": 1, + "callback": 2, + "getBeforeMatch": 1, + "getRouteId": 1, + "getPattern": 1, + "getCompiledPattern": 1, + "getPaths": 1, + "getReversedPaths": 1, + "reversed": 4, + "path": 3, + "position": 3, + "setHttpMethods": 1, + "getHttpMethods": 1, + "setHostname": 1, + "hostname": 2, + "getHostname": 1, + "convert": 1, + "converter": 2, + "getConverters": 1 } }, "language_tokens": { "ABAP": 1500, "Agda": 376, + "Alloy": 1143, "ApacheConf": 1449, "Apex": 4408, "AppleScript": 1862, @@ -54444,6 +54985,7 @@ "Scilab": 69, "SCSS": 39, "Shell": 3744, + "ShellSession": 233, "Shen": 3472, "Slash": 187, "SourcePawn": 2080, @@ -54471,11 +55013,13 @@ "XQuery": 801, "XSLT": 44, "Xtend": 399, - "YAML": 77 + "YAML": 77, + "Zephir": 1026 }, "languages": { "ABAP": 1, "Agda": 1, + "Alloy": 3, "ApacheConf": 3, "Apex": 6, "AppleScript": 7, @@ -54603,6 +55147,7 @@ "Scilab": 3, "SCSS": 1, "Shell": 37, + "ShellSession": 3, "Shen": 3, "Slash": 1, "SourcePawn": 1, @@ -54630,7 +55175,8 @@ "XQuery": 1, "XSLT": 1, "Xtend": 2, - "YAML": 2 + "YAML": 2, + "Zephir": 2 }, - "md5": "bea2304b61e5920c044b83aec7788dd8" + "md5": "37a50c87400d09dbc9cc99f1276d7e33" } \ No newline at end of file diff --git a/samples/Zephir/Cblock.zep b/samples/Zephir/Cblock.zep new file mode 100644 index 00000000..43db8d7a --- /dev/null +++ b/samples/Zephir/Cblock.zep @@ -0,0 +1,53 @@ +/** + * CBLOCK tests + * asfas + */ + +%{ +// top statement before namespace, add to after headers +#define MAX_FACTOR 40 +}% + +namespace Test; + +%{ +// top statement before class, add to after headers +// test include .h +#include "kernel/require.h" +}% + +%{ + +// c implement fibonacci +static long fibonacci(long n) { + if (n < 2) return n; + else return fibonacci(n - 2) + fibonacci(n - 1); +} + +}% + +class Cblock +{ + public function testCblock1() + { + int a = 0; + + %{ + a = MAX_FACTOR; + }% + + return a; + } + + public function testCblock2() + { + long a = 0; + + %{ + a = fibonacci(MAX_FACTOR); + }% + + return a; + } + +} diff --git a/samples/Zephir/Router.zep b/samples/Zephir/Router.zep new file mode 100644 index 00000000..a8d4f907 --- /dev/null +++ b/samples/Zephir/Router.zep @@ -0,0 +1,557 @@ + +namespace Test\Router; + +/** + * Test\Router\Route + * + * This class represents every route added to the router + */ +class Route +{ + protected _pattern; + + protected _compiledPattern; + + protected _paths; + + protected _methods; + + protected _hostname; + + protected _converters; + + protected _id; + + protected _name; + + protected _beforeMatch; + + /** + * Test\Router\Route constructor + * + * @param string pattern + * @param array paths + * @param array|string httpMethods + */ + public function __construct(pattern, paths=null, httpMethods=null) + { + // Configure the route (extract parameters, paths, etc) + this->reConfigure(pattern, paths); + + // Update the HTTP method constraints + let this->_methods = httpMethods; + } + + /** + * Replaces placeholders from pattern returning a valid PCRE regular expression + * + * @param string pattern + * @return string + */ + public function compilePattern(pattern) + { + var idPattern; + + // If a pattern contains ':', maybe there are placeholders to replace + if memstr(pattern, ":") { + + // This is a pattern for valid identifiers + let idPattern = "/([a-zA-Z0-9\\_\\-]+)"; + + // Replace the module part + if memstr(pattern, "/:module") { + let pattern = str_replace("/:module", idPattern, pattern); + } + + // Replace the controller placeholder + if memstr(pattern, "/:controller") { + let pattern = str_replace("/:controller", idPattern, pattern); + } + + // Replace the namespace placeholder + if memstr(pattern, "/:namespace") { + let pattern = str_replace("/:namespace", idPattern, pattern); + } + + // Replace the action placeholder + if memstr(pattern, "/:action") { + let pattern = str_replace("/:action", idPattern, pattern); + } + + // Replace the params placeholder + if memstr(pattern, "/:params") { + let pattern = str_replace("/:params", "(/.*)*", pattern); + } + + // Replace the int placeholder + if memstr(pattern, "/:int") { + let pattern = str_replace("/:int", "/([0-9]+)", pattern); + } + } + + // Check if the pattern has parantheses in order to add the regex delimiters + if memstr(pattern, "(") { + return "#^" . pattern . "$#"; + } + + // Square brackets are also checked + if memstr(pattern, "[") { + return "#^" . pattern . "$#"; + } + + return pattern; + } + + /** + * Set one or more HTTP methods that constraint the matching of the route + * + * + * $route->via('GET'); + * $route->via(array('GET', 'POST')); + * + * + * @param string|array httpMethods + * @return Test\Router\Route + */ + public function via(httpMethods) + { + let this->_methods = httpMethods; + return this; + } + + /** + * Extracts parameters from a string + * + * @param string pattern + */ + public function extractNamedParams(string pattern) + { + + char ch; + var tmp, matches; + boolean notValid = false; + int cursor, cursorVar, marker, bracketCount = 0, parenthesesCount = 0, foundPattern = 0; + int intermediate = 0, numberMatches = 0; + string route, item, variable, regexp; + + if strlen(pattern) <= 0 { + return false; + } + + let matches = [], + route = ""; + + for cursor, ch in pattern { + + if parenthesesCount == 0 { + if ch == '{' { + if bracketCount == 0 { + let marker = cursor + 1, + intermediate = 0, + notValid = false; + } + let bracketCount++; + } else { + if ch == '}' { + let bracketCount--; + if intermediate > 0 { + if bracketCount == 0 { + + let numberMatches++, + variable = null, + regexp = null, + item = (string) substr(pattern, marker, cursor - marker); + + for cursorVar, ch in item { + + if ch == '\0' { + break; + } + + if cursorVar == 0 && !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { + let notValid = true; + break; + } + + if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <='9') || ch == '-' || ch == '_' || ch == ':' { + if ch == ':' { + let variable = (string) substr(item, 0, cursorVar), + regexp = (string) substr(item, cursorVar + 1); + break; + } + } else { + let notValid = true; + break; + } + + } + + if !notValid { + + let tmp = numberMatches; + + if variable && regexp { + + let foundPattern = 0; + for ch in regexp { + if ch == '\0' { + break; + } + if !foundPattern { + if ch == '(' { + let foundPattern = 1; + } + } else { + if ch == ')' { + let foundPattern = 2; + break; + } + } + } + + if foundPattern != 2 { + let route .= '(', + route .= regexp, + route .= ')'; + } else { + let route .= regexp; + } + let matches[variable] = tmp; + } else { + let route .= "([^/]*)", + matches[item] = tmp; + } + } else { + let route .= "{" . item ."}"; + } + continue; + } + } + } + } + } + + if bracketCount == 0 { + if ch == '(' { + let parenthesesCount++; + } else { + if ch == ')' { + let parenthesesCount--; + if parenthesesCount == 0 { + let numberMatches++; + } + } + } + } + + if bracketCount > 0 { + let intermediate++; + } else { + let route .= ch; + } + } + + return [route, matches]; + } + + /** + * Reconfigure the route adding a new pattern and a set of paths + * + * @param string pattern + * @param array paths + */ + public function reConfigure(pattern, paths=null) + { + var moduleName, controllerName, actionName, + parts, routePaths, realClassName, namespaceName, + pcrePattern, compiledPattern, extracted; + + if typeof pattern != "string" { + throw new Exception("The pattern must be string"); + } + + if paths !== null { + if typeof paths == "string" { + + let moduleName = null, + controllerName = null, + actionName = null; + + // Explode the short paths using the :: separator + let parts = explode("::", paths); + + // Create the array paths dynamically + switch count(parts) { + case 3: + let moduleName = parts[0], + controllerName = parts[1], + actionName = parts[2]; + break; + case 2: + let controllerName = parts[0], + actionName = parts[1]; + break; + case 1: + let controllerName = parts[0]; + break; + } + + let routePaths = []; + + // Process module name + if moduleName !== null { + let routePaths["module"] = moduleName; + } + + // Process controller name + if controllerName !== null { + + // Check if we need to obtain the namespace + if memstr(controllerName, "\\") { + + // Extract the real class name from the namespaced class + let realClassName = get_class_ns(controllerName); + + // Extract the namespace from the namespaced class + let namespaceName = get_ns_class(controllerName); + + // Update the namespace + if namespaceName { + let routePaths["namespace"] = namespaceName; + } + } else { + let realClassName = controllerName; + } + + // Always pass the controller to lowercase + let routePaths["controller"] = uncamelize(realClassName); + } + + // Process action name + if actionName !== null { + let routePaths["action"] = actionName; + } + } else { + let routePaths = paths; + } + } else { + let routePaths = []; + } + + if typeof routePaths !== "array" { + throw new Exception("The route contains invalid paths"); + } + + // If the route starts with '#' we assume that it is a regular expression + if !starts_with(pattern, "#") { + + if memstr(pattern, "{") { + // The route has named parameters so we need to extract them + let extracted = this->extractNamedParams(pattern), + pcrePattern = extracted[0], + routePaths = array_merge(routePaths, extracted[1]); + } else { + let pcrePattern = pattern; + } + + // Transform the route's pattern to a regular expression + let compiledPattern = this->compilePattern(pcrePattern); + } else { + let compiledPattern = pattern; + } + + // Update the original pattern + let this->_pattern = pattern; + + // Update the compiled pattern + let this->_compiledPattern = compiledPattern; + + //Update the route's paths + let this->_paths = routePaths; + } + + /** + * Returns the route's name + * + * @return string + */ + public function getName() + { + return this->_name; + } + + /** + * Sets the route's name + * + * + * $router->add('/about', array( + * 'controller' => 'about' + * ))->setName('about'); + * + * + * @param string name + * @return Route + */ + public function setName(name) + { + let this->_name = name; + return this; + } + + /** + * Sets a callback that is called if the route is matched. + * The developer can implement any arbitrary conditions here + * If the callback returns false the route is treaded as not matched + * + * @param callback callback + * @return Test\Router\Route + */ + public function beforeMatch(callback) + { + let this->_beforeMatch = callback; + return this; + } + + /** + * Returns the 'before match' callback if any + * + * @return mixed + */ + public function getBeforeMatch() + { + return this->_beforeMatch; + } + + /** + * Returns the route's id + * + * @return string + */ + public function getRouteId() + { + return this->_id; + } + + /** + * Returns the route's pattern + * + * @return string + */ + public function getPattern() + { + return this->_pattern; + } + + /** + * Returns the route's compiled pattern + * + * @return string + */ + public function getCompiledPattern() + { + return this->_compiledPattern; + } + + /** + * Returns the paths + * + * @return array + */ + public function getPaths() + { + return this->_paths; + } + + /** + * Returns the paths using positions as keys and names as values + * + * @return array + */ + public function getReversedPaths() + { + var reversed, path, position; + + let reversed = []; + for path, position in this->_paths { + let reversed[position] = path; + } + return reversed; + } + + /** + * Sets a set of HTTP methods that constraint the matching of the route (alias of via) + * + * + * $route->setHttpMethods('GET'); + * $route->setHttpMethods(array('GET', 'POST')); + * + * + * @param string|array httpMethods + * @return Test\Router\Route + */ + public function setHttpMethods(httpMethods) + { + let this->_methods = httpMethods; + return this; + } + + /** + * Returns the HTTP methods that constraint matching the route + * + * @return string|array + */ + public function getHttpMethods() + { + return this->_methods; + } + + /** + * Sets a hostname restriction to the route + * + * + * $route->setHostname('localhost'); + * + * + * @param string|array httpMethods + * @return Test\Router\Route + */ + public function setHostname(hostname) + { + let this->_hostname = hostname; + return this; + } + + /** + * Returns the hostname restriction if any + * + * @return string + */ + public function getHostname() + { + return this->_hostname; + } + + /** + * Adds a converter to perform an additional transformation for certain parameter + * + * @param string name + * @param callable converter + * @return Test\Router\Route + */ + public function convert(name, converter) + { + let this->_converters[name] = converter; + return this; + } + + /** + * Returns the router converter + * + * @return array + */ + public function getConverters() + { + return this->_converters; + } + +}