metanorma-iso 1.7.1 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -4
- data/lib/asciidoctor/iso/base.rb +12 -12
- data/lib/asciidoctor/iso/cleanup.rb +1 -1
- data/lib/asciidoctor/iso/isodoc.rng +19 -1
- data/lib/asciidoctor/iso/isostandard-amd.rng +3 -0
- data/lib/asciidoctor/iso/isostandard.rng +6 -0
- data/lib/metanorma/iso/version.rb +1 -1
- data/spec/asciidoctor-iso/amd_spec.rb +575 -573
- data/spec/asciidoctor-iso/base_spec.rb +445 -454
- data/spec/asciidoctor-iso/blocks_spec.rb +333 -288
- data/spec/asciidoctor-iso/cleanup_spec.rb +813 -704
- data/spec/asciidoctor-iso/inline_spec.rb +116 -91
- data/spec/asciidoctor-iso/lists_spec.rb +128 -121
- data/spec/asciidoctor-iso/refs_spec.rb +308 -250
- data/spec/asciidoctor-iso/section_spec.rb +273 -242
- data/spec/asciidoctor-iso/table_spec.rb +258 -242
- data/spec/asciidoctor-iso/validate_spec.rb +1099 -1165
- data/spec/isodoc/amd_spec.rb +967 -946
- data/spec/isodoc/blocks_spec.rb +530 -507
- data/spec/isodoc/i18n_spec.rb +953 -911
- data/spec/isodoc/inline_spec.rb +355 -293
- data/spec/isodoc/iso_spec.rb +338 -314
- data/spec/isodoc/metadata_spec.rb +392 -382
- data/spec/isodoc/postproc_spec.rb +833 -656
- data/spec/isodoc/ref_spec.rb +374 -331
- data/spec/isodoc/section_spec.rb +608 -525
- data/spec/isodoc/table_spec.rb +472 -411
- data/spec/isodoc/terms_spec.rb +209 -185
- data/spec/isodoc/xref_spec.rb +1370 -1236
- data/spec/metanorma/processor_spec.rb +28 -26
- data/spec/spec_helper.rb +176 -193
- metadata +2 -4
- data/.rubocop.ribose.yml +0 -66
- data/spec/assets/xref_error.adoc +0 -7
@@ -2,9 +2,8 @@ require "spec_helper"
|
|
2
2
|
require "metanorma"
|
3
3
|
require "fileutils"
|
4
4
|
|
5
|
-
#RSpec.describe Asciidoctor::Gb do
|
5
|
+
# RSpec.describe Asciidoctor::Gb do
|
6
6
|
RSpec.describe Metanorma::Iso::Processor do
|
7
|
-
|
8
7
|
registry = Metanorma::Registry.instance
|
9
8
|
registry.register(Metanorma::Iso::Processor)
|
10
9
|
processor = registry.find_processor(:iso)
|
@@ -15,7 +14,7 @@ RSpec.describe Metanorma::Iso::Processor do
|
|
15
14
|
|
16
15
|
it "registers output formats against metanorma" do
|
17
16
|
expect(processor.output_formats.sort.to_s).to be_equivalent_to <<~"OUTPUT"
|
18
|
-
|
17
|
+
[[:doc, "doc"], [:html, "html"], [:html_alt, "alt.html"], [:isosts, "iso.sts.xml"], [:pdf, "pdf"], [:presentation, "presentation.xml"], [:rxl, "rxl"], [:sts, "sts.xml"], [:xml, "xml"]]
|
19
18
|
OUTPUT
|
20
19
|
end
|
21
20
|
|
@@ -25,37 +24,40 @@ RSpec.describe Metanorma::Iso::Processor do
|
|
25
24
|
|
26
25
|
it "generates IsoDoc XML from a blank document" do
|
27
26
|
expect(xmlpp(processor.input_to_isodoc(<<~"INPUT", nil))).to be_equivalent_to xmlpp(<<~"OUTPUT")
|
28
|
-
|
27
|
+
#{ASCIIDOC_BLANK_HDR}
|
29
28
|
INPUT
|
30
|
-
|
31
|
-
<sections/>
|
32
|
-
</iso-standard>
|
29
|
+
#{BLANK_HDR}
|
30
|
+
<sections/>
|
31
|
+
</iso-standard>
|
33
32
|
OUTPUT
|
34
33
|
end
|
35
34
|
|
36
35
|
it "generates HTML from IsoDoc XML" do
|
37
36
|
FileUtils.rm_f "test.xml"
|
38
37
|
processor.output(<<~"INPUT", "test.xml", "test.html", :html)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
<iso-standard xmlns="http://riboseinc.com/isoxml">
|
39
|
+
<sections>
|
40
|
+
<terms id="H" obligation="normative"><title>1  Terms, Definitions, Symbols and Abbreviated Terms</title>
|
41
|
+
<term id="J">
|
42
|
+
<name>1.1</name>
|
43
|
+
<preferred>Term2</preferred>
|
44
|
+
</term>
|
45
|
+
</terms>
|
47
46
|
</sections>
|
48
|
-
|
47
|
+
</iso-standard>
|
49
48
|
INPUT
|
50
|
-
expect(xmlpp(File.read("test.html", encoding: "utf-8")
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
49
|
+
expect(xmlpp(File.read("test.html", encoding: "utf-8")
|
50
|
+
.gsub(%r{^.*<main}m, "<main")
|
51
|
+
.gsub(%r{</main>.*}m, "</main>")))
|
52
|
+
.to be_equivalent_to xmlpp(<<~"OUTPUT")
|
53
|
+
<main class="main-section">
|
54
|
+
<button onclick="topFunction()" id="myBtn" title="Go to top">Top</button>
|
55
|
+
<p class="zzSTDTitle1"></p>
|
56
|
+
<div id="H"><h1 id="toc0">1  Terms, Definitions, Symbols and Abbreviated Terms</h1>
|
57
|
+
<h2 class="TermNum" id="J">1.1</h2>
|
58
|
+
<p class="Terms" style="text-align:left;">Term2</p>
|
59
|
+
</div>
|
60
|
+
</main>
|
61
|
+
OUTPUT
|
59
62
|
end
|
60
|
-
|
61
63
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -23,250 +23,235 @@ RSpec.configure do |config|
|
|
23
23
|
config.expect_with :rspec do |c|
|
24
24
|
c.syntax = :expect
|
25
25
|
end
|
26
|
+
|
27
|
+
config.around do |example|
|
28
|
+
Dir.mktmpdir("rspec-") do |dir|
|
29
|
+
tmp_assets = File.join(dir, "spec/assets/")
|
30
|
+
FileUtils.mkdir_p tmp_assets
|
31
|
+
FileUtils.cp_r Dir.glob("spec/assets/*"), tmp_assets
|
32
|
+
Dir.chdir(dir) { example.run }
|
33
|
+
end
|
34
|
+
end
|
26
35
|
end
|
27
36
|
|
28
|
-
def strip_guid(
|
29
|
-
|
37
|
+
def strip_guid(xml)
|
38
|
+
xml.gsub(%r{ id="_[^"]+"}, ' id="_"').gsub(%r{ target="_[^"]+"}, ' target="_"')
|
30
39
|
end
|
31
40
|
|
32
|
-
def metadata(
|
33
|
-
Hash[
|
41
|
+
def metadata(hash)
|
42
|
+
Hash[hash.sort].delete_if { |_, v| v.nil? || v.respond_to?(:empty?) && v.empty? }
|
34
43
|
end
|
35
44
|
|
36
|
-
def xmlpp(
|
45
|
+
def xmlpp(xml)
|
37
46
|
s = ""
|
38
47
|
f = REXML::Formatters::Pretty.new(2)
|
39
48
|
f.compact = true
|
40
|
-
f.write(REXML::Document.new(
|
49
|
+
f.write(REXML::Document.new(xml), s)
|
41
50
|
s
|
42
51
|
end
|
43
52
|
|
44
|
-
ASCIIDOC_BLANK_HDR = <<~"HDR"
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
53
|
+
ASCIIDOC_BLANK_HDR = <<~"HDR".freeze
|
54
|
+
= Document title
|
55
|
+
Author
|
56
|
+
:docfile: test.adoc
|
57
|
+
:nodoc:
|
58
|
+
:novalid:
|
59
|
+
:no-isobib:
|
51
60
|
|
52
61
|
HDR
|
53
62
|
|
54
|
-
AMD_BLANK_HDR = <<~"HDR"
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
AMD_BLANK_HDR = <<~"HDR".freeze
|
64
|
+
= Document title
|
65
|
+
Author
|
66
|
+
:docfile: test.adoc
|
67
|
+
:nodoc:
|
68
|
+
:novalid:
|
69
|
+
:no-isobib:
|
70
|
+
:doctype: amendment
|
62
71
|
|
63
72
|
HDR
|
64
73
|
|
65
|
-
ISOBIB_BLANK_HDR = <<~"HDR"
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
ISOBIB_BLANK_HDR = <<~"HDR".freeze
|
75
|
+
= Document title
|
76
|
+
Author
|
77
|
+
:docfile: test.adoc
|
78
|
+
:nodoc:
|
79
|
+
:novalid:
|
80
|
+
:no-isobib-cache:
|
72
81
|
|
73
82
|
HDR
|
74
83
|
|
75
|
-
FLUSH_CACHE_ISOBIB_BLANK_HDR = <<~"HDR"
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
84
|
+
FLUSH_CACHE_ISOBIB_BLANK_HDR = <<~"HDR".freeze
|
85
|
+
= Document title
|
86
|
+
Author
|
87
|
+
:docfile: test.adoc
|
88
|
+
:nodoc:
|
89
|
+
:novalid:
|
90
|
+
:flush-caches:
|
82
91
|
|
83
92
|
HDR
|
84
93
|
|
85
|
-
CACHED_ISOBIB_BLANK_HDR = <<~"HDR"
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
94
|
+
CACHED_ISOBIB_BLANK_HDR = <<~"HDR".freeze
|
95
|
+
= Document title
|
96
|
+
Author
|
97
|
+
:docfile: test.adoc
|
98
|
+
:nodoc:
|
99
|
+
:novalid:
|
91
100
|
|
92
101
|
HDR
|
93
102
|
|
94
|
-
LOCAL_CACHED_ISOBIB_BLANK_HDR = <<~"HDR"
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
103
|
+
LOCAL_CACHED_ISOBIB_BLANK_HDR = <<~"HDR".freeze
|
104
|
+
= Document title
|
105
|
+
Author
|
106
|
+
:docfile: test.adoc
|
107
|
+
:nodoc:
|
108
|
+
:novalid:
|
109
|
+
:local-cache:
|
101
110
|
|
102
111
|
HDR
|
103
112
|
|
104
|
-
VALIDATING_BLANK_HDR = <<~"HDR"
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
113
|
+
VALIDATING_BLANK_HDR = <<~"HDR".freeze
|
114
|
+
= Document title
|
115
|
+
Author
|
116
|
+
:docfile: test.adoc
|
117
|
+
:nodoc:
|
118
|
+
:no-isobib:
|
111
119
|
HDR
|
112
120
|
|
121
|
+
ASCIIDOCTOR_ISO_DIR = Pathname.new(File.dirname(__FILE__)) / "../lib/asciidoctor/iso"
|
122
|
+
|
113
123
|
BOILERPLATE =
|
114
124
|
HTMLEntities.new.decode(
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
)
|
125
|
+
File.read(ASCIIDOCTOR_ISO_DIR / "boilerplate.xml", encoding: "utf-8")
|
126
|
+
.gsub(/\{\{ agency \}\}/, "ISO").gsub(/\{\{ docyear \}\}/, Date.today.year.to_s)
|
127
|
+
.gsub(/\{% if unpublished %\}.*\{% endif %\}/m, "")
|
128
|
+
.gsub(/(?<=\p{Alnum})'(?=\p{Alpha})/, "’")
|
129
|
+
)
|
120
130
|
|
121
131
|
BOILERPLATE_FR =
|
122
132
|
HTMLEntities.new.decode(
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
)
|
128
|
-
|
129
|
-
BLANK_HDR1 = <<~"HDR"
|
130
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
131
|
-
<iso-standard xmlns="https://www.metanorma.org/ns/iso" type="semantic" version="#{Metanorma::ISO::VERSION}">
|
132
|
-
<bibdata type="standard">
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
</bibdata>
|
133
|
+
File.read(ASCIIDOCTOR_ISO_DIR / "boilerplate-fr.xml", encoding: "utf-8")
|
134
|
+
.gsub(/\{\{ agency \}\}/, "ISO").gsub(/\{\{ docyear \}\}/, Date.today.year.to_s)
|
135
|
+
.gsub(/\{% if unpublished %\}.*\{% endif %\}/m, "")
|
136
|
+
.gsub(/(?<=\p{Alnum})'(?=\p{Alpha})/, "’")
|
137
|
+
)
|
138
|
+
|
139
|
+
BLANK_HDR1 = <<~"HDR".freeze
|
140
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
141
|
+
<iso-standard xmlns="https://www.metanorma.org/ns/iso" type="semantic" version="#{Metanorma::ISO::VERSION}">
|
142
|
+
<bibdata type="standard">
|
143
|
+
<contributor>
|
144
|
+
<role type="author"/>
|
145
|
+
<organization>
|
146
|
+
<name>International Organization for Standardization</name>
|
147
|
+
<abbreviation>ISO</abbreviation>
|
148
|
+
</organization>
|
149
|
+
</contributor>
|
150
|
+
<contributor>
|
151
|
+
<role type="publisher"/>
|
152
|
+
<organization>
|
153
|
+
<name>International Organization for Standardization</name>
|
154
|
+
<abbreviation>ISO</abbreviation>
|
155
|
+
</organization>
|
156
|
+
</contributor>
|
157
|
+
<language>en</language>
|
158
|
+
<script>Latn</script>
|
159
|
+
<status>
|
160
|
+
<stage abbreviation="IS">60</stage>
|
161
|
+
<substage>60</substage>
|
162
|
+
</status>
|
163
|
+
<copyright>
|
164
|
+
<from>#{Time.new.year}</from>
|
165
|
+
<owner>
|
166
|
+
<organization>
|
167
|
+
<name>International Organization for Standardization</name>
|
168
|
+
<abbreviation>ISO</abbreviation>
|
169
|
+
</organization>
|
170
|
+
</owner>
|
171
|
+
</copyright>
|
172
|
+
<ext>
|
173
|
+
<doctype>article</doctype>
|
174
|
+
<editorialgroup>
|
175
|
+
<technical-committee/>
|
176
|
+
<subcommittee/>
|
177
|
+
<workgroup/>
|
178
|
+
</editorialgroup>
|
179
|
+
<stagename>International standard</stagename>
|
180
|
+
</ext>
|
181
|
+
</bibdata>
|
172
182
|
HDR
|
173
183
|
|
174
|
-
BLANK_HDR = <<~"HDR"
|
175
|
-
#{BLANK_HDR1}
|
176
|
-
#{BOILERPLATE}
|
184
|
+
BLANK_HDR = <<~"HDR".freeze
|
185
|
+
#{BLANK_HDR1}
|
186
|
+
#{BOILERPLATE}
|
177
187
|
HDR
|
178
188
|
|
179
|
-
BLANK_HDR_FR = <<~"HDR"
|
180
|
-
#{BLANK_HDR1.sub(%r{<language>en</language>},
|
181
|
-
#{BOILERPLATE_FR}
|
189
|
+
BLANK_HDR_FR = <<~"HDR".freeze
|
190
|
+
#{BLANK_HDR1.sub(%r{<language>en</language>}, '<language>fr</language>')}
|
191
|
+
#{BOILERPLATE_FR}
|
182
192
|
HDR
|
183
193
|
|
184
|
-
TERM_BOILERPLATE = <<~
|
194
|
+
TERM_BOILERPLATE = <<~TERM.freeze
|
185
195
|
<p id="_">For the purposes of this document,
|
186
196
|
the following terms and definitions apply.</p>
|
187
|
-
<p id="_">ISO and IEC maintain terminological databases for use in
|
188
|
-
standardization at the following addresses:</p>
|
189
|
-
|
190
|
-
<ul id="_">
|
191
|
-
<li>
|
192
|
-
|
193
|
-
<
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
</head>
|
218
|
-
<body lang="EN-US" link="blue" vlink="#954F72">
|
219
|
-
<div class="WordSection1">
|
220
|
-
<p> </p>
|
221
|
-
</div>
|
222
|
-
<p><br clear="all" class="section"/></p>
|
223
|
-
<div class="WordSection2">
|
224
|
-
<p> </p>
|
225
|
-
</div>
|
226
|
-
<p><br clear="all" class="section"/></p>
|
227
|
-
<div class="WordSection3">
|
228
|
-
END
|
229
|
-
|
230
|
-
|
231
|
-
def stub_fetch_ref(**opts)
|
232
|
-
xml = ""
|
233
|
-
|
234
|
-
hit = double("hit")
|
235
|
-
expect(hit).to receive(:"[]").with("title") do
|
236
|
-
Nokogiri::XML(xml).at("//docidentifier").content
|
237
|
-
end.at_least(:once)
|
238
|
-
|
239
|
-
hit_instance = double("hit_instance")
|
240
|
-
expect(hit_instance).to receive(:hit).and_return(hit).at_least(:once)
|
241
|
-
expect(hit_instance).to receive(:to_xml) do |builder, opt|
|
242
|
-
expect(builder).to be_instance_of Nokogiri::XML::Builder
|
243
|
-
expect(opt).to eq opts
|
244
|
-
builder << xml
|
245
|
-
end.at_least :once
|
246
|
-
|
247
|
-
hit_page = double("hit_page")
|
248
|
-
expect(hit_page).to receive(:first).and_return(hit_instance).at_least :once
|
197
|
+
<p id="_">ISO and IEC maintain terminological databases for use in
|
198
|
+
standardization at the following addresses:</p>
|
199
|
+
|
200
|
+
<ul id="_">
|
201
|
+
<li>
|
202
|
+
<p id="_">ISO Online browsing platform: available at
|
203
|
+
<link target="http://www.iso.org/obp"/></p>
|
204
|
+
</li>
|
205
|
+
<li>
|
206
|
+
<p id="_">IEC Electropedia: available at
|
207
|
+
<link target="http://www.electropedia.org"/>
|
208
|
+
</p>
|
209
|
+
</li>
|
210
|
+
</ul>
|
211
|
+
TERM
|
212
|
+
|
213
|
+
HTML_HDR = <<~HDR.freeze
|
214
|
+
<html xmlns:epub="http://www.idpf.org/2007/ops" lang="en">
|
215
|
+
<head/>
|
216
|
+
<body lang="en">
|
217
|
+
<div class="title-section">
|
218
|
+
<p> </p>
|
219
|
+
</div>
|
220
|
+
<br/>
|
221
|
+
<div class="prefatory-section">
|
222
|
+
<p> </p>
|
223
|
+
</div>
|
224
|
+
<br/>
|
225
|
+
<div class="main-section">
|
226
|
+
HDR
|
249
227
|
|
250
|
-
|
251
|
-
|
228
|
+
WORD_HDR = <<~HDR.freeze
|
229
|
+
<html xmlns:epub="http://www.idpf.org/2007/ops">
|
230
|
+
<head>
|
231
|
+
<title>test</title>
|
232
|
+
</head>
|
233
|
+
<body lang="EN-US" link="blue" vlink="#954F72">
|
234
|
+
<div class="WordSection1">
|
235
|
+
<p> </p>
|
236
|
+
</div>
|
237
|
+
<p><br clear="all" class="section"/></p>
|
238
|
+
<div class="WordSection2">
|
239
|
+
<p> </p>
|
240
|
+
</div>
|
241
|
+
<p><br clear="all" class="section"/></p>
|
242
|
+
<div class="WordSection3">
|
243
|
+
HDR
|
252
244
|
|
253
|
-
|
254
|
-
and_wrap_original do |search, *args|
|
255
|
-
code = args[0]
|
256
|
-
expect(code).to be_instance_of String
|
257
|
-
xml = get_xml(search, code, opts)
|
258
|
-
hit_pages
|
259
|
-
end.at_least :once
|
260
|
-
end
|
245
|
+
OPTIONS = [backend: :iso, header_footer: true].freeze
|
261
246
|
|
262
247
|
def mock_pdf
|
263
|
-
allow(::Mn2pdf).to receive(:convert) do |url, output
|
248
|
+
allow(::Mn2pdf).to receive(:convert) do |url, output,|
|
264
249
|
FileUtils.cp(url.gsub(/"/, ""), output.gsub(/"/, ""))
|
265
250
|
end
|
266
251
|
end
|
267
252
|
|
268
253
|
def mock_sts
|
269
|
-
allow(::Mn2sts).to receive(:convert) do |url, output
|
254
|
+
allow(::Mn2sts).to receive(:convert) do |url, output,|
|
270
255
|
FileUtils.cp(url.gsub(/"/, ""), output.gsub(/"/, ""))
|
271
256
|
end
|
272
257
|
end
|
@@ -274,7 +259,7 @@ end
|
|
274
259
|
private
|
275
260
|
|
276
261
|
def get_xml(search, code, opts)
|
277
|
-
c = code.gsub(%r{[
|
262
|
+
c = code.gsub(%r{[/\s:-]}, "_").sub(%r{_+$}, "").downcase
|
278
263
|
o = opts.keys.join "_"
|
279
264
|
file = "spec/examples/#{[c, o].join '_'}.xml"
|
280
265
|
if File.exist? file
|
@@ -289,11 +274,9 @@ def get_xml(search, code, opts)
|
|
289
274
|
end
|
290
275
|
|
291
276
|
def mock_open_uri(code)
|
292
|
-
#expect(OpenURI).to receive(:open_uri).and_wrap_original do |m, *args|
|
293
277
|
expect(Iev).to receive(:get).with(code, "en") do |m, *args|
|
294
278
|
file = "spec/examples/#{code.tr('-', '_')}.html"
|
295
279
|
File.write file, m.call(*args).read unless File.exist? file
|
296
280
|
File.read file
|
297
281
|
end.at_least :once
|
298
282
|
end
|
299
|
-
|