Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Removed references to IKanServe... Added some ioke dependencies

  • Loading branch information...
commit 097ca278760d3d139e8b9cdadac1eb0baa3a5e22 1 parent 6bf2f72
@felipero authored
Showing with 2,854 additions and 9 deletions.
  1. +1 −1  build.xml
  2. BIN  lib/ikanserve.jar
  3. BIN  lib/ioke.jar
  4. +9 −0 lib/ioke/blank_slate.ik
  5. +55 −0 lib/ioke/debugger.ik
  6. +7 −0 lib/ioke/dokgen.ik
  7. +116 −0 lib/ioke/dokgen/collector.ik
  8. +242 −0 lib/ioke/dokgen/generator.ik
  9. +50 −0 lib/ioke/dokgen/htmlGenerator/CellFrame.ik_template
  10. +59 −0 lib/ioke/dokgen/htmlGenerator/FileFile.ik_template
  11. +50 −0 lib/ioke/dokgen/htmlGenerator/FileFrame.ik_template
  12. +115 −0 lib/ioke/dokgen/htmlGenerator/KindFile.ik_template
  13. +50 −0 lib/ioke/dokgen/htmlGenerator/KindFrame.ik_template
  14. +51 −0 lib/ioke/dokgen/htmlGenerator/Readme.ik_template
  15. +51 −0 lib/ioke/dokgen/htmlGenerator/stationary/README.html
  16. +174 −0 lib/ioke/dokgen/htmlGenerator/stationary/dokgen-style.css
  17. +25 −0 lib/ioke/dokgen/htmlGenerator/stationary/index.html
  18. +64 −0 lib/ioke/dokgen/htmlGenerator/templates.ik
  19. +37 −0 lib/ioke/dokgen/runner.ik
  20. +238 −0 lib/ioke/iopt.ik
  21. +185 −0 lib/ioke/iopt/action.ik
  22. +108 −0 lib/ioke/iopt/commandLine.ik
  23. +12 −0 lib/ioke/iopt/conditions.ik
  24. +156 −0 lib/ioke/iopt/doc.ik
  25. +2 −0  lib/ioke/iopt/help.ik
  26. +35 −0 lib/ioke/iopt/help/plain.ik
  27. +19 −0 lib/ioke/ispec.ik
  28. +12 −0 lib/ioke/ispec/conditions.ik
  29. +51 −0 lib/ioke/ispec/describeContext.ik
  30. +184 −0 lib/ioke/ispec/expectations.ik
  31. +25 −0 lib/ioke/ispec/extendedDefaultBehavior.ik
  32. +187 −0 lib/ioke/ispec/formatter.ik
  33. +102 −0 lib/ioke/ispec/reporter.ik
  34. +229 −0 lib/ioke/ispec/runner.ik
  35. +110 −0 lib/ioke/text_scanner.ik
  36. +0 −2  src/ioke/iks_load.ik
  37. +43 −6 test/ikido_spec.ik
View
2  build.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<project basedir="." default="jar" name="ikido">
+<project basedir="." default="sample-app" name="ikido">
<description>
Ikido is a micro-framework for web apps
</description>
View
BIN  lib/ikanserve.jar
Binary file not shown
View
BIN  lib/ioke.jar
Binary file not shown
View
9 lib/ioke/blank_slate.ik
@@ -0,0 +1,9 @@
+
+BlankSlate = Origin mimic do(
+ create = method(callback,
+ bs = BlankSlate mimic
+ callback call(bs)
+ bs removeAllMimics!
+ bs
+ )
+)
View
55 lib/ioke/debugger.ik
@@ -0,0 +1,55 @@
+
+IokeDebugger = Origin mimic do(
+ NoSuchRestart = Condition Error mimic
+
+ currentlyRunning = []
+
+ invoke = method(condition, context,
+ newDebugger = self with(condition: condition, context: context)
+ newDebugger runDebugSession
+ )
+
+ runDebugSession = method(
+ IokeDebugger currentlyRunning << self
+ len = IokeDebugger currentlyRunning length
+
+
+ newIo = io mimic
+ newIo prompt = " dbg:#{len}> "
+
+ ensure(
+ loop(
+ restarts = availableRestarts(self condition)
+
+ "The following restarts are available:" println
+ restarts each(ix, re, out println(" %s: %-20s (%s)" format(ix, re name, re report call(re))))
+ out println
+
+ value = Message fromText(newIo gets)
+ if((value name == :"internal:createNumber") && (value next name == :"."),
+ restartToInvoke = value evaluateOn(condition context)
+ if(restarts[restartToInvoke],
+ argumentNames = restarts[restartToInvoke] argumentNames
+ restartArguments = argumentNames map(name,
+ newIo prompt = " dbg:#{len}:#{name}> "
+ argVal = Message fromText(newIo gets) evaluateOn(condition context)
+ out println(" +> #{cell(:argVal) inspect}")
+ out println
+
+ cell(:argVal)
+ )
+
+ out println
+ invokeRestart(restarts[restartToInvoke], *restartArguments)
+ )
+ error!(IokeDebugger NoSuchRestart, number: restartToInvoke),
+
+ out println(" +> #{value evaluateOn(condition context) inspect}")
+ out println)
+ )
+
+ invokeRestart(:abort),
+
+ IokeDebugger currentlyRunning = IokeDebugger currentlyRunning[0..-2])
+ )
+)
View
7 lib/ioke/dokgen.ik
@@ -0,0 +1,7 @@
+
+DokGen = Origin mimic
+
+use("dokgen/collector")
+use("dokgen/generator")
+use("dokgen/runner")
+
View
116 lib/ioke/dokgen/collector.ik
@@ -0,0 +1,116 @@
+
+DokGen do(
+ KindsToAvoid = [DokGen, JavaGround]
+
+ collect = method(
+ current, collected,
+ visited set,
+ idGenerator fn(current, fn(current++)) call(0),
+
+ cell(:current) cells each(c,
+ unless((KindsToAvoid include?(c value)),
+ if(kindName?(c key),
+ if(!(visited include?(c value kind)),
+ visited << c value kind
+ collected collectedKinds[c value kind] = [c value, {}]
+ collect(c value, collected, visited, idGenerator)),
+
+ id = idGenerator call
+ if(code?(c value),
+ fname = c value message filename
+ (collected collectedFiles[fname] ||= []) << [cell(:current), c key, c value, id])
+ (collected collectedCells[c key asText] ||= []) << [cell(:current), c key, c value, id, {}]))))
+
+ kindName? = method(name,
+ if((#/^[A-Z]/ =~ name) || ([:nil, :true, :false] include?(name)),
+ true,
+ false))
+
+ code? = method(val,
+ ((cell(:val) kind?("DefaultMethod")) ||
+ (cell(:val) kind?("LexicalBlock")) ||
+ (cell(:val) kind?("DefaultMacro")) ||
+ (cell(:val) kind?("LexicalMacro")) ||
+ (cell(:val) kind?("DefaultSyntax"))))
+
+ collectSpecs = method(specsPattern, collectedSpecs, collected,
+ use("ispec")
+
+ ISpec Options shouldRun? = false
+ ISpec shouldExit? = false
+
+ FileSystem[specsPattern] each(f, use(f))
+
+ ISpec specifications each(spec,
+ collectSpec(spec, collectedSpecs)
+ )
+
+ collectedSpecs each(cspec,
+ unless(cspec value cell?(:dokgenSpecAlreadyCollected),
+ ;; also check cells in the sub thingy
+
+ fixed = false
+ segments = cspec key split(" ")
+ kindName = "%[%s %]" format(segments[0..-2])[0..-2]
+
+ cellForSegment = collected collectedCells[segments[-1]]
+ if(cellForSegment,
+ place = cellForSegment find(x, (x[0] kind == kindName) || ((x[0] kind == "Ground") && kindName == "") || ((x[0] kind == "IokeGround") && kindName == ""))
+
+ if(place,
+ place[4][cspec key] = cspec value
+ cspec value dokgenSpecAlreadyCollected = true
+ fixed = true
+ )
+ )
+
+ segments = segments[0..-2]
+
+ cellForKind = collected collectedKinds[cspec key]
+ if(cellForKind,
+ cellForKind[1][cspec key] = cspec value
+ cspec value dokgenSpecAlreadyCollected = true
+ fixed = true
+ )
+
+ while(!fixed && (segments length > 0),
+ kindName = "%[%s %]" format(segments)[0..-2]
+ kindNameX = "%[%s %]" format(segments[0..-2])[0..-2]
+
+ cellForSegment = collected collectedCells[segments[-1]]
+ if(cellForSegment,
+ place = cellForSegment find(x, (x[0] kind == kindNameX) || ((x[0] kind == "Ground") && kindNameX == ""))
+
+ if(place,
+ place[4][cspec key] = cspec value
+ cspec value dokgenSpecAlreadyCollected = true
+ fixed = true
+ )
+ )
+
+ unless(fixed,
+ cellForKind = collected collectedKinds[kindName]
+
+ if(cellForKind,
+ cellForKind[1][cspec key] = cspec value
+ cspec value dokgenSpecAlreadyCollected = true
+ fixed = true
+ )
+ )
+
+ segments = segments[0..-2]
+ )
+ )
+ )
+ )
+
+ collectSpec = method(spec, collectedSpecs,
+ theList = (collectedSpecs[spec fullName] ||= [])
+
+ spec specs each(sp,
+ if(sp[0] == :description,
+ collectSpec(sp[1], collectedSpecs),
+ if(sp[0] == :test,
+ theList << [sp[1], sp[2]],
+ theList << [sp[1]]))))
+)
View
242 lib/ioke/dokgen/generator.ik
@@ -0,0 +1,242 @@
+
+DokGen do(
+ HtmlGenerator = Origin mimic do(
+ generate = method(directory, collection,
+ FileSystem ensureDirectory(directory)
+ FileSystem ensureDirectory("#{directory}/files")
+ FileSystem ensureDirectory("#{directory}/kinds")
+
+ copyStationaryFiles(directory)
+ copyReadmeIfAvailable(directory)
+
+ generateFileFrame(directory, collection collectedFiles)
+ generateKindFrame(directory, collection collectedKinds)
+ generateCellFrame(directory, collection collectedCells)
+
+ generateFileFiles(directory, collection collectedFiles)
+ generateKindFiles(directory, collection collectedKinds, collection collectedCells, collection collectedSpecs)
+ )
+
+ copyStationaryFiles = method(dir,
+ copyStationary("dokgen-style.css", dir)
+ copyStationary("index.html", dir)
+ )
+
+ copyReadmeIfAvailable = method(dir,
+ if(FileSystem exists?("README"),
+
+ generateFromTemplate(Templates Readme,
+ out: "#{dir}/files/README.html",
+ content: FileSystem readFully("README"),
+ basePath: "../"),
+
+ copyStationary("README.html", "#{dir}/files"))
+ )
+
+ copyStationary = method(file, dir,
+ FileSystem copyFile("#{System currentDirectory}/htmlGenerator/stationary/#{file}", dir)
+ )
+
+ generateFromTemplate = method(template, out:, +:krest,
+ FileSystem withOpenFile(out, fn(f, template generateIntoFile(f, *krest)))
+ )
+
+ generateFileFrame = method(dir, files,
+ names = (files keys sort - ["<init>"]) map(fname,
+ [htmlizeName(fname), fname])
+
+ content = "%*[<a href=\"files/%s\">%s</a><br />\n%]" format(names)
+
+ generateFromTemplate(Templates FileFrame,
+ out: "#{dir}/fr_file_index.html",
+ content: content)
+ )
+
+ htmlizeName = method(name,
+ if(#/ik$/ =~ name,
+ "#{name[0..-4]}.html",
+ "#{name}.html"))
+
+ generateKindFrame = method(dir, kinds,
+ allKinds = kinds keys sort map(x, [x replaceAll(" ", "/"), x])
+
+ content = "%*[<a href=\"kinds/%s.html\">%s</a><br />\n%]" format(allKinds)
+ generateFromTemplate(Templates KindFrame,
+ out: "#{dir}/fr_kind_index.html",
+ content: content)
+ )
+
+ generateCellFrame = method(dir, cells,
+ cellData = []
+ cells keys sort each(c,
+ xx = cells[c] sortBy(cc, [cc[0] kind, cc[3]])
+ xx each(ccc,
+ cellData << [ccc[0] kind replaceAll(" ", "/"), ccc[3], makeTextHtmlSafe(c asText), ccc[0] kind]))
+
+ content = "%*[<a href=\"kinds/%s.html#C00%s\">%s (%s)</a><br />\n%]" format(cellData)
+ generateFromTemplate(Templates CellFrame,
+ out: "#{dir}/fr_cell_index.html",
+ content: content)
+ )
+
+ generateKindFile = method(dir, kindName, theKind, cells, specs, kindSpecs,
+ segments = kindName split(" ")
+ beforeLinks = "../" * (segments length)
+ htmlFile = "#{dir}/kinds/#{kindName replaceAll(" ", "/")}.html"
+
+ parent = FileSystem parentOf(htmlFile)
+ FileSystem ensureDirectory(parent)
+
+ mainMimicContent = "none"
+ allMimicsContent = "none"
+
+ unless(Base == cell(:theKind),
+ allMimics = if(cell(:theKind) cell?(:mimic),
+ cell(:theKind) mimics,
+ [])
+ mainMimic = if(cell(:theKind) cell?(:mimic),
+ cell(:theKind) mimics first,
+ nil)
+
+ if(allMimics length > 0,
+ mainMimicContent = "<a href=\"#{beforeLinks}kinds/%s.html\">%s</a>" format(cell(:mainMimic) kind replaceAll(" ", "/"), cell(:mainMimic) kind)
+ allMimicsContent = "%*[<li><a href=\"#{beforeLinks}kinds/%s.html\">%s</a></li>%]" format(allMimics map(mm, [cell(:mm) kind replaceAll(" ", "/"), cell(:mm) kind]))
+ )
+ )
+
+
+ names = (kindSpecs keys sort) - [kindName]
+ mainSpecs = kindSpecs[kindName]
+
+ kindSpecsContent = ""
+
+ specIndex = 0
+
+ if(mainSpecs,
+ kindSpecsContent = "<ul style=\"list-style-type: none;\">\n#{createCellSpecsOnlyFor("K0#{specIndex++}", nil, mainSpecs)}</ul>"
+ )
+
+ names each(name,
+ kindSpecsContent = "#{kindSpecsContent}\n<b>#{name}</b><br/>\n<ul style=\"list-style-type: none;\">\n#{createCellSpecsOnlyFor("K0#{specIndex++}", nil, kindSpecs[name])}</ul>"
+ )
+
+ inactiveCells = []
+ activeCells = []
+
+ cell(:theKind) cells each(cc,
+ if(cells[cc key asText],
+ vex = cells[cc key asText] find(val, (cell(:theKind) == val[0]) && (cell(:theKind) kind == val[0] kind))
+ if((cc value cell?(:activatable)) && (cc value cell(:activatable)),
+ theKey = "#{vex[0] kind} #{cc key}"
+ activeCells << [cc key, cc value, vex, vex[2] argumentsCode],
+ inactiveCells << [cc key, cc value, vex])))
+
+ activeCells = activeCells sortBy(v, [v[0], v[2][3]])
+ inactiveCells = inactiveCells sortBy(v, [v[0], v[2][3]])
+
+ inactiveCellsSummary = "%*[<li><a href=\"#C00%s\">%s</a></li>\n%]" format(inactiveCells map(val, [val[2][3], makeTextHtmlSafe(val[0] asText)]))
+ activeCellsSummary = "%*[<li><a href=\"#C00%s\">%s(%s)</a></li>\n%]" format(activeCells map(val, [val[2][3], makeTextHtmlSafe(val[0] asText), makeTextHtmlSafe(val[3])]))
+
+ inactiveCellsContent = "%[%s\n%]" format(inactiveCells map(ic, Templates KindFile inactiveCellData(cellName: makeTextHtmlSafe(ic[0] asText), cellValue: ic[1] notice, cellId: ic[2][3])))
+ activeCellsContent = "%[%s\n%]" format(activeCells map(ic, Templates KindFile activeCellData(cellName: makeTextHtmlSafe(ic[0] asText), cellDescription: ic[1] documentation, cellId: ic[2][3], cellArguments: makeTextHtmlSafe(ic[3]), cellSpecs: createCellSpecsFor(ic[2][3], ic, ic[2][4]), cellMessage: if(ic[2][2] cell?(:formattedCode), makeTextHtmlSafe(ic[2][2] formattedCode), nil))))
+
+ generateFromTemplate(Templates KindFile,
+ out: htmlFile,
+ kindName: kindName,
+ kindSpecs: kindSpecsContent,
+ kindDescription: cell(:theKind) documentation || "",
+ allMimics: allMimicsContent,
+ mainMimic: mainMimicContent,
+ inactiveCellsSummary: inactiveCellsSummary,
+ activeCellsSummary: activeCellsSummary,
+ inactiveCellsContent: inactiveCellsContent,
+ activeCellsContent: activeCellsContent,
+ basePath: beforeLinks
+ )
+ )
+
+ createCellSpecsFor = method(cellId, data, specData,
+ ks = specData keys sort
+ first = true
+ if(ks length > 0,
+ first = ks[0] split(" ")[-1] == data[0]
+ )
+
+ ix = 0
+
+ "%[%s\n%]" format(ks map(key,
+ if(first,
+ first = false
+ "<ul style=\"list-style-type: none;\">\n#{createCellSpecsOnlyFor("#{cellId}#{ix++}", nil, specData[key])}</ul>",
+ "<b>#{key}</b><br/>\n<ul style=\"list-style-type: none;\">\n#{createCellSpecsOnlyFor("#{cellId}#{ix++}", nil, specData[key])}</ul>"
+ )))
+ )
+
+ createCellSpecsOnlyFor = method(cellId, data, specData,
+ specIndex = 0
+ "%[<li>- %s</li>\n%]" format(specData map(sd,
+ if(sd length == 1,
+ sd[0],
+
+ result = "#{sd[0]} <span class=\"sourcecode\">
+ <span class=\"source-link\">[ <a href=\"javascript:toggleSource('C00#{cellId}S#{specIndex}_source')\" id=\"l_C00#{cellId}S#{specIndex}_source\">show source</a> ]</span>
+ <div id=\"C00#{cellId}S#{specIndex}_source\" class=\"dyn-source\">
+<pre>
+#{makeTextHtmlSafe(sd[1] formattedCode)}
+</pre>
+ </div>
+ </span>"
+ specIndex++
+ result
+ ))))
+
+ makeTextHtmlSafe = method(text,
+ text replaceAll("<", "&lt;") replaceAll(">", "&gt;"))
+
+ generateFileFile = method(dir, sourceFileName, info,
+ segments = sourceFileName split("/")
+ beforeLinks = "../" * (segments length)
+
+ htmlFile = "#{dir}/files/#{htmlizeName(sourceFileName)}"
+ parent = FileSystem parentOf(htmlFile)
+ FileSystem ensureDirectory(parent)
+ methods = []
+ macros = []
+
+ ;; we need to sort on both the method name, the surrounding kind and the unique ID
+ ;; since we need to guarantee a ordering.
+ ;; bad things will happen if the sort starts looking at the other elements in the list
+ info sortBy(x, [x[1], x[0] kind, x[3]]) each(v,
+ if(v[2] kind?("DefaultMacro"),
+ macros << [v[0] kind replaceAll(" ", "/"), v[3], makeTextHtmlSafe(v[1] asText), v[0] kind],
+ if(v[2] kind?("Method"),
+ methods << [v[0] kind replaceAll(" ", "/"), v[3], makeTextHtmlSafe(v[1] asText), v[0] kind])))
+
+ methodContent = "%*[<li><a href=\"#{beforeLinks}kinds/%s.html#C00%s\">%s (%s)</a><br /></li>\n%]" format(methods)
+ macroContent = "%*[<li><a href=\"#{beforeLinks}kinds/%s.html#C00%s\">%s (%s)</a><br /></li>\n%]" format(macros)
+
+ generateFromTemplate(Templates FileFile,
+ out: htmlFile,
+ filePath: sourceFileName,
+ simpleFileName: segments last,
+ fileDate: "---fluxie---",
+ methodContent: methodContent,
+ macroContent: macroContent,
+ syntaxContent: "",
+ basePath: beforeLinks
+ )
+ )
+
+ generateFileFiles = method(dir, files,
+ files each(f, unless(f key == "<init>", generateFileFile(dir, f key, f value)))
+ )
+
+ generateKindFiles = method(dir, kinds, cells, specs,
+ kinds each(k, generateKindFile(dir, k key, k value first, cells, specs, k value second))
+ )
+ )
+
+ generate = method(+args, HtmlGenerator generate(*args))
+)
+
+use("dokgen/htmlGenerator/templates")
View
50 lib/ioke/dokgen/htmlGenerator/CellFrame.ik_template
@@ -0,0 +1,50 @@
+<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
+<!DOCTYPE html
+ PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<html xmlns=\"http://www.w3.org/1999/xhtml\">
+ <head>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />
+ <title>Index</title>
+ <style type=\"text/css\">
+<!--
+ body {
+ background-color: #EEE;
+ font-family: Arial, Verdana, Sans-Serif;
+ color: #222;
+ margin: 0px;
+ font-size:12px;
+ }
+ .banner {
+ background: #303;
+ color: #FFF;
+ padding: 0.2em;
+ font-size: small;
+ font-weight: bold;
+ text-align: center;
+ }
+ .entries {
+ margin: 0.25em 1em 0 1em;
+ font-size: x-small;
+ }
+ a {
+ color: #222;
+ text-decoration: none;
+ font-weight: bold;
+ white-space: nowrap;
+ }
+ a:hover {
+ color: #606;
+ text-decoration: underline;
+ }
+-->
+ </style>
+ <base target=\"docwin\"/>
+ </head>
+ <body>
+ <div class=\"banner\">Cells</div>
+ <div class=\"entries\">
+ #{content}
+ </div>
+ </body>
+</html>
View
59 lib/ioke/dokgen/htmlGenerator/FileFile.ik_template
@@ -0,0 +1,59 @@
+<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
+<!DOCTYPE html
+PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<html xmlns=\"http://www.w3.org/1999/xhtml\">
+ <head>
+ <title>File: #{simpleFileName}</title>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />
+ <link rel=\"stylesheet\" href=\"#{basePath}./dokgen-style.css\" type=\"text/css\" media=\"screen\" />
+ </head>
+
+ <body>
+ <table border='0' cellpadding='0' cellspacing='0' width=\"100%\" class='banner'>
+ <tr>
+ <td>
+ <table width=\"100%\" border='0' cellpadding='0' cellspacing='0'>
+ <tr>
+ <td class=\"file-title\" colspan=\"2\">
+ <span class=\"file-title-prefix\">File</span>
+ <br />
+ #{simpleFileName}
+ </td>
+ <td align=\"right\">
+ <table border='0' cellspacing=\"0\" cellpadding=\"2\">
+ <tr>
+ <td>Path:</td>
+ <td>#{filePath}</td>
+ </tr>
+ <tr>
+ <td>Modified:</td>
+ <td>#{fileDate}</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <br />
+ <div id=\"bodyContent\">
+ <div id=\"content\">
+ <div class=\"sectiontitle\">Defined methods</div>
+ <ul>
+ #{methodContent}
+ </ul>
+
+ <div class=\"sectiontitle\">Defined macros</div>
+ <ul>
+ #{macroContent}
+ </ul>
+
+ <div class=\"sectiontitle\">Defined syntax</div>
+ <ul>
+ </ul>
+ </div>
+ </div>
+ </body>
+</html>
View
50 lib/ioke/dokgen/htmlGenerator/FileFrame.ik_template
@@ -0,0 +1,50 @@
+<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
+<!DOCTYPE html
+ PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<html xmlns=\"http://www.w3.org/1999/xhtml\">
+ <head>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />
+ <title>Index</title>
+ <style type=\"text/css\">
+<!--
+ body {
+ background-color: #EEE;
+ font-family: Arial, Verdana, Sans-Serif;
+ color: #222;
+ margin: 0px;
+ font-size:12px;
+ }
+ .banner {
+ background: #303;
+ color: #FFF;
+ padding: 0.2em;
+ font-size: small;
+ font-weight: bold;
+ text-align: center;
+ }
+ .entries {
+ margin: 0.25em 1em 0 1em;
+ font-size: x-small;
+ }
+ a {
+ color: #222;
+ text-decoration: none;
+ font-weight: bold;
+ white-space: nowrap;
+ }
+ a:hover {
+ color: #606;
+ text-decoration: underline;
+ }
+-->
+ </style>
+ <base target=\"docwin\"/>
+ </head>
+ <body>
+ <div class=\"banner\">Files</div>
+ <div class=\"entries\">
+ #{content}
+ </div>
+ </body>
+</html>
View
115 lib/ioke/dokgen/htmlGenerator/KindFile.ik_template
@@ -0,0 +1,115 @@
+<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
+<!DOCTYPE html
+PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<html xmlns=\"http://www.w3.org/1999/xhtml\">
+ <head>
+ <title>Kind: DefaultBehavior</title>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />
+ <link rel=\"stylesheet\" href=\"#{basePath}./dokgen-style.css\" type=\"text/css\" media=\"screen\" />
+ <script language=\"JavaScript\" type=\"text/javascript\">
+ // <![CDATA[
+
+ function toggleSource( id )
+ {
+ var elem
+ var link
+
+ if( document.getElementById )
+ {
+ elem = document.getElementById( id )
+ link = document.getElementById( \"l_\" + id )
+ }
+ else if ( document.all )
+ {
+ elem = eval( \"document.all.\" + id )
+ link = eval( \"document.all.l_\" + id )
+ }
+ else
+ return false;
+
+ if( elem.style.display == \"block\" )
+ {
+ elem.style.display = \"none\"
+ link.innerHTML = \"show source\"
+ }
+ else
+ {
+ elem.style.display = \"block\"
+ link.innerHTML = \"hide source\"
+ }
+ }
+
+ function openCode( url )
+ {
+ window.open( url, \"SOURCE_CODE\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=480,width=750\" ).focus();
+ }
+ // ]]>
+ </script>
+ </head>
+
+ <body>
+ <table border='0' cellpadding='0' cellspacing='0' width=\"100%\" class='banner'>
+ <tr>
+ <td>
+ <table width=\"100%\" border='0' cellpadding='0' cellspacing='0'>
+ <tr>
+ <td class=\"file-title\" colspan=\"2\">
+ <span class=\"file-title-prefix\">Kind</span>
+ <br />
+ #{kindName}
+ </td>
+ <td align=\"right\">
+ <table cellspacing=\"0\" cellpadding=\"2\">
+ <tr>
+ <td>Main mimic:</td>
+ <td>
+ #{mainMimic}
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+
+ <div id=\"bodyContent\">
+ <div id=\"content\">
+ <div class=\"description\">
+ <p>
+#{kindDescription}
+ </p>
+ </div>
+
+ <div class=\"sectiontitle\">Mimics</div>
+ <ul>
+ #{allMimics}
+ </ul>
+
+ <div class=\"sectiontitle\">Inactive cells</div>
+ <ul>
+ #{inactiveCellsSummary}
+ </ul>
+
+ <div class=\"sectiontitle\">Active cells</div>
+ <ul>
+ #{activeCellsSummary}
+ </ul>
+
+ <div class=\"sectiontitle\">Specs</div>
+ <div class=\"specs\">
+ #{kindSpecs}
+ </div>
+
+ <div class=\"sectiontitle\">Inactive cells (details)</div>
+ #{inactiveCellsContent}
+
+ <div class=\"sectiontitle\">Active cells (details)</div>
+ #{activeCellsContent}
+
+ </div>
+ </div>
+ </body>
+</html>
View
50 lib/ioke/dokgen/htmlGenerator/KindFrame.ik_template
@@ -0,0 +1,50 @@
+<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
+<!DOCTYPE html
+ PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+ \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<html xmlns=\"http://www.w3.org/1999/xhtml\">
+ <head>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />
+ <title>Index</title>
+ <style type=\"text/css\">
+<!--
+ body {
+ background-color: #EEE;
+ font-family: Arial, Verdana, Sans-Serif;
+ color: #222;
+ margin: 0px;
+ font-size:12px;
+ }
+ .banner {
+ background: #303;
+ color: #FFF;
+ padding: 0.2em;
+ font-size: small;
+ font-weight: bold;
+ text-align: center;
+ }
+ .entries {
+ margin: 0.25em 1em 0 1em;
+ font-size: x-small;
+ }
+ a {
+ color: #222;
+ text-decoration: none;
+ font-weight: bold;
+ white-space: nowrap;
+ }
+ a:hover {
+ color: #606;
+ text-decoration: underline;
+ }
+-->
+ </style>
+ <base target=\"docwin\"/>
+ </head>
+ <body>
+ <div class=\"banner\">Kinds</div>
+ <div class=\"entries\">
+ #{content}
+ </div>
+ </body>
+</html>
View
51 lib/ioke/dokgen/htmlGenerator/Readme.ik_template
@@ -0,0 +1,51 @@
+<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
+<!DOCTYPE html
+PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
+\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
+<html xmlns=\"http://www.w3.org/1999/xhtml\">
+ <head>
+ <title>File: README</title>
+ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />
+ <link rel=\"stylesheet\" href=\"#{basePath}./dokgen-style.css\" type=\"text/css\" media=\"screen\" />
+ </head>
+
+ <body>
+ <table border='0' cellpadding='0' cellspacing='0' width=\"100%\" class='banner'>
+ <tr>
+ <td>
+ <table width=\"100%\" border='0' cellpadding='0' cellspacing='0'>
+ <tr>
+ <td class=\"file-title\" colspan=\"2\">
+ <span class=\"file-title-prefix\">File</span>
+ <br />
+ README
+ </td>
+ <td align=\"right\">
+ <table border='0' cellspacing=\"0\" cellpadding=\"2\">
+ <tr>
+ <td>Path:</td>
+ <td>README</td>
+ </tr>
+ <tr>
+ <td>Modified:</td>
+ <td>00-00-00</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <br />
+ <div id=\"bodyContent\">
+ <div id=\"content\">
+ <div class=\"description\">
+ <p>
+ #{content}
+ </p>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
View
51 lib/ioke/dokgen/htmlGenerator/stationary/README.html
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>File: README</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <link rel="stylesheet" href=".././dokgen-style.css" type="text/css" media="screen" />
+ </head>
+
+ <body>
+ <table border='0' cellpadding='0' cellspacing='0' width="100%" class='banner'>
+ <tr>
+ <td>
+ <table width="100%" border='0' cellpadding='0' cellspacing='0'>
+ <tr>
+ <td class="file-title" colspan="2">
+ <span class="file-title-prefix">File</span>
+ <br />
+ README
+ </td>
+ <td align="right">
+ <table border='0' cellspacing="0" cellpadding="2">
+ <tr>
+ <td>Path:</td>
+ <td>README</td>
+ </tr>
+ <tr>
+ <td>Modified:</td>
+ <td>00-00-00</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <br />
+ <div id="bodyContent">
+ <div id="content">
+ <div class="description">
+ <p>
+ This project have no description
+ </p>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
View
174 lib/ioke/dokgen/htmlGenerator/stationary/dokgen-style.css
@@ -0,0 +1,174 @@
+body, td, p {color:#222;font-family:Arial, Verdana, Sans-Serif;font-size:12px;background:#fff;}
+
+a {
+ color: #222;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:hover {
+ color: #606;
+ text-decoration: underline;
+}
+
+body, td, p {
+ margin: 0px;
+}
+
+#content {
+ margin: 2em;
+}
+
+#description p {
+ margin-bottom: 0.5em;
+}
+
+.sectiontitle {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding: 0.5em;
+ padding-left: 2em;
+ background: #505;
+ color: #FFF;
+ font-weight: bold;
+ border: 1px dotted black;
+}
+
+.cell-rw {
+ padding-left: 1em;
+ padding-right: 1em;
+ text-align: center;
+ color: #055;
+}
+
+.cell-name {
+ font-weight: bold;
+}
+
+.cell-desc {
+}
+
+.cell-value {
+ font-family: monospace;
+}
+
+.file-title-prefix {
+ font-size: large;
+}
+
+.file-title {
+ font-size: large;
+ font-weight: bold;
+ background: #005;
+ color: #FFF;
+}
+
+.banner {
+ background: #303;
+ color: #FFF;
+ border: 1px solid black;
+ padding: 1em;
+}
+
+.banner td {
+ background: transparent;
+ color: #FFF;
+}
+
+h1 a, h2 a, .sectiontitle a, .banner a {
+ color: #FF0;
+}
+
+h1 a:hover, h2 a:hover, .sectiontitle a:hover, .banner a:hover {
+ color: #FF7;
+}
+
+.dyn-source {
+ display: none;
+ background: #FFE;
+ color: #000;
+ border: 1px dotted black;
+ margin: 0.5em 2em 0.5em 2em;
+ padding: 0.5em;
+}
+
+.dyn-source .cmt {
+ color: #40F;
+ font-style: italic;
+}
+
+.dyn-source .kw {
+ color: #070;
+ font-weight: bold;
+}
+
+.cell {
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-bottom: 1em;
+}
+
+.description pre {
+ padding: 0.5em;
+ border: 1px dotted black;
+ background: #FFE;
+}
+
+.cell .title {
+ font-family: monospace;
+ font-size: large;
+ border-bottom: 1px dashed black;
+ margin-bottom: 0.3em;
+ padding-bottom: 0.1em;
+}
+
+.cell .description, .cell .sourcecode {
+ margin-left: 1em;
+}
+
+.description p, .sourcecode p {
+ margin-bottom: 0.5em;
+}
+
+.cell .sourcecode p.source-link {
+ text-indent: 0em;
+ margin-top: 0.5em;
+}
+
+.cell .aka {
+ margin-top: 0.3em;
+ margin-left: 1em;
+ font-style: italic;
+ text-indent: 2em;
+}
+
+h1 {
+ padding: 1em;
+ border: 1px solid black;
+ font-size: x-large;
+ font-weight: bold;
+ color: #FFF;
+ background: #607;
+}
+
+h2 {
+ padding: 0.5em 1em 0.5em 1em;
+ border: 1px solid black;
+ font-size: large;
+ font-weight: bold;
+ color: #FFF;
+ background: #809;
+}
+
+h3, h4, h5, h6 {
+ padding: 0.2em 1em 0.2em 1em;
+ border: 1px dashed black;
+ color: #000;
+ background: #AAF;
+}
+
+.sourcecode > pre {
+ padding: 0.5em;
+ border: 1px dotted black;
+ background: #FFE;
+}
View
25 lib/ioke/dokgen/htmlGenerator/stationary/index.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Ioke documentation</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
+ </head>
+
+ <frameset cols="20%,*">
+ <frameset rows="15%,35%,50%">
+ <frame src="fr_file_index.html" title="Files" />
+ <frame src="fr_kind_index.html" />
+ <frame src="fr_cell_index.html" />
+ </frameset>
+
+ <frame src="files/README.html" id="docwin" name="docwin"/>
+
+ <noframes>
+ <body bgcolor="white">
+ You're kinda out of luck.
+ </body>
+ </noframes>
+ </frameset>
+</html>
View
64 lib/ioke/dokgen/htmlGenerator/templates.ik
@@ -0,0 +1,64 @@
+
+DokGen do(
+ HtmlGenerator do(
+ Templates = Origin mimic
+ Templates do(
+ Template = Origin mimic
+ Template generateIntoFile = method(file, +:krest,
+ file print(self data(*krest))
+ )
+
+ Readme = Template mimic
+ Readme data = Message doText("method(content:, basePath: \"./\", \"#{FileSystem readFully("#{System currentDirectory}/Readme.ik_template")}\")")
+
+ FileFrame = Template mimic
+ FileFrame data = Message doText("method(content:, basePath: \"./\", \"#{FileSystem readFully("#{System currentDirectory}/FileFrame.ik_template")}\")")
+
+ KindFrame = Template mimic
+ KindFrame data = Message doText("method(content:, basePath: \"./\", \"#{FileSystem readFully("#{System currentDirectory}/KindFrame.ik_template")}\")")
+
+ CellFrame = Template mimic
+ CellFrame data = Message doText("method(content:, basePath: \"./\", \"#{FileSystem readFully("#{System currentDirectory}/CellFrame.ik_template")}\")")
+
+ FileFile = Template mimic
+ FileFile data = Message doText("method(simpleFileName:, filePath:, fileDate:, methodContent:, macroContent:, syntaxContent:, basePath:, \"#{FileSystem readFully("#{System currentDirectory}/FileFile.ik_template")}\")")
+
+ KindFile = Template mimic
+ KindFile data = Message doText("method(kindName:, kindDescription:, kindSpecs:, inactiveCellsSummary:, activeCellsSummary:, inactiveCellsContent:, activeCellsContent:, allMimics:, mainMimic:, basePath:, \"#{FileSystem readFully("#{System currentDirectory}/KindFile.ik_template")}\")")
+
+ KindFile inactiveCellData = method(cellName:, cellValue:, cellId:,
+" <div class=\"cell\">
+ <a name=\"C00#{cellId}\"></a>
+ <table border=\"0\" cellpadding=\"5\">
+ <tr valign=\"top\">
+ <td class=\"cell-name\">#{cellName}</td>
+ <td>=</td>
+ <td class=\"cell-value\">#{cellValue}</td>
+ </tr>
+ </table>
+ </div>")
+
+ KindFile activeCellData = method(cellName:, cellArguments:, cellDescription:, cellId:, cellSpecs:, cellMessage:,
+" <div class=\"cell\">
+ <div class=\"title\">
+ <a name=\"C00#{cellId}\"></a><b>#{cellName}</b>(#{cellArguments})
+ </div>
+ <div class=\"description\">
+ <p>#{cellDescription}</p>
+ </div>
+ #{if(cellMessage,
+" <div class=\"sourcecode\">
+ <p class=\"source-link\">[ <a href=\"javascript:toggleSource('C00#{cellId}_source')\" id=\"l_C00#{cellId}_source\">show source</a> ]</p>
+ <div id=\"C00#{cellId}_source\" class=\"dyn-source\">
+<pre>
+#{cellMessage}
+</pre>
+ </div>
+ </div>","")}
+ <div class=\"specs\">
+ #{cellSpecs}
+ </div>
+ </div>")
+ )
+ )
+)
View
37 lib/ioke/dokgen/runner.ik
@@ -0,0 +1,37 @@
+
+DokGen do(
+ Collected = [{},{},{},{}] mimic do(
+ from = method(files, kinds, cells, specs {},
+ newObj = self mimic
+ newObj[0] = files
+ newObj[1] = kinds
+ newObj[2] = cells
+ newObj[3] = specs
+ newObj)
+
+ collectedFiles = method([0])
+ collectedKinds = method([1])
+ collectedCells = method([2])
+ collectedSpecs = method([3])
+ )
+
+ document = method(
+ "Takes a list of command line arguments, parses these and then builds up the documentation about all data in the system",
+ arguments,
+
+ outputDir = "dok"
+
+ combineWithSpecs = true
+ specsPattern = "test/**/*_spec.ik"
+
+ collected = Collected from({}, {"IokeGround" => IokeGround, "Ground" => Ground}, {})
+
+ collect(IokeGround, collected)
+
+ if(combineWithSpecs,
+ collectSpecs(specsPattern, collected collectedSpecs, collected)
+ )
+
+ generate(outputDir, collected)
+ )
+)
View
238 lib/ioke/iopt.ik
@@ -0,0 +1,238 @@
+IOpt = Origin mimic
+;; read the documentation at iopt/doc.ik
+use("iopt/conditions")
+use("iopt/commandLine")
+use("iopt/action")
+use("iopt/help")
+
+IOpt do(
+
+ initialize = method(
+ @iopt:receiver = nil
+ @iopt:actions = dict()
+ @iopt:help = dict(plain: IOpt Help Plain Simple mimic(self))
+ @initialize = method())
+
+ iopt:ion = method("If the argument is a valid option name, it MUST return
+ an object with the following cells:
+
+ short: an string like '-' if it is a short option, otherwise nil.
+ this value must be '-' or whatever prefix you use for short options.
+ option e.g. '-f', '--foo'. this value will be used to look for the
+ the option action by the iopt:get method.
+ immediate: if non-nil indicates this option has an immediate value,
+ for example in --foo=bar the inlined value should be bar
+ for short options like -l22 it should be 22.
+
+ If the argument is not a valid option name, return nil.
+
+ IOpt imposes no restriction on how an option looks like, by default
+ this method handles traditional unix style options. -f --foo.
+ But you can easily change that and have your options look like you
+ want for example like Mike tasks or windows /? style options if you
+ override this method.
+ ", arg,
+ if(m = #/^-({long}-)?({name}[\w_-]+)(=({immediate}.+))?$/ match(arg),
+ if(m long nil? && m immediate nil? && m name length > 1,
+ m immediate = m name[1..-1]
+ m name = m name[0..0])
+ m short = if(m long, nil, "-")
+ m option = if(m long, "--", "-") + m name
+ m))
+
+ iopt:key = method("Return non-nil if the argument is an option keyword.
+ If non-nil, the object should have the following cells defined:
+
+ name: The keyword name
+ immediate: The value if it has been provided with the keyword.
+
+ ", arg,
+ #/({name}[\w_-]+):({immediate}.+)?$/ match(arg))
+
+ iopt:get = method("Return the handler for option", arg,
+ if(handler = iopt:ion(arg),
+ if(handler action = iopt:actions[handler option],
+ unless(handler action mimics?(IOpt Action),
+ signal!(NoActionForOption, text: "Not a valid action for #{arg}",
+ option: arg, value: handler action)))
+ handler))
+
+ cell("[]") = method("Return the action handling the option given as argument",
+ arg, if(h = iopt:get(arg), if(h cell?(:action), h action)))
+
+ cell("[]=") = macro("Create an action that handles the options given as indeces.
+ This RHS action can be one of several things:
+
+ nil - Will unregister the options from this object.
+ Symbol - Will create an Action CellActivation that will activate the cell with
+ that name upon execution.
+ :@ - Will create an Action CellAssignment that will store the required
+ option argument on the named cell.
+ e.g. :@here will store its value in cell(:here)
+ Text - Will create an alias for the RHS option.
+ Action - Will register the action to handle options.
+ Message - Will create an Action MessageEvaluation that will evaluate the
+ message given on the action receiver.
+ value - Will create an Action ValueActivation that will activate the given
+ value, this can anything like Method, LexicalContext, Macros, etc.
+ ",
+ options = set()
+ call arguments butLast each(i, a,
+ a = call argAt(i)
+ unless(m = iopt:ion(a),
+ error!(MalformedOption, text: "Not a valid option: #{a}", option: a))
+ options << m option)
+ action = call arguments last
+ action = if(action name == :":@" && action next && action next next nil?,
+ Action CellAssignment mimic(action next name),
+ call argAt(call arguments length - 1))
+ case(cell(:action) kind,
+ "nil", options each(o, iopt:actions[o] = nil). return,
+
+ "Symbol",
+ if(action asText[0..0] == "@", ;; assign a cell
+ action = Action CellAssignment mimic(:(action asText[1..-1])),
+ action = Action CellActivation mimic(action)),
+
+ "Text",
+ o = iopt:ion(action)
+ unless(o,
+ signal!(MalformedOption, text: "Not a valid option: #{action}", option: action))
+ unless(action = iopt:actions[o option],
+ signal!(NoActionForOption,
+ text: "No action registered for option #{o option}", option: o option)),
+
+ "Message",
+ action = Action MessageEvaluation mimic(action),
+
+ unless(cell(:action) mimics?(Action),
+ action = Action ValueActivation mimic(cell(:action))))
+
+ action iopt = self
+ if(@cell("iopt:receiver"), action receiver = iopt:receiver)
+
+ options each(o, action options << o. iopt:actions[o] = action)
+ action)
+
+ on = dmacro("You can use this to create actions having an object as receiver.
+
+ - If the first arguments are options, the remaining arguments
+ will be used to create a LexicalBlock which will be the action handler.
+ These lexical blocks can access '@' and 'self' cells that reference
+ the action receiver. (in this case the iopt object itself)
+
+ on(\"-h\", \"--help\", \"Show help\", @println. System exit)
+
+ - If only given one argument, will return a mimic of self, having
+ the given argument as receiver for all actions created with it.
+
+ opts = IOpt on(myApp)
+ opts on(\"--me\", \"Print myApp\", @println)
+ opts on(\"--path\", \"Set the path cell on myApp\", :@path)
+ opts on(\"-f\", \"Call method doSomething on myApp\", :doSomething)
+
+ - If the first argument is an object the remaining arguments
+ are used to create a lexicalBlock to handle the action, having
+ the first argument as receiver.
+
+ on(myApp, \"-v\", \"Print myApp version\", @version println)
+ ",
+ []
+ self,
+
+ [>receiver]
+ other = @mimic
+ other iopt:receiver = cell(:receiver)
+ other,
+
+
+ [>receiver, +args]
+ options = list()
+ docs = list()
+ body = nil
+ action = nil
+
+ if(cell(:receiver) kind?("Text"),
+ unless(handler = iopt:ion(receiver),
+ signal!(MalformedOption, text: "Not a valid option: #{receiver}", option: receiver))
+ receiver = nil
+ options << handler option)
+
+ while(
+ list(:"internal:createText", :"internal:concatenateText") include?(args first name) && args first last == args first,
+ txt = args first evaluateOn(call ground)
+ if(handler = iopt:ion(txt),
+ options << handler option,
+ docs << txt)
+ args = args rest)
+
+ body = if(args last symbol?,
+ if(args last name == :":@",
+ :("@#{args last next name}"), call argAt(call arguments length - 1)),
+ if(args last name == :cachedResult,
+ args last evaluateOn(call ground),
+ args inject('fn, m, a, m << a) evaluateOn(call ground)))
+
+ action = options inject(cell(:body), a, f, @[f] = cell(:a))
+
+ if(docs empty?,
+ if(cell(:body) documentation, action documentation = cell(:body) documentation),
+ action documentation = docs join("\n"))
+
+ if(cell(:receiver), action receiver = cell(:receiver))
+ action
+ );on
+
+ cell("on=") = dmacro(
+ [first, second, +rest]
+ msg = call arguments butLast inject('on, m, a, m << a)
+ msg << Message wrap(call argAt(call arguments length - 1))
+ msg evaluateOn(call ground, call receiver))
+
+ parse! = method("Execute the options specified on argv.
+
+ This method will first obtain the actions for each option present on argv,
+ consume option arguments for each of them according to their arity.
+
+ The argument given to this method will be stored at cell argv on this object.
+ Elements from argv not consumed by any option will be available at
+ programArguments cell on this object.
+
+ After processing the command line, each action will be executed by priority.
+
+ See CommandLine initialize for a list of keyword arguments
+ ", argv, errorUnknownOptions: true, +:krest,
+ cmd = CommandLine mimic(self, argv, *krest)
+ @argv = cmd argv
+ @programArguments = cmd programArguments
+ @rest = cmd rest
+
+ if(errorUnknownOptions && !cmd unknownOptions empty?,
+ error!(UnknownOption, text: "Unknown options: %[%s %]" format(cmd unknownOptions)))
+
+ cmd execute
+ );parse!
+
+ parse = method("Just parse the command line, don't execute actions.
+
+ If you need to do advanced stuff, like validate mutual exclusive options, or handle
+ unknown options in some way, executing only some actions under certain conditions,
+ then this method is for you.
+
+ See CommandLine initialize for a list of keyword arguments",
+ argv, +:krest,
+ CommandLine mimic(self, argv, *krest))
+
+ asText = method(help(:plain) asText)
+
+ help = dmacro(
+ [>format]
+ iopt:help[format],
+
+ [>format, +body]
+ name = (format asText[0..0] upper) + format asText[1..-1]
+ msg = ('mimic << Message wrap(self))
+ body each(a, msg << a)
+ iopt:help[format] = msg sendTo(IOpt Help cell(name)))
+
+); IOpt
View
185 lib/ioke/iopt/action.ik
@@ -0,0 +1,185 @@
+IOpt Action = Origin mimic
+IOpt Action do(
+
+ ValueActivation = IOpt Action mimic do (
+ initialize = method(valueToActivate,
+ super()
+ @valueToActivate = cell(:valueToActivate)
+ @argumentsCode = cell(:valueToActivate) argumentsCode
+ @documentation = cell(:valueToActivate) documentation)
+
+ call = macro(
+ kargs = dict()
+ if(@cell(:valueToActivate) kind?("LexicalBlock") ||
+ @cell(:valueToActivate) kind?("LexicalMacro"),
+ kargs[:"@"] = kargs[:self] = receiver)
+ call activateValue(@cell(:valueToActivate), receiver, *kargs))
+
+ );ValueActivation
+
+ CellActivation = IOpt Action mimic do (
+ initialize = method(cellName,
+ super()
+ @cellName = cellName)
+
+ cell(:documentation) = method(
+ if(receiver, @documentation = receiver cell(cellName) documentation, nil))
+
+ argumentsCode = method(
+ if(receiver, receiver cell(cellName) argumentsCode, nil))
+
+ call = macro(call resendToValue(receiver cell(cellName), receiver))
+
+ );CellActivation
+
+ CellAssignment = IOpt Action mimic do (
+ initialize = method(cellName,
+ super()
+ @cellName = cellName
+ @documentation = "Set #{cellName asText}"
+ @argumentsCode = cellName asText)
+
+ call = method(value, receiver cell(cellName) = value)
+
+ );CellAssinment
+
+ MessageEvaluation = IOpt Action mimic do (
+ initialize = method(messageToEval,
+ super()
+ @documentation = "Evaluate message #{messageToEval code}"
+ @argumentsCode = nil
+ @messageToEval = messageToEval)
+
+ call = dmacro(
+ []
+ messageToEval evaluateOn(call ground, receiver),
+
+ [>value]
+ messageToEval evaluateOn(call ground with(it: value), receiver))
+
+ );MessageEvaluation
+
+ initialize = method(
+ @options = set()
+ @priority = 0
+ )
+
+ receiver = method(if(@cell?(:iopt), iopt iopt:receiver || iopt))
+
+ <=> = method("Compare by priority", other, priority <=> other priority)
+
+ cell("priority=") = method("Set the option priority.
+ Default priority level is 0.
+ Negative values are higher priority for options that
+ must be processed before those having priority(0).
+ Positive ones are executed just after all priority(0)",
+ value,
+ @cell(:priority) = value
+ self)
+
+ ; The object used to coerce arguments for this action.
+ coerce = nil
+ coercing = method(+types, +:coersions,
+ @coerce = IOpt CommandLine Coerce mimic(*types, *coersions)
+ self)
+
+ consume = method("Take arguments for this action according to its arity.
+
+ The argv list must have its first element be one of the options handled by this action
+ otherwise a NoActionForOption will be signaled.
+
+ This method returns an object with the following cells:
+
+ option: The option that was processed
+ remnant: The elements from argv that were not taken as arguments for this action.
+ positional: A list of positional arguments for this action.
+ keywords: A dict of keyword arguments for this action.
+
+ ", argv, handler iopt iopt:ion(argv first), untilNextOption: true, coerce: nil,
+ if(handler nil? || !options include?(handler option),
+ error!(NoActionForOption,
+ text: "Cannot handle option %s not in %s" format(
+ if(handler, handler option, argv first), options inspect),
+ option: if(handler, handler option, argv first)))
+
+ remnant = argv rest
+ currentKey = nil
+ args = list
+ klist = list
+ kmap = dict
+ arity = @arity
+
+ coerced = fn(txt,
+ if(coerce == false || @coerce == false, txt,
+ (coerce || @coerce || IOpt CommandLine Coerce mimic) coerce(txt)))
+
+ shouldContinue = fn(arg,
+ cond(
+ ;; if we have found the next option
+ untilNextOption && iopt[arg], false,
+
+ ;; if we need a value for a keyword argument
+ currentKey, true,
+
+ ;; if takes rest positional or rest keywords
+ arity rest || arity krest, true,
+
+ ;; keyword argument
+ iopt iopt:key(arg),
+ klist length < arity keywords length,
+
+ ;; positional argument
+ args length < arity positionals length
+ )
+ )
+
+ if(handler short && handler immediate && arity max abs zero?,
+ opt = iopt iopt:get(handler short + handler immediate)
+ if(opt && opt action && opt short,
+ remnant = [handler short + handler immediate] + remnant
+ handler immediate = nil))
+
+ if(handler immediate && arity max abs > 0,
+ args << coerced(handler immediate))
+
+ idx = remnant findIndex(arg,
+ cond(
+ !shouldContinue(arg), true,
+
+ (key = iopt iopt:key(arg)) &&
+ (arity krest || arity keywords include?(:(key name))),
+ keyword = :(key name)
+ if(kmap key?(keyword),
+ error!(OptionKeywordAlreadyProvided,
+ text: "Keyword #{keyword} was specified more than once.",
+ keyword: keyword),
+ kmap[keyword] = coerced(key immediate)
+ if(key immediate, klist << keyword, currentKey = keyword))
+ false,
+
+ currentKey, ;; set last keyword if missing value
+ klist << currentKey
+ kmap[currentKey] = coerced(arg)
+ currentKey = nil,
+
+ args << coerced(arg)
+ false))
+
+ Origin with(
+ option: handler option,
+ remnant: remnant[(idx || 0-1)..-1],
+ positional: args,
+ keywords: kmap)
+
+ );consume
+
+ perform = method(args, iopt nil,
+ messageName = args option
+ let(@cell(messageName), @cell(:call),
+ @iopt, if(@cell?(:iopt), iopt || @iopt, iopt),
+ send(messageName, *(args positional), *(args keywords))))
+
+ argumentsCode = nil
+ arity = method(Arity fromArgumentsCode(argumentsCode))
+
+); IOpt Action
View
108 lib/ioke/iopt/commandLine.ik
@@ -0,0 +1,108 @@
+IOpt CommandLine = Origin mimic do(
+
+ initialize = method("Parses the command line arguments given on argv using iopt to handle options.
+ This method takes the following arguments:
+
+ stopAt: When non nil, it must be a text, indicating when to stop processing arguments.
+ You can use this to have your program ignore arguments before -- like many unix programs.
+
+ argUntilNextOption: When true, option argument processing will stop when next option is seen.
+
+ Suppose you have an option named --foo taking one required argument and
+ an also have an option named --bar.
+
+ If argUntilNextOption is false, parsing --foo --bar will result on a single action
+ (--foo) taking one argument ('--bar'). If argUntilNextOption is true, the
+ parsed command line would result in two actions, each having no arguments.
+
+ If an argument looks like an option but that option has not been registered on the
+ iopt object, then it would be treated just as any other argument. e.g.
+ Parsing --foo --man would create just an action for --foo taking argument '--man'
+
+ includeUnknownOption: When true, unknown options will be included in the programArguments list.
+
+ coerce: a CommandLine Coerce object or false to avoid argument coercion.
+
+ This object has the following cells available:
+
+ argv: The original array of command line arguments.
+ iopt: The IOpt object used to parse argv.
+ options: A list of objects having cells: :option, :action and :args (the option arguments)
+ unknownOptions: A list of elements from argv that look like options but arent.
+ programArguments: A list of elements from argv that are neither an option nor par of an option arguments
+ rest: A list arguments found after stopAt
+ ",
+ iopt, argv, coerce: nil, argUntilNextOption: true, includeUnknownOption: true, stopAt: nil,
+
+ @iopt = iopt
+ @argv = argv
+ @options = list()
+ @unknownOptions = list()
+ @programArguments = list()
+ @rest = list()
+ ary = argv
+
+ if(stopAt,
+ ary = argv takeWhile(a, case(a, stopAt, false, true))
+ @rest = argv[ary length succ .. -1])
+
+ until(ary empty?,
+ if(handler = iopt iopt:get(ary first),
+ if(handler action
+ , ;; a recognized option
+ options << handler
+ handler <=> = method(o, action <=> o action)
+ handler args = handler action consume(
+ ary, handler, untilNextOption: argUntilNextOption, coerce: coerce)
+ ary = handler args remnant
+ handler args removeCell!(:remnant)
+ , ;; else it just looks like an option but isnt
+ unknownOptions << ary first
+ if(includeUnknownOption, programArguments << ary first)
+ ary = ary rest
+ ),
+ ;; not an option like argument
+ programArguments << ary first
+ ary = ary rest))
+
+ );initialize
+
+ empty? = method(options empty?)
+
+ include? = method(+options, options all?(opt, @options any?(o, opt === o option)))
+
+ execute = method("Execute the actions by priority",
+ options sort each(o, o action perform(o args, iopt)))
+
+ Coerce = Origin mimic do (
+
+ initialize = method(+names, +:coercions,
+ coercions each(pair,
+ @cell("coerce_#{pair key}?") = if(
+ pair value key cell?(:activatable) && pair value key activatable,
+ pair value key,
+ match = pair value key
+ fn(t, match === t))
+ @cell("coerce_#{pair key}") = pair value value)
+ all = names + coercions keys asList
+ unless(all empty?, @all = all)
+ )
+
+ coerce = method(txt,
+ all each(name,
+ if(send("coerce_#{name}?", txt),
+ return( send("coerce_#{name}", txt) )))
+ txt)
+
+ ) mimic (
+ nil: "nil" => method(t, nil),
+ boolean: #/^(true|false)$/ => method(t, t == "true"),
+ symbol: #/^:\w+$/ => method(t, :(t[1..-1])),
+ integer: #/^[+-]?\d+$/ => method(t,
+ n = Message fromText(if(#/^[+-]/ === t, t[1..-1], t)) evaluateOn(self)
+ if(#/^-/ === t, n negation, n)),
+ decimal: #/^[+-]?\d+\.(\d+)?([eE]\d*)?$/ => method(t, t toDecimal)
+ ); Coerce
+
+ );CommandLine
+
View
12 lib/ioke/iopt/conditions.ik
@@ -0,0 +1,12 @@
+IOpt do(
+ Condition = Ground Condition mimic
+
+ NoActionForOption = Condition mimic
+
+ MalformedOption = Condition mimic
+
+ OptionKeywordAlreadyProvided = Condition mimic
+
+ UnknownOption = Condition mimic
+
+)
View
156 lib/ioke/iopt/doc.ik
@@ -0,0 +1,156 @@
+IOpt documentation = #[Command line processing the Ioke way.
+
+Introduction.
+
+ IOpt is a tool for command line option analysis. It tries to
+ take advantage of Ioke's homoiconic nature, to provide a DSL
+ interface and make you write less.
+
+ IOpt has been influenced by similar tools like ruby's optparse,
+ trying to make command line parsing as easy as possible for ioke
+ programs, but still providing great degree of control over
+ how options look like, and how they should be processed.
+
+ Features:
+
+ - Doesn't impose an option style, by default IOpt provides support
+ for unix style options (short and long), but you can easily define
+ how an option looks like for your application.
+
+ - Interface for easily creating options that will store a cell on a given
+ object, or activate a value, call methods, blocks, etc.
+
+ - Option execution priority, so that you can choose which actions
+ should be handled before others (like --help or --version).
+ Default priority is 0, more negative values are higher priority.
+
+ - Support for clustered short options, eg if -x -v -f are short options
+ you can feed -xvf to your program.
+
+ - Options can take arguments directly from command line.
+ These can be any of those supported by Ioke, thus your
+ options can take required arguments, optionals, keywords, and
+ +rest, +:krest arguments just like any other ioke method.
+
+ - Option Arguments can be coerced to Ioke objects.
+ By default IOpt recognizes option arguments that are literals
+ nil, true, false, symbols, numbers.
+ It is also pretty easy to create your own coercing strategies
+ so you could for example transform "yes" or "no" to true/false,
+ or something more advanced. Coercion can be customized per
+ option, so that you can adapt how arguments are send to the
+ action.
+
+
+Basic Usage
+
+ The following is an interesting example application to show some IOpt features:
+
+ app = Origin with(name: "app", version: "1.0", style: "none", verbosity: 1)
+ app stdout = method("Default output strategy", block, block(System out))
+ app withOut = app cell(:stdout)
+
+ app loadConfig = method("Load configuration from io", io, "Reading" println)
+
+ app outStrategy = method("Use new output strategy for file", file, append: false,
+ if(file == "-", return(@withOut = @cell(:stdout)))
+ @withOut = fn("New output strategy that writes to \#{file}", block,
+ ensure(
+ os = if(file kind?("java:net:Socket"), os getOutputStream,
+ java:io:FileOutputStream new(file, append))
+ ps = java:io:PrintStream new(os, true)
+ block(ps),
+ ps close,
+ os close)))
+
+ app run = method("Execute the application", args,
+ withOut(fn(out,
+ verbosity times(i,
+ out println("\#{i}: \#{name} is running \#{args inspect}, my style is \#{style}")))
+ ))
+
+ ;; Done with app implementation, now let's define it's command line options
+ opt = IOpt on(app) ; app will be the receiver object to execute actions on
+ opt banner = "Usage: \#{app name} [options\]"
+
+ ; Print the opt object and exit. Highest priority option.
+ opt on("-h", "--help", "HALP!", opt println. System exit) priority = -10
+
+ ; Print the application version before any option with more positive prio.
+ opt on("--version", "Print version and exit", version println) priority = -5
+
+ ; An option taking one required argument, and calling app loadConfig
+ opt on("-c", "--config", "Use config file", path,
+ FileSystem withOpenFile(path, fn(f, self loadConfig(f))))
+
+ ; Store a cell in app
+ opt on("-s", "--style", "Set output style", :@style)
+
+ ; increase app verbosity. takes an optional argument
+ opt on("-v", "Increase verbosity", value 1,
+ @verbosity += value)
+
+ ; An option that will activate the outStrategy cell on app
+ ;
+ ; help string will be taken from that cell's documentation
+ ; This action will take aditional arguments according to outStrategy's arity
+ ;
+ ; Also this action uses a custom coercing strategy to convert
+ ; english yes/no and japanese hai/iie to true/false ioke objects.
+ ; if output is host:port then it will be converted to a java socket.
+ ;
+ ; This action priority is greater than the default (0), that means
+ ; it will be executed after higher (more negative) actions, thus
+ ; if the user specified --style, this action will be executing having
+ ; the user specified style already set.
+ opt on("-o", "--output", :outStrategy) coercing (
+ english: #/^yes|no$/ => method(t, t == "yes"),
+ japanese: #/^hai|iie$/ => method(t, t == "hai"),
+ net: #/:\\d+$/ => method(t,
+ addr = t.split(":")
+ java:net:Socket new(addr first, addr second toDecimal))
+ ) priority = 1
+
+ ; will parse the command line arguments before the first --
+ ; and execute the actions by order of priority.
+ opt parse!(System programArguments, stopAt: "--")
+ ; give app the arguments that arent options
+ app run(opt programArguments)
+
+ ;; this are example command lines for app:
+ ;; app --help
+ ;; app -vvvv --version -c ~/.appConfig -o -
+ ;; app -v4 -o there append:yes -s xml
+ ;; app -o nihon.jp:2200 --style origami
+
+More Advanced Usage
+
+ If you need more control over how options are handled, IOpt provides
+ great deal of flexibility. Please read the IOpt API to get familiar with it.
+
+
+ IOpt parse
+
+ Some times you would like to process the command line actions yourself,
+ maybe you want to be sure no option is given twice, or that some option
+ is always required, or have mutually exclusive actions, etc. You can
+ implement all of this by obtaining an IOpt CommandLine object, that
+ represents the parsed command line, including all options found, etc.
+
+ cl = opt parse(argv, stopAt: "--", includeUnknownOption: false)
+ unless(cl unknownOptions emtpy?,
+ error!("Unknown options: %[%s %\]" format(cl unknownOptions)))
+ unless(cl include?("--required"),
+ error!("The --required option must be present!"))
+ once = cl options select(o, o option == "--once")
+ if(once length > 1, error!("You specified --once more than once"))
+ if(cl programArguments empty?,
+ error!("Please provide at least one argument"))
+ sendToSubProgram(cl rest) ; elements found after --
+ fileOption = cl options find(o, o option == "--file")
+ fileOption args positional[0\] = "IDontMindUserInput.txt"
+ fileOption action priority = -99 ; set higher priority
+ cl execute
+
+]; documentation
+
View
2  lib/ioke/iopt/help.ik
@@ -0,0 +1,2 @@
+IOpt Help = Origin mimic
+use("iopt/help/plain")
View
35 lib/ioke/iopt/help/plain.ik
@@ -0,0 +1,35 @@
+IOpt Help Plain = Origin mimic
+IOpt Help Plain do(
+ Simple = Origin mimic do(
+
+ initialize = method(iopt,
+ @iopt = iopt)
+
+ asList = method(
+ lines = list()
+
+ if(iopt cell?(:banner), lines << iopt banner << "")
+ lines << "OPTIONS:" << ""
+
+ actions = set()
+ iopt cell("iopt:actions") each(pair, actions << pair value)
+ actions sort each(action,
+ option = action options join(", ")
+ arity = action arity
+ unless(arity max abs == 0 && arity keywords empty?,
+ option += " (" + action argumentsCode + ")")
+ docs = list()
+ if(action documentation && !action documentation empty?,
+ docs = action documentation split("\n"))
+ lines << " %-40s %s" format(option, docs first)
+ docs rest each(d, lines << " %-40s %s" format("", d))
+ lines << "")
+
+ lines)
+
+ asText = method("Help string as simple plain text.",
+ "%[%s\n%]" format(asList))
+
+ ); Simple
+
+ ); IOpt Help Plain
View
19 lib/ioke/ispec.ik
@@ -0,0 +1,19 @@
+
+ISpec = Origin mimic
+
+use("ispec/conditions")
+use("ispec/formatter")
+use("ispec/reporter")
+use("ispec/expectations")
+use("ispec/extendedDefaultBehavior")
+use("ispec/describeContext")
+use("ispec/runner")
+
+ISpec specifications = []
+
+ISpec ispec_options = method(
+ parser = ISpec Runner OptionParser create(System err, System out)
+ parser order!(System programArguments)
+ ISpec ispec_options = parser options)
+
+DefaultBehavior mimic!(ISpec ExtendedDefaultBehavior)
View
12 lib/ioke/ispec/conditions.ik
@@ -0,0 +1,12 @@
+
+ISpec do(
+ Condition = Ground Condition mimic
+
+ ExpectationNotMet = Condition mimic
+ ExamplePending = Condition mimic
+ UnhandledErrorCondition = Condition mimic
+
+ ExampleStarted = Condition mimic
+ ExamplePassed = Condition mimic
+ ExampleFailed = Condition mimic
+)
View
51 lib/ioke/ispec/describeContext.ik
@@ -0,0 +1,51 @@
+
+ISpec do(
+ DescribeContext = Origin mimic do(
+ create = method(
+ ISpec Runner registerAtExitHook
+ newSelf = mimic
+ newSelf specs = []
+ newSelf)
+
+ stackTraceAsText = method(
+ if(cell?(:shouldMessage),
+ "#{shouldMessage filename}:#{shouldMessage line}:#{shouldMessage position}",
+ "#{code filename}:#{code line}:#{code position}")
+ )
+
+ fullName = method(
+ "returns the name of this context, prepended with the surrounding names",
+ if(cell?(:surrounding),
+ "#{surrounding fullName} #{describesWhat}",
+ describesWhat))
+
+ onlyWhen = dmacro(
+ [>condition, code]
+ if(condition,
+ code evaluateOn(call ground, call ground))
+ )
+
+ run = method(
+ "runs all the defined descriptions and specs",
+ reporter,
+
+ reporter addExampleGroup(self)
+ success = true
+ specs each(n,
+ insideSuccess = if(n first == :description,
+ n second run(reporter),
+ ISpec runTest(self, n second, n third, reporter))
+ if(success, success = insideSuccess))
+ success
+ )
+
+ it = macro(
+ "takes one text argument, and one optional code argument. if the code argument is left out, this spec will be marked as pending",
+ shouldText = call argAt(0)
+ if(call arguments length == 1,
+ self specs << [:pending, shouldText],
+ self specs << [:test, shouldText, call arguments second])
+ ISpec ispec_options exampleAdded(self)
+ )
+ )
+)
View
184 lib/ioke/ispec/expectations.ik
@@ -0,0 +1,184 @@
+
+ISpec do(
+ ShouldContext = Origin mimic
+ ShouldContext __mimic__ = Origin cell(:mimic)
+
+ NotShouldContext = ShouldContext __mimic__
+
+ ShouldContext inspect = "ISpec ShouldContext"
+ ShouldContext notice = "ISpec ShouldContext"
+ NotShouldContext inspect = "ISpec NotShouldContext"
+ NotShouldContext notice = "ISpec NotShouldContext"
+
+ ShouldContext create = method(value, shouldMessage,
+ newSelf = self __mimic__
+ newSelf realValue = cell(:value)
+ newSelf shouldMessage = shouldMessage
+ newSelf)
+
+ ShouldContext be = method("fluff word", self)
+ ShouldContext have = method("fluff word", self)
+
+ ShouldContext pass = macro(
+ realName = call message name
+ msg = call message deepCopy
+ msg name = "#{realName}?"
+ unless(msg sendTo(self cell(:realValue), call ground),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue} #{msg code} to be true", shouldMessage: self shouldMessage)))
+
+ ShouldContext == = method(value,
+ unless(realValue == value,
+ if(realValue kind == "List" && value kind == "List",
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to == #{value inspect}. difference: #{(realValue - value) inspect}. #{realValue length} vs #{value length}", shouldMessage: self shouldMessage),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to == #{value inspect}", shouldMessage: self shouldMessage))))
+
+ ShouldContext close = method(value, epsilon 0.0001,
+ unless(((realValue - value) < epsilon) && ((realValue - value) > -epsilon),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to be close to #{value inspect}", shouldMessage: self shouldMessage)))
+
+ ShouldContext === = method(value,
+ unless(realValue === value,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to === #{value inspect}", shouldMessage: self shouldMessage)))
+
+ ShouldContext match = method(regex,
+ unless(regex =~ realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to match #{regex inspect}", shouldMessage: self shouldMessage)))
+
+ ShouldContext checkReceiverTypeOn = method(name, +args, +:keywordArgs,
+ x = Origin mimic
+ x cell(name) = self cell(:realValue) cell(name)
+ fn(x send(name, *args, *keywordArgs)) should signal(Condition Error Type IncorrectType)
+ )
+
+ ShouldContext signal = method(condition,
+ signalled = "none"
+ bind(
+ rescue(Ground Condition Error, fn(c, signalled = c)),
+ rescue(condition, fn(c, signalled = c)),
+ realValue call)
+
+ unless(signalled mimics?(condition),
+ error!(ISpec ExpectationNotMet, text: "expected #{condition} to be signalled in #{realValue code} - got #{signalled}", shouldMessage: self shouldMessage)))
+
+ ShouldContext offer = method(theRestart,
+ rst = Ground nil
+ bind(
+ rescue(Ground Condition, fn(c, Ground nil)),
+ handle(Ground Condition, fn(c, rst = findRestart(theRestart name))),
+ realValue call)
+
+ unless(rst name == theRestart name,
+ error!(ISpec ExpectationNotMet, text: "expected a restart with name #{theRestart name} to be offered", shouldMessage: self shouldMessage)))
+
+ ShouldContext returnFromRestart = method(+args,
+ retVal = bind(
+ handle(Ground Condition, fn(c, invokeRestart(*args))),
+ realValue call)
+ self realValue = retVal
+ self
+ )
+
+ ShouldContext mimic = method(value,
+ unless(realValue mimics?(value),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to mimic #{value kind}", shouldMessage: self shouldMessage)))
+
+ ShouldContext kind = method(value nil,
+ if(value nil?,
+ "ISpec ShouldContext",
+ unless(realValue kind?(value),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to be kind #{value kind}", shouldMessage: self shouldMessage))))
+
+ ShouldContext true = method(
+ unless(Ground true == realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to be true", shouldMessage: self shouldMessage)))
+
+ ShouldContext false = method(
+ unless(Ground false == realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to be false", shouldMessage: self shouldMessage)))
+
+ ShouldContext nil = method(
+ unless(Ground nil == realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to be nil", shouldMessage: self shouldMessage)))
+
+ ShouldContext not = method(
+ "inverts the expected matching",
+ ISpec NotShouldContext create(self))
+
+ NotShouldContext pass = macro(
+ realName = call message name
+ msg = call message deepCopy
+ msg name = "#{realName}?"
+ if(msg sendTo(self realValue, call ground),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue} #{msg code} to be false", shouldMessage: self shouldMessage)))
+
+ NotShouldContext create = method(former,
+ newSelf = self __mimic__
+ newSelf outsideShouldContext = former
+ newSelf realValue = former realValue
+ newSelf shouldMessage = former shouldMessage
+ newSelf)
+
+ NotShouldContext == = method(value,
+ if(realValue == value,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not == #{value inspect}", shouldMessage: self shouldMessage)))
+
+ NotShouldContext close = method(value, epsilon 0.0001,
+ if(((realValue - value) < epsilon) && ((realValue - value) > -epsilon),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not be close to #{value inspect}", shouldMessage: self shouldMessage)))
+
+ NotShouldContext === = method(value,
+ if(realValue === value,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not === #{value inspect}", shouldMessage: self shouldMessage)))
+
+ NotShouldContext match = method(regex,
+ if(regex =~ realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not match #{regex inspect}", shouldMessage: self shouldMessage)))
+
+ NotShouldContext signal = method(condition,
+ signalled = "none"
+ bind(
+ rescue(Ground Condition Error, fn(c, signalled = c)),
+ rescue(condition, fn(c, signalled = c)),
+ realValue call)
+
+ if(signalled mimics?(condition),
+ error!(ISpec ExpectationNotMet, text: "expected #{condition} to not be signalled in #{realValue code} - got #{signalled}", shouldMessage: self shouldMessage)))
+
+ NotShouldContext mimic = method(value,
+ if(realValue mimics?(value),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not mimic #{value kind}", shouldMessage: self shouldMessage)))
+
+ NotShouldContext kind = method(value nil,
+ if(value nil?,
+ "ISpec NotShouldContext",
+ if(realValue kind?(value),
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not have kind #{value kind}", shouldMessage: self shouldMessage))))
+
+ NotShouldContext true = method(
+ if(Ground true == realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not be true", shouldMessage: self shouldMessage)))
+
+ NotShouldContext false = method(
+ if(Ground false == realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not be false", shouldMessage: self shouldMessage)))
+
+ NotShouldContext nil = method(
+ if(Ground nil == realValue,
+ error!(ISpec ExpectationNotMet, text: "expected #{realValue inspect} to not be nil", shouldMessage: self shouldMessage)))
+
+ NotShouldContext checkReceiverTypeOn = method(name, +args, +:keywordArgs,
+ x = Origin mimic
+ x cell(name) = self cell(:realValue) cell(name)
+ fn(x send(name, *args, *keywordArgs)) should not signal(Condition Error Type IncorrectType)
+ )
+
+ NotShouldContext offer = method(theRestart,