manager 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHART.html +71 -67
- data/MANUAL.html +64 -60
- data/index.html +1252 -0
- data/manager.gemspec +3 -3
- data/spec/documentation +16 -2
- metadata +4 -3
data/index.html
ADDED
@@ -0,0 +1,1252 @@
|
|
1
|
+
<html><head><meta charset="UTF-8" /><style>/*Author:sawa.The default design */*{box-sizing:border-box;-webkit-user-select:text;-khtml-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;}body,table{font-family:sans-serif;font-size:12px;}body{margin:0;display:flex;flex-wrap:nowrap;align-items:stretch;flex-direction:row;height:100%;text-align:justify;text-rendering:optimizelegibility;color:hsl(100,0%,30%);background-color:hsl(0,0%,100%);word-break:normal;}#top,#top-title{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;font-size:18px;}#top *{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}#top,#user #top-title{padding:2;background-color:hsl(0,0%,97%);color:hsl(0,0%,30%);}#dev #top-title{margin:1em;color:white;}#user #top-title,#dev #top{border-bottom:solid 6px hsl(211,85%,29%);}#top >span{margin-left:5;margin-right:5;display:inline-flex;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center;white-space:pre;padding-top:4;padding-bottom:4;}.separator{font-size:18px;color:hsl(60,5%,72%);margin-left:0.5em;margin-right:0.5em;}#left{padding:0 20 24 40;flex-basis:480px;flex-shrink:0;display:flex;flex-wrap:nowrap;align-items:stretch;flex-direction:column;border-right:solid 1px hsl(60,5%,68%);background-color:#4F6B89;color:hsl(0,0%,100%);}#left .tablewrapper{max-height:32%;overflow-y:auto;border-top:solid 1px hsl(60,5%,85%);border-bottom:solid 1px hsl(60,5%,85%);}#left table{margin:0;width:100%;background-color:hsl(0,0%,100%);}#gemspec td:nth-child(1){white-space:nowrap;}#gemspec td:nth-child(2){word-break:break-all;}#files td:nth-child(3),#files td:nth-child(4){white-space:nowrap;}#files td:nth-child(4){text-align:right;}#right{display:flex;flex-wrap:nowrap;align-items:stretch;flex-direction:column;overflow:hidden;flex-grow:1;}#main{flex-basis:0;flex-grow:1;display:flex;flex-wrap:nowrap;align-items:stretch;flex-direction:column;overflow-y:auto;}#user #main{padding-top:12;padding-bottom:12;padding-right:240;padding-left:240;}#dev #main{padding-top:12;padding-bottom:12;padding-right:40;padding-left:20;}#main:before{position:fixed;margin-top:20px;margin-left:-20px;content:"\25B8";/*blacktriangleright */}#user #main:before{top:234;}#dev #main:before{top:300;}[onclick]:not([folded]){cursor:pointer;}[onclick][folded="true"]{cursor:s-resize;}[onclick][folded="false"]{cursor:n-resize;}table{border-collapse:collapse;margin-top:1em;margin-bottom:1em;}tr{border-color:hsl(60,27%,78%);border-style:solid;}#left tr:first-of-type{border-left-width:1px;border-right-width:1px;border-top-width:0;border-bottom-width:1px;}#left tr:last-of-type{border-left-width:1px;border-right-width:1px;border-top-width:1px;border-bottom-width:0;}#main tr,#left tr:not(:last-of-type):not(:first-of-type){border-left-width:1px;border-right-width:1px;border-top-width:1px;border-bottom-width:1px;}td{padding-left:3px;padding-right:3px;border-style:solid;border-color:hsl(60,27%,78%);border-width:1px;}figure{text-align:center;margin-left:0;margin-right:0;}figcaption{text-align:center;margin:2;}input{vertical-align:middle;}h1,h2,h3,h4{display:flex;flex-direction:row;align-items:center;white-space:pre-wrap;word-break:break-word;font-weight:normal;/*color:hsl(180,93%,6%);*/}h1{color:hsl(9,30%,15%);}h2{font-size:163%;margin-left:1em;margin-right:0.5em;color:hsl(9,30%,15%);}h3{font-size:140%;margin-left:1em;margin-right:0.5em;padding-left:1em;border-bottom:solid 1px hsl(0,0%,80%);color:hsl(9,30%,15%);}h4{font-size:120%;margin-left:1em;margin-right:0.5em;padding-left:2em;border-bottom:solid 1px hsl(0,0%,80%);font-style:oblique;color:hsl(9,30%,15%);}h5{font-size:110%;margin-left:1em;margin-right:0.5em;padding-left:3em;border-bottom:solid 1px hsl(0,0%,80%);color:hsl(9,30%,15%);}h6{font-size:100%;margin-left:1em;margin-right:0.5em;padding-left:4em;border-bottom:solid 1px hsl(0,0%,80%);color:hsl(9,30%,15%);}.module-header{/*Margin among `h2.module-header`does not collapse because of extra embedding level `.margin`.Hence margin needs to be set to half of other `h2`.*/margin-top:0.415em;margin-bottom:0.415em;}.feature:not(:first-child)[onclick]:hover{background-color:hsl(90,10%,97%);}.feature-name{font-size:110%;font-weight:bold;font-family:sans-serif;}[folded="true"]>h1,[folded="true"]>h2,[folded="true"]>h3,[folded="true"]>h4,[folded="true"]>h5,[folded="true"]>h6{box-shadow:inset 0px -21px 46px -26px hsla(0,0%,0%,0.2);}.feature-contents{padding-left:1em;}.head{font-weight:bold;font-family:sans-serif;font-size:15px;}.user-item,.dev-item{margin-top:1;margin-bottom:1;padding-left:0.5em;padding-right:0.5em;border-radius:5px;}#dev .user-item{background-color:hsl(180,20%,86%);padding-top:0.1px;padding-bottom:0.1px;}.diagram{text-align:left;margin:0.75em 2em;}.mixins{display:inline-block;margin:2 1;background-color:#c2ccd5;border:solid 1px #246a7d;color:#246a7d;padding:1 4;border-radius:2px;font-size:10.5px;}.mixins >div{width:100%;text-align:center;line-height:2.55ex;}.mixins >.baseline ~div{float:left;clear:both;}.p,li{font-family:serif;font-size:17px;}.p{margin-top:1em;margin-bottom:1em;}.CodeRay,table,figure{margin-top:1.33em;margin-bottom:1.33em;margin-left:2em;margin-right:2em;}.dev-text,table{font-family:sans-serif;font-size:13px;}.CodeRay{overflow-x:auto;}.CodeRay,code{font-size:12px;}.inline{padding:3px 4px;line-height:2.5ex;border-radius:0.4ex;white-space:pre-wrap;font-size:12px;background-color:hsl(50,35%,89%);color:hsl(0,0%,40%);word-break:break-all;}li{margin-top:5;margin-bottom:5;}.indent{padding-left:2.3em;}.hang-indent{margin-right:-2.3em;}.statistics{font-size:12px;}#current{color:black;font-weight:bold;}.navigation{display:inline-flex;flex-direction:row;align-items:center;}.mode.tag,.arrow.tag,.missing_doc.tag,.navigation .bad_doc.tag,.agenda.tag,.log.tag,.missing_test.tag,.bad_test.tag,.untestable.tag,.bug.tag,.success.tag,.benchmark.tag{display:inline-flex;flex-direction:row;align-items:center;justify-content:center;white-space:pre;height:18px;margin:2 0;padding-left:5.5;padding-right:5.5;font-family:sans-serif;font-size:10px;font-weight:500;border-radius:9px;}.unimplemented.tag,.protected.tag,.private.tag,.public.tag,.constant.tag,.singleton.tag,.instance.tag,.undocumented.tag,.hidden.tag,.misplaced.tag,.moved.tag{display:inline-flex;flex-direction:row;align-items:center;justify-content:center;white-space:pre;height:18px;margin:2 0;padding-left:5.5;padding-right:5.5;font-family:sans-serif;font-size:10px;font-weight:500;border-radius:2px;}.tag.mode,.tag.arrow{color:hsl(9,69%,16%);vertical-align:middle;line-height:100%;font-size:12px;}.constant{color:#DB7551;}.constant.tag{background-color:#DB7551;color:white;}.singleton{color:#68894F;}.singleton.tag{background-color:#68894F;color:white;}.instance{color:#4F6589;}.instance.tag{background-color:#4F6589;color:white;}.public{color:#090705;}.public.tag{background-color:#CCBBA7;border:solid 1px;}.private{color:#090705;}.private.tag{background-color:#9B7C59;border:solid 1px;}.protected{color:#D6AF86;}.protected.tag{background-color:#47160D;border:solid 1px;}.hidden,.moved{color:gray;}.hidden.tag,.moved.tag{background-color:white;color:#878787;border:solid 1px;}.agenda{color:#878787;}.agenda.tag{background-color:#878787;color:white;}.log{color:#878787;}.log.tag{background-color:white;color:#878787;border:solid 1px;}.undocumented,.misplaced,.missing_doc,.bad_doc,.missing_test,.bad_test{color:#F79833;}.navigation .bad_doc{font-weight:inherit;text-decoration:inherit;}.anchor .bad_doc{font-weight:bold;border-bottom:dotted 2px;}.undocumented.tag,.misplaced.tag,.missing_doc.tag,.navigation .bad_doc.tag,.missing_test.tag,.bad_test.tag{background-color:#F79833;color:white;}.untestable{color:hsl(54,43%,38%);}.untestable.tag{background-color:hsl(54,43%,38%);color:white;}.unimplemented,.bug{color:hsl(0,80%,50%);}.unimplemented.tag,.bug.tag{background-color:hsl(0,80%,50%);color:white;}.success{color:#00a15a;}.success.tag{background-color:#00a15a;color:white;}.backtrace col:nth-child(1){width:100%;}.backtrace td:nth-child(2)>code{white-space:nowrap;}.benchmark{color:hsl(263,43%,38%);}.benchmark.tag{background-color:hsl(263,43%,38%);color:white;}.barcharts{border-collapse:separate;border-spacing:3 0;}.barcharts col:nth-child(2){width:100%;}.barcharts td:nth-child(1)>code{float:right;font-size:73%;white-space:nowrap;}.barcharts td:nth-child(2){padding:3 0;background-color:hsl(250,7%,92%);}caption{margin:4;}.barchart{display:flex;flex-wrap:nowrap;align-items:stretch;flex-direction:row;height:21px;}.barchart .fill{padding:0 6;background-color:hsl(240,40%,50%);min-width:1;color:hsl(0,0%,63%);font-family:sans-serif;font-size:75%;text-align:right;white-space:nowrap;overflow:visible;line-height:21px;}.barchart .minedge{background-color:hsl(0,50%,50%);border-style:solid;border-left-width:0;border-right-width:0;border-top-width:5px;border-bottom-width:5px;border-color:hsl(240,40%,50%);width:1px;}.barchart .maxedge{background-color:hsl(0,50%,50%);border-style:solid;border-left-width:0;border-right-width:0;border-top-width:5px;border-bottom-width:5px;border-color:hsl(250,7%,92%);width:1px;}.barchart .min{background-color:hsl(0,50%,50%);border-style:solid;border-left-width:0;border-right-width:0;border-top-width:10px;border-bottom-width:10px;border-color:hsl(240,40%,50%);}.barchart .max{background-color:hsl(0,50%,50%);border-style:solid;border-left-width:0;border-right-width:0;border-top-width:10px;border-bottom-width:10px;border-color:hsl(250,7%,92%);}.verification{color:hsl(180,61%,50%);}.gray{color:darkgray;}.right{float:right;}.clear{clear:both;}/*Terminal decorations*/.italic{font-style:italic;}.bold{font-weight:bold;}.underline{text-decoration:underline;}.black{color:#000000;}.red{color:#c75646;}.green{color:#8eb33b;}.yellow{color:#d0b03c;}.blue{color:#72b3cc;}.magenta{color:#c8a0d1;}.cyan{color:#218693;}.white{color:#b0b0b0;}.bg-black{background-color:#5d5d5d;}.bg-red{background-color:#e09690;}.bg-green{background-color:#cdee69;}.bg-yellow{background-color:#ffe337;}.bg-blue{background-color:#9cd9f0;}.bg-magenta{background-color:#fbb1f9;}.bg-cyan{background-color:#77dfd8;}.bg-white{background-color:#f7f7f7;}</style><style>.CodeRay {background-color:#FFF;border:1px solid #CCC;font-family:Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;color:#000;padding:1em 0px 1em 1em;}.CodeRay pre {margin:0px;}div.CodeRay {}span.CodeRay {white-space:pre;border:0px;padding:2px }table.CodeRay {border-collapse:collapse;width:100%;padding:2px }table.CodeRay td {padding:1em 0.5em;vertical-align:top;}.CodeRay .line-numbers,.CodeRay .no {background-color:#ECECEC;color:#AAA;text-align:right;}.CodeRay .line-numbers a {color:#AAA;}.CodeRay .line-numbers tt {font-weight:bold }.CodeRay .line-numbers .highlighted {color:red }.CodeRay .line {display:block;float:left;width:100%;}.CodeRay span.line-numbers {padding:0px 4px }.CodeRay .code {width:100%}ol.CodeRay {font-size:10pt }ol.CodeRay li {white-space:pre }.CodeRay .code pre {overflow:auto }.CodeRay .debug {color:white !important;background:blue !important;}.CodeRay .annotation {color:#007 }.CodeRay .attribute-name {color:#f08 }.CodeRay .attribute-value {color:#700 }.CodeRay .binary {color:#509;font-weight:bold }.CodeRay .comment {color:#998;font-style:italic;}.CodeRay .char {color:#04D }.CodeRay .char .content {color:#04D }.CodeRay .char .delimiter {color:#039 }.CodeRay .class {color:#458;font-weight:bold }.CodeRay .complex {color:#A08;font-weight:bold }.CodeRay .constant {color:teal;}.CodeRay .color {color:#0A0 }.CodeRay .class-variable {color:#369 }.CodeRay .decorator {color:#B0B;}.CodeRay .definition {color:#099;font-weight:bold }.CodeRay .directive {color:#088;font-weight:bold }.CodeRay .delimiter {color:black }.CodeRay .doc {color:#970 }.CodeRay .doctype {color:#34b }.CodeRay .doc-string {color:#D42;font-weight:bold }.CodeRay .escape {color:#666;font-weight:bold }.CodeRay .entity {color:#800;font-weight:bold }.CodeRay .error {color:#F00;background-color:#FAA }.CodeRay .exception {color:#C00;font-weight:bold }.CodeRay .filename {color:#099;}.CodeRay .function {color:#900;font-weight:bold }.CodeRay .global-variable {color:teal;font-weight:bold }.CodeRay .hex {color:#058;font-weight:bold }.CodeRay .integer {color:#099;}.CodeRay .include {color:#B44;font-weight:bold }.CodeRay .inline {color:black }.CodeRay .inline .inline {background:#ccc }.CodeRay .inline .inline .inline {background:#bbb }.CodeRay .inline .inline-delimiter {color:#D14;}.CodeRay .inline-delimiter {color:#D14;}.CodeRay .important {color:#f00;}.CodeRay .interpreted {color:#B2B;font-weight:bold }.CodeRay .instance-variable {color:teal }.CodeRay .label {color:#970;font-weight:bold }.CodeRay .local-variable {color:#963 }.CodeRay .octal {color:#40E;font-weight:bold }.CodeRay .operator {}.CodeRay .predefined-constant {font-weight:bold }.CodeRay .predefined {color:#369;font-weight:bold }.CodeRay .preprocessor {color:#579;}.CodeRay .pseudo-class {color:#00C;font-weight:bold }.CodeRay .predefined-type {color:#074;font-weight:bold }.CodeRay .reserved,.keyword {color:#000;font-weight:bold }.CodeRay .key {color:#808;}.CodeRay .key .delimiter {color:#606;}.CodeRay .key .char {color:#80f;}.CodeRay .value {color:#088;}.CodeRay .regexp {background-color:#fff0ff }.CodeRay .regexp .content {color:#808 }.CodeRay .regexp .delimiter {color:#404 }.CodeRay .regexp .modifier {color:#C2C }.CodeRay .regexp .function {color:#404;font-weight:bold }.CodeRay .string {color:#D20;}.CodeRay .string .string {}.CodeRay .string .string .string {background-color:#ffd0d0 }.CodeRay .string .content {color:#D14;}.CodeRay .string .char {color:#D14;}.CodeRay .string .delimiter {color:#D14;}.CodeRay .shell {color:#D14 }.CodeRay .shell .content {}.CodeRay .shell .delimiter {color:#D14 }.CodeRay .symbol {color:#990073 }.CodeRay .symbol .content {color:#A60 }.CodeRay .symbol .delimiter {color:#630 }.CodeRay .tag {color:#070 }.CodeRay .tag-special {color:#D70;font-weight:bold }.CodeRay .type {color:#339;font-weight:bold }.CodeRay .variable {color:#036 }.CodeRay .insert {background:#afa;}.CodeRay .delete {background:#faa;}.CodeRay .change {color:#aaf;background:#007;}.CodeRay .head {color:#f8f;background:#505 }.CodeRay .insert .insert {color:#080;font-weight:bold }.CodeRay .delete .delete {color:#800;font-weight:bold }.CodeRay .change .change {color:#66f;}.CodeRay .head .head {color:#f4f;}</style><title>Manager User's Manual</title></head><body id="user"><div id="right"><div id="top"><span class="navigation"><span class="tag mode" onclick="displayMode(true, true)">Modules</span><span class="tag mode" onclick="displayMode(false, true)">Features</span><span class="tag mode" onclick="displayMode(false, false)">Full</span></span><span class="separator">│</span><span class="navigation"><span class="tag private" onclick="toggleFeatures(this, 'private', 'user-feature-navigation1')">private</span> <span class="private" id="tagsum-private">1</span> <span class="tag public" onclick="toggleFeatures(this, 'public', 'user-feature-navigation1')">public</span> <span class="public" id="tagsum-public">27</span> <span id="user-feature-navigation1" data-tags="unimplemented protected private public"><span class="tag arrow" onclick="navigateTag(this.parentNode, -1)">◂</span><span class="tag arrow" onclick="navigateTag(this.parentNode, 1)">▸</span> <span class="statistics"><span class="current">1</span>/<span class="sum"></span>+<span class="excluded"></span></span> </span></span> <span class="navigation"><span class="tag singleton" onclick="toggleFeatures(this, 'singleton', 'user-feature-navigation2')">Singleton method</span> <span class="singleton" id="tagsum-singleton">2</span> <span class="tag instance" onclick="toggleFeatures(this, 'instance', 'user-feature-navigation2')">Instance method</span> <span class="instance" id="tagsum-instance">19</span> <span id="user-feature-navigation2" data-tags="constant singleton instance"><span class="tag arrow" onclick="navigateTag(this.parentNode, -1)">◂</span><span class="tag arrow" onclick="navigateTag(this.parentNode, 1)">▸</span> <span class="statistics"><span class="current">1</span>/<span class="sum"></span>+<span class="excluded"></span></span> </span></span></div><div id="top-title">“Manager” User's Manual</div><div id="main" onmouseover="this.focus()" onmouseout="this.blur()" tabindex="0"><div class="module"><div class="feature"><div></div><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature2">1. License</h2><div class="feature-contents"><div class="user-item"><div class="p">The MIT License (MIT)</div><div class="p">Copyright (c) 2014–2016 sawa</div><div class="p">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</div><div class="p">The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</div><div class="p">THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature3">2. Overview</h2><div class="feature-contents"><div class="user-item"><div class="p">Manager generates a user's manual and a developer's chart simultaneously from a single spec file that contains both kinds of information. More precisely, it is a document generator, annotation extractor, program code analyzer, unit test framework, benchmark measure, all in one.</div><div class="p">Manager combines software documentation and software test in a single process. The leading idea is that documentation and test should be closely related to each other and be separated from program coding process in order to put Documentation Driven Development (DDD) and Test Driven Development (TDD) into practice. Documentation and tests describe a piece of software from the designing side whereas the program code describes it from the implementation side. Manager allows a programmer to describe the software from each perspective in a separate file.</div><div class="p">Separating documentation and tests on the one hand and the program code on the other is beneficial to both. Majority of conventional documentation generation tools require documentation to interleave with the program code within the same file, and in order to avoid affecting the program code, documentation is embedded within comments, and is written in a markup language especially designed for the documentation generator. This requires the developer to learn additional syntax. Also with most text editors, documentation embedded inside a comment cannot be highlighted for the markup language, making it difficult for the programmer to write or read. Writing or reading the program code is also disrupted by the noise of documentation. In contrast, Manager requires documentation to be written in a separate file from the program code and in the Ruby language. With the files separated, both the documentation and the program code are kept clean.</div><div class="p">An often heard argumentation against separating documentation from the program code is that it would easily break synchronization of the two as a programmer may update one without updating the other (either forgetting to do so or by laziness), and that having both written in the same file alongside each other would lower the mental barrier against updating both at the same time. Manager features functionality to warn the developer about discrepancies between the documentation and the program code, motivating the developer to fix them.</div><div class="p">Regarding tests, a major advantage of Manager as opposed to most conventional Ruby test frameworks is that Manager does not use matchers: methods especially designed for unit testing. Using Manager, unit tests and benchmarks are written naturally as if one were writing conditional expressions in Ruby code.</div><div class="p">Tests in Manager also uses placeholder methods for a constant or a method that is the object of the test. This enforces tests to follow the proper format; each unit testing expression would be forced to have a receiver that belongs to an appropriate class, and the examined feature will be called once automatically, whose result will be verified once per unit testing expression. There is no way to test a constant or a method other than what is supposed to be tested where the test is written. Any testing expressions that do not follow the format will be reported as failure. It is highly unlikely for an inappropriately written unit test to succeed by accident (if it does, it is Manager's bug).</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature4">2.1. Simple Example</h3><div class="feature-contents"><div class="user-item"><div class="p">Suppose we have the following problem:</div><blockquote>Write an instance method <code class="inline">same_counts</code> on <code class="inline">Array</code> that takes another array as an argument, and returns <code class="inline">true</code> if <code class="inline">self</code> and the other array have the composition of elements (i.e. counts of all elements are the same) and otherwise returns <code class="inline">false</code>.</blockquote><div class="p">Let us start by writing a test. Create a new file named <code class="inline">test.rb</code>, and write the following line at the top:</div><div class="CodeRay">
|
2
|
+
<div class="code"><pre><span class="comment"># frozen_string_literal: false</span>
|
3
|
+
</pre></div>
|
4
|
+
</div>
|
5
|
+
<div class="p">Under it, we shall describe a specification for the instance method <code class="inline">same_counts</code> on <code class="inline">Array</code>. We write the following:</div><div class="CodeRay">
|
6
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
7
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#same_counts</span><span class="delimiter">"</span></span>,
|
8
|
+
coda
|
9
|
+
<span class="keyword">end</span>
|
10
|
+
</pre></div>
|
11
|
+
</div>
|
12
|
+
<div class="p">Now we are ready to fill in some unit tests inside the <code class="inline">spec</code> ... <code class="inline">coda</code>. The first test may be a trivial case:</div><div class="CodeRay">
|
13
|
+
<div class="code"><pre>[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
14
|
+
</pre></div>
|
15
|
+
</div>
|
16
|
+
<div class="p">Here, <code class="inline">UT</code> is a placeholder for the object of the test (<code class="inline">same_counts</code>), and the whole expression describes what we expect to be evaluated to be a truthy value. Don't forget the comma at the end. Next, we might want to add an example with a shuffled argument:</div><div class="CodeRay">
|
17
|
+
<div class="code"><pre>[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
18
|
+
</pre></div>
|
19
|
+
</div>
|
20
|
+
<div class="p">To make sure that not only the inventory of the elements but also the number of them matters, we can a test like this:</div><div class="CodeRay">
|
21
|
+
<div class="code"><pre>[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">false</span>,
|
22
|
+
</pre></div>
|
23
|
+
</div>
|
24
|
+
<div class="p">Now, the file <code class="inline">test.rb</code> should look like:</div><div class="CodeRay">
|
25
|
+
<div class="code"><pre><span class="comment"># frozen_string_literal: false</span>
|
26
|
+
|
27
|
+
<span class="keyword">class</span> <span class="class">Array</span>
|
28
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#same_counts</span><span class="delimiter">"</span></span>,
|
29
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
30
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
31
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">false</span>,
|
32
|
+
coda
|
33
|
+
<span class="keyword">end</span>
|
34
|
+
</pre></div>
|
35
|
+
</div>
|
36
|
+
<div class="p">Let us run this on Manager. On the command line, move to the directory we wrote the <code class="inline">test.rb</code> file, and type:</div><div class="CodeRay">
|
37
|
+
<div class="code"><pre>manager test.rb
|
38
|
+
</pre></div>
|
39
|
+
</div>
|
40
|
+
<div class="p">Two files named <code class="inline">MANUAL.html</code> and <code class="inline">CHART.html</code> should have been generated in the directory. Open <code class="inline">CHART.html</code> with a web browser. It should have a section that looks like this:</div><figure><img alt="Simple example step 1" src="spec/tutorial_1.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 1. Simple example step 1</figcaption></figure><div class="p">From this, we can read that we wrote a specification for an instance method <code class="inline">same_counts</code> in the <code class="inline">Array</code> class. It is tagged as “Unimplemented” because we have not defined the method yet. It has three tests, all of which are shown with a numbered colored bullet and with a message saying that the method is not implemented.</div><div class="p">Let us go on and implement the method. The simplest way is to write it in the same file we are working on. At the bottom of what we have, write a line:</div><div class="CodeRay">
|
41
|
+
<div class="code"><pre><span class="comment">__END__</span>
|
42
|
+
</pre></div>
|
43
|
+
</div>
|
44
|
+
<div class="p">This will be the border between the specification code and the program code that we are about to write. Under this line, let us add an implementation of the method. The file <code class="inline">test.rb</code> should now look like this:</div><div class="CodeRay">
|
45
|
+
<div class="code"><pre><span class="comment"># frozen_string_literal: false</span>
|
46
|
+
|
47
|
+
<span class="keyword">class</span> <span class="class">Array</span>
|
48
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#same_counts</span><span class="delimiter">"</span></span>,
|
49
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
50
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
51
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">false</span>,
|
52
|
+
coda
|
53
|
+
<span class="keyword">end</span>
|
54
|
+
|
55
|
+
<span class="comment">__END__
|
56
|
+
|
57
|
+
class Array
|
58
|
+
def same_counts other
|
59
|
+
sort == other.sort
|
60
|
+
end
|
61
|
+
end</span>
|
62
|
+
</pre></div>
|
63
|
+
</div>
|
64
|
+
<div class="p">After we run the same command from the terminal, a portion of <code class="inline">CHART.html</code> should have now changed to this:</div><figure><img alt="Simple example step 2" src="spec/tutorial_2.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 2. Simple example step 2</figcaption></figure><div class="p">The “Unimplemented” tag is gone, and the method is shown with a bullet that it is defined in <code class="inline">test.rb:14</code>. The three tests have succeeded.</div><div class="p">Suppose we came up with another implementation of this method. If we name it with a prefix <code class="inline">same_counts__</code>, then it will be automatically recognized by Manager as an alternative implementation of the method <code class="inline">same_counts</code>. The program code can now look like:</div><div class="CodeRay">
|
65
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
66
|
+
<span class="keyword">def</span> <span class="function">same_counts</span> other
|
67
|
+
sort == other.sort
|
68
|
+
<span class="keyword">end</span>
|
69
|
+
<span class="keyword">def</span> <span class="function">same_counts__using_hash</span> other
|
70
|
+
inject(<span class="constant">Hash</span>.new(<span class="integer">0</span>)){|h, e| h[e] += <span class="integer">1</span>} == other.inject(<span class="constant">Hash</span>.new(<span class="integer">0</span>)){|h, e| h[e] += <span class="integer">1</span>}
|
71
|
+
<span class="keyword">end</span>
|
72
|
+
<span class="keyword">end</span>
|
73
|
+
</pre></div>
|
74
|
+
</div>
|
75
|
+
<div class="p">Let us run the command again, and see what happened.</div><figure><img alt="Simple example step 3" src="spec/tutorial_3.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 3. Simple example step 3</figcaption></figure><div class="p">Oops, it looks like I forgot to add the memo object in the block of the definition. We can tell this from the backtrace displayed in the report. Let us fix this, and also implement another version:</div><div class="CodeRay">
|
76
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
77
|
+
<span class="keyword">def</span> <span class="function">same_counts</span> other
|
78
|
+
sort == other.sort
|
79
|
+
<span class="keyword">end</span>
|
80
|
+
<span class="keyword">def</span> <span class="function">same_counts__using_hash</span> other
|
81
|
+
inject(<span class="constant">Hash</span>.new(<span class="integer">0</span>)){|h, e| h[e] += <span class="integer">1</span>; h} == other.inject(<span class="constant">Hash</span>.new(<span class="integer">0</span>)){|h, e| h[e] += <span class="integer">1</span>; h}
|
82
|
+
<span class="keyword">end</span>
|
83
|
+
<span class="keyword">def</span> <span class="function">same_counts__using_group_by</span> other
|
84
|
+
group_by(&<span class="symbol">:itself</span>) == other.group_by(&<span class="symbol">:itself</span>)
|
85
|
+
<span class="keyword">end</span>
|
86
|
+
<span class="keyword">end</span>
|
87
|
+
</pre></div>
|
88
|
+
</div>
|
89
|
+
<div class="p">And then we run Manager again:</div><figure><img alt="Simple example step 4" src="spec/tutorial_4.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 4. Simple example step 4</figcaption></figure><div class="p">All three implementations have passed the tests given. Now, we might be interested in comparing the performance of these three implementations. That is done by using the benchmark method <code class="inline">BM</code>. Using the same objects that we used for the unit tests, We should add some lines to the spec portion of the code to make it look like:</div><div class="CodeRay">
|
90
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
91
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#same_counts</span><span class="delimiter">"</span></span>,
|
92
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
93
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
94
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">false</span>,
|
95
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].BM([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]),
|
96
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].BM([<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>]),
|
97
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].BM([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]),
|
98
|
+
coda
|
99
|
+
<span class="keyword">end</span>
|
100
|
+
</pre></div>
|
101
|
+
</div>
|
102
|
+
<div class="p">Running Manger will take more time because of the benchmark tests performed. Now we see benchmark reports under the unit test reports:</div><figure><img alt="Simple example step 5" src="spec/tutorial_5.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 5. Simple example step 5</figcaption></figure><div class="p">In all test cases, it looks like the first implementation <code class="inline">same_counts</code> is the most efficient. If this were production code, we might want to decide to use this implementation.</div><div class="p">So far, we have been ignoring the tag “Missing Doc” with a message. We have been looking at <code class="inline">CHART.html</code>, which should be used by the developer of the program, but opening the other file <code class="inline">MANUAL.html</code>,</div><figure><img alt="Simple example step 6" src="spec/tutorial_6.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 6. Simple example step 6</figcaption></figure><div class="p">we see that its content is nearly blank. This file is a manual for the users of the program. The message in <code class="inline">CHART.html</code> was warning that the this part of <code class="inline">MANUAL.html</code> does not have any descriptive content. Manager encourages a developer to properly do testing as well as documentation. When something is missing, it alerts the developer with such tags. So we can add a description to the spec portion:</div><div class="CodeRay">
|
103
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
104
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#same_counts</span><span class="delimiter">"</span></span>,
|
105
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Takes another array, and compares it with `self` whether the counts of all
|
106
|
+
elements are the same.</span><span class="delimiter">"</span></span>,
|
107
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
108
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>].UT([<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>]) == <span class="predefined-constant">true</span>,
|
109
|
+
...
|
110
|
+
coda
|
111
|
+
<span class="keyword">end</span>
|
112
|
+
</pre></div>
|
113
|
+
</div>
|
114
|
+
<div class="p">The description then appears in <code class="inline">CHART.html</code> as well as in <code class="inline">MANUAL.html</code>, but we now have a different tag alerting that no method signature is given:</div><figure><img alt="Simple example step 7" src="spec/tutorial_7.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 7. Simple example step 7</figcaption></figure><div class="p">A method signature is expressed as a hash. We should add a hash like this before the description we have just added:</div><div class="CodeRay">
|
115
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#same_counts</span><span class="delimiter">"</span></span>,
|
116
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(other)</span><span class="delimiter">"</span></span> => value(<span class="predefined-constant">true</span>) | value(<span class="predefined-constant">false</span>)},
|
117
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Takes another array, and compares it with `self` whether the counts of all
|
118
|
+
elements are the same.</span><span class="delimiter">"</span></span>,
|
119
|
+
...
|
120
|
+
</pre></div>
|
121
|
+
</div>
|
122
|
+
<div class="p">After running Manager, we can see that the warning is gone from <code class="inline">CHART.html</code>, and for <code class="inline">MANUAL.html</code>, by clicking the header “Array#same_counts”, we can see that we now have documentation for the user:</div><figure><img alt="Simple example step 8" src="spec/tutorial_8.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 8. Simple example step 8</figcaption></figure><div class="p">For more examples, please see the spec files of the following gems: manager, dom, pretty_debug, compact_time, and the spec files under the directory <code class="inline">manager/examples</code>.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature5">2.2. Release Notes</h3><div class="feature-contents"><div class="user-item"><div class="p">Manager follows semantic versioning, i.e., the first number section of a version (major) corresponds to backwards incompatible API changes, the second number (minor) describes backwards compatible API changes, such as new functionality/features, and the third number (teeny) describes implementation level detail changes, such as small bug fixes.</div><ul><li>0.0.0<ul><li>Initial release.</li></ul></li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature6">3. Viewing The Files</h2><div class="feature-contents"><div class="user-item"><div class="p">Manager generates two HTML format files: a <span class="italic">user's manual</span> and a <span class="italic">developer's chart</span>. They are to be viewed on a web browser.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature7">3.1. User's Manual</h3><div class="feature-contents"><div class="user-item"><div class="p">User's manual includes <span class="italic">documentation</span> about described or implemented modules and features. It is intended to be read by the users of the software.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature8">3.1.1. Main Information</h4><div class="feature-contents"><div class="user-item"><div class="p">The <span class="italic">main information</span> is displayed in three levels:</div><ul><li><span class="italic">Modules</span> (including classes)</li><li><span class="italic">Features</span> (i.e., constants, singleton methods, instance methods, see <a href="#feature35">5.2.1. Feature</a>) and <span class="italic">section headers</span> (see <a href="#feature37">5.2.3. Section Header</a>)</li><li><span class="italic">Items</span> (contents)</li></ul><div class="p">Features described in the spec as well as features implemented within the listed files (see <a href="#feature31">5.1. Reference to Program Code</a>) will be displayed by modules. Features in the spec file will be placed first and in the order they are described in the spec. However, if the module bodies of a single module (which include feature descriptions) are scattered across multiple locations in the spec file, then they are merged together in the first location. Features implemented but not described in the spec will follow the described ones within their owner modules. They will be described with their original name in case of an alias method.</div><div class="p">Modules, features, and description sections are clickable unless their content is empty. Each one toggles elements that are more detailed than itself between hidden/displayed states. Each feature has a <span class="italic">visibility</span> tag (valued “<span class="italic">Unimplemented</span>”, “<span class="italic">protected</span>”, “<span class="italic">private</span>”, or “<span class="italic">public</span>”) and a numbered <span class="italic">type</span> tag (distinguished by “<span class="italic">Constant</span>”, “<span class="italic">Singleton method</span>”, or “<span class="italic">Instance method</span>”) except for constants that are modules.</div><div class="p">Modules (including classes) within the name space of a module other than <code class="inline">Object</code> are only displayed under the (constant) feature section with a link to where they are displayed as an independent module section. The <code class="inline">Object</code> class is displayed only if it has a feature described in the spec file or if a non-module feature of <code class="inline">Object</code> is implemented in the program code.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature9">3.1.2. Top Bar</h4><div class="feature-contents"><div class="user-item"><div class="p">At the top of the user's manual is the <span class="italic">top bar</span>, which has buttons and information to help users navigate through the file.</div><ul><li>“Modules”, “Features”, and “Full” buttons: Reset the level of detail to be displayed. “Module” button only displays the module names. “Feature” button displays up to the inventory of features as well as the headers of description sections. “Full” button displays to the full detail. Features and items can be further hidden/displayed independently or in groups by other buttons, as to be explained below; the three buttons are only responsible for the level of detail right after they are clicked.</li><li>Visibility buttons: Each button toggles between showing/hiding states of the features with the corresponding visibility. The digits beside each button represent the number of features with the visibility, and remain constant even if any of them become hidden. Buttons with numbers are omitted if the number of features is zero.</li><li>Type buttons: Each button toggles between showing/hiding states of the features of the corresponding type. The digits beside each button represent the number of features of the type, and remain constant even if any of them become hidden. Buttons with numbers are omitted if the number of features is zero.</li></ul><div class="p">The <span class="italic">left/right arrows</span> on the right of a group of buttons allow navigation through features. The numerator on the right side describes the position that was last navigated using the arrow buttons (or “1” by default). If the last navigation was done using the associated arrow buttons, then the number is displayed with emphasis. The denominator describes the number of displayed (i.e. not hidden) features. The number following the plus sign tells the user how many features they are implicitly skipping during navigation; it indicates the number of features hidden for reasons other than any property in the group being hidden. For example, the following situation:</div><figure><img alt="Navigation" src="spec/navigation.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 9. Navigation</figcaption></figure><div class="p">shows that the arrow keys next to the “Unimplemented”/“protected”/“private”/“public” group were the ones last clicked for navigation, and that the current scroll position points to the third feature among the 140 visible ones (features that are not private and not constant) unless the user has further scrolled without using any navigation buttons. As the sum of 11 (Unimplemented), 10 (protected), and 126 (public) is 147, 147 features would be expected to be displayed if nothing but private features were hidden. However, the features are hidden not only because they are private. Since constants are hidden, Unimplemented/protected/public features that are constants are hidden. The number seven after the plus sign in the first group indicates this amount. Similarly, 58 is the number of singleton/instance methods hidden because they are private.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature10">3.2. Developer's Chart</h3><div class="feature-contents"><div class="user-item"><div class="p">The contents of the developer's chart is a superset of that of the user's manual. It includes annotations, test reports, and warnings. It is intended to be utilized by the developers of the software.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature11">3.2.1. Left Panel</h4><div class="feature-contents"><div class="user-item"><div class="p">“Gem Spec” displays information given in a gem spec file if the object of Manager is a gem, and a <a href="#feature150"><code class="inline"><<::#gemspec</code></a> command is called in the spec (see below, <a href="#feature31">5.1. Reference to Program Code</a>).</div><div class="p">The <span class="italic">base directory</span> is the directory in which the spec file resides. Throughout Manager, file names are displayed either as a path relative to the base directory or as an absolute path, whichever is shorter.</div><div class="p">The “Files” table lists information about the relevant files.</div><ul><li>“Category”: Files are classified into the following.<ul><li>“Depended”: Pieces of software that are loaded during Manager run, but are neither the subject nor the object of documentation or test. In particular, the Ruby implementation that is used to run Manager, and any gems that are loaded.</li><li>“Specification”: The subject of description/tests. Also called <span class="italic">spec</span> in this manual/chart.</li><li>“Program”: Files that are the object of analysis/tests. They are described with the percentage of the number of lines covered in tests against the number of all lines in the file.</li></ul></li><li>“Version”: Version is described by the version number for depended files and by the last modified time for specification and program code files. Among the last modified times, the latest one is displayed with emphasis. This may give a hint on which file has mainly undergone modification right before the Manager was run, so that the developer can focus on reading the relevant contents.</li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature12">3.2.2. Main Information</h4><div class="feature-contents"><div class="user-item"><div class="p">Features in the developer's chart, unlike those in the user's manual, may be tagged by one of the followings that describe <span class="italic">documentation status</span>. They are exclusive (i.e. no feature may be tagged by more than one of them), and are not complementary (i.e. a feature may be tagged by none of them). Among them, “Undocumented” and “Misplaced” are warnings, and “hidden” or “moved” indicate markings in the spec file (see <a href="#feature35">5.2.1. Feature</a>).</div><ul><li>“Undocumented”: The feature is implemented in the program code, but is not described in the spec file.</li><li>“hidden”: The feature is marked in the spec file as to be hidden in the user's manual. This is intended to be used for features that are internal implementations, and are not meant to be public API.</li><li>“Misplaced”: The feature is under one or more of the following three occasions. This tag is suppressed when the feature is marked as “moved”.<ul><li>The feature (method) is implemented within a file that is not listed (see <a href="#feature31">5.1. Reference to Program Code</a> on how to list a feature).</li><li>The feature is implemented on an ancestor module rather than in the module in which it is described in the spec file.</li><li>The feature (method) is described in the spec file, but is implemented as an alias of another method.</li></ul></li><li>“moved”: The feature is marked as to be described in a manner different from its implementation. Suppresses “Misplaced” tag.</li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature13">3.2.2.1. Module Diagrams</h5><div class="feature-contents"><div class="user-item"><div class="p">Each module section has two <span class="italic">module diagrams</span>. For example, the following may appear under the section of a class <code class="inline">B</code>:</div><figure><img alt="Module diagrams" src="spec/module_diagram.png" style="border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 10. Module diagrams</figcaption></figure><div class="p">The first diagram represents mixins and ancestors related to <code class="inline">B</code> itself, and the second one is for its singleton class <code class="inline"><<B</code>. Each bordered area includes exactly one class and zero or more modules it has mixin relations with. The classes are vertically aligned at the same height. A mixin relation is expressed with the character <code class="inline">┊</code>; modules located below the class are the prepended ones, those located above are the included modules. They are ordered so that a lower module/class has priority over a higher one in method call. Thus, the diagram tells that module <code class="inline">C</code> was prepended to class <code class="inline">B</code>, and module <code class="inline">D</code> was included into <code class="inline">B</code>, after which module <code class="inline">E</code> was included into <code class="inline">B</code>. The bordered areas are related with the character <code class="inline"><</code>, which expresses a minimum subclass relation between the respective classes in the bordered areas. The diagram tells that class <code class="inline">B</code> has class <code class="inline">A</code> as its parent. Note that the entire method search path (priority) can be followed by going from the bottom to top, left to right: <code class="inline">C</code> → <code class="inline">B</code> → <code class="inline">E</code> → <code class="inline">D</code> → <code class="inline">A</code> → <code class="inline">Object</code> → <code class="inline">Kernel</code> → <code class="inline">BasicObject</code>. Links are available for navigation to the module sections that are displayed.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature14">3.2.2.2. Alternative Implementations</h5><div class="feature-contents"><div class="user-item"><div class="p">The developer's chart displays information about <span class="italic">alternative implementations</span>. This functionality is intended to help developers test and compare different implementations of a feature by following a convention. Singleton or instance methods implemented in the program code and whose name includes exactly one occurrence of the sequence <code class="inline">__</code> will be considered alternative implementations of the <span class="italic">main implementation</span>, whose name corresponds to the sequence preceding <code class="inline">__</code>. The (possibly empty) sequence following <code class="inline">__</code> is intended to be used as a label for distinguishing each alternative; perhaps a serial number, a few-word summary of the implementation detail, the developer's name, or implementation date can be used. For example, the following methods are all considered alternatives of the main implementation <code class="inline">foo</code>:</div><div class="CodeRay">
|
123
|
+
<div class="code"><pre>foo__
|
124
|
+
foo__1
|
125
|
+
foo__2
|
126
|
+
foo__map
|
127
|
+
foo__without_map
|
128
|
+
foo__mary
|
129
|
+
foo__john
|
130
|
+
foo__20151201
|
131
|
+
foo__20160101
|
132
|
+
</pre></div>
|
133
|
+
</div>
|
134
|
+
<div class="p">To avoid conflict or confusion with (mostly Ruby core) methods or keywords with balanced <code class="inline">__</code> (such as <code class="inline">__FILE__</code> or <code class="inline">__send__</code>), a method that has more than one <code class="inline">__</code> (such as <code class="inline">foo__map__1</code>) is not considered an alternative implementation.</div><div class="p">Alternative (as well as main) implementations are detected and displayed together after bullets with the title “Implementation candidates” under the feature named for the main implementation. As such, an alternative implementation cannot be described in the spec file as an independent feature. It is possible that alternatives are implemented without the main one being implemented. In such case, the feature header will have the visibility “unimplemented”. Each alternative will have the visibility described within parentheses if the value differs from the main implementation. In this example,</div><figure><img alt="Alternatives with unimplemented main" src="spec/alternatives_unimplemented.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 11. Alternatives with unimplemented main</figcaption></figure><div class="p">instance methods <code class="inline">A#foo__1</code> and <code class="inline">A#foo__2</code> are implemented in the ;program code as private and public methods respectively, but the corresponding main method <code class="inline">A#foo</code> is not implemented. So the feature header has a tag “unimplemented”. In this example,</div><figure><img alt="Alternatives with implemented main" src="spec/alternatives_implemented.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 12. Alternatives with implemented main</figcaption></figure><div class="p">three instance methods <code class="inline">A#bar</code>, <code class="inline">A#bar__1</code>, and <code class="inline">A#bar__2</code> are implemented in the program code. The “public” tag indicates that the main implementation <code class="inline">A#bar</code> is public. <code class="inline">A#bar__1</code> is implemented as a protected method, and the absence of visibility description for <code class="inline">A#bar__2</code> indicates that it is the same as the main implementation, i.e. public.</div><div class="p">In order for alternative implementations to pursue their purpose, their visibility should match that of the main implementation (if implemented). Thus, visibility description in parentheses is indication that the implementation is wrong; the description is intended to work as a warning to the developer.</div><div class="p">On the right side, the source location (i.e. file name and line number) of each implementation is described if it is detectable.</div><div class="p">In one use of this functionality, a main method has already been implemented in a program code file, and the developer wants to test its alternative implementations that appeared afterwards. In such case, it may be better to implement the alternatives in a file different from the main program file or in the scratch code (see <a href="#feature31">5.1. Reference to Program Code</a>) in order not to mess the original code file.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature15">3.2.2.3. Documentation Reports</h5><div class="feature-contents"><div class="user-item"><div class="p">Items in the developer's chart is marked with various <span class="italic">warnings</span>. Appropriate fix should be made when a warning is displayed.</div><ul><li>“Missing”: There are items that a feature described in the spec file should minimally have. If any of the following (see <a href="#feature30">5. Spec File</a>) is missing in a feature documented in the spec file, this tag is displayed. These warnings are suppressed when the feature is marked as “hidden” or “moved”.<ul><li>The feature does not include any unit test.</li><li>The feature does not have any paragraph for the user.</li><li>The feature (method) has no description about its method signature.</li></ul></li><li>Spell errors are shown in distinct type faces (If <code class="inline">spell_check</code> option is on, see <a href="#feature21">4.1.1. Spell Check (spell_check, spell-check-list, spell-check-filter, case_sensitive, case_insensitive)</a>).</li><li>Bad links (see <a href="#feature42">5.3.3. Link</a>) within annotation, test description, list item, citation, or paragraph are shown in distinct type faces. This is also shown in user's manual.</li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h6 id="feature16">3.2.2.3.1. Annotations and Editorial Markings</h6><div class="feature-contents"><div class="user-item"><div class="p">Whereas documentation describes the Application Programming Interface (API), it is sometimes helpful to have information on the implementation level details of the software. Manager detects <span class="italic">annotations</span> in the spec file and the program code. It also detects comments in the program code that follow a certain format (traces of temporal edits) and regards them as <span class="italic">editorial markings</span>. While documentation should appear in the user's manual, annotations and editorial markings should be hidden from the users and only be displayed in the developer's chart.</div><div class="p">Among annotations and editorial markings, there are two types:</div><ul><li><span class="italic">Agenda</span>: Those that should be kept temporarily and should be aimed to be resolved after some time, such as markings on incomplete or buggy parts of the program code, or commented out parts that are undergoing changes by the developers</li><li><span class="italic">Log</span>: Those that should be kept permanently or for a relatively long time for future reference, such as remarks on the reason a certain algorithm was chosen in the implementation, or the intent of a certain routine</li></ul><div class="p">Different annotations written in the spec file or the program code may be <span class="italic">related</span> by a <span class="italic">tag</span> (see <a href="#feature46">5.3.4. Annotation</a>). For example, a single remark may be made for multiple locations in a program code file, and one may not want to repeat writing the same annotation in each location. Or one may want to annotate something in the spec file about a certain portion of the program code at some location. An annotation tag either has a <span class="italic">file scope</span> or a <span class="italic">method-body scope</span>, and annotations with the same tag within the same scope consist a <span class="italic">set</span> of related annotations and are displayed as one; their contents are joined with a space character, the file names and line numbers are compacted, and the line numbers where the content is taken from are emphasized. A tag is displayed after the locations. Similarly, same types of editorial markings are related per file, and are displayed chart together. Annotations with a file scope are displayed in the main context.</div><div class="p">An assumption made about the development cycle is that annotations can be first written in isolation and free style as temporal annotation (i.e. agenda). Then, as it turns out to be organized information that should be recorded (i.e. log), they should be tagged, and the content should be moved into the spec file, with a tag relating the original location in the program code and the corresponding annotation in the spec file. Based on this, annotations and editorial markings are categorized as agenda or log by the following rule:</div><ul><li>Un-tagged annotations are log.</li><li>Tagged annotations are agenda.</li><li>Editorial markings are agenda.</li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature17">3.2.2.4. Test Reports</h5><div class="feature-contents"><div class="user-item"><div class="p">A feature can have <span class="italic">tests</span> (unit tests or benchmarks). A unit test is run against each alternative implementation of the feature. A benchmark is run together for the alternative implementations of the feature. Each test results in one of the following in the order of priority given below (for terminology and <a href="#feature115"><code class="inline">::#expr</code></a>, see <a href="#feature53">5.4. Testing</a>):</div><ol><li>If the string argument of <code class="inline">expr</code> cannot be parsed as Ruby code, then the result is “Bad test”.</li><li>If the string argument of <code class="inline">expr</code> within the exercise receiver or arguments of a test cannot be evaluated in the given context, then the result is “Bad test”.</li><li>If the exercise receiver of a test is not an instance (of a subclass) of the module that the feature is described under, then the result is “Untestable”.</li><li>If the feature to be tested is not defined on the exercise receiver, then the result is “Untestable” (if there is an alternative implementation, then the feature is regarded as defined with respect to the test even if the main implementation is not defined).</li><li>If calling the feature on the exercise receiver and arguments raises an error, then the result is “Bug”.</li><li>If the string argument of <code class="inline">expr</code> within the verifying arguments of a test cannot be evaluated in the given context, then the result is “Bad test”.</li><li>If a unit test contingent on another one is not preceded by a successfully exercised unit test, then the result is “Untestable”.</li><li>If calling the tested feature on the exercise result and the verifying arguments raises an unexpected error, then the result is “Bug”.</li><li>If the test is a unit test, and the verification result is falsy, then the result “Bug”.</li><li>The result is “Success”.</li></ol><div class="p">Tests are reported per feature in the following way:</div><ul><li>If a test results in “Bad test” or “Untestable” (for an implementation of the feature), then its report for the entire feature will be as such (“Bad test” or “Untestable”), with a common message.</li><li>If a test results in “Bug” for any implementation of the feature, then its report for the entire feature will be “Bug”. If the test is a unit test, a message is shown under a bullet for each implementation that resulted in “Bug”. If it is a benchmark, a message is shown only for the first implementation that resulted in “Bug”.</li><li>If a test results in “Success” for all implementations of the feature, then “Success” is displayed if it is a unit test, or a graph is shown if it is a benchmark.</li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature18">3.2.3. Top Bar</h4><div class="feature-contents"><div class="user-item"><div class="p">The top bar in developer's chart is a superset of that of the user's manual. The numbers displayed aside visibility buttons and type buttons may be greater than the corresponding number displayed in the user's manual. This is due to some features being marked as “hidden” (see <a href="#feature35">5.2.1. Feature</a>). In addition to the functionality in the user's manual, the top bar has the following.</div><ul><li>“User Items” button: Toggles <span class="italic">user items</span>, i.e. items that are primarily for the user's manual. Relevant items are in distinct background color when displayed.</li><li>Documentation status buttons (“Undocumented”, “Hidden”, “Misplaced”, “Moved”), documentation report buttons (“Missing doc”, “Bad doc”, “Agenda”, “Log”), and test report buttons (“Missing test”, “Bad test”, “Untestable”, “Bug”, “Success”, “Benchmark”): They work similarly to visibility buttons and type buttons.</li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature19">4. Running Manager</h2><div class="feature-contents"><div class="user-item"><div class="p">Manager can either be run as a command on the terminal, or be called within a Ruby code.</div><ul><li>To run Manager on the terminal, execute the command <code class="inline">manager</code> with the path to the spec file as an argument. To skip a time-consuming test, type Ctrl+C during the test.</li></ul><div class="CodeRay">
|
135
|
+
<div class="code"><pre>$ manager some_directory/spec_file
|
136
|
+
</pre></div>
|
137
|
+
</div>
|
138
|
+
<ul><li>To run Manager within in a Ruby code, execute the method <a href="#feature80"><code class="inline">Manager.new</code></a> with the path to the spec file as an argument.</li></ul><div class="CodeRay">
|
139
|
+
<div class="code"><pre><span class="constant">Manager</span>.new(<span class="string"><span class="delimiter">"</span><span class="content">some_directory/spec_file</span><span class="delimiter">"</span></span>)
|
140
|
+
</pre></div>
|
141
|
+
</div>
|
142
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature20">4.1. Customization and Options</h3><div class="feature-contents"><div class="user-item"><div class="p">Customization is done either through a command line option using a double hyphen <code class="inline">--</code> before a key, possibly followed by the value, or through the <a href="#feature68"><code class="inline">Manager.config</code></a> method in the spec file with a symbol key and a value. The options in this section are given for <code class="inline">Manager.config</code>. To use them in the command line, read underscores <code class="inline">_</code> in them as hyphens <code class="inline">-</code>. Multiple options can be specified with a single command/method. When an option is specified in both ways, the command line option overrides the <code class="inline">config</code> method.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature21">4.1.1. Spell Check (spell_check, spell-check-list, spell-check-filter, case_sensitive, case_insensitive)</h4><div class="feature-contents"><div class="user-item"><div class="p">Spell checking is available if the <code class="inline">ffi-aspell</code> gem and the relevant natural language component are installed. The inventory of available languages is shown in the command line by the <code class="inline">--spell-check-list</code> option:</div><div class="CodeRay">
|
143
|
+
<div class="code"><pre>$ manager --spell-check-list
|
144
|
+
</pre></div>
|
145
|
+
</div>
|
146
|
+
<div class="p">The <code class="inline">spell_check</code> option sets the language to be used for spell checking the text. When set to <code class="inline">nil</code>, spell check is turned off. The default is <code class="inline">nil</code>.</div><div class="CodeRay">
|
147
|
+
<div class="code"><pre>$ manager some-directory/spec-file --spell-check en
|
148
|
+
</pre></div>
|
149
|
+
</div>
|
150
|
+
<div class="p">or</div><div class="CodeRay">
|
151
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">spell_check</span>: <span class="string"><span class="delimiter">"</span><span class="content">en</span><span class="delimiter">"</span></span>
|
152
|
+
</pre></div>
|
153
|
+
</div>
|
154
|
+
<div class="p">To check which words among a short list are not in the dictionary, run in the command line with the <code class="inline">spell-check-filter</code> option followed by the dictionary and the words to check.</div><div class="CodeRay">
|
155
|
+
<div class="code"><pre>$ manager --spell-check-filter en prefix prepend affix append
|
156
|
+
The following words are not in the dictionary `en`:
|
157
|
+
prepend
|
158
|
+
</pre></div>
|
159
|
+
</div>
|
160
|
+
<div class="p">To exempt words that are not listed in the dictionary from spell errors, list them in an array and pass them with <code class="inline">case_sensitive</code> and <code class="inline">case_insensitive</code> options respectively, depending on whether the case matters.</div><div class="CodeRay">
|
161
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">case_sensitive</span>: <span class="string"><span class="delimiter">%w[</span><span class="content">
|
162
|
+
API
|
163
|
+
CSS
|
164
|
+
...
|
165
|
+
</span><span class="delimiter">]</span></span>
|
166
|
+
<span class="constant">Manager</span>.config <span class="key">case_insensitive</span>: <span class="string"><span class="delimiter">%w[</span><span class="content">
|
167
|
+
falsy
|
168
|
+
matchers
|
169
|
+
...
|
170
|
+
</span><span class="delimiter">]</span></span>
|
171
|
+
</pre></div>
|
172
|
+
</div>
|
173
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature22">4.1.2. Output Directory (odir)</h4><div class="feature-contents"><div class="user-item"><div class="p">The output directory is by default the directory of the spec file. To override this, use the <code class="inline">odir</code> option. Relative path can be used. In such case, it will be expanded relative to the directory of the spec file.</div><div class="CodeRay">
|
174
|
+
<div class="code"><pre>$ manager some-directory/spec-file --odir ../documents
|
175
|
+
</pre></div>
|
176
|
+
</div>
|
177
|
+
<div class="p">or</div><div class="CodeRay">
|
178
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">odir</span>: <span class="string"><span class="delimiter">"</span><span class="content">../documents</span><span class="delimiter">"</span></span>
|
179
|
+
</pre></div>
|
180
|
+
</div>
|
181
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature23">4.1.3. User's Manual File Name (user)</h4><div class="feature-contents"><div class="user-item"><div class="p">The user's manual is written as the file name <code class="inline">MANUAL.html</code> by default. To override this, use the <code class="inline">user</code> option.</div><div class="CodeRay">
|
182
|
+
<div class="code"><pre>$ manager some-directory/spec-file --user README.html
|
183
|
+
</pre></div>
|
184
|
+
</div>
|
185
|
+
<div class="p">or</div><div class="CodeRay">
|
186
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">user</span>: <span class="string"><span class="delimiter">"</span><span class="content">README.html</span><span class="delimiter">"</span></span>
|
187
|
+
</pre></div>
|
188
|
+
</div>
|
189
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature24">4.1.4. Developer's Chart File Name (dev)</h4><div class="feature-contents"><div class="user-item"><div class="p">The developer's chart is written as the file name <code class="inline">CHART.html</code> by default. To override this, use the <code class="inline">dev</code> option.</div><div class="CodeRay">
|
190
|
+
<div class="code"><pre>$ manager some-directory/spec-file --dev result.html
|
191
|
+
</pre></div>
|
192
|
+
</div>
|
193
|
+
<div class="p">or</div><div class="CodeRay">
|
194
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">dev</span>: <span class="string"><span class="delimiter">"</span><span class="content">result.html</span><span class="delimiter">"</span></span>
|
195
|
+
</pre></div>
|
196
|
+
</div>
|
197
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature25">4.1.5. Title (title)</h4><div class="feature-contents"><div class="user-item"><div class="p">A certain string is used as part of the title to describe what the user's manual and developer's chart are about. By default, the directory name of the spec file is used in hope that in many cases, that should describe the software's project name. To override this, use the <code class="inline">title</code> option.</div><div class="CodeRay">
|
198
|
+
<div class="code"><pre>$ manager some-directory/spec-file --title Foo\ Software
|
199
|
+
</pre></div>
|
200
|
+
</div>
|
201
|
+
<div class="p">or</div><div class="CodeRay">
|
202
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">title</span>: <span class="string"><span class="delimiter">"</span><span class="content">Foo Software</span><span class="delimiter">"</span></span>
|
203
|
+
</pre></div>
|
204
|
+
</div>
|
205
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature26">4.1.6. Base Directory (bdir)</h4><div class="feature-contents"><div class="user-item"><div class="p">The base directory is the reference point for describing relative file names in the output. It does not affect <code class="inline">require</code>/<code class="inline">load</code> commands or the like. By default, it is the directory of the spec file. To override this, use the <code class="inline">bdir</code> option. Relative path can be used. In such case, it will be expanded relative to the directory of the spec file.</div><div class="CodeRay">
|
206
|
+
<div class="code"><pre>$ manager some-directory/spec-file --bdir ../lib
|
207
|
+
</pre></div>
|
208
|
+
</div>
|
209
|
+
<div class="p">or</div><div class="CodeRay">
|
210
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">bdir</span>: <span class="string"><span class="delimiter">"</span><span class="content">../lib</span><span class="delimiter">"</span></span>
|
211
|
+
</pre></div>
|
212
|
+
</div>
|
213
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature27">4.1.7. Theme (theme, theme-list)</h4><div class="feature-contents"><div class="user-item"><div class="p">The design of the output files are controlled by a theme. New themes are occasionally added to Manager gem within version updates. Each theme is described as a CSS format file, and is named after a four digit number describing the publishing year, followed by a letter (starting from <code class="inline">a</code> and incremented) to distinguish multiple designs in a single year, followed by the <code class="inline">.css</code> extension. In addition, another CSS format file describes the part of the design related to syntax highlighting of the code blocks (see <a href="#feature28">4.1.8. Syntax Highlighting (highlight, highlight-list)</a>). These files are incorporated as part of the output HTML files. The inventory of available theme files and highlight files can be accessed from the command line by the <code class="inline">theme-list</code> option.</div><div class="CodeRay">
|
214
|
+
<div class="code"><pre>$ manager --theme-list
|
215
|
+
</pre></div>
|
216
|
+
</div>
|
217
|
+
<div class="p">The default theme is selected among the newest ones included at the time of shipping of a version of Manager. To select a theme, use the <code class="inline">theme</code> option with the theme file name.</div><div class="CodeRay">
|
218
|
+
<div class="code"><pre>$ manager some-directory/spec-file --theme 2016a.css
|
219
|
+
</pre></div>
|
220
|
+
</div>
|
221
|
+
<div class="p">or</div><div class="CodeRay">
|
222
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">dev</span>: <span class="string"><span class="delimiter">"</span><span class="content">2016a.css</span><span class="delimiter">"</span></span>
|
223
|
+
</pre></div>
|
224
|
+
</div>
|
225
|
+
<div class="p">To add a custom theme, describe the design in CSS format, and place the file within the directory <code class="inline">manager/theme</code>. Designs for user's manual and developer's chart can be written independently by placing the CSS selector under the id selectors <code class="inline">#user</code> and <code class="inline">#dev</code>, respectively. Otherwise, the design is common to both.</div><ul><li>Common design</li></ul><div class="CodeRay">
|
226
|
+
<div class="code"><pre><span class="id">#main</span>{
|
227
|
+
<span class="key">padding-top</span>: <span class="float">20</span>;
|
228
|
+
<span class="key">padding-bottom</span>: <span class="float">20</span>;
|
229
|
+
}
|
230
|
+
</pre></div>
|
231
|
+
</div>
|
232
|
+
<ul><li>Only for user's manual</li></ul><div class="CodeRay">
|
233
|
+
<div class="code"><pre><span class="id">#user</span> <span class="id">#main</span>{
|
234
|
+
<span class="key">padding-right</span>: <span class="float">240</span>;
|
235
|
+
<span class="key">padding-left</span>: <span class="float">240</span>;
|
236
|
+
}
|
237
|
+
</pre></div>
|
238
|
+
</div>
|
239
|
+
<ul><li>Only for developer's chart</li></ul><div class="CodeRay">
|
240
|
+
<div class="code"><pre><span class="id">#dev</span> <span class="id">#main</span>{
|
241
|
+
<span class="key">padding-right</span>: <span class="float">40</span>;
|
242
|
+
<span class="key">padding-left</span>: <span class="float">20</span>;
|
243
|
+
}
|
244
|
+
</pre></div>
|
245
|
+
</div>
|
246
|
+
<div class="p">If there is a comment <code class="inline">/* ... */</code> that starts and ends within the first line of a theme file, then its content (with spaces at the edges stripped) will be displayed in brackets alongside the file name in response to the <code class="inline">theme-list</code> option.</div><ul><li>Theme file</li></ul><div class="CodeRay">
|
247
|
+
<div class="code"><pre><span class="comment">/* Author: sawa. The default design */</span>
|
248
|
+
...
|
249
|
+
</pre></div>
|
250
|
+
</div>
|
251
|
+
<ul><li>Showing the inventory</li></ul><div class="CodeRay">
|
252
|
+
<div class="code"><pre>$ manager --theme-list
|
253
|
+
2016a.css [Author: sawa. The default design]
|
254
|
+
...
|
255
|
+
</pre></div>
|
256
|
+
</div>
|
257
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature28">4.1.8. Syntax Highlighting (highlight, highlight-list)</h4><div class="feature-contents"><div class="user-item"><div class="p">To select a design for syntax highlighting of code blocks, use the <code class="inline">highlight</code> option with the highlight file name.</div><div class="CodeRay">
|
258
|
+
<div class="code"><pre>$ manager some-directory/spec-file --highlight coderay_github.css
|
259
|
+
</pre></div>
|
260
|
+
</div>
|
261
|
+
<div class="p">or</div><div class="CodeRay">
|
262
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">highlight</span>: <span class="string"><span class="delimiter">"</span><span class="content">coderay_github.css</span><span class="delimiter">"</span></span>
|
263
|
+
</pre></div>
|
264
|
+
</div>
|
265
|
+
<div class="p">To add a highlight design, place the file within the directory <code class="inline">manager/theme</code>.</div><div class="p">To obtain the list of symbols for the languages that can be highlighted, use the <code class="inline">highlight-list</code> option (see <a href="#feature50">5.3.8. Code Block</a> for its usage).</div><div class="CodeRay">
|
266
|
+
<div class="code"><pre>$ manager --highlight-list
|
267
|
+
</pre></div>
|
268
|
+
</div>
|
269
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature29">4.1.9. Debugging of Manager (debug)</h4><div class="feature-contents"><div class="user-item"><div class="p">This is not intended for normal use. When the <code class="inline">debug</code> option takes the <code class="inline">true</code> value as follows,</div><div class="CodeRay">
|
270
|
+
<div class="code"><pre>$ manager some-directory/spec-file --debug true
|
271
|
+
</pre></div>
|
272
|
+
</div>
|
273
|
+
<div class="p">or</div><div class="CodeRay">
|
274
|
+
<div class="code"><pre><span class="constant">Manager</span>.config <span class="key">debug</span>: <span class="predefined-constant">true</span>
|
275
|
+
</pre></div>
|
276
|
+
</div>
|
277
|
+
<div class="p">it has the following effects:</div><ol><li>Errors raised by running a spec file and reported on the command line will have backtraces including files internal to Manager. By default, such detailed outputs are suppressed.</li><li>Outputs to standard output and standard error due to running tests are displayed on the command line. By default, they are redirected and are displayed in the output section of test reports.</li><li>Files internal to Manager are displayed in backtraces in test reports when an error or a bug is detected. By default, they are excluded.</li></ol></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature30">5. Spec File</h2><div class="feature-contents"><div class="user-item"><div class="p">Documentation and Tests are written in a spec file. When the spec file contains some higher level errors, they will be reported in the developer's chart in the manner mentioned in <a href="#feature15">3.2.2.3. Documentation Reports</a>, but when there is a syntax error or some low level error, Manager will terminate with an error message without generating any file. In order to feed back the source location of a string in case of an error, Manager stores some objects taken from the spec file with the source location. Particularly, it is important to set the strings in the spec file to be mutable in order for Manager to fully function. Especially under future Ruby 3.0, where strings are frozen by default, it is necessary to ensure this by placing a frozen string pragma with the <code class="inline">false</code> value at the beginning of the spec file:</div><div class="CodeRay">
|
278
|
+
<div class="code"><pre><span class="comment"># frozen_string_literal: false</span>
|
279
|
+
</pre></div>
|
280
|
+
</div>
|
281
|
+
<div class="p">Specification can be divided in multiple files as long as there is a single main spec file whose name is directly passed as an argument to the <code class="inline">manager</code> command or <a href="#feature80"><code class="inline">Manager.new</code></a> method, which loads the other spec files.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature31">5.1. Reference to Program Code</h3><div class="feature-contents"><div class="user-item"><div class="p">Program code can be written in files different from the spec file or in the same file as the (main) spec file as <span class="italic">scratch code</span>, or in combination of both. A program and spec should be normally written in separate files, but in order to do a quick test with a short snippet of code, using scratch code is convenient.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature32">5.1.1. Listing A File</h4><div class="feature-contents"><div class="user-item"><div class="p">In order for a program code file to be the object of analysis by Manager, it has to be <span class="italic">listed</span> in the spec file. Listing a file has two effects:</div><ol><li>The file becomes the object of analysis, i.e. constants and methods implemented in the file will be detected by Manager, and will be displayed (even if they are not described in the spec file).</li><li>The file is marked as one of the locations where the constants and methods described in the spec file are expected to reside. Any feature that has an unlisted source location is marked as “Misplaced” (see <a href="#feature12">3.2.2. Main Information</a>).</li></ol><div class="p">To list a program file, pass its path as an argument to <code class="inline">manage</code> method in the spec file in a position before the specifications. The file path may be either absolute or be relative to the spec file. A program file <code class="inline">foo.rb</code> may internally load a subfile <code class="inline">bar.rb</code>. If <code class="inline">bar.rb</code> is to be the object of analysis, it has to listed in the spec file (after <code class="inline">foo.rb</code>). The beginning of a spec file may look like this:</div><div class="CodeRay">
|
282
|
+
<div class="code"><pre><span class="comment"># frozen_string_literal: false</span>
|
283
|
+
manage <span class="string"><span class="delimiter">"</span><span class="content">foo.rb</span><span class="delimiter">"</span></span>
|
284
|
+
manage <span class="string"><span class="delimiter">"</span><span class="content">bar.rb</span><span class="delimiter">"</span></span>
|
285
|
+
</pre></div>
|
286
|
+
</div>
|
287
|
+
<div class="p">If a path passed to <code class="inline">manage</code> is a directory, then all of its (recursive) entry files are listed (and loaded). If a specific loading order should be imposed among them, write the more specific files or directories that should be loaded earlier in an earlier position. Any files that have already been listed would be skipped when they appear within a directory later passed to <code class="inline">manage</code>. For example, suppose directory <code class="inline">foo</code> has files <code class="inline">main.rb</code>, <code class="inline">sub1.rb</code>, and <code class="inline">sub2.rb</code>. Writing:</div><div class="CodeRay">
|
288
|
+
<div class="code"><pre>manage <span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>
|
289
|
+
</pre></div>
|
290
|
+
</div>
|
291
|
+
<div class="p">will list all three files, but will not guarantee any loading order among them. If <code class="inline">sub1.rb</code> and <code class="inline">sub2.rb</code> both depend on <code class="inline">main.rb</code> (but do not depend on each other), then <code class="inline">main.rb</code> has to be loaded first. This can be described as:</div><div class="CodeRay">
|
292
|
+
<div class="code"><pre>manage <span class="string"><span class="delimiter">"</span><span class="content">foo/main.rb</span><span class="delimiter">"</span></span>
|
293
|
+
manage <span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>
|
294
|
+
</pre></div>
|
295
|
+
</div>
|
296
|
+
<div class="p">and <code class="inline">main.rb</code> will not be loaded twice.</div><div class="p">To avoid “Misplaced” markings on features whose source location is unknown (for example, when it is implemented in C), list unknown source locations by passing <code class="inline">nil</code> to <code class="inline">manage</code>:</div><div class="CodeRay">
|
297
|
+
<div class="code"><pre>manage <span class="predefined-constant">nil</span>
|
298
|
+
</pre></div>
|
299
|
+
</div>
|
300
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature33">5.1.2. Scratch Code</h4><div class="feature-contents"><div class="user-item"><div class="p">Scratch code should appear within the main spec file after the line <code class="inline">__END__</code> after the spec code. Writing in this order encourages test driven development (see <a href="#feature4">2.1. Simple Example</a> for examples).</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature34">5.2. The <code class="inline">spec</code> method</h3><div class="feature-contents"><div class="user-item"><div class="p">Description in Manager is done in units using the method <a href="#feature158"><code class="inline">Module#spec</code></a> (This method can appear in the main environment as well as in a module body). The <code class="inline">spec</code> method is placed in a <span class="italic">context</span>, i.e, a module (including class) body or the main environment. It takes a <span class="italic">label</span>, which must be either of the following:</div><ol><li>A string starting with <code class="inline">::</code>, which represents a constant (including modules, classes)</li><li>A string starting with <code class="inline">.</code>, which represents a singleton method</li><li>A string starting with <code class="inline">#</code>, which represents an instance method</li><li>A string starting with one or more consecutive <code class="inline">=</code>s and has no other <code class="inline">=</code>, which represents a description with a numbered section header</li><li><code class="inline">nil</code>, which represents a description without a section header</li></ol><div class="p">followed by an arbitrary number of items (explained in <a href="#feature39">5.3. Documentation</a> and <a href="#feature53">5.4. Testing</a>), and ends with a pseudo-keyword <a href="#feature159"><code class="inline">Module#coda</code></a>. 1–3 above describe a feature, and 4,5 describe a section header. The recommended way of writing descriptions looks like this (empty lines between <code class="inline">coda</code> and the next <code class="inline">spec</code> are optional):</div><div class="CodeRay">
|
301
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">A</span>
|
302
|
+
spec <span class="predefined-constant">nil</span>,
|
303
|
+
<span class="string"><span class="delimiter">"</span><span class="content">This class provides API for doing foos.</span><span class="delimiter">"</span></span>,
|
304
|
+
coda
|
305
|
+
|
306
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=How to Create a New Foo</span><span class="delimiter">"</span></span>,
|
307
|
+
coda
|
308
|
+
|
309
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
310
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(argument)</span><span class="delimiter">"</span></span> => <span class="constant">Foo</span>},
|
311
|
+
<span class="string"><span class="delimiter">"</span><span class="content">This method takes a string and converts it into an instance of `Foo`</span><span class="delimiter">"</span></span>,
|
312
|
+
coda
|
313
|
+
|
314
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">::Foo</span><span class="delimiter">"</span></span>,
|
315
|
+
coda
|
316
|
+
<span class="keyword">end</span>
|
317
|
+
</pre></div>
|
318
|
+
</div>
|
319
|
+
<div class="p">which may result in a user's manual that looks like this:</div><figure><img alt="Example of `spec`" src="spec/spec_example.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 13. Example of <code class="inline">spec</code></figcaption></figure><div class="p">The <code class="inline">spec</code> method requires its final argument to be the pseudo-keyword <code class="inline">coda</code>, which is similar to, but different from, the <code class="inline">end</code> keyword of Ruby syntax. This design serves two purposes:</div><ol><li>All items passed to the <code class="inline">spec</code> method uniformly have to be appended by a comma <code class="inline">,</code>, which makes it easier for writing or modifying a spec file; the writer does not have to think whether or not to put a comma depending on whether the item is the last one.</li><li>Without this requirement, an item may be unintentionally skipped because of a forgotten comma after the preceding item. It makes it easier to detect such mistakes.</li></ol><div class="p">The order of the items passed to <code class="inline">spec</code> is respected in the generated files, but when the same feature is described under multiple calls of the <code class="inline">spec</code> method, all items will be gathered at the position of the first <code class="inline">spec</code> call of the feature.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature35">5.2.1. Feature</h4><div class="feature-contents"><div class="user-item"><div class="p">By default, a feature description is expected to have:</div><ul><li>At least one paragraph (see <a href="#feature41">5.3.2. Paragraph</a>) and</li><li>At least one unit test (see <a href="#feature54">5.4.1. Unit Test</a>).</li></ul><div class="p">Additionally, a feature that is a method is expected to have:</div><ul><li>At least one method signature (see <a href="#feature40">5.3.1. Method Signature</a>).</li></ul><div class="p">If a feature description lacks a paragraph (or a method signature), then by default it is tagged as “Missing doc”. If a feature description lacks a unit test, then by default it is tagged as “Missing test”.</div><div class="p">Depending on the implementation and description status, a feature may be marked as follows:</div><ul><li>A feature that is described in the spec file but is not implemented in the program code is marked its visibility as “Unimplemented” (see <a href="#feature8">3.1.1. Main Information</a>).</li><li>A feature that is not described but is implemented is, by default, marked as “Undocumented” (see <a href="#feature12">3.2.2. Main Information</a>).</li><li>A feature that is described and is implemented is, by default, expected to confirm to the followings. If it violates any, then by default it is marked as “Misplaced”.<ul><li>Be defined within one of the files listed (see <a href="#feature32">5.1.1. Listing A File</a>) or in scratch code (see <a href="#feature33">5.1.2. Scratch Code</a>),</li><li>Belong to the module it is described under (i.e. not by inheritance), and</li><li>Not be an alias method (Aliases are shown with the main method).</li></ul></li></ul></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature36">5.2.2. Hiding or Moving A Feature</h4><div class="feature-contents"><div class="user-item"><div class="p">Placing the <a href="#feature156"><code class="inline">Module#hide</code></a> method before <code class="inline">spec</code> hides the feature in the user's manual (but not in the developer's chart), and exempts the feature from “Missing doc” and “Missing test” tags.</div><div class="CodeRay">
|
320
|
+
<div class="code"><pre>hide spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
321
|
+
...,
|
322
|
+
coda
|
323
|
+
</pre></div>
|
324
|
+
</div>
|
325
|
+
<div class="p">Placing either the <code class="inline">hide</code> method or the <a href="#feature157"><code class="inline">Module#move</code></a> method before <code class="inline">spec</code> indicates that such violation is intended, and exempts the feature from “Undocumented” and “Misplaced” markings.</div><div class="CodeRay">
|
326
|
+
<div class="code"><pre>move spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
327
|
+
...,
|
328
|
+
coda
|
329
|
+
</pre></div>
|
330
|
+
</div>
|
331
|
+
<div class="p">Since <code class="inline">move</code> plays a proper subset of the roles of <code class="inline">hide</code>, using both methods simultaneously on a single feature is redundant and is not valid.</div><div class="p">When <code class="inline">hide</code> or <code class="inline">move</code> is applied to a method or a constant that is not a module, “Hidden” or “Moved” tag will respectively appear on the features. When they are applied to a module constant, the tag is displayed under the module section, and not on the feature that lists it as a constant. In such case, the effect is inherited by the features and section headers of itself and its (recursive) sub-modules (by they are not tagged). The <code class="inline">hide</code> method applied to a feature overrides <code class="inline">move</code> applied to a (less specific) module. For example, the following spec descriptions:</div><div class="CodeRay">
|
332
|
+
<div class="code"><pre>move spec <span class="string"><span class="delimiter">"</span><span class="content">::A</span><span class="delimiter">"</span></span>,
|
333
|
+
...,
|
334
|
+
coda
|
335
|
+
|
336
|
+
<span class="keyword">class</span> <span class="class">A</span>
|
337
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#foo_a</span><span class="delimiter">"</span></span>,
|
338
|
+
...,
|
339
|
+
coda
|
340
|
+
|
341
|
+
hide spec <span class="string"><span class="delimiter">"</span><span class="content">#bar_a</span><span class="delimiter">"</span></span>,
|
342
|
+
...,
|
343
|
+
coda
|
344
|
+
|
345
|
+
<span class="keyword">class</span> <span class="class">B</span>
|
346
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#foo_b</span><span class="delimiter">"</span></span>,
|
347
|
+
...,
|
348
|
+
coda
|
349
|
+
|
350
|
+
hide spec <span class="string"><span class="delimiter">"</span><span class="content">bar_b</span><span class="delimiter">"</span></span>,
|
351
|
+
...,
|
352
|
+
coda
|
353
|
+
<span class="keyword">end</span>
|
354
|
+
<span class="keyword">end</span>
|
355
|
+
</pre></div>
|
356
|
+
</div>
|
357
|
+
<div class="p">will make <code class="inline">A</code>, <code class="inline">A#foo_a</code>, <code class="inline">B</code>, and <code class="inline">B#foo_b</code> moved, and <code class="inline">A#bar_a</code> and <code class="inline">B#bar_b</code> hidden.</div><div class="p">The methods <code class="inline">hide</code> and <code class="inline">move</code> should be used to hide implementation details in the user's manual. If some features are implemented not for the user's use, but for internal use, then they should be hidden from the user by the <code class="inline">hide</code> method. If some features are implemented under a module <code class="inline">A</code> aimed for developers, which is included in, or prepended to, some modules <code class="inline">B</code> and <code class="inline">C</code> aimed for the users, then <code class="inline">A</code> should be marked by <code class="inline">hide</code>, and <code class="inline">B</code> and <code class="inline">C</code> should be marked by <code class="inline">move</code>.</div><div class="p">A hidden feature cannot include a user item (Cf. <a href="#feature18">3.2.3. Top Bar</a>. See subsections in <a href="#feature39">5.3. Documentation</a> for whether an item is a user item. No item under <a href="#feature53">5.4. Testing</a> is a user item).</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature37">5.2.3. Section Header</h4><div class="feature-contents"><div class="user-item"><div class="p">Section header starts a section about a module or the entire software (if written in the main environment). If the label passed to <code class="inline">spec</code> is <code class="inline">nil</code>, then the section does not have an explicit header. If the label starts with <code class="inline">=</code>, then the header is numbered, and has the content that is the substring following the <code class="inline">=</code>s. Header numbering has hierarchy; the number of <code class="inline">=</code> characters describes the depth of the numbering (one, outermost level to fifth, innermost level). If that is more than five, then, it will be set to the fifth depth.</div><div class="p">No two numbered headers in a sibling position to each other in the same module can have the same content. This is an example of an invalid heading:</div><div class="CodeRay">
|
358
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">A</span>
|
359
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=About Foo</span><span class="delimiter">"</span></span>,
|
360
|
+
coda
|
361
|
+
|
362
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=About Bar</span><span class="delimiter">"</span></span>,
|
363
|
+
coda
|
364
|
+
|
365
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=About Foo</span><span class="delimiter">"</span></span>,
|
366
|
+
coda
|
367
|
+
<span class="keyword">end</span>
|
368
|
+
</pre></div>
|
369
|
+
</div>
|
370
|
+
<div class="p">This is an example of a valid heading:</div><div class="CodeRay">
|
371
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">=How to Use It</span><span class="delimiter">"</span></span>,
|
372
|
+
coda
|
373
|
+
|
374
|
+
<span class="keyword">class</span> <span class="class">A</span>
|
375
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=How to Use It</span><span class="delimiter">"</span></span>,
|
376
|
+
coda
|
377
|
+
<span class="keyword">end</span>
|
378
|
+
|
379
|
+
<span class="keyword">class</span> <span class="class">B</span>
|
380
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=How to Use It</span><span class="delimiter">"</span></span>,
|
381
|
+
coda
|
382
|
+
|
383
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Foo</span><span class="delimiter">"</span></span>,
|
384
|
+
coda
|
385
|
+
|
386
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">==How to Use It</span><span class="delimiter">"</span></span>,
|
387
|
+
coda
|
388
|
+
|
389
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Bar</span><span class="delimiter">"</span></span>,
|
390
|
+
coda
|
391
|
+
|
392
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">==How to Use It</span><span class="delimiter">"</span></span>,
|
393
|
+
coda
|
394
|
+
<span class="keyword">end</span>
|
395
|
+
</pre></div>
|
396
|
+
</div>
|
397
|
+
<div class="p">and will be displayed as:</div><figure><img alt="Valid Heading" src="spec/valid_heading.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 14. Valid Heading</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature38">5.2.4. Main Context</h4><div class="feature-contents"><div class="user-item"><div class="p">In Ruby code, methods and constants defined in the main context are owned by the <code class="inline">Object</code> class, hence with respect to the ownership (but not for visibility), it would not make a difference if they were defined in an <code class="inline">Object</code> class body. Manager handles feature descriptions in the same way; describing a feature in the main context is equivalent to describing it within the <code class="inline">Object</code> class body.</div><div class="p">However, Manager distinguishes between describing a section header in the main context and describing it within the <code class="inline">Object</code> class body. The former should be used to describe the entire software, whereas the latter should be done to describe particularly the <code class="inline">Object</code> class.</div><div class="p">In the following example,</div><div class="CodeRay">
|
398
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">=About This Software</span><span class="delimiter">"</span></span>,
|
399
|
+
<span class="string"><span class="delimiter">"</span><span class="content">To install, type `gem install foo`.</span><span class="delimiter">"</span></span>,
|
400
|
+
coda
|
401
|
+
|
402
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#bar</span><span class="delimiter">"</span></span>,
|
403
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Some description about the method `bar`.</span><span class="delimiter">"</span></span>,
|
404
|
+
coda
|
405
|
+
|
406
|
+
<span class="keyword">class</span> <span class="class">Object</span>
|
407
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Some Notes about The `Object` Class</span><span class="delimiter">"</span></span>,
|
408
|
+
<span class="string"><span class="delimiter">"</span><span class="content">There are some original methods defined, so be careful.</span><span class="delimiter">"</span></span>,
|
409
|
+
coda
|
410
|
+
|
411
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#bar</span><span class="delimiter">"</span></span>,
|
412
|
+
<span class="string"><span class="delimiter">"</span><span class="content">More description about the method `bar`.</span><span class="delimiter">"</span></span>,
|
413
|
+
coda
|
414
|
+
<span class="keyword">end</span>
|
415
|
+
</pre></div>
|
416
|
+
</div>
|
417
|
+
<div class="p">the main context and the <code class="inline">Object</code> class each has a section header and a feature description. It is rendered as:</div><figure><img alt="Main context and Object" src="spec/main_and_object.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 15. Main context and Object</figcaption></figure><div class="p">The descriptions for the instance method <code class="inline">bar</code>, which is scattered between the main context and <code class="inline">Object</code> in the spec file, have been combined within <code class="inline">Object</code> under a single feature header <code class="inline">bar</code>, whereas the section headers in main and <code class="inline">Object</code> appear separately.</div></div></div></div><div class="feature"><h3 id="feature39">5.3. Documentation</h3><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature40">5.3.1. Method Signature</h4><div class="feature-contents"><div class="user-item"><div class="p">A method signature is a user item.</div><div class="p">Method signature is described by a hash, with a string key describing arguments and the value describing a (range of) return value. The return value may be described by a class to which the return value belongs to, or by the <a href="#feature160"><code class="inline">Module#value</code></a> method with the argument <code class="inline">obj</code>, which describes the return value as a particular object <code class="inline">obj</code>, or by the <a href="#feature161"><code class="inline">Module#error</code></a> method with the argument <code class="inline">exception_class</code> that describes a class of exceptions that may be raised. Multiple types of return values may be joined by the method <a href="#feature166"><code class="inline">Class#|</code></a> to express alternatives. (The parentheses around the argument of <code class="inline">value</code> or <code class="inline">error</code> should not be omitted, as <code class="inline">|</code> has stronger associativity than method call.)</div><div class="CodeRay">
|
418
|
+
<div class="code"><pre>{<span class="string"><span class="delimiter">"</span><span class="content">(str, *arr)</span><span class="delimiter">"</span></span> => value(<span class="integer">-1</span>) | value(<span class="integer">0</span>) | value(<span class="integer">1</span>) | <span class="constant">Array</span> | error(<span class="constant">ArgumentError</span>)}
|
419
|
+
</pre></div>
|
420
|
+
</div>
|
421
|
+
<div class="p">From the point of view of implementation, a method only has one signature (with possibly optional arguments and varying number of arguments), but form the user's side, it is often helpful to regard some methods as having multiple usages, and to have them documented separately. For example, a method <code class="inline">foo</code> may be implemented to have an obligatory argument <code class="inline">a</code> and an optional argument <code class="inline">b</code>, and an optional block <code class="inline">pr</code>,</div><div class="CodeRay">
|
422
|
+
<div class="code"><pre><span class="keyword">def</span> <span class="function">foo</span> a, b = <span class="predefined-constant">nil</span>, &pr
|
423
|
+
...
|
424
|
+
<span class="keyword">end</span>
|
425
|
+
</pre></div>
|
426
|
+
</div>
|
427
|
+
<div class="p">These options can be split into several usages. One documentation might be as follows:</div><div class="CodeRay">
|
428
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
429
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(a)</span><span class="delimiter">"</span></span> => <span class="constant">Foo</span>, <span class="string"><span class="delimiter">"</span><span class="content">(a, b)</span><span class="delimiter">"</span></span> => <span class="constant">Foo</span> | error(<span class="constant">RuntimeError</span>)},
|
430
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Without a block, `foo` calculates the foo using the foo algorithm. If an optinal argument `b`
|
431
|
+
is given, an error might be raised.</span><span class="delimiter">"</span></span>,
|
432
|
+
...,
|
433
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(a, &pr)</span><span class="delimiter">"</span></span> => <span class="constant">Foo</span> | value(<span class="predefined-constant">nil</span>)},
|
434
|
+
<span class="string"><span class="delimiter">"</span><span class="content">When a block is given, `foo` passes the foo value to the block.</span><span class="delimiter">"</span></span>,
|
435
|
+
...,
|
436
|
+
coda
|
437
|
+
</pre></div>
|
438
|
+
</div>
|
439
|
+
<div class="p">which would be displayed as:</div><figure><img alt="Method signature" src="spec/signature.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 16. Method signature</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature41">5.3.2. Paragraph</h4><div class="feature-contents"><div class="user-item"><div class="p">A paragraph is described by a string not beginning with <code class="inline">></code>, <code class="inline">*</code>, or <code class="inline">#</code>, and optionally beginning with <code class="inline">!</code> (see <a href="#feature46">5.3.4. Annotation</a> for exceptions). A paragraph is a user item if and only if it does not begin with <code class="inline">!</code>.</div><div class="p">The following markups are applied to a paragraph, with the priority in the order given:</div><ol><li>Locally minimum substring surrounded by balanced sequences of one or more backticks <code class="inline">`...`</code>: inline code</li><li>Substring not including <code class="inline">*</code> surrounded by double asterisks <code class="inline">**...**</code>: bold face</li><li>Substring not including <code class="inline">*</code> surrounded by single asterisks <code class="inline">*...*</code>: italics</li><li>Substring not including <code class="inline">{</code> and <code class="inline">}</code> surrounded by a pair of braces <code class="inline">{...}</code>: link (see <a href="#feature42">5.3.3. Link</a>)</li></ol><div class="p">In order to mark an inline code that includes backticks, surround it with a pair of identical sequences of backticks that are longer than any consecutive backticks in the inline code.</div><div class="p">If an inline code begins and/or ends with a backtick, or if the beginning of a paragraph is to be italicized or bold faced, then insert a space to avoid interference with the notation. Such spaces will be stripped.</div><div class="p">Consecutive space characters in a part of string that is not marked up by any of the above are squeezed into single space characters, so line changes can be made in the middle of a string without affecting the output.</div><div class="p">For example,</div><div class="CodeRay">
|
440
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content">The part `* bar *` in `foo * bar * baz` is not interpreted as an italicized word
|
441
|
+
because inline code has precedence over bold face in markup.</span><span class="delimiter">"</span></span>,
|
442
|
+
<span class="string"><span class="delimiter">'</span><span class="content">Suppose we have this expression: ``` `echo #{string.sub(/``/, "x")}` ```.
|
443
|
+
If we run it, it will echo something.</span><span class="delimiter">'</span></span>,
|
444
|
+
<span class="string"><span class="delimiter">"</span><span class="content"> *This is a paragraph that starts with an italicized sentence.*</span><span class="delimiter">"</span></span>,
|
445
|
+
<span class="string"><span class="delimiter">"</span><span class="content">! This is a non-user (i.e. developer) paragraph.</span><span class="delimiter">"</span></span>,
|
446
|
+
</pre></div>
|
447
|
+
</div>
|
448
|
+
<div class="p">is rendered in the developer's chart as:</div><figure><img alt="Markup" src="spec/markup.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 17. Markup</figcaption></figure><div class="p">Note that the developer paragraphs are hidden in the user's manual, and the user's paragraphs have a distinct background in the developer's chart.</div><div class="p">As a tip, characters that are difficult to be input from the keyboard can be described by their UTF-16 code in hexadecimal notation after the escape character <code class="inline">\u</code> (this is Ruby's feature). For example,</div><div class="CodeRay">
|
449
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="char">\u</span><span class="content">25B8</span><span class="delimiter">"</span></span> <span class="comment"># => "▸"</span>
|
450
|
+
</pre></div>
|
451
|
+
</div>
|
452
|
+
<div class="p">Non-marked up portion of a string is also subject to spell checking if the option is turned on (see <a href="#feature21">4.1.1. Spell Check (spell_check, spell-check-list, spell-check-filter, case_sensitive, case_insensitive)</a>).</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature42">5.3.3. Link</h4><div class="feature-contents"><div class="user-item"><div class="p">Links are expressed in a pair of braces <code class="inline">{</code> and <code class="inline">}</code>. No link can have a brace character inside. Depending on the surrounded string, there are three types.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature43">5.3.3.1. External Links</h5><div class="feature-contents"><div class="user-item"><div class="p">An external link is expressed by a string that includes a URL that includes the scheme <code class="inline">://</code>. The URL can optionally be preceded by a link name and a comma <code class="inline">,</code>. The name cannot include <code class="inline">=</code> (This is to avoid ambiguity. See <a href="#feature45">5.3.3.3. Links to Section Headers</a>). This example:</div><div class="CodeRay">
|
453
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content">This is a link without a name: {https://www.ruby-lang.org}, and
|
454
|
+
{this, https://www.ruby-lang.org} is a link with a name</span><span class="delimiter">"</span></span>,
|
455
|
+
</pre></div>
|
456
|
+
</div>
|
457
|
+
<div class="p">results in:</div><figure><img alt="External link" src="spec/external_link.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 18. External link</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature44">5.3.3.2. Links to Features</h5><div class="feature-contents"><div class="user-item"><div class="p">A link to a feature is expressed by a string that has a feature name (which starts with <code class="inline">::</code>, <code class="inline">#</code>, or <code class="inline">.</code>), and is optionally preceded by a module. Absence of a module makes the current context/module be the relevant domain. If a module is given, it is interpreted with the same rule as in Ruby code, relative to the current context. The following are possible links:</div><div class="CodeRay">
|
458
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#a</span><span class="delimiter">"</span></span>,
|
459
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Links in each list item have the same target.</span><span class="delimiter">"</span></span>,
|
460
|
+
<span class="string"><span class="delimiter">"</span><span class="content">* {#b}, {Object#b}</span><span class="delimiter">"</span></span>,
|
461
|
+
<span class="string"><span class="delimiter">"</span><span class="content">* {A}, {::A}, {Object::A}</span><span class="delimiter">"</span></span>,
|
462
|
+
coda
|
463
|
+
|
464
|
+
<span class="keyword">class</span> <span class="class">A</span>
|
465
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#c</span><span class="delimiter">"</span></span>,
|
466
|
+
<span class="string"><span class="delimiter">"</span><span class="content">* {#d}, {::A#d}, {Object::A#d}</span><span class="delimiter">"</span></span>,
|
467
|
+
coda
|
468
|
+
<span class="keyword">end</span>
|
469
|
+
</pre></div>
|
470
|
+
</div>
|
471
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature45">5.3.3.3. Links to Section Headers</h5><div class="feature-contents"><div class="user-item"><div class="p">A link to a section header is expressed by a string that starts with a single <code class="inline">=</code>, followed by the name of the section header, and is optionally preceded by a module.</div><div class="p">Omission of a module makes the link refer to the current context. The main context is described as <code class="inline">::</code>, which has different effect from <code class="inline">Object</code> when linking to section headers, unlike when linking to features (see <a href="#feature38">5.2.4. Main Context</a>). When the link target belongs to a different context from where it is written, the context is described in parentheses. Suppose we have section headers named “Summary” in the main context, the <code class="inline">Object</code> class, and another class <code class="inline">A</code>, and some some links:</div><div class="CodeRay">
|
472
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">=Summary</span><span class="delimiter">"</span></span>,
|
473
|
+
coda
|
474
|
+
|
475
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Links</span><span class="delimiter">"</span></span>,
|
476
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Here is a link: {::=Summary}.</span><span class="delimiter">"</span></span>,
|
477
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Here is another: {=Summary}.</span><span class="delimiter">"</span></span>,
|
478
|
+
coda
|
479
|
+
|
480
|
+
<span class="keyword">class</span> <span class="class">Object</span>
|
481
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Place Holder 1</span><span class="delimiter">"</span></span>,
|
482
|
+
coda
|
483
|
+
|
484
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Summary</span><span class="delimiter">"</span></span>,
|
485
|
+
coda
|
486
|
+
|
487
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Links</span><span class="delimiter">"</span></span>,
|
488
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Here is a link: {::=Summary}.</span><span class="delimiter">"</span></span>,
|
489
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Here is another: {=Summary}.</span><span class="delimiter">"</span></span>,
|
490
|
+
coda
|
491
|
+
<span class="keyword">end</span>
|
492
|
+
|
493
|
+
<span class="keyword">class</span> <span class="class">A</span>
|
494
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Place Holder 1</span><span class="delimiter">"</span></span>,
|
495
|
+
coda
|
496
|
+
|
497
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Place Holder 2</span><span class="delimiter">"</span></span>,
|
498
|
+
coda
|
499
|
+
|
500
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Summary</span><span class="delimiter">"</span></span>,
|
501
|
+
coda
|
502
|
+
|
503
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Links</span><span class="delimiter">"</span></span>,
|
504
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Here is a link: {::=Summary}.</span><span class="delimiter">"</span></span>,
|
505
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Here is another: {=Summary}.</span><span class="delimiter">"</span></span>,
|
506
|
+
coda
|
507
|
+
<span class="keyword">end</span>
|
508
|
+
</pre></div>
|
509
|
+
</div>
|
510
|
+
<figure><img alt="Context of Module Evaluation" src="spec/context_module.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 19. Context of Module Evaluation</figcaption></figure><div class="p">The three links <code class="inline">{::=Summary}</code> all refer to the same section header in the main context (among which the two that are not written in the main context are displayed with “(main)”), but the three links <code class="inline">{=Summary}</code> respectively refer to the section header of the context it is written in; only the link <code class="inline">{=Summary}</code> in the main context has the same target as the <code class="inline">{::=Summary}</code> links.</div><div class="p">Regardless of the depth of numbering on the target header, the section header name in a link should be prefixed by exactly one <code class="inline">=</code>. Multiple section headers with the same name within a module can be disambiguated by sufficient levels of ancestor header names joined by <code class="inline">=</code>, put in front of the <code class="inline">=</code> before the target header name. Among the matching candidates, the one with the least depth will be referred to. Given a section structure:</div><div class="CodeRay">
|
511
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">=Summary</span><span class="delimiter">"</span></span>,
|
512
|
+
coda
|
513
|
+
|
514
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Foo</span><span class="delimiter">"</span></span>,
|
515
|
+
coda
|
516
|
+
|
517
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">==Summary</span><span class="delimiter">"</span></span>,
|
518
|
+
coda
|
519
|
+
|
520
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">=Bar</span><span class="delimiter">"</span></span>,
|
521
|
+
coda
|
522
|
+
|
523
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">==Summary</span><span class="delimiter">"</span></span>,
|
524
|
+
coda
|
525
|
+
|
526
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">==Bar</span><span class="delimiter">"</span></span>,
|
527
|
+
coda
|
528
|
+
|
529
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">===Summary</span><span class="delimiter">"</span></span>,
|
530
|
+
coda
|
531
|
+
</pre></div>
|
532
|
+
</div>
|
533
|
+
<div class="p">rendered as:</div><figure><img alt="Nested Section Headers" src="spec/nested_section_headers.png" style="width:100%;;border:1px solid hsl(0, 0%, 80%);;" /><figcaption>Figure 20. Nested Section Headers</figcaption></figure><div class="p">the four section headers named “Summary” can be unambiguously targeted by the links:</div><div class="CodeRay">
|
534
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content">{=Summary}, {=Foo=Summary}, {=Bar=Summary}, {=Bar=Bar=Summary}</span><span class="delimiter">"</span></span>
|
535
|
+
</pre></div>
|
536
|
+
</div>
|
537
|
+
<div class="p">which will be rendered as:</div><figure><img alt="Unambiguous Links" src="spec/unambiguous_links.png" style="width:100%;;border:1px solid hsl(0, 0%, 80%);;" /><figcaption>Figure 21. Unambiguous Links</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature46">5.3.4. Annotation</h4><div class="feature-contents"><div class="user-item"><div class="p">Annotations are not user items.</div><div class="p">A string item in the spec file that starts with with <code class="inline">!!</code> or <code class="inline">!</code>, followed by an optional space, an <span class="italic">annotation tag</span> consisting of non-space characters, and a colon <code class="inline">:</code> is an annotation, particularly a log item (rather than a developer's paragraph). A spec file may look like:</div><div class="CodeRay">
|
538
|
+
<div class="code"><pre>manage <span class="string"><span class="delimiter">"</span><span class="content">sample.rb</span><span class="delimiter">"</span></span>
|
539
|
+
|
540
|
+
spec <span class="predefined-constant">nil</span>,
|
541
|
+
<span class="string"><span class="delimiter">"</span><span class="content">!! todo_by_summer: This must be done by the end of summer.</span><span class="delimiter">"</span></span>,
|
542
|
+
<span class="string"><span class="delimiter">"</span><span class="content">!! foo_algorithm: This code chunk implements the foo algorithm.
|
543
|
+
It assumes blah blah blah, then calculates blah blah.</span><span class="delimiter">"</span></span>,
|
544
|
+
coda
|
545
|
+
|
546
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
547
|
+
<span class="string"><span class="delimiter">"</span><span class="content">! nil_proof: This routine takes care of the cases when `bar` is `nil`.</span><span class="delimiter">"</span></span>,
|
548
|
+
<span class="string"><span class="delimiter">"</span><span class="content">! This is not an annotation but is a developer's paragraph since it does not have a tag.</span><span class="delimiter">"</span></span>,
|
549
|
+
...
|
550
|
+
coda
|
551
|
+
</pre></div>
|
552
|
+
</div>
|
553
|
+
<div class="p">Comment inside a method body in a program code starting with <code class="inline">#!!</code> or <code class="inline">#!</code>, and comment lines immediately following such lines are also annotations. If an annotations in a program code has an annotation tag (followed by a colon <code class="inline">:</code>), the annotation is a log, and is related to other logs extracted from the program code and spec file. If it does not have a tag, then the annotation is an agenda. A method definition in the program code may have annotations like this:</div><div class="CodeRay">
|
554
|
+
<div class="code"><pre><span class="keyword">def</span> <span class="function">foo</span>
|
555
|
+
...
|
556
|
+
... <span class="comment">#! nil_proof:</span>
|
557
|
+
...
|
558
|
+
<span class="comment">#!! foo_algorithm:</span>
|
559
|
+
...
|
560
|
+
<span class="keyword">end</span>
|
561
|
+
<span class="keyword">def</span> <span class="function">bar</span>
|
562
|
+
... <span class="comment">#!! todo_by_summer:</span>
|
563
|
+
<span class="comment">#!! foo_algorithm:</span>
|
564
|
+
...
|
565
|
+
<span class="comment">#! Somehow this routine is required.</span>
|
566
|
+
<span class="comment"># But I don't know why.</span>
|
567
|
+
<span class="keyword">end</span>
|
568
|
+
</pre></div>
|
569
|
+
</div>
|
570
|
+
<div class="p">The purpose of a tag is to relate different annotations. Annotations in the same scope with the same tag are concatenated and displayed as one (see <a href="#feature16">3.2.2.3.1. Annotations and Editorial Markings</a>). The number of exclamation marks at the beginning of an annotation expresses the scope:</div><ul><li><code class="inline">#!!</code> in the spec file or <code class="inline">!!</code> in a program code expresses file scope; all annotations with the same tag within the same program file are concatenated together.</li><li><code class="inline">#!</code> in the spec file or <code class="inline">!</code> in a program code expresses method-body scope; all annotations with the same tag within the body of the same method in a program code are concatenated together.</li></ul><div class="p">Running Manager with the spec file above and the program code above (named as <code class="inline">sample.rb</code>) will result in the following (with irrelevant content removed):</div><figure><img alt="Annotations" src="spec/annotations.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 22. Annotations</figcaption></figure><div class="p">An annotation in the spec file with a file-scope tag can only appear in the main context with an implicit or an explicit section header (i.e. not with a constant or a method). The following spec file is invalid.</div><div class="CodeRay">
|
571
|
+
<div class="code"><pre>manage <span class="string"><span class="delimiter">"</span><span class="content">sample.rb</span><span class="delimiter">"</span></span>
|
572
|
+
|
573
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
574
|
+
<span class="string"><span class="delimiter">"</span><span class="content">!! todo_by_summer: This must be done by the end of summer.</span><span class="delimiter">"</span></span>,
|
575
|
+
coda
|
576
|
+
|
577
|
+
<span class="keyword">class</span> <span class="class">A</span>
|
578
|
+
spec <span class="predefined-constant">nil</span>,
|
579
|
+
<span class="string"><span class="delimiter">"</span><span class="content">!! foo_algorithm: This code chunk implements the foo algorithm.
|
580
|
+
It assumes blah blah blah, then calculates blah blah.</span><span class="delimiter">"</span></span>,
|
581
|
+
coda
|
582
|
+
<span class="keyword">end</span>
|
583
|
+
</pre></div>
|
584
|
+
</div>
|
585
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature47">5.3.5. Citation</h4><div class="feature-contents"><div class="user-item"><div class="p">Citation is described by a string starting with <code class="inline">></code>. If the string has <code class="inline">!</code> right after it, then it is not a user item, otherwise, it is a user item.</div><div class="CodeRay">
|
586
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content">> This is user citation</span><span class="delimiter">"</span></span>,
|
587
|
+
<span class="string"><span class="delimiter">"</span><span class="content">>! This is developer citation</span><span class="delimiter">"</span></span>,
|
588
|
+
</pre></div>
|
589
|
+
</div>
|
590
|
+
<div class="p">These citations are displayed in the developer's chart as:</div><figure><img alt="Citations" src="spec/citation.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 23. Citations</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature48">5.3.6. List</h4><div class="feature-contents"><div class="user-item"><div class="p">A list item is described by a string starting with a sequence of one or more <code class="inline">*</code> or <code class="inline">#</code>. If the string has <code class="inline">!</code> right after it, then it is not a user item, otherwise it is a user item.</div><div class="p">Consecutive list items constitute a list. Each <code class="inline">*</code> or <code class="inline">#</code> at the beginning of an item represents an un-numbered or numbered item respectively at the corresponding level. No other type of items may intervene list items in order for the list items to be recognized as a single list. This is important for lists that have numbered items, as the numbers will be reset by interruption. The following spec file:</div><div class="CodeRay">
|
591
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content"># user item</span><span class="delimiter">"</span></span>,
|
592
|
+
<span class="string"><span class="delimiter">"</span><span class="content">## user item</span><span class="delimiter">"</span></span>,
|
593
|
+
<span class="string"><span class="delimiter">"</span><span class="content">##* user item</span><span class="delimiter">"</span></span>,
|
594
|
+
<span class="string"><span class="delimiter">"</span><span class="content">## user item</span><span class="delimiter">"</span></span>,
|
595
|
+
<span class="string"><span class="delimiter">"</span><span class="content"># user item</span><span class="delimiter">"</span></span>,
|
596
|
+
<span class="string"><span class="delimiter">"</span><span class="content">#! developer item</span><span class="delimiter">"</span></span>,
|
597
|
+
<span class="string"><span class="delimiter">"</span><span class="content">##! developer item</span><span class="delimiter">"</span></span>,
|
598
|
+
<span class="string"><span class="delimiter">"</span><span class="content">#! developer item</span><span class="delimiter">"</span></span>,
|
599
|
+
<span class="string"><span class="delimiter">"</span><span class="content">! Some intervening developer's paragraph</span><span class="delimiter">"</span></span>,
|
600
|
+
<span class="string"><span class="delimiter">"</span><span class="content">#! developer item</span><span class="delimiter">"</span></span>,
|
601
|
+
<span class="string"><span class="delimiter">"</span><span class="content">##! developer item</span><span class="delimiter">"</span></span>,
|
602
|
+
<span class="string"><span class="delimiter">"</span><span class="content">##*! developer item</span><span class="delimiter">"</span></span>,
|
603
|
+
<span class="string"><span class="delimiter">"</span><span class="content">#! developer item</span><span class="delimiter">"</span></span>,
|
604
|
+
</pre></div>
|
605
|
+
</div>
|
606
|
+
<div class="p">is displayed in the developer's chart as:</div><figure><img alt="List" src="spec/list.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 24. List</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature49">5.3.7. Line</h4><div class="feature-contents"><div class="user-item"><div class="p">A string that starts with one or more consecutive <code class="inline">-</code> describes a line. It can be used to split units that are larger than paragraphs. If it is followed by <code class="inline">!</code>, then it is not a user item. Otherwise, it is a user item.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature50">5.3.8. Code Block</h4><div class="feature-contents"><div class="user-item"><div class="p">A code block is expressed by a string followed by the method <a href="#feature227"><code class="inline">String#code</code></a> or <a href="#feature228"><code class="inline">String#code!</code></a>. These methods take an optional symbol argument in lower case, which describes the programming language in which syntax highlighting takes place (see <a href="#feature28">4.1.8. Syntax Highlighting (highlight, highlight-list)</a>). By default, this is <code class="inline">:ruby</code>. Method <code class="inline">code</code> is for user item, and <code class="inline">code!</code> is for developer item. The recommended practice is to use a here document with an identifier of the form <code class="inline">~'RUBY'</code>.</div><ul><li>The <code class="inline">~</code> un-indents the code block to its least indented level.</li><li>The single quotes <code class="inline">'...'</code> assure verbatim interpretation of the code block.</li><li>A string expressing the language in capital, like <code class="inline">RUBY</code>, is recognized by many text editors so that syntax highlighting inside the code string will be done in that language.</li></ul></div><div class="user-item"><div class="p">The following example:</div><div class="CodeRay">
|
607
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content">A Ruby example for users:</span><span class="delimiter">"</span></span>,
|
608
|
+
<span class="string"><span class="delimiter"><<~'RUBY'</span></span>.code,<span class="string"><span class="content">
|
609
|
+
def foo
|
610
|
+
puts "This is Ruby code."
|
611
|
+
end</span><span class="delimiter">
|
612
|
+
RUBY</span></span>
|
613
|
+
<span class="string"><span class="delimiter">"</span><span class="content">! and a CSS code for developers:</span><span class="delimiter">"</span></span>,
|
614
|
+
<span class="string"><span class="delimiter"><<~'CSS'</span></span>.code!(<span class="symbol">:css</span>),<span class="string"><span class="content">
|
615
|
+
#main{
|
616
|
+
background-color: green;
|
617
|
+
}</span><span class="delimiter">
|
618
|
+
CSS</span></span>
|
619
|
+
</pre></div>
|
620
|
+
</div>
|
621
|
+
<div class="p">is displayed in the developer's chart as:</div><figure><img alt="Code block" src="spec/code_block.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 25. Code block</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature51">5.3.9. Image</h4><div class="feature-contents"><div class="user-item"><div class="p">An image is expressed by the method <a href="#feature162"><code class="inline">Module#image</code></a> or <a href="#feature163"><code class="inline">Module#image!</code></a>. Method <code class="inline">image</code> is for user item, and <code class="inline">image!</code> is for developer item. These methods take an obligatory string argument expressing the caption, an obligatory string argument describing the path of the image file (either absolute or relative to the output directory; see <a href="#feature22">4.1.2. Output Directory (odir)</a>), and an optional hash of symbol keys and string or numeral values, which will be expanded into CSS commands in the generated HTML files.</div><div class="p">The following example:</div><div class="CodeRay">
|
622
|
+
<div class="code"><pre><span class="string"><span class="delimiter">"</span><span class="content">For users</span><span class="delimiter">"</span></span>,
|
623
|
+
image(<span class="string"><span class="delimiter">"</span><span class="content">Ruby logo (Copyright © 2006, Yukihiro Matsumoto)</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">ruby.png</span><span class="delimiter">"</span></span>, <span class="key">width</span>: <span class="integer">200</span>),
|
624
|
+
<span class="string"><span class="delimiter">"</span><span class="content">! For developers</span><span class="delimiter">"</span></span>,
|
625
|
+
image!(<span class="string"><span class="delimiter">"</span><span class="content">Ruby logo (Copyright © 2006, Yukihiro Matsumoto)</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">ruby.png</span><span class="delimiter">"</span></span>, <span class="key">width</span>: <span class="integer">100</span>,
|
626
|
+
<span class="key">border</span>: <span class="string"><span class="delimiter">"</span><span class="content">1px solid hsl(0, 0%, 80%)</span><span class="delimiter">"</span></span>),
|
627
|
+
</pre></div>
|
628
|
+
</div>
|
629
|
+
<div class="p">is displayed in the developer's chart as:</div><figure><img alt="Image" src="spec/image.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 26. Image</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature52">5.3.10. Table</h4><div class="feature-contents"><div class="user-item"><div class="p">Tables are user items. They are described by an array of arrays, each of which expresses a row, whose elements are strings, each of which expresses a cell.</div><div class="p">Text alignment of each cell is controlled by initial/final spacing in the string. Depending on whether the string has only a final space, only an initial space, or both, the cell will be left aligned, right aligned, or center aligned, respectively. Otherwise, the string will be left aligned by default. This item:</div><div class="CodeRay">
|
630
|
+
<div class="code"><pre>[
|
631
|
+
[<span class="string"><span class="delimiter">"</span><span class="content"> Right aligned.</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">A very very very very very long cell.</span><span class="delimiter">"</span></span>],
|
632
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">Another cell that is quite loooooooooooooooooong.</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content"> This is centered. </span><span class="delimiter">"</span></span>]
|
633
|
+
],
|
634
|
+
</pre></div>
|
635
|
+
</div>
|
636
|
+
<div class="p">is rendered as a table like this:</div><figure><img alt="Table" src="spec/table.png" style="border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 27. Table</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h3 id="feature53">5.4. Testing</h3><div class="feature-contents"><div class="user-item"><div class="p">Manager can perform two types of tests: <span class="italic">unit test</span> and <span class="italic">benchmark</span>.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature54">5.4.1. Unit Test</h4><div class="feature-contents"><div class="user-item"><div class="p">A unit test can be defined by the following steps:</div><ol><li><span class="italic">Setup</span>: Prepare objects and states required for the test. Often described by the term <code class="inline">Given</code> in conventional test frameworks.</li><li><span class="italic">Exercise</span>: Perform the behavior that is the object of test. Often described by <code class="inline">When</code>.</li><li><span class="italic">Verification</span>: Check the result of exercise. Often described by <code class="inline">Then</code>.</li><li>Additional verification: In required, do more checks on the result or on any change that is caused by the exercise. Often described by <code class="inline">And</code> after <code class="inline">Then</code>.</li></ol><div class="p">In unit test in Manager, each step is described in the following way:</div><ol><li>Setup: Describe the objects using Ruby literal expressions, or using <a href="#feature226"><code class="inline">String#setup</code></a> and <a href="#feature115"><code class="inline">::#expr</code></a> methods (see <a href="#feature58">5.4.4. The `expr` Method</a>, <a href="#feature59">5.4.5. Setup and Teardown</a>).</li><li>Exercise: Describe the Ruby expression that should be performed using the objects prepared by setup, but substitute the relevant feature (method or constant) call with the placeholder <a href="#feature153"><code class="inline">BasicObject#UT</code></a>.</li><li>Verification: After the exercise, chain method call(s) that should be evaluated to a truthy value. (For this step, a methods named <code class="inline">initialize</code> and <code class="inline">method_missing</code> cannot be used. But this should rarely be a problem.)</li><li>Additional verification: Describe in a similar way as verification, but substitute the return value of exercise and the original receiver of exercise with the placeholders <code class="inline">RETURN</code> and <code class="inline">RECEIVER</code>, respectively.</li></ol><div class="p">Every time <code class="inline">UT</code> is called, the value of <code class="inline">RETURN</code> and <code class="inline">RECEIVER</code> are reset.</div><div class="p">The following is an example of testing the <code class="inline">Array#push</code> method.</div><div class="CodeRay">
|
637
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
638
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#push</span><span class="delimiter">"</span></span>,
|
639
|
+
[].UT(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>) == [<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>],
|
640
|
+
<span class="constant">RETURN</span>.length == <span class="integer">1</span>,
|
641
|
+
<span class="constant">RECEIVER</span> == [<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>],
|
642
|
+
[].UT(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>) == [<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>],
|
643
|
+
<span class="constant">RETURN</span>.length == <span class="integer">2</span>,
|
644
|
+
<span class="constant">RECEIVER</span> == [<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>],
|
645
|
+
coda
|
646
|
+
<span class="keyword">end</span>
|
647
|
+
</pre></div>
|
648
|
+
</div>
|
649
|
+
<div class="p">The first instance of <code class="inline">RETURN</code> and <code class="inline">RECEIVER</code> refer to the result of the first exercise (expressed by <code class="inline">UT</code>) and its original array receiver. By the second <code class="inline">UT</code> call, they are reset, so that the second instance of <code class="inline">RETURN</code> and <code class="inline">RECEIVER</code> refer to the new return value and the new receiver array.</div><div class="p">The result is as follows:</div><figure><img alt="Unit test succeeded" src="spec/unit_test_success.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 28. Unit test succeeded</figcaption></figure><div class="p">An example of test failure is as follows:</div><div class="CodeRay">
|
650
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
651
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#concat</span><span class="delimiter">"</span></span>,
|
652
|
+
<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span>.UT(<span class="symbol">:a</span>) == <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>,
|
653
|
+
<span class="constant">RETURN</span>.length == <span class="integer">1</span>,
|
654
|
+
<span class="constant">RECEIVER</span> == <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>,
|
655
|
+
coda
|
656
|
+
<span class="keyword">end</span>
|
657
|
+
</pre></div>
|
658
|
+
</div>
|
659
|
+
<figure><img alt="Unit test failed" src="spec/unit_test_failure.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 29. Unit test failed</figcaption></figure><div class="p">After the first exercise is reported as resulting in a bug, the two verifications following (using <code class="inline">RETURN</code> and <code class="inline">RECEIVER</code>) are reported as untestable. They are reported as success or bug only when there is a preceding exercise that has succeeded. There are some other possibilities for the result of a unit test. See <a href="#feature17">3.2.2.4. Test Reports</a> for detail.</div><div class="p">In order to repeat the same test schema over data, a tip is to use <code class="inline">map</code> with splat <code class="inline">*</code>.</div><div class="CodeRay">
|
660
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
661
|
+
*[
|
662
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="integer">1</span>],
|
663
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>, <span class="integer">2</span>],
|
664
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">c</span><span class="delimiter">"</span></span>, <span class="integer">3</span>],
|
665
|
+
].map{|receiver, argument| receiver.UT(argument)},
|
666
|
+
coda
|
667
|
+
</pre></div>
|
668
|
+
</div>
|
669
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h5 id="feature55">5.4.1.1. Testing with <code class="inline">succeed?</code>, <code class="inline">raise?</code>, and <code class="inline">throw?</code></h5><div class="feature-contents"><div class="user-item"><div class="p">Sometimes, it is necessary to only verify that examination was performed without raising an exception. In such cases, use the method <code class="inline">succeed?</code>. Tests using this method will report success whenever examination was performed without an exception, without particular verification on the return value.</div><div class="CodeRay">
|
670
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
671
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#concat</span><span class="delimiter">"</span></span>,
|
672
|
+
<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span>.UT(<span class="symbol">:a</span>).succeed?,
|
673
|
+
<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span>.UT(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>).succeed?,
|
674
|
+
coda
|
675
|
+
<span class="keyword">end</span>
|
676
|
+
</pre></div>
|
677
|
+
</div>
|
678
|
+
<figure><img alt="Unit test checking successful examination" src="spec/unit_test_succeed.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 30. Unit test checking successful examination</figcaption></figure><div class="p">This method is useful also when one is interested in verifying the receiver of the feature, without particular expectation on the return value.</div><div class="CodeRay">
|
679
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
680
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#concat</span><span class="delimiter">"</span></span>,
|
681
|
+
<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span>.UT(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>).succeed?,
|
682
|
+
<span class="constant">RECEIVER</span> == <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>,
|
683
|
+
coda
|
684
|
+
<span class="keyword">end</span>
|
685
|
+
</pre></div>
|
686
|
+
</div>
|
687
|
+
<figure><img alt="Unit test verifying the receiver" src="spec/unit_test_receiver.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 31. Unit test verifying the receiver</figcaption></figure><div class="p">On the contrary, to unit test with the expectation that an exception be raised, use the <code class="inline">raise?(exception = StandardError, include_subclass = true, message: nil)</code> method as verification. When <code class="inline">include_subclass</code> is truthy (as in default), an instance of <code class="inline">exception</code> should be raised for the unit test to succeed. Otherwise, a kind of <code class="inline">exception</code> class should be raised. When <code class="inline">message</code> (assumed to be an instance of a <code class="inline">String</code> or <code class="inline">RegExp</code>) is given, <code class="inline">message ===</code> will be evaluated with the message string as argument. It must return a truthy value for the unit test to succeed. An example is this:</div><div class="CodeRay">
|
688
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
689
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#concat</span><span class="delimiter">"</span></span>,
|
690
|
+
<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span>.UT(<span class="symbol">:a</span>).raise?(<span class="constant">TypeError</span>, <span class="key">message</span>: <span class="regexp"><span class="delimiter">/</span><span class="content">no implicit conversion</span><span class="delimiter">/</span><span class="modifier">i</span></span>),
|
691
|
+
<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span>.UT(<span class="symbol">:a</span>).raise?(<span class="constant">StandardError</span>, <span class="predefined-constant">false</span>),
|
692
|
+
coda
|
693
|
+
<span class="keyword">end</span>
|
694
|
+
</pre></div>
|
695
|
+
</div>
|
696
|
+
<figure><img alt="Unit test expecting an exception" src="spec/unit_test_raise.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 32. Unit test expecting an exception</figcaption></figure><div class="p">The first test succeeded with the raise exception class being <code class="inline">TypeError</code>, and its message matching the pattern. The second test failed because, although <code class="inline">StandardError</code> is an ancestor of <code class="inline">TypeError</code>, the <code class="inline">include_subclass</code> option was set to <code class="inline">false</code>.</div><div class="p">Similarly, to check that examining the feature throws an object, use the <code class="inline">throw?(tag [,obj])</code> method. Suppose the following method is defined:</div><div class="CodeRay">
|
697
|
+
<div class="code"><pre><span class="keyword">def</span> <span class="function">throw_check</span>
|
698
|
+
throw(<span class="symbol">:yes</span>, <span class="string"><span class="delimiter">"</span><span class="content">correct</span><span class="delimiter">"</span></span>)
|
699
|
+
<span class="keyword">end</span>
|
700
|
+
</pre></div>
|
701
|
+
</div>
|
702
|
+
<div class="p">Under such situation, the thrown tag and the returned object can be checked as follows:</div><div class="CodeRay">
|
703
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#throw_check</span><span class="delimiter">"</span></span>,
|
704
|
+
<span class="constant">UT</span>.throw?(<span class="symbol">:yes</span>),
|
705
|
+
<span class="constant">UT</span>.throw?(<span class="symbol">:no</span>),
|
706
|
+
<span class="constant">UT</span>.throw?(<span class="symbol">:yes</span>, <span class="key">value</span>: <span class="string"><span class="delimiter">"</span><span class="content">correct</span><span class="delimiter">"</span></span>),
|
707
|
+
<span class="constant">UT</span>.throw?(<span class="symbol">:yes</span>, <span class="key">value</span>: <span class="string"><span class="delimiter">"</span><span class="content">wrong</span><span class="delimiter">"</span></span>),
|
708
|
+
coda
|
709
|
+
</pre></div>
|
710
|
+
</div>
|
711
|
+
<figure><img alt="Unit test expecting throwing" src="spec/unit_test_throw.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 33. Unit test expecting throwing</figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature56">5.4.2. Benchmark</h4><div class="feature-contents"><div class="user-item"><div class="p">Benchmark is described similarly to unit test, but it only has the setup and exercise steps. For the exercise step, use the placeholder <a href="#feature154"><code class="inline">BasicObject#BM</code></a>. Benchmark is meaningful only when there are alternative implementations for the method in question (see <a href="#feature14">3.2.2.2. Alternative Implementations</a>). Suppose the following three alternative implementations are examined for a feature that parses an integer from a string:</div><div class="CodeRay">
|
712
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
713
|
+
<span class="keyword">def</span> <span class="function">check_int__1</span>
|
714
|
+
Integer(<span class="predefined-constant">self</span>) <span class="keyword">rescue</span> <span class="predefined-constant">false</span>
|
715
|
+
<span class="keyword">end</span>
|
716
|
+
<span class="keyword">def</span> <span class="function">check_int__2</span>
|
717
|
+
to_i.to_s == <span class="predefined-constant">self</span>
|
718
|
+
<span class="keyword">end</span>
|
719
|
+
<span class="keyword">def</span> <span class="function">check_int__3</span>
|
720
|
+
<span class="predefined-constant">self</span> =~ <span class="regexp"><span class="delimiter">/</span><span class="char">\A</span><span class="char">\d</span><span class="content">+</span><span class="char">\z</span><span class="delimiter">/</span></span>
|
721
|
+
<span class="keyword">end</span>
|
722
|
+
<span class="keyword">end</span>
|
723
|
+
</pre></div>
|
724
|
+
</div>
|
725
|
+
<div class="p">Under such situation, the following benchmark test:</div><div class="CodeRay">
|
726
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
727
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#check_int</span><span class="delimiter">"</span></span>,
|
728
|
+
<span class="string"><span class="delimiter">"</span><span class="content">220000</span><span class="delimiter">"</span></span>.BM,
|
729
|
+
<span class="string"><span class="delimiter">"</span><span class="content">22.to.2</span><span class="delimiter">"</span></span>.BM,
|
730
|
+
coda
|
731
|
+
<span class="keyword">end</span>
|
732
|
+
</pre></div>
|
733
|
+
</div>
|
734
|
+
<div class="p">can have a result like:</div><figure><img alt="Benchmark test" src="spec/benchmark_test.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 34. Benchmark test</figcaption></figure><div class="p">Based on the result, one may discuss that <code class="inline">check_int__1</code> performs the best with string expressing valid integers like <code class="inline">"220000"</code>, but its performance is not stable, as can be seen in the slowness with invalid strings like <code class="inline">"22.to.2"</code>.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature57">5.4.3. Test Header</h4><div class="feature-contents"><div class="user-item"><div class="p">Test items can be grouped into a hierarchy, numbered, and named using <span class="italic">test headers</span>. A test header is described as a string that starts with one or more question mark characters <code class="inline">?</code>. Each header is numbered at the depth represented by the number of <code class="inline">?</code> characters at the beginning. Examples are shown below:</div><div class="CodeRay">
|
735
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
736
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#capitalize!</span><span class="delimiter">"</span></span>,
|
737
|
+
<span class="string"><span class="delimiter">"</span><span class="content">? When `self` is not capitalized, it should return the capitalized string.</span><span class="delimiter">"</span></span>,
|
738
|
+
<span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>.UT == <span class="string"><span class="delimiter">"</span><span class="content">Foo</span><span class="delimiter">"</span></span>,
|
739
|
+
<span class="string"><span class="delimiter">"</span><span class="content">? When there is nothing to capitalize, it should return `nil`.</span><span class="delimiter">"</span></span>,
|
740
|
+
<span class="string"><span class="delimiter">"</span><span class="content">?? When `self` is already capitalized</span><span class="delimiter">"</span></span>,
|
741
|
+
<span class="string"><span class="delimiter">"</span><span class="content">Foo</span><span class="delimiter">"</span></span>.UT == <span class="predefined-constant">nil</span>,
|
742
|
+
<span class="string"><span class="delimiter">"</span><span class="content">?? When `self` does not start with a letter</span><span class="delimiter">"</span></span>,
|
743
|
+
<span class="string"><span class="delimiter">"</span><span class="content">@foo</span><span class="delimiter">"</span></span>.UT == <span class="predefined-constant">nil</span>,
|
744
|
+
coda
|
745
|
+
<span class="keyword">end</span>
|
746
|
+
</pre></div>
|
747
|
+
</div>
|
748
|
+
<div class="p">The result may be displayed as follows:</div><figure><img alt="Test header" src="spec/test_header.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 35. Test header</figcaption></figure><div class="p">In future versions of Manager, test header is planned to play a role in doing test setups in hierarchy (cf. nested setup syntax in conventional test frameworks), but its specification is not decided yet. Feedback is welcome.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature58">5.4.4. The <code class="inline">expr</code> Method</h4><div class="feature-contents"><div class="user-item"><div class="p">Besides being directly described as objects, the receiver and arguments of tests can be described using the method <a href="#feature115"><code class="inline">Object#expr</code></a>, which takes a string argument. The string is evaluated at the timing of the relevant test step. The <code class="inline">expr</code> method has three purposes:</div><ol><li>Reset the object in case performing the tests modifies the objects involved</li><li>Control the inspection form that is displayed in the test reports</li><li>Refer to objects in the context of the test (such as is defined in a setup, see <a href="#feature59">5.4.5. Setup and Teardown</a>)</li></ol><div class="p">As an example of the first purpose, suppose some alternative implementations of a destructive method are defined:</div><div class="CodeRay">
|
749
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
750
|
+
<span class="keyword">def</span> <span class="function">push_a</span>
|
751
|
+
push(<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>)
|
752
|
+
<span class="keyword">end</span>
|
753
|
+
<span class="keyword">def</span> <span class="function">push_a__length</span>
|
754
|
+
<span class="predefined-constant">self</span>[length] = <span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>
|
755
|
+
<span class="predefined-constant">self</span>
|
756
|
+
<span class="keyword">end</span>
|
757
|
+
<span class="keyword">end</span>
|
758
|
+
</pre></div>
|
759
|
+
</div>
|
760
|
+
<div class="p">and they are to be tested. A test simply written with an array literal like this:</div><div class="CodeRay">
|
761
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
762
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#push_a</span><span class="delimiter">"</span></span>,
|
763
|
+
[].UT == [<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>],
|
764
|
+
coda
|
765
|
+
<span class="keyword">end</span>
|
766
|
+
</pre></div>
|
767
|
+
</div>
|
768
|
+
<div class="p">succeeds for the main implementation <code class="inline">push_a</code>, but will fail for the alternative implementation <code class="inline">push_a__length</code> because the same array object described by a literal expression in the spec file is modified during the exercise of <code class="inline">push_a</code>, then is further used in exercising <code class="inline">push_a__length</code>:</div><figure><img alt="Problem with testing destructive method" src="spec/without_expr.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 36. Problem with testing destructive method</figcaption></figure><div class="p">Such problem is avoided by using the <code class="inline">expr</code> method with the relevant expression. Doing as follows:</div><div class="CodeRay">
|
769
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
770
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#push_a</span><span class="delimiter">"</span></span>,
|
771
|
+
expr(<span class="string"><span class="delimiter">"</span><span class="content">[]</span><span class="delimiter">"</span></span>).UT == [<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>],
|
772
|
+
coda
|
773
|
+
<span class="keyword">end</span>
|
774
|
+
</pre></div>
|
775
|
+
</div>
|
776
|
+
<div class="p">makes the test succeed:</div><figure><img alt="Using `expr` with destructive method" src="spec/with_expr.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 37. Using <code class="inline">expr</code> with destructive method</figcaption></figure><div class="p">The <code class="inline">expr</code> method can be used:</div><ul><li>At the receiver and the argument positions of <code class="inline">UT</code>, <code class="inline">BM</code>,</li></ul><div class="CodeRay">
|
777
|
+
<div class="code"><pre>expr(<span class="string"><span class="delimiter">"</span><span class="content">[]</span><span class="delimiter">"</span></span>).UT(expr(<span class="string"><span class="delimiter">"</span><span class="content">{a: 1}</span><span class="delimiter">"</span></span>)).foo?,
|
778
|
+
expr(<span class="string"><span class="delimiter">"</span><span class="content">Array.new(3)</span><span class="delimiter">"</span></span>).BM(expr(<span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>)),
|
779
|
+
</pre></div>
|
780
|
+
</div>
|
781
|
+
<ul><li>At the argument positions of a method within a method chain of verification,</li></ul><div class="CodeRay">
|
782
|
+
<div class="code"><pre>[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>].UT(<span class="symbol">:foo</span>).foo?(expr(<span class="string"><span class="delimiter">"</span><span class="content">[</span><span class="char">\"</span><span class="content">a</span><span class="char">\"</span><span class="content">]</span><span class="delimiter">"</span></span>)).bar == expr(<span class="string"><span class="delimiter">"</span><span class="content">bar</span><span class="delimiter">"</span></span>),
|
783
|
+
</pre></div>
|
784
|
+
</div>
|
785
|
+
<ul><li>At the argument positions of a method within a method chain following <code class="inline">expr</code>,</li></ul><div class="CodeRay">
|
786
|
+
<div class="code"><pre>expr(<span class="string"><span class="delimiter">"</span><span class="content">[]</span><span class="delimiter">"</span></span>).expr(<span class="string"><span class="delimiter">"</span><span class="content">aa(1)</span><span class="delimiter">"</span></span>).UT(expr(<span class="string"><span class="delimiter">"</span><span class="content">{b: :x}</span><span class="delimiter">"</span></span>).baz.expr(<span class="string"><span class="delimiter">"</span><span class="content">[</span><span class="char">\"</span><span class="content">a</span><span class="char">\"</span><span class="content">]</span><span class="delimiter">"</span></span>)).foo?,
|
787
|
+
<span class="constant">RECEIVER</span>.foo?(expr(<span class="string"><span class="delimiter">"</span><span class="content">[</span><span class="char">\"</span><span class="content">a</span><span class="char">\"</span><span class="content">]</span><span class="delimiter">"</span></span>).bar.expr(<span class="string"><span class="delimiter">"</span><span class="content">baz</span><span class="delimiter">"</span></span>)),
|
788
|
+
</pre></div>
|
789
|
+
</div>
|
790
|
+
<ul><li>At the argument positions of <code class="inline">expr</code>,</li></ul><div class="CodeRay">
|
791
|
+
<div class="code"><pre><span class="constant">RETURN</span>.bar?(expr(expr(<span class="string"><span class="delimiter">"</span><span class="content">baz(foo)</span><span class="delimiter">"</span></span>), <span class="integer">2</span>)),
|
792
|
+
</pre></div>
|
793
|
+
</div>
|
794
|
+
<ul><li>At the block positions of any of the above. (It should be in the form <code class="inline">&expr("{...}")</code>.)</li></ul><div class="CodeRay">
|
795
|
+
<div class="code"><pre>[].UT(<span class="key">a</span>: <span class="integer">1</span>, &expr(<span class="string"><span class="delimiter">"</span><span class="content">{|s| s.upcase}</span><span class="delimiter">"</span></span>)),
|
796
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>].UT(<span class="symbol">:foo</span>).foo?([<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>], &expr(<span class="string"><span class="delimiter">"</span><span class="content">{|x, y| x + y}</span><span class="delimiter">"</span></span>)).bar,
|
797
|
+
<span class="constant">RECEIVER</span>.foo?(expr(<span class="string"><span class="delimiter">"</span><span class="content">[</span><span class="char">\"</span><span class="content">a</span><span class="char">\"</span><span class="content">]</span><span class="delimiter">"</span></span>).bar(<span class="integer">5</span>, &expr(<span class="string"><span class="delimiter">"</span><span class="content">{|e| e.baz}</span><span class="delimiter">"</span></span>))),
|
798
|
+
<span class="constant">RETURN</span>.bar?(expr(<span class="string"><span class="delimiter">"</span><span class="content">baz(foo)</span><span class="delimiter">"</span></span>, &expr(<span class="string"><span class="delimiter">"</span><span class="content">{|e| e + 2}</span><span class="delimiter">"</span></span>))),
|
799
|
+
</pre></div>
|
800
|
+
</div>
|
801
|
+
<div class="p">If <code class="inline">expr</code> appears in other positions, i.e. in an embedded position of these positions, it may not work correctly. The following are illicit uses of <code class="inline">expr</code>.</div><div class="CodeRay">
|
802
|
+
<div class="code"><pre>[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, expr(<span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>)].UT(bar({<span class="key">a</span>: <span class="integer">1</span>})).foo?,
|
803
|
+
[<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>].UT(bar(expr(<span class="string"><span class="delimiter">"</span><span class="content">{a: 1}</span><span class="delimiter">"</span></span>))).foo?,
|
804
|
+
</pre></div>
|
805
|
+
</div>
|
806
|
+
<div class="p">As an example of the second purpose, suppose the receiver for test examination is a huge array. The result of a test like:</div><div class="CodeRay">
|
807
|
+
<div class="code"><pre><span class="constant">Array</span>.new(<span class="integer">1000</span>){<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>}.UT(<span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>) == <span class="constant">Array</span>.new(<span class="integer">1000</span>){<span class="string"><span class="delimiter">"</span><span class="content">a</span><span class="delimiter">"</span></span>} + <span class="constant">Array</span>.new(<span class="integer">1000</span>){<span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>},
|
808
|
+
</pre></div>
|
809
|
+
</div>
|
810
|
+
<div class="p">would have huge arrays displayed in their inspection form like this:</div><figure><img alt="Long inspected expression" src="spec/long.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 38. Long inspected expression</figcaption></figure><div class="p">When you do not want an object to be displayed in its expanded and inspected form because it is too long as in this case, or when it would not be readable, you can use the <code class="inline">expr</code> method. Wrapping the long arrays in the example above with <code class="inline">expr</code> as in:</div><div class="CodeRay">
|
811
|
+
<div class="code"><pre>expr(<span class="string"><span class="delimiter">"</span><span class="content">Array.new(1000){</span><span class="char">\"</span><span class="content">a</span><span class="char">\"</span><span class="content">}</span><span class="delimiter">"</span></span>).UT(<span class="string"><span class="delimiter">"</span><span class="content">b</span><span class="delimiter">"</span></span>) ==
|
812
|
+
expr(<span class="string"><span class="delimiter">"</span><span class="content">Array.new(1000){</span><span class="char">\"</span><span class="content">a</span><span class="char">\"</span><span class="content">} + Array.new(1000){</span><span class="char">\"</span><span class="content">b</span><span class="char">\"</span><span class="content">}</span><span class="delimiter">"</span></span>),
|
813
|
+
</pre></div>
|
814
|
+
</div>
|
815
|
+
<div class="p">would make the displayed result shorter and understandable. The parts of the expression using <code class="inline">expr</code> are displayed in the form of the string passed:</div><figure><img alt="Display made short with `expr`" src="spec/short.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 39. Display made short with <code class="inline">expr</code></figcaption></figure></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h4 id="feature59">5.4.5. Setup and Teardown</h4><div class="feature-contents"><div class="user-item"><div class="p">The third purpose of using <code class="inline">expr</code> in tests is to refer to variables and methods that have been set up in advance. A setup can be described as a string followed by the <a href="#feature226"><code class="inline">String#setup</code></a> method. The recommended way is to write this as a here document, as with code blocks (<a href="#feature50">5.3.8. Code Block</a>). Setups are accumulated over the spec file, and is evaluated for each exercise step in a test. The <a href="#feature164"><code class="inline">Module#teardown</code></a> item will reset all preceding setups. Following is an example of using these methods.</div><div class="CodeRay">
|
816
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">Array</span>
|
817
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#flatten!</span><span class="delimiter">"</span></span>,
|
818
|
+
<span class="string"><span class="delimiter"><<~'RUBY'</span></span>.setup,<span class="string"><span class="content">
|
819
|
+
a1 = [1, 2, 3]
|
820
|
+
a2 = [4, [5, 6]]
|
821
|
+
a3 = [a1, [], a2]</span><span class="delimiter">
|
822
|
+
RUBY</span></span>
|
823
|
+
expr(<span class="string"><span class="delimiter">'</span><span class="content">[a1, a2]</span><span class="delimiter">'</span></span>).UT == [<span class="integer">1</span>, <span class="integer">2</span>, <span class="integer">3</span>, <span class="integer">4</span>, <span class="integer">5</span>, <span class="integer">6</span>],
|
824
|
+
<span class="constant">RECEIVER</span> == [<span class="integer">1</span>, <span class="integer">2</span>, <span class="integer">3</span>, <span class="integer">4</span>, <span class="integer">5</span>, <span class="integer">6</span>],
|
825
|
+
expr(<span class="string"><span class="delimiter">'</span><span class="content">a3</span><span class="delimiter">'</span></span>).UT == [<span class="integer">1</span>, <span class="integer">2</span>, <span class="integer">3</span>, <span class="integer">4</span>, <span class="integer">5</span>, <span class="integer">6</span>],
|
826
|
+
expr(<span class="string"><span class="delimiter">'</span><span class="content">a3</span><span class="delimiter">'</span></span>).UT(<span class="integer">0</span>).nil?,
|
827
|
+
<span class="constant">RECEIVER</span> == expr(<span class="string"><span class="delimiter">'</span><span class="content">[a1, [], a2]</span><span class="delimiter">'</span></span>),
|
828
|
+
teardown,
|
829
|
+
<span class="string"><span class="delimiter"><<~'RUBY'</span></span>.setup,<span class="string"><span class="content">
|
830
|
+
a1 = []</span><span class="delimiter">
|
831
|
+
RUBY</span></span>
|
832
|
+
expr(<span class="string"><span class="delimiter">'</span><span class="content">a1</span><span class="delimiter">'</span></span>).UT.nil?,
|
833
|
+
coda
|
834
|
+
<span class="keyword">end</span>
|
835
|
+
</pre></div>
|
836
|
+
</div>
|
837
|
+
<div class="p">This will result in the following:</div><figure><img alt="Setup and teardown" src="spec/setup_teardown.png" style="width:100%;border:1px solid hsl(0, 0%, 80%);" /><figcaption>Figure 40. Setup and teardown</figcaption></figure><div class="p">Any changes made by <code class="inline">setup</code> to global variables are not reset by <code class="inline">teardown</code>, and needs to be undone manually. Not doing so properly can result in Manager not running correctly.</div><div class="p">In future versions of Manager, test setups are planned to be more structured, i.e. in hierarchy as in nested setup syntax in conventional test frameworks, but its specification is not decided yet. Feedback is welcome.</div></div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature60"><span class="anchor" id="public1"><span class="tag public">public</span></span> class <span class="feature-name">Manager</span></h1><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature68"><span class="anchor" id="public2"><span class="tag public">public</span></span> <span class="anchor" id="singleton1"><span class="tag singleton">1</span></span> Manager.<span class="feature-name">config</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(symbol)</code> → Object<div class="p">Gets the Manager configuration. <code class="inline">symbol</code> can take the following values. See <a href="#feature20">(main) 4.1. Customization and Options</a> for detail.</div><ul><li><code class="inline">:bdir</code></li><li><code class="inline">:odir</code></li><li><code class="inline">:user</code></li><li><code class="inline">:dev</code></li><li><code class="inline">:theme</code></li><li><code class="inline">:highlight</code></li><li><code class="inline">:debug</code></li><li><code class="inline">:spell_check</code></li><li><code class="inline">:case_sensitive</code></li><li><code class="inline">:case_insensitive</code></li><li><code class="inline">:title</code></li></ul><div class="CodeRay">
|
838
|
+
<div class="code"><pre><span class="constant">Manager</span>.config(<span class="symbol">:odir</span>)
|
839
|
+
</pre></div>
|
840
|
+
</div>
|
841
|
+
</div><div class="user-item"><span class="head">Usage</span> <code class="inline">(hash)</code> → <code class="inline">nil</code><div class="p">Sets the Manager configuration. <code class="inline">hash</code> should be a symbol key with the value to be set.</div><div class="CodeRay">
|
842
|
+
<div class="code"><pre><span class="constant">Manager</span>.config(<span class="key">odir</span>: <span class="string"><span class="delimiter">"</span><span class="content">../</span><span class="delimiter">"</span></span>, <span class="key">title</span>: <span class="string"><span class="delimiter">"</span><span class="content">My Special Program</span><span class="delimiter">"</span></span>, <span class="key">spell_check</span>: <span class="string"><span class="delimiter">"</span><span class="content">en</span><span class="delimiter">"</span></span>)
|
843
|
+
</pre></div>
|
844
|
+
</div>
|
845
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature80"><span class="anchor" id="public3"><span class="tag public">public</span></span> <span class="anchor" id="singleton2"><span class="tag singleton">2</span></span> Manager.<span class="feature-name">new</span></h2><div class="feature-contents"><div class="user-item"><div class="p">The main method to be called when running Manager. See <a href="#feature19">(main) 4. Running Manager</a>.</div><span class="head">Usage</span> <code class="inline">(file, **command_options)</code> → <code class="inline">nil</code><div class="p">The <code class="inline">file</code> argument is a string expressing the path to the spec file. <code class="inline">command_options</code> are options as explained in <a href="#feature20">(main) 4.1. Customization and Options</a>.</div><div class="CodeRay">
|
846
|
+
<div class="code"><pre><span class="constant">Manager</span>.new(<span class="string"><span class="delimiter">"</span><span class="content">../spec_file.rb</span><span class="delimiter">"</span></span>, <span class="key">bdir</span>: <span class="string"><span class="delimiter">"</span><span class="content">../</span><span class="delimiter">"</span></span>)
|
847
|
+
</pre></div>
|
848
|
+
</div>
|
849
|
+
</div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature114"><span class="anchor" id="public4"><span class="tag public">public</span></span> class <span class="feature-name">Object</span></h1><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature115"><span class="anchor" id="private1"><span class="tag private">private</span></span> <span class="anchor" id="instance1"><span class="tag instance">1</span></span> Object#<span class="feature-name">expr</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(string)</code> → Manager::Expr<div class="p">Wraps a expression (string). Its content is evaluated during tests. Its inspected form is the original string expression, not the inspection form of the object it represents.</div><div class="CodeRay">
|
850
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
851
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#upcase</span><span class="delimiter">"</span></span>,
|
852
|
+
<span class="string"><span class="delimiter">"</span><span class="content">long_foo = </span><span class="char">\"</span><span class="content">foo</span><span class="char">\"</span><span class="content"> * 100</span><span class="delimiter">"</span></span>.setup,
|
853
|
+
expr(<span class="string"><span class="delimiter">"</span><span class="content">long_foo</span><span class="delimiter">"</span></span>).UT.length == <span class="integer">300</span>,
|
854
|
+
coda
|
855
|
+
<span class="keyword">end</span>
|
856
|
+
</pre></div>
|
857
|
+
</div>
|
858
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature116"><span class="anchor" id="public5"><span class="tag public">public</span></span> <span class="anchor" id="instance2"><span class="tag instance">2</span></span> Object#<span class="feature-name">in?</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(array)</code> → <code class="inline">true</code> | <code class="inline">false</code><div class="p">A helper method for writing tests. It switches the receiver and the argument of <code class="inline">Array#include?</code>.</div><div class="CodeRay">
|
859
|
+
<div class="code"><pre><span class="integer">1</span>.in?([<span class="integer">1</span>, <span class="integer">2</span>]) <span class="comment">#=> true</span>
|
860
|
+
<span class="integer">3</span>.in?([<span class="integer">1</span>, <span class="integer">2</span>]) <span class="comment">#=> false</span>
|
861
|
+
</pre></div>
|
862
|
+
</div>
|
863
|
+
</div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature149"><span class="anchor" id="public6"><span class="tag public">public</span></span> class <span class="feature-name"><< main</span></h1><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature150"><span class="anchor" id="public7"><span class="tag public">public</span></span> <span class="anchor" id="instance3"><span class="tag instance">3</span></span> << main#<span class="feature-name">gemspec</span></h2><div class="feature-contents"><div class="user-item"><div class="p">When the program under analysis is a Ruby gem, and this method is called, the gem spec information is displayed in the left panel of developer's chart.</div><span class="head">Usage</span> <code class="inline">(file)</code> → Gem::Specification<div class="p"><code class="inline">file</code> should be the path to the <code class="inline">.gemspec</code> file either absolute or relative to the spec file.</div><div class="CodeRay">
|
864
|
+
<div class="code"><pre>gemspec <span class="string"><span class="delimiter">"</span><span class="content">../manager.gemspec</span><span class="delimiter">"</span></span>
|
865
|
+
</pre></div>
|
866
|
+
</div>
|
867
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature151"><span class="anchor" id="public8"><span class="tag public">public</span></span> <span class="anchor" id="instance4"><span class="tag instance">4</span></span> << main#<span class="feature-name">manage</span></h2><div class="feature-contents"><div class="user-item"><div class="p">Registers the files to be analyzed. Files that are loaded or required other than by method would not be the object of analysis.</div><span class="head">Usage</span> <code class="inline">(file)</code> → <code class="inline">nil</code><div class="p"><code class="inline">file</code> should be the path to the <code class="inline">.gemspec</code> file either absolute or relative to the spec file.</div><div class="CodeRay">
|
868
|
+
<div class="code"><pre>manage <span class="string"><span class="delimiter">"</span><span class="content">../lib/helpers/foo.rb</span><span class="delimiter">"</span></span>
|
869
|
+
manage <span class="string"><span class="delimiter">"</span><span class="content">../lib/helpers/bar.rb</span><span class="delimiter">"</span></span>
|
870
|
+
</pre></div>
|
871
|
+
</div>
|
872
|
+
</div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature152"><span class="anchor" id="public9"><span class="tag public">public</span></span> class <span class="feature-name">BasicObject</span></h1><div class="feature-contents"><div class="user-item"><div class="p">Besides, <code class="inline">UT</code> and <code class="inline">BM</code> explained below, <code class="inline">RETURN</code> and <code class="inline">RECEIVER</code> can be used in tests.</div></div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature153"><span class="anchor" id="public10"><span class="tag public">public</span></span> <span class="anchor" id="instance5"><span class="tag instance">5</span></span> BasicObject#<span class="feature-name">UT</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(*args, **kargs, &pr)</code> → <code class="inline">Manager::UnitTest</code><div class="p">A placeholder for the feature (method or constant) examined in unit tests.</div><div class="CodeRay">
|
873
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
874
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#capitalize</span><span class="delimiter">"</span></span>,
|
875
|
+
<span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>.UT == <span class="string"><span class="delimiter">"</span><span class="content">Foo</span><span class="delimiter">"</span></span>,
|
876
|
+
coda
|
877
|
+
<span class="keyword">end</span>
|
878
|
+
</pre></div>
|
879
|
+
</div>
|
880
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature154"><span class="anchor" id="public11"><span class="tag public">public</span></span> <span class="anchor" id="instance6"><span class="tag instance">6</span></span> BasicObject#<span class="feature-name">BM</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(*args, **kargs, &pr)</code> → Manager::Benchmark<div class="p">A placeholder for the feature (method or constant) examined in benchmark tests.</div><div class="CodeRay">
|
881
|
+
<div class="code"><pre><span class="keyword">class</span> <span class="class">String</span>
|
882
|
+
spec <span class="string"><span class="delimiter">"</span><span class="content">#capitalize</span><span class="delimiter">"</span></span>,
|
883
|
+
<span class="string"><span class="delimiter">"</span><span class="content">foo</span><span class="delimiter">"</span></span>.BM,
|
884
|
+
coda
|
885
|
+
<span class="keyword">end</span>
|
886
|
+
</pre></div>
|
887
|
+
</div>
|
888
|
+
</div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature155"><span class="anchor" id="public12"><span class="tag public">public</span></span> class <span class="feature-name">Module</span></h1><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature156"><span class="anchor" id="public13"><span class="tag public">public</span></span> <span class="anchor" id="instance7"><span class="tag instance">7</span></span> Module#<span class="feature-name">hide</span></h2><div class="feature-contents"><div class="user-item"><div class="p">When a <code class="inline">spec</code> method is prefixed with this method, the specification will be hided in the user' manual.</div><span class="head">Usage</span> <code class="inline">()</code> → <div class="CodeRay">
|
889
|
+
<div class="code"><pre>hide spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
890
|
+
...
|
891
|
+
coda
|
892
|
+
</pre></div>
|
893
|
+
</div>
|
894
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature157"><span class="anchor" id="public14"><span class="tag public">public</span></span> <span class="anchor" id="instance8"><span class="tag instance">8</span></span> Module#<span class="feature-name">move</span></h2><div class="feature-contents"><div class="user-item"><div class="p">When a <code class="inline">spec</code> method is prefixed with this method, the specification will be immune to the misplaced warning.</div><span class="head">Usage</span> <code class="inline">()</code> → <div class="CodeRay">
|
895
|
+
<div class="code"><pre>move spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
896
|
+
...
|
897
|
+
coda
|
898
|
+
</pre></div>
|
899
|
+
</div>
|
900
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature158"><span class="anchor" id="public15"><span class="tag public">public</span></span> <span class="anchor" id="instance9"><span class="tag instance">9</span></span> Module#<span class="feature-name">spec</span></h2><div class="feature-contents"><div class="user-item"><div class="p">The main method to describe a specification.</div><span class="head">Usage</span> <code class="inline">(feature, *[items])</code> → <code class="inline">nil</code><div class="CodeRay">
|
901
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
902
|
+
...
|
903
|
+
coda
|
904
|
+
</pre></div>
|
905
|
+
</div>
|
906
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature159"><span class="anchor" id="public16"><span class="tag public">public</span></span> <span class="anchor" id="instance10"><span class="tag instance">10</span></span> Module#<span class="feature-name">coda</span></h2><div class="feature-contents"><div class="user-item"><div class="p">A pseudo-keyword to close the block opened by the <code class="inline">spec</code> method.</div><span class="head">Usage</span> <code class="inline">()</code> → Manager::Coda<div class="CodeRay">
|
907
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
908
|
+
...
|
909
|
+
coda
|
910
|
+
</pre></div>
|
911
|
+
</div>
|
912
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature160"><span class="anchor" id="public17"><span class="tag public">public</span></span> <span class="anchor" id="instance11"><span class="tag instance">11</span></span> Module#<span class="feature-name">value</span></h2><div class="feature-contents"><div class="user-item"><div class="p">Wraps an individual object in a method signature.</div><span class="head">Usage</span> <code class="inline">(object)</code> → Module<div class="CodeRay">
|
913
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
914
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(string, array)</span><span class="delimiter">"</span></span> => <span class="constant">String</span> | value(<span class="predefined-constant">nil</span>)},
|
915
|
+
...
|
916
|
+
coda
|
917
|
+
</pre></div>
|
918
|
+
</div>
|
919
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature161"><span class="anchor" id="public18"><span class="tag public">public</span></span> <span class="anchor" id="instance12"><span class="tag instance">12</span></span> Module#<span class="feature-name">error</span></h2><div class="feature-contents"><div class="user-item"><div class="p">Wraps an exception class in a method signature.</div><span class="head">Usage</span> <code class="inline">(exception, **message: nil)</code> → Module<div class="CodeRay">
|
920
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
921
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(string, array)</span><span class="delimiter">"</span></span> => <span class="constant">String</span> | error(<span class="constant">ArgumentError</span>)},
|
922
|
+
...
|
923
|
+
coda
|
924
|
+
</pre></div>
|
925
|
+
</div>
|
926
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature162"><span class="anchor" id="public19"><span class="tag public">public</span></span> <span class="anchor" id="instance13"><span class="tag instance">13</span></span> Module#<span class="feature-name">image</span></h2><div class="feature-contents"><div class="user-item"><div class="p">Describe an image for the user's manual.</div><span class="head">Usage</span> <code class="inline">(title, path)</code> → Manager::Render::Image<div class="CodeRay">
|
927
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
928
|
+
image(<span class="string"><span class="delimiter">"</span><span class="content">Initial diagram</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">asset/initial_diagram.png</span><span class="delimiter">"</span></span>),
|
929
|
+
...
|
930
|
+
coda
|
931
|
+
</pre></div>
|
932
|
+
</div>
|
933
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature163"><span class="anchor" id="public20"><span class="tag public">public</span></span> <span class="anchor" id="instance14"><span class="tag instance">14</span></span> Module#<span class="feature-name">image!</span></h2><div class="feature-contents"><div class="user-item"><div class="p">Describe an image for the developer's chart.</div><span class="head">Usage</span> <code class="inline">(title, path)</code> → Manager::Render::Image<div class="CodeRay">
|
934
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
935
|
+
image!(<span class="string"><span class="delimiter">"</span><span class="content">Initial diagram</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">asset/initial_diagram.png</span><span class="delimiter">"</span></span>),
|
936
|
+
...
|
937
|
+
coda
|
938
|
+
</pre></div>
|
939
|
+
</div>
|
940
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature164"><span class="anchor" id="public21"><span class="tag public">public</span></span> <span class="anchor" id="instance15"><span class="tag instance">15</span></span> Module#<span class="feature-name">teardown</span></h2><div class="feature-contents"><div class="user-item"><div class="p">Resets the effect of all previous setups.</div><span class="head">Usage</span> <code class="inline">()</code> → <div class="CodeRay">
|
941
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
942
|
+
<span class="string"><span class="delimiter">"</span><span class="content">a = 3</span><span class="delimiter">"</span></span>.setup,
|
943
|
+
...
|
944
|
+
teardown,
|
945
|
+
coda
|
946
|
+
</pre></div>
|
947
|
+
</div>
|
948
|
+
</div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature165"><span class="anchor" id="public22"><span class="tag public">public</span></span> class <span class="feature-name">Class</span></h1><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature166"><span class="anchor" id="public23"><span class="tag public">public</span></span> <span class="anchor" id="instance16"><span class="tag instance">16</span></span> Class#<span class="feature-name">|</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(other)</code> → Manager::MethodSignatureAlternatives<div class="p">Expresses alternatives in the output of method signatures.</div><div class="CodeRay">
|
949
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
950
|
+
{<span class="string"><span class="delimiter">"</span><span class="content">(string, array)</span><span class="delimiter">"</span></span> => <span class="constant">String</span> | error(<span class="constant">ArgumentError</span>) | value(<span class="predefined-constant">nil</span>)},
|
951
|
+
...
|
952
|
+
coda
|
953
|
+
</pre></div>
|
954
|
+
</div>
|
955
|
+
</div></div></div></div><div class="module"><div class="feature" onclick="toggleModuleContents(this)"><h1 class="module-header" id="feature225"><span class="anchor" id="public24"><span class="tag public">public</span></span> class <span class="feature-name">String</span></h1><div class="feature-contents"></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature226"><span class="anchor" id="public25"><span class="tag public">public</span></span> <span class="anchor" id="instance17"><span class="tag instance">17</span></span> String#<span class="feature-name">setup</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">()</code> → Manager::Setup<div class="p">Describes a setup to be used in tests.</div><div class="CodeRay">
|
956
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
957
|
+
<span class="string"><span class="delimiter"><<~'RUBY'</span></span>.setup,<span class="string"><span class="content">
|
958
|
+
a = []
|
959
|
+
b = a * 10
|
960
|
+
c = [a, b]</span><span class="delimiter">
|
961
|
+
RUBY</span></span>
|
962
|
+
coda
|
963
|
+
</pre></div>
|
964
|
+
</div>
|
965
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature227"><span class="anchor" id="public26"><span class="tag public">public</span></span> <span class="anchor" id="instance18"><span class="tag instance">18</span></span> String#<span class="feature-name">code</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(*language)</code> → Manager::Render::Code<div class="p">Describes a code block for the user's manual. The optional <code class="inline">language</code> argument determines the language to be used in highlighting. By default, it is <code class="inline">:ruby</code>.</div><div class="CodeRay">
|
966
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
967
|
+
<span class="string"><span class="delimiter"><<~'RUBY'</span></span>.code,<span class="string"><span class="content">
|
968
|
+
def foo
|
969
|
+
puts "This is Ruby code."
|
970
|
+
end</span><span class="delimiter">
|
971
|
+
RUBY</span></span>
|
972
|
+
<span class="string"><span class="delimiter"><<~'CSS'</span></span>.code(<span class="symbol">:css</span>),<span class="string"><span class="content">
|
973
|
+
#main{
|
974
|
+
background-color: green;
|
975
|
+
}</span><span class="delimiter">
|
976
|
+
CSS</span></span>
|
977
|
+
coda
|
978
|
+
</pre></div>
|
979
|
+
</div>
|
980
|
+
</div></div></div><div class="feature" onclick="toggleFeatureContents(this)"><h2 id="feature228"><span class="anchor" id="public27"><span class="tag public">public</span></span> <span class="anchor" id="instance19"><span class="tag instance">19</span></span> String#<span class="feature-name">code!</span></h2><div class="feature-contents"><div class="user-item"><span class="head">Usage</span> <code class="inline">(*language)</code> → Manager::Render::Code<div class="p">Describes a code block for the developer's chart. The optional <code class="inline">language</code> argument determines the language to be used in highlighting. By default, it is <code class="inline">:ruby</code>.</div><div class="CodeRay">
|
981
|
+
<div class="code"><pre>spec <span class="string"><span class="delimiter">"</span><span class="content">#foo</span><span class="delimiter">"</span></span>,
|
982
|
+
<span class="string"><span class="delimiter"><<~'RUBY'</span></span>.code!,<span class="string"><span class="content">
|
983
|
+
def foo
|
984
|
+
puts "This is Ruby code."
|
985
|
+
end</span><span class="delimiter">
|
986
|
+
RUBY</span></span>
|
987
|
+
<span class="string"><span class="delimiter"><<~'CSS'</span></span>.code!(<span class="symbol">:css</span>),<span class="string"><span class="content">
|
988
|
+
#main{
|
989
|
+
background-color: green;
|
990
|
+
}</span><span class="delimiter">
|
991
|
+
CSS</span></span>
|
992
|
+
coda
|
993
|
+
</pre></div>
|
994
|
+
</div>
|
995
|
+
</div></div></div></div></div></div><script>//-*-mode: javascript-*-
|
996
|
+
|
997
|
+
// Copyright (c) 2014-2016 sawa
|
998
|
+
|
999
|
+
var main;
|
1000
|
+
var scrollMargin;
|
1001
|
+
|
1002
|
+
// Scroll to the anchor.
|
1003
|
+
window.onhashchange = function(e) {
|
1004
|
+
// location.href = location.hash;
|
1005
|
+
// main.scrollTop -= main.offsetHeight * 0.5 + scrollMargin;
|
1006
|
+
main.scrollTop -= scrollMargin;
|
1007
|
+
};
|
1008
|
+
|
1009
|
+
document.body.onload = function() {
|
1010
|
+
main = document.getElementById('main');
|
1011
|
+
//This line is needed to invoke `window.onhashchange` even when `location.hash`
|
1012
|
+
// is the same as the previous load.
|
1013
|
+
location.hash = '';
|
1014
|
+
//TODO. Import data from webstore.
|
1015
|
+
//location.hash =
|
1016
|
+
var joinQuery = function(obj, prefix, affix){
|
1017
|
+
return prefix + obj.dataset.tags.split(' ').join(affix + ', ' + prefix) + affix;
|
1018
|
+
}
|
1019
|
+
var tagsumPrefix = '#tagsum-', tagsumAffix = ':not([style="opacity: 0.2;"])';
|
1020
|
+
var i, obj, query;
|
1021
|
+
query = '.feature:not([style="display: none;"]) .tag.';
|
1022
|
+
for(i = 1; obj = document.getElementById('user-feature-navigation' + i); i++) {
|
1023
|
+
obj.query = joinQuery(obj, query, '');
|
1024
|
+
obj.tagsums = joinQuery(obj, tagsumPrefix, tagsumAffix);
|
1025
|
+
initializeNavigation(obj);
|
1026
|
+
}
|
1027
|
+
for(i = 1; obj = document.getElementById('dev-feature-navigation' + i); i++) {
|
1028
|
+
obj.query = joinQuery(obj, query, '');
|
1029
|
+
obj.tagsums = joinQuery(obj, tagsumPrefix, tagsumAffix);
|
1030
|
+
initializeNavigation(obj);
|
1031
|
+
}
|
1032
|
+
query = '\
|
1033
|
+
.feature:not([style="display: none;"]):not([folded="true"]) \
|
1034
|
+
.feature-contents > :not([style="display: none;"]) \
|
1035
|
+
.anchor:not([style="display: none;"]) \
|
1036
|
+
.tag.';
|
1037
|
+
for(i = 1; obj = document.getElementById('anchor-navigation' + i); i++) {
|
1038
|
+
obj.query = joinQuery(obj, query, '');
|
1039
|
+
obj.tagsums = joinQuery(obj, tagsumPrefix, tagsumAffix);
|
1040
|
+
initializeNavigation(obj);
|
1041
|
+
}
|
1042
|
+
var objs = document.getElementsByClassName('feature');
|
1043
|
+
for(var i = 0; i < objs.length; i++) {
|
1044
|
+
// TODO. copy from webstore if any.
|
1045
|
+
objs[i].hiddenFor = {};
|
1046
|
+
// hide(objs[i], Object.keys(objs[i].hiddenFor).length);
|
1047
|
+
}
|
1048
|
+
switch(document.body.id){
|
1049
|
+
case 'user':
|
1050
|
+
scrollMargin = 200;
|
1051
|
+
// Click "Features" button.
|
1052
|
+
document.getElementById('top').children[0].children[1].onclick();
|
1053
|
+
break;
|
1054
|
+
case 'dev':
|
1055
|
+
// Approximates half of line height from experience. TODO: Do it logically.
|
1056
|
+
scrollMargin = 200;
|
1057
|
+
// Click "Full" button. (Neccessary to do this also for adding `folded` attribute)
|
1058
|
+
document.getElementById('top').children[0].children[2].onclick();
|
1059
|
+
break;
|
1060
|
+
}
|
1061
|
+
// Prevents feature toggling.
|
1062
|
+
// Overwriting `onclick` does not interfere with linking to `href`; it is different from `onclick`.
|
1063
|
+
var objs = document.getElementsByTagName('a');
|
1064
|
+
for(var i = 0; i < objs.length; i++) objs[i].onclick = function(e) {e.stopPropagation();};
|
1065
|
+
};
|
1066
|
+
|
1067
|
+
initializeNavigation = function(obj) {
|
1068
|
+
obj.features = document.querySelectorAll(obj.query);
|
1069
|
+
var sum = obj.features.length;
|
1070
|
+
obj.querySelector('.sum').innerText = sum;
|
1071
|
+
var excluded = -sum;
|
1072
|
+
var objs = document.querySelectorAll(obj.tagsums);
|
1073
|
+
for(var i = 0; i < objs.length; i++) excluded += parseInt(objs[i].innerText);
|
1074
|
+
obj.querySelector('.excluded').innerText = excluded;
|
1075
|
+
var current = obj.querySelector('.current');
|
1076
|
+
if(sum == 0) {
|
1077
|
+
current.innerText = 1;
|
1078
|
+
} else {if(parseInt(current.innerText) > sum
|
1079
|
+
) current.innerText = sum;
|
1080
|
+
};
|
1081
|
+
};
|
1082
|
+
|
1083
|
+
initializeNavigations = function() {
|
1084
|
+
for(var i = 1, obj; obj = document.getElementById('user-feature-navigation' + i); i++
|
1085
|
+
) initializeNavigation(obj);
|
1086
|
+
for(var i = 1, obj; obj = document.getElementById('dev-feature-navigation' + i); i++
|
1087
|
+
) initializeNavigation(obj);
|
1088
|
+
for(var i = 1, obj; obj = document.getElementById('anchor-navigation' + i); i++
|
1089
|
+
) initializeNavigation(obj);
|
1090
|
+
};
|
1091
|
+
|
1092
|
+
getFeatureNodeFromId = function(id) {
|
1093
|
+
var obj = document.getElementById(id);
|
1094
|
+
if(!obj) return null;
|
1095
|
+
while(true) {
|
1096
|
+
if(obj.className == 'feature') return obj;
|
1097
|
+
obj = obj.parentNode;
|
1098
|
+
if(!obj) return null;
|
1099
|
+
}
|
1100
|
+
};
|
1101
|
+
|
1102
|
+
getIdFromObj = function(obj) {
|
1103
|
+
while(true) {
|
1104
|
+
if(obj.id) return obj.id;
|
1105
|
+
obj = obj.parentNode;
|
1106
|
+
if(!obj) return null;
|
1107
|
+
}
|
1108
|
+
};
|
1109
|
+
|
1110
|
+
hide = function(obj, bool) {obj.style.display = bool ? 'none' : null;};
|
1111
|
+
|
1112
|
+
inactivate = function(obj, bool) {obj.style.opacity = bool ? 0.2 : null;};
|
1113
|
+
|
1114
|
+
mark = function(obj, bool) {return obj.marking = bool;};
|
1115
|
+
|
1116
|
+
toggleMarking = function(obj) {return obj.marking = !obj.marking;};
|
1117
|
+
|
1118
|
+
hideByTag = function(obj, tag, bool) {
|
1119
|
+
if(bool) {obj.hiddenFor[tag] = true;} else {delete obj.hiddenFor[tag];};
|
1120
|
+
hide(obj, Object.keys(obj.hiddenFor).length);
|
1121
|
+
};
|
1122
|
+
|
1123
|
+
foldModuleContents = function(obj, bool){
|
1124
|
+
obj.firstChild.setAttribute('folded', bool);
|
1125
|
+
var objs = obj.childNodes;
|
1126
|
+
foldFeatureContents(objs[0], bool);
|
1127
|
+
// From the second children.
|
1128
|
+
for (var i = 1; i < objs.length; i++) hideByTag(objs[i], 'folded', bool);
|
1129
|
+
return bool;
|
1130
|
+
};
|
1131
|
+
|
1132
|
+
foldFeatureContents = function(obj, bool){
|
1133
|
+
obj.setAttribute('folded', bool);
|
1134
|
+
hide(obj.firstChild.nextSibling, bool);
|
1135
|
+
return bool;
|
1136
|
+
};
|
1137
|
+
|
1138
|
+
displayMode = function(bool1, bool2) {
|
1139
|
+
var objs = document.getElementsByClassName('module');
|
1140
|
+
for(var i = 0; i < objs.length; i++) foldModuleContents(objs[i], mark(objs[i], bool1));
|
1141
|
+
// `[onclick]`: Features with `type` `:module_as_constant` are not clickable.
|
1142
|
+
// `:not(:first-child)`: Don't fold module headers here.
|
1143
|
+
var objs = document.querySelectorAll('.feature[onclick]:not(:first-child)');
|
1144
|
+
for(var i = 0; i < objs.length; i++) foldFeatureContents(objs[i], mark(objs[i], bool2));
|
1145
|
+
initializeNavigations();
|
1146
|
+
};
|
1147
|
+
|
1148
|
+
toggleModuleContents = function(feature) {
|
1149
|
+
var module = feature.parentNode;
|
1150
|
+
var bool = foldModuleContents(module, toggleMarking(module));
|
1151
|
+
if(bool) {
|
1152
|
+
module.scrollIntoView();
|
1153
|
+
window.onhashchange();
|
1154
|
+
}
|
1155
|
+
initializeNavigations();
|
1156
|
+
};
|
1157
|
+
|
1158
|
+
toggleFeatureContents = function(feature) {
|
1159
|
+
var bool = foldFeatureContents(feature, toggleMarking(feature));
|
1160
|
+
if(bool) {
|
1161
|
+
feature.scrollIntoView();
|
1162
|
+
window.onhashchange();
|
1163
|
+
}
|
1164
|
+
initializeNavigations();
|
1165
|
+
};
|
1166
|
+
|
1167
|
+
toggleUserItems = function(button) {
|
1168
|
+
// recordScrollPosition();
|
1169
|
+
var bool = toggleMarking(button);
|
1170
|
+
inactivate(button, bool);
|
1171
|
+
objs = document.getElementsByClassName('user-item');
|
1172
|
+
for(i = 0; i < objs.length; i++) hide(objs[i], bool);
|
1173
|
+
initializeNavigations();
|
1174
|
+
// resumeScrollPosition();
|
1175
|
+
};
|
1176
|
+
|
1177
|
+
toggleFeatures = function(button, tag, navigation) {
|
1178
|
+
// recordScrollPosition();
|
1179
|
+
var bool = toggleMarking(button);
|
1180
|
+
inactivate(button, bool);
|
1181
|
+
inactivate(document.getElementById('tagsum-' + tag), bool);
|
1182
|
+
for(var i = 1, obj; obj = getFeatureNodeFromId(tag + i); i ++) hideByTag(obj, tag, bool);
|
1183
|
+
navigation = document.getElementById(navigation);
|
1184
|
+
initializeNavigations();
|
1185
|
+
// resumeScrollPosition();
|
1186
|
+
};
|
1187
|
+
|
1188
|
+
toggleAnchors = function(button, tag, navigation) {
|
1189
|
+
// recordScrollPosition();
|
1190
|
+
var bool = toggleMarking(button);
|
1191
|
+
inactivate(button, bool);
|
1192
|
+
inactivate(document.getElementById('tagsum-' + tag), bool);
|
1193
|
+
for(var i = 1, obj; obj = document.getElementById(tag + i); i ++) hide(obj, bool);
|
1194
|
+
navigation = document.getElementById(navigation);
|
1195
|
+
initializeNavigation(navigation);
|
1196
|
+
// resumeScrollPosition();
|
1197
|
+
};
|
1198
|
+
|
1199
|
+
navigateTag = function(navigation, d) {
|
1200
|
+
var n = navigation.features.length;
|
1201
|
+
if(n == 0) return;
|
1202
|
+
var old = document.getElementById('current');
|
1203
|
+
if(old) old.removeAttribute('id');
|
1204
|
+
var current = navigation.querySelector('.current');
|
1205
|
+
current.id = 'current';
|
1206
|
+
var i = parseInt(current.innerText) + d;
|
1207
|
+
if(i < 1) i = 1;
|
1208
|
+
if(i > n) i = n;
|
1209
|
+
current.innerText = i;
|
1210
|
+
location.hash = getIdFromObj(navigation.features[i - 1]);
|
1211
|
+
};
|
1212
|
+
|
1213
|
+
//var lastToggled =
|
1214
|
+
//var lastViewPort =
|
1215
|
+
recordScrollPosition = function() {
|
1216
|
+
// main.scrollTop = navigation.features[i - 1].offsetTop - main.offsetTop;
|
1217
|
+
/*
|
1218
|
+
foo = function(obj) {
|
1219
|
+
var ref = window.scrollY - window.pageYOffset + document.documentElement.clientTop;
|
1220
|
+
var checkChildDivs = function() {
|
1221
|
+
var children = obj.childNodes;
|
1222
|
+
if (children.length) {[].forEach.call(children, function(e, i, a) {
|
1223
|
+
if (e.toString() === "[object HTMLDivElement]") {
|
1224
|
+
// the top of the div relative to the document
|
1225
|
+
// minus the height of window hidden above the top of the screen
|
1226
|
+
var top = e.getBoundingClientRect().top;
|
1227
|
+
// top and bottom posns relative to the top of the screen
|
1228
|
+
// the top and bottom distances of the element relative to the top of the screen
|
1229
|
+
// the div overlaps the screen top
|
1230
|
+
if ((top <= ref) && (ref <= top + e.offsetHeight)) {
|
1231
|
+
obj = e;
|
1232
|
+
checkChildDivs();
|
1233
|
+
return false;
|
1234
|
+
}
|
1235
|
+
}
|
1236
|
+
});}
|
1237
|
+
};
|
1238
|
+
checkChildDivs();
|
1239
|
+
return obj;
|
1240
|
+
};
|
1241
|
+
*/
|
1242
|
+
};
|
1243
|
+
|
1244
|
+
resumeScrollPosition = function() {
|
1245
|
+
};
|
1246
|
+
|
1247
|
+
coverage = function(obj){
|
1248
|
+
alert("Sorry, this function is not implemented.");
|
1249
|
+
// alert(obj.nextSibling.contentDocument.querySelector('body').innerText);
|
1250
|
+
// var f = obj.dataset.file;
|
1251
|
+
};
|
1252
|
+
</script></body></html>
|