plain_text 0.7.1 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/ChangeLog +11 -0
- data/Makefile +2 -1
- data/README.en.rdoc +67 -61
- data/lib/plain_text/builtin_type.rb +64 -0
- data/lib/plain_text/error.rb +6 -0
- data/lib/plain_text/part/boundary.rb +38 -28
- data/lib/plain_text/part/paragraph.rb +41 -18
- data/lib/plain_text/part/string_type.rb +90 -0
- data/lib/plain_text/part.rb +316 -275
- data/lib/plain_text/util.rb +13 -12
- data/lib/plain_text.rb +14 -10
- data/plain_text.gemspec +3 -3
- data/test/test_plain_text.rb +17 -2
- data/test/test_plain_text_parse_rule.rb +17 -3
- data/test/test_plain_text_part.rb +207 -39
- data/test/test_plain_text_split.rb +17 -2
- data/test/test_plain_text_util.rb +17 -2
- metadata +5 -5
data/lib/plain_text/part.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
|
3
|
+
require_relative "error"
|
4
|
+
require_relative "builtin_type"
|
5
|
+
require_relative "util"
|
4
6
|
|
5
7
|
module PlainText
|
6
8
|
|
7
|
-
# Class to represent a Chapter-like entity like an Array
|
9
|
+
# Class to represent a Chapter-like entity, which behaves like an Array
|
8
10
|
#
|
9
11
|
# An instance of this class contains always an even number of elements,
|
10
12
|
# either another {Part} instance or {Paragraph}-type String-like instance,
|
@@ -17,65 +19,80 @@ module PlainText
|
|
17
19
|
# An example instance looks like this:
|
18
20
|
#
|
19
21
|
# Part (
|
20
|
-
# (0) Paragraph::Empty,
|
21
|
-
# (1) Boundary::General,
|
22
|
+
# (0) Part::Paragraph::Empty,
|
23
|
+
# (1) Part::Boundary::General,
|
22
24
|
# (2) Part::ArticleHeader(
|
23
|
-
# (0) Paragraph::Title,
|
24
|
-
# (1) Boundary::Empty
|
25
|
+
# (0) Part::Paragraph::Title,
|
26
|
+
# (1) Part::Boundary::Empty
|
25
27
|
# ),
|
26
|
-
# (3) Boundary::TitleMain,
|
28
|
+
# (3) Part::Boundary::TitleMain,
|
27
29
|
# (4) Part::ArticleMain(
|
28
30
|
# (0) Part::ArticleSection(
|
29
|
-
# (0) Paragraph::Title,
|
30
|
-
# (1) Boundary::General,
|
31
|
-
# (2) Paragraph::General,
|
32
|
-
# (3) Boundary::General,
|
31
|
+
# (0) Part::Paragraph::Title,
|
32
|
+
# (1) Part::Boundary::General,
|
33
|
+
# (2) Part::Paragraph::General,
|
34
|
+
# (3) Part::Boundary::General,
|
33
35
|
# (4) Part::ArticleSubSection(...),
|
34
|
-
# (5) Boundary::General,
|
35
|
-
# (6) Paragraph::General,
|
36
|
-
# (7) Boundary::Empty
|
36
|
+
# (5) Part::Boundary::General,
|
37
|
+
# (6) Part::Paragraph::General,
|
38
|
+
# (7) Part::Boundary::Empty
|
37
39
|
# ),
|
38
|
-
# (1) Boundary::General,
|
39
|
-
# (2) Paragraph::General,
|
40
|
-
# (3) Boundary::Empty
|
40
|
+
# (1) Part::Boundary::General,
|
41
|
+
# (2) Part::Paragraph::General,
|
42
|
+
# (3) Part::Boundary::Empty
|
41
43
|
# ),
|
42
|
-
# (5) Boundary::General
|
44
|
+
# (5) Part::Boundary::General
|
43
45
|
# )
|
44
46
|
#
|
45
47
|
# A Section (Part) always has an even number of elements: pairs of a Para ({Part}|{Paragraph}) and {Boundary} in this order.
|
46
48
|
#
|
47
|
-
#
|
49
|
+
# This class behaves like an Array and so Array methods that usually return
|
50
|
+
# an Array returns an instance of this class, such as +pt[0..-2]+.
|
51
|
+
# However, not all Array methods are accepted in the same way.
|
52
|
+
# For example, for the instance +pt+, +pt[0..-2]+ raises an Exception
|
53
|
+
# because it would violate the principle of the instance of this class
|
54
|
+
# having always an even number of elements. Use +to_a+ to obtain
|
55
|
+
# a standard Array; e.g., +pt.to_a[0..-2]+ returns an Array with
|
56
|
+
# an odd number of elements.
|
57
|
+
#
|
58
|
+
# Some destructive Array operations, most notably +#delete+, +#delete_if+, +#reject!+,
|
48
59
|
# +#select!+, +#filter!+, +#keep_if+, +#flatten!+, +#uniq!+ may alter the content in a way
|
49
|
-
# it breaks the self-
|
60
|
+
# it breaks the self-consistency of the object.
|
50
61
|
# Use it at your own risk, if you wish (or don't).
|
62
|
+
# Such operations may become prohibited in the future release.
|
63
|
+
# {#<<} and {#delete_at} are currently disabled.
|
51
64
|
#
|
52
65
|
# An instance of this class is always *non-equal* to that of the standard Array class.
|
53
|
-
# To compare it at the Array level, convert a {Part} class instance into Array
|
66
|
+
# To compare it at the Array level, convert a {Part} class instance into Array
|
67
|
+
# with {#to_a} first: +pt.to_a == my_array+
|
54
68
|
#
|
55
69
|
# For CRUD of elements (contents) of an instance, the following methods are most basic:
|
56
70
|
#
|
57
71
|
# * Create:
|
58
|
-
# *
|
59
|
-
# * {#<<} is disabled.
|
72
|
+
# * Use +PlainText::Part.new+ (see {PlainText::Part.initialize})
|
60
73
|
# * Read:
|
61
|
-
# *
|
62
|
-
#
|
74
|
+
# * All non-destructive Array operations are permitted and returns an instance of this class if the corresponding Array method returns an Array, providing it does not break the self-consistency.
|
75
|
+
# * {#to_a} gives or exposes the internal Array object, and then you can do whatever manipulation allowed for Array with it, if you insist. Note that destructive modification of the object carries a risk of breaking self-consistency of the instance and so is highly discouraged. You must know what you are doing if you do.
|
63
76
|
# * Update:
|
77
|
+
# * Insert/Append: {#insert} to insert. If the specified index is #size}, it means "append". For primitive operations, specify +primitive: true+ to skip various checks performed to guarantee the self-consistency as an instance of this class.
|
64
78
|
# * Replace: {#[]=} has some restrictions, such as, if multiple elements are replaced, they have to be pairs of Paragraph and Boundary. To skip all the checks, do {#insert} with +primitive: true+
|
65
79
|
# * Delete:
|
66
80
|
# * Delete: {#slice!} to delete. For primitive operations, specify +primitive: true+ to skip various checks performed to guarantee the self-consistency as an instance of this class.
|
67
|
-
# * +#delete_at+ is disabled. +#delete+, +#delete_if+, +#reject!+, +#select!+, +#filter!+, +#keep_if+ (and +#drop_while+ and +#take_whie+ in recent Ruby) remain enabled, but if you use them,
|
81
|
+
# * +#delete_at+ is disabled. +#delete+, +#delete_if+, +#reject!+, +#select!+, +#filter!+, +#keep_if+ (and +#drop_while+ and +#take_whie+ in recent Ruby) remain enabled, but if you use them, do so at your own risk, as no self-consistency checks would be performed automatically. {#normalize} would return the self-consistent instance, or its destructive version, {#normalize!}.
|
68
82
|
#
|
69
83
|
# @author Masa Sakano (Wise Babel Ltd)
|
70
84
|
#
|
71
85
|
# @todo methods
|
72
86
|
# * flatten
|
73
|
-
# * SAFE level for command-line tools?
|
74
87
|
#
|
75
|
-
class Part
|
88
|
+
class Part
|
76
89
|
|
90
|
+
include PlainText::BuiltinType
|
77
91
|
include PlainText::Util
|
78
92
|
|
93
|
+
# Array methods that are disabled for this class.
|
94
|
+
DISABLED_ARRAY_METHODS = %i(<< delete_at)
|
95
|
+
|
79
96
|
# Error messages
|
80
97
|
ERR_MSGS = {
|
81
98
|
even_num: 'even number of elements must be specified.',
|
@@ -83,25 +100,44 @@ module PlainText
|
|
83
100
|
}
|
84
101
|
private_constant :ERR_MSGS
|
85
102
|
|
86
|
-
#
|
103
|
+
# Constructor
|
104
|
+
#
|
105
|
+
# New String-type objects are always created, i.e.,
|
106
|
+
# regardless of whether the input is a pure String or {Paragraph} etc,
|
107
|
+
# a new {Paragraph} is always created from {Paragraph#to_s}. Therefore,
|
108
|
+
# even if one of the String given to the argument is destructively
|
109
|
+
# modified, it does not affect the generated {Part} object. This also means
|
110
|
+
# that if the input {Paragraph} has special singloton methods or
|
111
|
+
# instance variables, the information will be lost.
|
112
|
+
#
|
113
|
+
# @param arin [Array] of [Paragraph1, Boundary1, Para2, Bd2, ...] or just of Paragraphs if boundaries is given as the second arguments
|
87
114
|
# @param boundaries [Array] of Boundary
|
88
115
|
# @option recursive: [Boolean] if true (Default), normalize recursively.
|
89
116
|
# @option compact: [Boolean] if true (Default), pairs of nil paragraph and boundary are removed. Otherwise, nil is converted to an empty string.
|
90
117
|
# @option compacter: [Boolean] if true (Default), pairs of nil or empty paragraph and boundary are removed.
|
91
118
|
# @return [self]
|
92
119
|
def initialize(arin, boundaries=nil, recursive: true, compact: true, compacter: true)
|
120
|
+
raise ArgumentError, "Arguments must be an Array(s) or equivalent: "+arin.inspect+(boundaries ? ", "+boundaries.inspect : "") if (!arin.respond_to?(:compact) && !arin.respond_to?(:paras)) || boundaries && !boundaries.respond_to?(:compact) # arin must be an Array or Part
|
93
121
|
if !boundaries
|
94
|
-
|
122
|
+
@array = arin.clone
|
123
|
+
#super(arin)
|
95
124
|
else
|
125
|
+
raise ArgumentError, "Two main Arrays must have the same size." if arin.size != boundaries.size
|
96
126
|
|
97
127
|
armain = []
|
98
128
|
arin.each_with_index do |ea_e, i|
|
99
129
|
armain << ea_e
|
100
130
|
armain << (boundaries[i] || Boundary.new(''))
|
101
131
|
end
|
102
|
-
|
132
|
+
@array = armain
|
133
|
+
#super armain
|
134
|
+
end
|
135
|
+
|
136
|
+
begin
|
137
|
+
normalize!(recursive: recursive, compact: compact, compacter: compacter)
|
138
|
+
rescue PlainText::PartNormalizeError => err
|
139
|
+
raise TypeError, err.message
|
103
140
|
end
|
104
|
-
normalize!(recursive: recursive, compact: compact, compacter: compacter)
|
105
141
|
end
|
106
142
|
|
107
143
|
# Parses a given string (or {Part}) and returns this class of instance.
|
@@ -114,6 +150,33 @@ module PlainText
|
|
114
150
|
self.new(arin)
|
115
151
|
end
|
116
152
|
|
153
|
+
# Returns true if it is {PlainText::Part}
|
154
|
+
def self.part?(other)
|
155
|
+
_part_paragraph_boundary?(other, __method__)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns true if it is {PlainText::Part::Boundary}
|
159
|
+
def self.boundary?(other)
|
160
|
+
_part_paragraph_boundary?(other, __method__)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns true if it is {PlainText::Part::Paragraph}
|
164
|
+
def self.paragraph?(other)
|
165
|
+
_part_paragraph_boundary?(other, __method__)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns true if it is built-in String or similar
|
169
|
+
def self.builtin_string?(other)
|
170
|
+
other.respond_to?(:to_str) && !boundary? && !paragraph?
|
171
|
+
end
|
172
|
+
|
173
|
+
# Core routines for {Part.part?} etc.
|
174
|
+
def self._part_paragraph_boundary?(other, metho)
|
175
|
+
%i(boundary? paragraph? part?).all?{|i| other.respond_to? i} && other.send(metho)
|
176
|
+
end
|
177
|
+
private_class_method :_part_paragraph_boundary?
|
178
|
+
|
179
|
+
|
117
180
|
####################################################
|
118
181
|
# Instance methods
|
119
182
|
####################################################
|
@@ -122,12 +185,24 @@ module PlainText
|
|
122
185
|
# Unique instance methods (not existing in Array)
|
123
186
|
##########
|
124
187
|
|
188
|
+
def boundary?
|
189
|
+
false
|
190
|
+
end
|
191
|
+
|
192
|
+
def paragraph?
|
193
|
+
false
|
194
|
+
end
|
195
|
+
|
196
|
+
def part?
|
197
|
+
true
|
198
|
+
end
|
199
|
+
|
125
200
|
# Returns an array of boundaries (odd-number-index elements), consisting of Boundaries
|
126
201
|
#
|
127
202
|
# @return [Array<Boundary>]
|
128
203
|
# @see #paras
|
129
204
|
def boundaries
|
130
|
-
select.with_index { |_, i| i.odd? } rescue select.each_with_index { |_, i| i.odd? } # Rescue for Ruby 2.1 or earlier
|
205
|
+
@array.select.with_index { |_, i| i.odd? } rescue @array.select.each_with_index { |_, i| i.odd? } # Rescue for Ruby 2.1 or earlier
|
131
206
|
end
|
132
207
|
|
133
208
|
# returns all the Boundaries immediately before the index and at it as an Array
|
@@ -139,16 +214,19 @@ module PlainText
|
|
139
214
|
def boundary_extended_at(index)
|
140
215
|
(i_pos = get_valid_ipos_for_boundary(index)) || return
|
141
216
|
arret = []
|
142
|
-
prt =
|
143
|
-
arret = prt.public_send(__method__, -1) if prt.
|
144
|
-
arret <<
|
217
|
+
prt = @array[i_pos-1]
|
218
|
+
arret = prt.public_send(__method__, -1) if prt.respond_to? __method__
|
219
|
+
arret << @array[index]
|
145
220
|
end
|
146
221
|
|
147
222
|
# Returns a dup-ped instance with all the Arrays and Strings dup-ped.
|
148
223
|
#
|
149
224
|
# @return [Part]
|
150
225
|
def deepcopy
|
151
|
-
|
226
|
+
_return_this_or_other{
|
227
|
+
@array.dup.map!{ |i| i.respond_to?(:deepcopy) ? i.deepcopy : (i.dup rescue i)}
|
228
|
+
# the "rescue" deals with cases where i is immutable (which should never happen and in fact it would not raise an Exception in Ruby 3 seemingly).
|
229
|
+
}
|
152
230
|
end
|
153
231
|
|
154
232
|
# each method for boundaries only, providing also the index (always an odd number) to the block.
|
@@ -164,7 +242,7 @@ module PlainText
|
|
164
242
|
# @param (see #map_boundary_with_index)
|
165
243
|
# @return as self
|
166
244
|
def each_boundary_with_index(**kwd, &bl)
|
167
|
-
map_boundary_core(
|
245
|
+
map_boundary_core(do_map: false, with_index: true, **kwd, &bl)
|
168
246
|
end
|
169
247
|
|
170
248
|
# each method for Paras only, providing also the index (always an even number) to the block.
|
@@ -180,7 +258,7 @@ module PlainText
|
|
180
258
|
# @param (see #map_para_with_index)
|
181
259
|
# @return as self
|
182
260
|
def each_para_with_index(**kwd, &bl)
|
183
|
-
map_para_core(
|
261
|
+
map_para_core(do_map: false, with_index: false, **kwd, &bl)
|
184
262
|
end
|
185
263
|
|
186
264
|
# The first significant (=non-empty) element.
|
@@ -190,7 +268,7 @@ module PlainText
|
|
190
268
|
# @return [Integer, nil] if self.empty? nil is returned.
|
191
269
|
def first_significant_element
|
192
270
|
(i = first_significant_index) || return
|
193
|
-
|
271
|
+
@array[i]
|
194
272
|
end
|
195
273
|
|
196
274
|
# Index of the first significant (=non-empty) element.
|
@@ -199,20 +277,19 @@ module PlainText
|
|
199
277
|
#
|
200
278
|
# @return [Integer, nil] if self.empty? nil is returned.
|
201
279
|
def first_significant_index
|
202
|
-
return nil if empty?
|
203
|
-
|
204
|
-
|
205
|
-
end
|
206
|
-
return size-1
|
280
|
+
return nil if @array.empty?
|
281
|
+
@array.find_index do |val|
|
282
|
+
val && !val.empty?
|
283
|
+
end || (@array.size-1)
|
207
284
|
end
|
208
285
|
|
209
286
|
# True if the index should be semantically for Paragraph?
|
210
287
|
#
|
211
288
|
# @param i [Integer] index for the array of self
|
212
|
-
# @option
|
289
|
+
# @option accept_negative: [Boolean] if false (Default: true), skip conversion of the negative index to positive.
|
213
290
|
# @see #paras
|
214
|
-
def index_para?(i,
|
215
|
-
|
291
|
+
def index_para?(i, accept_negative: true)
|
292
|
+
accept_negative ? positive_array_index_checked(i, @array).even? : i.even?
|
216
293
|
end
|
217
294
|
|
218
295
|
# The last significant (=non-empty) element.
|
@@ -222,7 +299,7 @@ module PlainText
|
|
222
299
|
# @return [Integer, nil] if self.empty? nil is returned.
|
223
300
|
def last_significant_element
|
224
301
|
(i = last_significant_index) || return
|
225
|
-
|
302
|
+
@array[i]
|
226
303
|
end
|
227
304
|
|
228
305
|
# Index of the last significant (=non-empty) element.
|
@@ -233,7 +310,7 @@ module PlainText
|
|
233
310
|
def last_significant_index
|
234
311
|
return nil if empty?
|
235
312
|
(0..(size-1)).to_a.reverse.each do |i|
|
236
|
-
return i if
|
313
|
+
return i if @array[i] && !@array[i].empty? # self for sanity
|
237
314
|
end
|
238
315
|
return 0
|
239
316
|
end
|
@@ -298,12 +375,12 @@ module PlainText
|
|
298
375
|
# @return [self, false] false if no pairs of Paras are merged, else self.
|
299
376
|
def merge_para_if()
|
300
377
|
arind2del = [] # Indices to delete (both paras and boundaries)
|
301
|
-
each_index do |ei|
|
302
|
-
break if ei >= size - 3 # 2nd last paragraph or later.
|
303
|
-
next if !index_para?(ei,
|
304
|
-
ar1st =
|
305
|
-
ar2nd = ((ei==0) ? nil :
|
306
|
-
do_merge = yield(ar1st, ar2nd,
|
378
|
+
@array.each_index do |ei|
|
379
|
+
break if ei >= @array.size - 3 # 2nd last paragraph or later.
|
380
|
+
next if !index_para?(ei, accept_negative: false)
|
381
|
+
ar1st = @array[ei..ei+2]
|
382
|
+
ar2nd = ((ei==0) ? nil : @array[ei-1])
|
383
|
+
do_merge = yield(ar1st, ar2nd, @array[ei+3], ei)
|
307
384
|
return false if do_merge == :abort
|
308
385
|
arind2del.push ei, ei+1, ei+2 if do_merge
|
309
386
|
end
|
@@ -332,11 +409,9 @@ module PlainText
|
|
332
409
|
# @return [self, nil] nil if nothing is merged (because of wrong indices).
|
333
410
|
def merge_para!(*rest, use_para_index: false)
|
334
411
|
$myd = true
|
335
|
-
#warn "DEBUG:m00: #{rest}\n"
|
336
412
|
(ranchk = build_index_range_for_merge_para!(*rest, use_para_index: use_para_index)) || (return self) # Do nothing.
|
337
413
|
# ranchk is guaranteed to have a size of 2 or greater.
|
338
|
-
#
|
339
|
-
self[ranchk] = [self[ranchk].to_a[0..-2].join, self[ranchk.end]] # 2-elements (Para, Boundary)
|
414
|
+
@array[ranchk] = [Paragraph.new(@array[ranchk][0..-2].join), @array[ranchk.end]] # Array[Range] replaced with 2-elements (Para, Boundary)
|
340
415
|
self
|
341
416
|
end
|
342
417
|
|
@@ -351,13 +426,10 @@ $myd = true
|
|
351
426
|
# @param use_para_index [Boolean] false
|
352
427
|
# @return [Range, nil] nil if no range is selected.
|
353
428
|
def build_index_range_for_merge_para!(*rest, use_para_index: false)
|
354
|
-
#warn "DEBUG:b0: #{rest.inspect} to_a=#{to_a}\n"
|
355
429
|
inary = rest.flatten
|
356
430
|
return nil if inary.empty?
|
357
431
|
# inary = inary[0] if like_range?(inary[0])
|
358
|
-
#
|
359
|
-
(ary = to_ary_positive_index(inary, to_a)) || return # Guaranteed to be an array of positive indices (sorted and uniq-ed).
|
360
|
-
#warn "DEBUG:b3: #{ary}\n"
|
432
|
+
(ary = to_ary_positive_index(inary, @array)) || return # Guaranteed to be an array of positive indices (sorted and uniq-ed).
|
361
433
|
return nil if ary.empty?
|
362
434
|
|
363
435
|
# Normalize so the array contains both Paragraph and Boundaries in between.
|
@@ -367,7 +439,7 @@ $myd = true
|
|
367
439
|
# of elements, ending with Boundary.
|
368
440
|
if use_para_index
|
369
441
|
ary = ary.map{|i| [i*2, i*2+1]}.flatten
|
370
|
-
elsif index_para?(ary[-1],
|
442
|
+
elsif index_para?(ary[-1], accept_negative: false)
|
371
443
|
# The last index in the given Array or Range was for Paragraph (Likely case).
|
372
444
|
ary.push(ary[-1]+1)
|
373
445
|
end
|
@@ -377,7 +449,7 @@ $myd = true
|
|
377
449
|
|
378
450
|
$myd = false
|
379
451
|
# Exception if the first index is for Boundary and no Paragraph.
|
380
|
-
raise ArgumentError, "The first index (#{ary[0]}) is not for Paragraph." if !index_para?(ary[0],
|
452
|
+
raise ArgumentError, "The first index (#{ary[0]}) is not for Paragraph." if !index_para?(ary[0], accept_negative: false)
|
381
453
|
|
382
454
|
i_end = [ary[-1], size-1].min
|
383
455
|
return if i_end - ary[0] < 3 # No more than 1 para selected.
|
@@ -399,22 +471,22 @@ $myd = false
|
|
399
471
|
# @return [self]
|
400
472
|
def normalize!(recursive: true, ignore_array_boundary: true, compact: true, compacter: true)
|
401
473
|
# Trim pairs of consecutive Paragraph and Boundary of nil
|
402
|
-
size_parity = (size.even? ? 0 : 1)
|
403
|
-
if (compact || compacter) && (size > 0+size_parity)
|
404
|
-
((size-2-size_parity)..0).each do |i|
|
474
|
+
size_parity = (@array.size.even? ? 0 : 1)
|
475
|
+
if (@array.compact || compacter) && (@array.size > 0+size_parity)
|
476
|
+
((@array.size-2-size_parity)..0).each do |i|
|
405
477
|
# Loop over every Paragraph
|
406
478
|
next if i.odd?
|
407
|
-
slice! i, 2 if compact
|
408
|
-
slice! i, 2 if compacter
|
479
|
+
@array.slice! i, 2 if @array.compact && !@array[i] && !@array[i+1]
|
480
|
+
@array.slice! i, 2 if compacter && (!@array[i] || @array[i].empty?) && (!@array[i+1] || @array[i+1].empty?)
|
409
481
|
end
|
410
482
|
end
|
411
483
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
normalize_core(ea,
|
484
|
+
@array.map!.with_index{ |ea, ind|
|
485
|
+
ax = normalize_core(ea, ind, recursive: recursive)
|
486
|
+
ax
|
487
|
+
#normalize_core(ea, ind, recursive: recursive)
|
416
488
|
}
|
417
|
-
|
489
|
+
@array.insert(@array.size, Boundary.new('')) if @array.size.odd?
|
418
490
|
self
|
419
491
|
end
|
420
492
|
|
@@ -428,14 +500,14 @@ $myd = false
|
|
428
500
|
# @see #normalize!
|
429
501
|
def normalize(recursive: true, ignore_array_boundary: true, compact: true, compacter: true)
|
430
502
|
# Trims pairs of consecutive Paragraph and Boundary of nil
|
431
|
-
arall =
|
432
|
-
size_parity = (size.even? ? 0 : 1)
|
433
|
-
if (compact || compacter) && (size > 0+size_parity)
|
434
|
-
((size-2-size_parity)..0).each do |i|
|
503
|
+
arall = @array
|
504
|
+
size_parity = (@array.size.even? ? 0 : 1)
|
505
|
+
if (@array.compact || compacter) && (@array.size > 0+size_parity)
|
506
|
+
((@array.size-2-size_parity)..0).each do |i|
|
435
507
|
# Loop over every Paragraph
|
436
508
|
next if i.odd?
|
437
|
-
arall.slice! i, 2 if compact &&
|
438
|
-
arall.slice! i, 2 if compacter && (
|
509
|
+
arall.slice! i, 2 if compact && !@array[i] && !@array[i+1]
|
510
|
+
arall.slice! i, 2 if compacter && (!@array[i] || @array[i].empty?) && (!@array[i+1] || @array[i+1].empty?)
|
439
511
|
end
|
440
512
|
end
|
441
513
|
|
@@ -454,7 +526,7 @@ $myd = false
|
|
454
526
|
# @return [Array<Part, Paragraph>]
|
455
527
|
# @see #boundaries
|
456
528
|
def paras
|
457
|
-
select.with_index { |_, i| i.even? } rescue select.each_with_index { |_, i| i.even? } # Rescue for Ruby 2.1 or earlier
|
529
|
+
@array.select.with_index { |_, i| i.even? } rescue @array.select.each_with_index { |_, i| i.even? } # Rescue for Ruby 2.1 or earlier
|
458
530
|
# ret.freeze
|
459
531
|
end
|
460
532
|
|
@@ -465,7 +537,7 @@ $myd = false
|
|
465
537
|
# @option range [Range, nil] Range of indices of self to reparse. In Default, the entire self.
|
466
538
|
# @return [self]
|
467
539
|
def reparse!(rule: PlainText::ParseRule::RuleConsecutiveLbs, name: nil, range: (0..-1))
|
468
|
-
insert range.begin, self.class.parse((range ?
|
540
|
+
insert range.begin, self.class.parse((range ? @array[range] : self), rule: rule, name: name)
|
469
541
|
self
|
470
542
|
end
|
471
543
|
|
@@ -474,7 +546,7 @@ $myd = false
|
|
474
546
|
# @param (see #reparse!)
|
475
547
|
# @return [PlainText::Part]
|
476
548
|
def reparse(**kwd)
|
477
|
-
ret =
|
549
|
+
ret = @array.dup
|
478
550
|
ret.reparse!(**kwd)
|
479
551
|
ret
|
480
552
|
end
|
@@ -488,17 +560,17 @@ $myd = false
|
|
488
560
|
# @return [Boundary, nil] nil if a too large index is specified.
|
489
561
|
def squash_boundary_at!(index)
|
490
562
|
(i_pos = get_valid_ipos_for_boundary(index)) || return
|
491
|
-
prt =
|
563
|
+
prt = @array[i_pos-1]
|
492
564
|
m = :emptify_last_boundary!
|
493
|
-
|
494
|
-
|
565
|
+
@array[i_pos] << prt.public_send(m) if prt.respond_to? m
|
566
|
+
@array[i_pos]
|
495
567
|
end
|
496
568
|
|
497
569
|
|
498
570
|
# Wrapper of {#squash_boundary_at!} to loop over the whole {Part}
|
499
571
|
#
|
500
572
|
# @return [self]
|
501
|
-
def
|
573
|
+
def squash_boundaries!
|
502
574
|
each_boundary_with_index do |ec, i|
|
503
575
|
squash_boundary_at!(i)
|
504
576
|
end
|
@@ -506,70 +578,37 @@ $myd = false
|
|
506
578
|
end
|
507
579
|
|
508
580
|
|
509
|
-
# Boundary sub-class name only
|
510
|
-
#
|
511
|
-
# Make sure your class is a child class of Part
|
512
|
-
# Otherwise this method would not be inherited, obviously.
|
513
|
-
#
|
514
|
-
# @example
|
515
|
-
# class PlainText::Part
|
516
|
-
# class Section < self
|
517
|
-
# class Subsection < self; end # It must be a child class!
|
518
|
-
# end
|
519
|
-
# end
|
520
|
-
# ss = PlainText::Part::Section::Subsection.new ["abc"]
|
521
|
-
# ss.subclass_name # => "Section::Subsection"
|
522
|
-
#
|
523
|
-
# @return [String]
|
524
|
-
# @see PlainText::Part#subclass_name
|
525
|
-
def subclass_name
|
526
|
-
printf "__method__=(%s)\n", __method__
|
527
|
-
self.class.name.split(/\A#{Regexp.quote method(__method__).owner.name}::/)[1] || ''
|
528
|
-
end
|
529
|
-
|
530
581
|
##########
|
531
582
|
# Overwriting instance methods of the parent Object or Array class
|
532
583
|
##########
|
533
584
|
|
534
|
-
|
535
|
-
hsmethod = {
|
536
|
-
:equal_original_b4_part => :==,
|
537
|
-
:substitute_original_b4_part => :[]=,
|
538
|
-
:insert_original_b4_part => :insert,
|
539
|
-
:delete_at_original_b4_part => :delete_at,
|
540
|
-
:slice_original_b4_part => :slice,
|
541
|
-
:slice_original_b4_part! => :slice!,
|
542
|
-
}
|
585
|
+
########## Most basic methods (Object/BasicObject) ##########
|
543
586
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
warn sprintf("WARNING: Method %s#%s has been already defined, which should not be. Contact the code developer. Line %d in %s%s", self.name, k.to_s, __FILE__, __LINE__, ($DEBUG ? "\n"+caller_locations.join("\n").map{|i| " "+i} : ""))
|
548
|
-
else
|
549
|
-
alias_method k, ea_orig
|
550
|
-
end
|
587
|
+
# @return [String]
|
588
|
+
def inspect
|
589
|
+
self.class.name + @array.inspect
|
551
590
|
end
|
552
591
|
|
553
|
-
|
554
|
-
|
555
|
-
|
592
|
+
# @return [Array]
|
593
|
+
def to_a
|
594
|
+
@array
|
595
|
+
end
|
596
|
+
alias_method :to_ary, :to_a
|
597
|
+
alias_method :instance, :to_a if ! self.method_defined?(:instance)
|
556
598
|
|
557
|
-
# @
|
558
|
-
|
559
|
-
|
599
|
+
# Work around because Object#dup does not dup the instance variable @array
|
600
|
+
#
|
601
|
+
# @return [PlainText::Part]
|
602
|
+
def dup
|
603
|
+
dup_or_clone(super, __method__, '@array') # defined in builtin_type.rb
|
560
604
|
end
|
561
605
|
|
562
|
-
# # clone
|
563
|
-
#
|
564
|
-
#
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
# copied = super
|
569
|
-
# val = (@sep.clone rescue @sep) # rescue in case of immutable.
|
570
|
-
# copied.instance_eval{ @sep = val }
|
571
|
-
# copied
|
572
|
-
# end
|
606
|
+
# Work around because Object#clone does not clone the instance variable @array
|
607
|
+
#
|
608
|
+
# @return [PlainText::Part]
|
609
|
+
def clone
|
610
|
+
dup_or_clone(super, __method__, '@array') # defined in builtin_type.rb
|
611
|
+
end
|
573
612
|
|
574
613
|
# Equal operator
|
575
614
|
#
|
@@ -579,44 +618,23 @@ $myd = false
|
|
579
618
|
#
|
580
619
|
# @param other [Object]
|
581
620
|
def ==(other)
|
582
|
-
return false if
|
621
|
+
return false if !other.respond_to?(:to_ary) || !other.respond_to?(:normalize!)
|
583
622
|
%i(paras boundaries).each do |ea_m| # %i(...) defined in Ruby 2.0 and later
|
584
|
-
return false if !other.
|
623
|
+
return false if !other.respond_to?(ea_m) || (self.public_send(ea_m) != other.public_send(ea_m)) # public_send() defined in Ruby 2.0 (1.9?) and later
|
585
624
|
end
|
586
|
-
|
625
|
+
@array == other.to_a # or you may just return true?
|
587
626
|
end
|
588
627
|
|
589
628
|
|
590
|
-
# # Multiplication operator
|
591
|
-
# #
|
592
|
-
# # @param other [Integer, String]
|
593
|
-
# # @return as self
|
594
|
-
# def *(other)
|
595
|
-
# super
|
596
|
-
# end
|
597
|
-
|
598
|
-
|
599
629
|
# Plus operator
|
600
630
|
#
|
601
631
|
# @param other [Object]
|
602
632
|
# @return as self
|
603
633
|
def +(other)
|
604
|
-
# ## The following is strict, but a bit redundant.
|
605
|
-
# # is_para = true # Whether "other" is a Part class instance.
|
606
|
-
# # %i(to_ary paras boundaries).each do |ea_m| # %i(...) defined in Ruby 2.0 and later
|
607
|
-
# # is_para &&= other.class.method_defined?(ea_m)
|
608
|
-
# # end
|
609
|
-
|
610
|
-
# begin
|
611
|
-
# other_even_odd =
|
612
|
-
# ([other.paras, other.boundaries] rescue even_odd_arrays(self, size_even: true, filler: ""))
|
613
|
-
# rescue NoMethodError
|
614
|
-
# raise TypeError, sprintf("no implicit conversion of %s into %s", other.class.name, self.class.name)
|
615
|
-
# end
|
616
|
-
|
617
634
|
# # eg., if self is PlainText::Part::Section, the returned object is the same.
|
618
635
|
# ret = self.class.new(self.paras+other_even_odd[0], self.boundaries+other_even_odd[1])
|
619
|
-
|
636
|
+
raise(TypeError, "cannot operate with no #{self.class.name} instance (#{other.class.name})") if (!other.respond_to?(:to_ary) && !other.respond_to?(:normalize!))
|
637
|
+
ret = self.class.new(@array+other.to_ary)
|
620
638
|
ret.normalize!
|
621
639
|
end
|
622
640
|
|
@@ -626,17 +644,43 @@ $myd = false
|
|
626
644
|
# @param other [Object]
|
627
645
|
# @return as self
|
628
646
|
def -(other)
|
629
|
-
|
647
|
+
raise ArgumentError, "cannot operate with no {self.class.name} instance" if !other.respond_to?(:to_ary) || !other.respond_to?(:normalize!)
|
648
|
+
ret = self.class.new(@array+other.to_ary)
|
630
649
|
ret.normalize!
|
631
650
|
end
|
632
651
|
|
633
|
-
# Array
|
634
|
-
#
|
635
|
-
|
652
|
+
# if the Array method returns an Array, returns this class instance.
|
653
|
+
#
|
654
|
+
# Note that even the value is this-class instance, a new instance is created
|
655
|
+
# in default unless it is +eql?(self)+.
|
656
|
+
#
|
657
|
+
# @param obj [Object] the value to be evaluated.
|
658
|
+
# @return [Object]
|
659
|
+
# @yield [] the returned value is evaluated, if no argument is given
|
660
|
+
# @yieldreturn [Object] Either this-class instance or Object
|
661
|
+
def _return_this_or_other(obj=nil)
|
662
|
+
ret = (block_given? ? yield : obj)
|
663
|
+
(ret.respond_to?(:to_ary) && !ret.eql?(self)) ? self.class.new(ret) : ret
|
664
|
+
end
|
665
|
+
private :_return_this_or_other
|
636
666
|
|
637
|
-
#
|
638
|
-
#
|
639
|
-
|
667
|
+
# Basically delegates everything to Array
|
668
|
+
#
|
669
|
+
# Array#<< and Array#delete_at are undefined
|
670
|
+
# because the instances of this class must take always an even number of elements.
|
671
|
+
def method_missing(method_name, *args, **kwds)
|
672
|
+
if DISABLED_ARRAY_METHODS.include? method_name
|
673
|
+
raise NoMethodError, "no method "+method_name.to_s
|
674
|
+
end
|
675
|
+
_return_this_or_other{
|
676
|
+
@array.public_send(method_name, *args, **kwds)
|
677
|
+
}
|
678
|
+
end
|
679
|
+
|
680
|
+
# Redefines the behaviour of +respond_to?+ (essential when defining +method_missing+)
|
681
|
+
def respond_to_missing?(method_name, *rest) # include_all=false
|
682
|
+
!DISABLED_ARRAY_METHODS.include?(method_name) && @array.respond_to?(method_name, *rest) || super
|
683
|
+
end
|
640
684
|
|
641
685
|
# Returns a partial Part-Array (or Object, if a single Integer is specified)
|
642
686
|
#
|
@@ -649,7 +693,7 @@ $myd = false
|
|
649
693
|
# @return [Object]
|
650
694
|
def [](arg1, *rest)
|
651
695
|
arg2 = rest[0]
|
652
|
-
return
|
696
|
+
return @array[arg1] if !arg2 && !arg1.respond_to?(:exclude_end?)
|
653
697
|
|
654
698
|
check_bracket_args_type_error(arg1, arg2) # Args are now either (Int, Int) or (Range)
|
655
699
|
|
@@ -657,11 +701,13 @@ $myd = false
|
|
657
701
|
size2ret = size2extract(arg1, arg2, ignore_error: true) # maybe nil (if the index is too small).
|
658
702
|
raise ArgumentError, ERR_MSGS[:even_num]+" "+ERR_MSGS[:use_to_a] if size2ret.odd?
|
659
703
|
begin
|
660
|
-
raise ArgumentError, "odd index is not allowed as the starting index for #{self.class.name}. It must be even. "+ERR_MSGS[:use_to_a] if positive_array_index_checked(arg1,
|
704
|
+
raise ArgumentError, "odd index is not allowed as the starting index for #{self.class.name}. It must be even. "+ERR_MSGS[:use_to_a] if positive_array_index_checked(arg1, @array).odd?
|
661
705
|
rescue TypeError, IndexError
|
662
706
|
# handled by super
|
663
707
|
end
|
664
|
-
return
|
708
|
+
return _return_this_or_other{
|
709
|
+
@array[arg1, arg2]
|
710
|
+
}
|
665
711
|
end
|
666
712
|
|
667
713
|
begin
|
@@ -675,13 +721,17 @@ $myd = false
|
|
675
721
|
|
676
722
|
# The end is smaller than the begin in the positive index. Empty instance of this class is returned.
|
677
723
|
if rang.end < rang.begin
|
678
|
-
return
|
724
|
+
return _return_this_or_other{
|
725
|
+
@array[arg1, *rest]
|
726
|
+
}
|
679
727
|
end
|
680
728
|
|
681
729
|
raise RangeError, "odd index is not allowed as the starting Range for #{sefl.class.name}. It must be even. "+ERR_MSGS[:use_to_a] if rang.begin.odd?
|
682
730
|
size2ret = size2extract(rang, skip_renormalize: true)
|
683
731
|
raise ArgumentError, ERR_MSGS[:even_num]+" "+ERR_MSGS[:use_to_a] if size2ret.odd?
|
684
|
-
|
732
|
+
_return_this_or_other{
|
733
|
+
@array[arg1, *rest]
|
734
|
+
}
|
685
735
|
end
|
686
736
|
|
687
737
|
|
@@ -698,17 +748,23 @@ $myd = false
|
|
698
748
|
end
|
699
749
|
|
700
750
|
# Simple substitution to a single element
|
701
|
-
|
751
|
+
if !arg2 && !arg1.respond_to?(:exclude_end?)
|
752
|
+
return _return_this_or_other{
|
753
|
+
@array[arg1] = val
|
754
|
+
}
|
755
|
+
end
|
702
756
|
|
703
757
|
check_bracket_args_type_error(arg1, arg2) # Args are now either (Int, Int) or (Range)
|
704
758
|
|
705
|
-
# raise TypeError, "object to replace must be Array type with an even number of elements." if !val.
|
759
|
+
# raise TypeError, "object to replace must be Array type with an even number of elements." if !val.respond_to?(:to_ary) || val.size.odd?
|
706
760
|
|
707
761
|
vals = (val.to_ary rescue [val])
|
708
762
|
if arg2
|
709
763
|
size2delete = size2extract(arg1, arg2, ignore_error: true) # maybe nil (if the index is too small).
|
710
764
|
raise ArgumentError, "odd-even parity of size of array to replace must be identical to that to slice." if size2delete && ((size2delete % 2) != (vals.size % 2))
|
711
|
-
return
|
765
|
+
return _return_this_or_other{
|
766
|
+
@array[arg1] = val
|
767
|
+
}
|
712
768
|
end
|
713
769
|
|
714
770
|
begin
|
@@ -727,41 +783,53 @@ $myd = false
|
|
727
783
|
|
728
784
|
size2delete = size2extract(rang, skip_renormalize: true)
|
729
785
|
raise ArgumentError, "odd-even parity of size of array to replace must be identical to that to slice." if size2delete && ((size2delete % 2) != (vals.size % 2))
|
730
|
-
|
786
|
+
@array[arg1] = val
|
731
787
|
|
732
788
|
# The result may not be in an even number anymore. Correct it.
|
733
|
-
Boundary.
|
789
|
+
Boundary.insert(@array.size, "") if @array.size.odd? ############## is it correct???
|
734
790
|
|
735
791
|
# Original method may fill some elements of the array with String or even nil.
|
736
792
|
normalize!
|
737
|
-
ret
|
738
793
|
end
|
739
794
|
|
740
795
|
# Array#insert
|
741
796
|
#
|
742
797
|
# The most basic method to add/insert elements to self. Called from {#[]=} and {#push}, for example.
|
743
798
|
#
|
744
|
-
#
|
799
|
+
# The maximum permitted position index is the size of self,s
|
800
|
+
# unlike +Array#insert+, which allows an index larger than the size,
|
801
|
+
# in which case +nil+ is inserted in between.
|
802
|
+
#
|
803
|
+
# The number of the inserted elements must be always even.
|
745
804
|
#
|
746
|
-
# @param ind [Index]
|
747
|
-
# @param rest [Array] This must have an even number of arguments
|
748
|
-
# @option primitive: [
|
805
|
+
# @param ind [Index] +rest+ is inserted *before* +ind+ if non-negative and *after* if negative.
|
806
|
+
# @param rest [Array] This must have an even number of arguments.
|
807
|
+
# @option primitive: [Boolean] if true (Def: false), no wrapper action is performed.
|
749
808
|
# @return [self]
|
750
809
|
def insert(ind, *rest, primitive: false)
|
751
|
-
return insert_original_b4_part(ind, *rest) if primitive
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
810
|
+
#return insert_original_b4_part(ind, *rest) if primitive
|
811
|
+
return _return_this_or_other(@array.insert(ind, *rest)) if primitive
|
812
|
+
|
813
|
+
ipos = positive_array_index_checked(ind, @array) # IndexError may be raised.
|
814
|
+
ipos += 1 if ind < 0
|
815
|
+
# If ipos is negative, it should be inserted AFTER the index according to Array#index,
|
816
|
+
# whereas if ipos is non-negative, inserted BEFORE.
|
817
|
+
|
818
|
+
if ipos > @array.size
|
819
|
+
raise IndexError, sprintf("index (%s) too large for array: maximum: %d.", ipos, @array.size)
|
820
|
+
elsif rest.size.odd?
|
756
821
|
raise ArgumentError, sprintf("number of arguments (%d) must be even.", rest.size)
|
757
822
|
end
|
758
823
|
|
759
|
-
|
760
|
-
rest = Array.new(ipos - size).map{|i| ""} + rest
|
761
|
-
ipos = size
|
762
|
-
end
|
824
|
+
return self if rest.empty?
|
763
825
|
|
764
|
-
|
826
|
+
begin
|
827
|
+
_return_this_or_other{
|
828
|
+
@array.insert(ipos, *rest) && normalize! && self
|
829
|
+
}
|
830
|
+
rescue PlainText::PartNormalizeError => err
|
831
|
+
raise TypeError, err.message
|
832
|
+
end
|
765
833
|
end
|
766
834
|
|
767
835
|
|
@@ -771,24 +839,24 @@ $myd = false
|
|
771
839
|
#
|
772
840
|
# @param arg1 [Integer, Range]
|
773
841
|
# @option arg2 [Integer, NilClass]
|
774
|
-
# @option primitive: [Boolean] if true (Def: false),
|
842
|
+
# @option primitive: [Boolean] if true (Def: false), no wrapper action is performed.
|
775
843
|
# @return as self or NilClass
|
776
844
|
def slice!(arg1, *rest, primitive: false)
|
777
|
-
return slice_original_b4_part!(arg1, *rest) if primitive
|
845
|
+
#return slice_original_b4_part!(arg1, *rest) if primitive
|
846
|
+
return _return_this_or_other(@array.slice(ind, *rest)) if primitive
|
778
847
|
|
779
848
|
arg2 = rest[0]
|
780
849
|
|
781
850
|
# Simple substitution to a single element
|
782
|
-
raise ArgumentError, ERR_MSGS[:even_num] if !arg2 && !arg1.
|
851
|
+
raise ArgumentError, ERR_MSGS[:even_num] if !arg2 && !arg1.respond_to?(:exclude_end?)
|
783
852
|
|
784
853
|
check_bracket_args_type_error(arg1, arg2) # Args are now either (Int, Int) or (Range)
|
785
854
|
|
786
855
|
if arg2
|
787
856
|
size2delete = size2extract(arg1, arg2, ignore_error: true) # maybe nil (if the index is too small).
|
788
|
-
# raise ArgumentError, ERR_MSGS[:even_num] if arg2.to_int.odd?
|
789
857
|
raise ArgumentError, ERR_MSGS[:even_num] if size2delete && size2delete.odd?
|
790
858
|
raise ArgumentError, "odd index is not allowed as the starting Range for #{self.class.name}. It must be even." if arg1.odd? # Because the returned value is this class of instance.
|
791
|
-
return
|
859
|
+
return _return_this_or_other(@array.slice!(arg1, *rest))
|
792
860
|
end
|
793
861
|
|
794
862
|
begin
|
@@ -799,12 +867,13 @@ $myd = false
|
|
799
867
|
|
800
868
|
raise RangeError if rang.begin < 0 || rang.end < 0
|
801
869
|
|
802
|
-
return
|
870
|
+
return _return_this_or_other(@array.slice!(arg1, *rest)) if (rang.begin > rang.end) # nil or [] is returned
|
871
|
+
|
803
872
|
|
804
873
|
size2delete = size2extract(rang, skip_renormalize: true)
|
805
874
|
raise ArgumentError, ERR_MSGS[:even_num] if size2delete && size2delete.odd?
|
806
875
|
raise ArgumentError, "odd index is not allowed as the starting Range for #{self.class.name}. It must be even." if rang.begin.odd? # Because the returned value is this class of instance.
|
807
|
-
|
876
|
+
_return_this_or_other(@array.slice!(arg1, *rest))
|
808
877
|
end
|
809
878
|
|
810
879
|
|
@@ -816,8 +885,8 @@ $myd = false
|
|
816
885
|
#
|
817
886
|
# @return [self, NilClass]
|
818
887
|
def compact!
|
819
|
-
ret =
|
820
|
-
ret ?
|
888
|
+
ret = @array.send(__method__)
|
889
|
+
ret ? normalize!(recursive: false) : ret
|
821
890
|
end
|
822
891
|
|
823
892
|
# Array#concat
|
@@ -827,7 +896,7 @@ $myd = false
|
|
827
896
|
# @param rest [Array<Array>]
|
828
897
|
# @return [self]
|
829
898
|
def concat(*rest)
|
830
|
-
insert(size, *(rest.sum([])))
|
899
|
+
insert(@array.size, *(rest.sum([])))
|
831
900
|
end
|
832
901
|
|
833
902
|
# Array#push
|
@@ -863,9 +932,9 @@ $myd = false
|
|
863
932
|
# @raise [TypeError] if not conforms.
|
864
933
|
def check_bracket_args_type_error(arg1, arg2=nil)
|
865
934
|
if arg2
|
866
|
-
raise TypeError, sprintf("no implicit conversion of #{arg2.class} into Integer") if !arg2.
|
935
|
+
raise TypeError, sprintf("no implicit conversion of #{arg2.class} into Integer") if !arg2.respond_to?(:to_int)
|
867
936
|
else
|
868
|
-
raise TypeError if !arg1.
|
937
|
+
raise TypeError if !arg1.respond_to?(:exclude_end?)
|
869
938
|
end
|
870
939
|
end
|
871
940
|
private :check_bracket_args_type_error
|
@@ -875,11 +944,11 @@ $myd = false
|
|
875
944
|
#
|
876
945
|
# @return [Boundary] all the descendants' last Boundaries merged.
|
877
946
|
def emptify_last_boundary!
|
878
|
-
return Boundary::Empty.dup if size == 0
|
947
|
+
return Boundary::Empty.dup if @array.size == 0
|
879
948
|
ret = ""
|
880
|
-
ret << prt.public_send(__method__) if prt.
|
881
|
-
ret <<
|
882
|
-
|
949
|
+
ret << prt.public_send(__method__) if prt.respond_to? __method__
|
950
|
+
ret << @array[-1]
|
951
|
+
@array[-1] = Boundary::Empty.dup
|
883
952
|
ret
|
884
953
|
end
|
885
954
|
private :emptify_last_boundary!
|
@@ -890,8 +959,8 @@ $myd = false
|
|
890
959
|
# @param index [Integer]
|
891
960
|
# @return [Integer, nil] nil if a too large index is specified.
|
892
961
|
def get_valid_ipos_for_boundary(index)
|
893
|
-
i_pos = positive_array_index_checked(index,
|
894
|
-
raise ArgumentError, "Index #{index} specified was for Para, which should be for Boundary." if index_para?(i_pos,
|
962
|
+
i_pos = positive_array_index_checked(index, @array)
|
963
|
+
raise ArgumentError, "Index #{index} specified was for Para, which should be for Boundary." if index_para?(i_pos, accept_negative: false)
|
895
964
|
(i_pos > size - 1) ? nil : i_pos
|
896
965
|
end
|
897
966
|
private :get_valid_ipos_for_boundary
|
@@ -899,44 +968,44 @@ $myd = false
|
|
899
968
|
|
900
969
|
# Core routine for {#map_boundary} and similar.
|
901
970
|
#
|
902
|
-
# @option
|
971
|
+
# @option do_map opts: [Boolean] if true (Default), map is performed. Else just each.
|
903
972
|
# @option with_index: [Boolean] if true (Default: false), yield with also index
|
904
973
|
# @option recursive: [Boolean] if true (Default), map is performed recursively.
|
905
974
|
# @return as self if map: is true, else void
|
906
|
-
def map_boundary_core(
|
975
|
+
def map_boundary_core(do_map: true, with_index: false, recursive: true, **kwd, &bl)
|
907
976
|
ind = -1
|
908
|
-
arnew = map{ |ec|
|
977
|
+
arnew = @array.map{ |ec|
|
909
978
|
ind += 1
|
910
|
-
if recursive && index_para?(ind,
|
979
|
+
if recursive && index_para?(ind, accept_negative: false) && ec.respond_to?(__method__)
|
911
980
|
ec.public_send(__method__, recursive: true, **kwd, &bl)
|
912
|
-
elsif !index_para?(ind,
|
981
|
+
elsif !index_para?(ind, accept_negative: false)
|
913
982
|
with_index ? yield(ec, ind) : yield(ec)
|
914
983
|
else
|
915
984
|
ec
|
916
985
|
end
|
917
986
|
}
|
918
|
-
self.class.new arnew, recursive: recursive, **kwd if
|
987
|
+
self.class.new arnew, recursive: recursive, **kwd if do_map
|
919
988
|
end
|
920
989
|
private :map_boundary_core
|
921
990
|
|
922
991
|
# Core routine for {#map_para}
|
923
992
|
#
|
924
|
-
# @option
|
993
|
+
# @option do_map: [Boolean] if true (Default), map is performed. Else just each.
|
925
994
|
# @option with_index: [Boolean] if true (Default: false), yield with also index
|
926
995
|
# @option recursive: [Boolean] if true (Default), map is performed recursively.
|
927
996
|
# @return as self
|
928
997
|
# @see #initialize for the other options (:compact and :compacter)
|
929
|
-
def map_para_core(
|
998
|
+
def map_para_core(do_map: true, with_index: false, recursive: true, **kwd, &bl)
|
930
999
|
ind = -1
|
931
1000
|
new_paras = paras.map{ |ec|
|
932
1001
|
ind += 1
|
933
|
-
if recursive && ec.
|
1002
|
+
if recursive && ec.respond_to?(__method__)
|
934
1003
|
ec.public_send(__method__, recursive: true, **kwd, &bl)
|
935
1004
|
else
|
936
1005
|
with_index ? yield(ec, ind) : yield(ec)
|
937
1006
|
end
|
938
1007
|
}
|
939
|
-
self.class.new new_paras, boundaries, recursive: recursive, **kwd if
|
1008
|
+
self.class.new new_paras, boundaries, recursive: recursive, **kwd if do_map
|
940
1009
|
end
|
941
1010
|
private :map_para_core
|
942
1011
|
|
@@ -948,18 +1017,25 @@ $myd = false
|
|
948
1017
|
# @option ignore_array_boundary: [Boolean] if true (Default), even if a Boundary element (odd-numbered index) is an Array, ignore it.
|
949
1018
|
# @return [Part, Paragraph, Boundary]
|
950
1019
|
def normalize_core(ea, i, recursive: true, ignore_array_boundary: true)
|
951
|
-
if ea.
|
952
|
-
if index_para?(i,
|
1020
|
+
if ea.respond_to?(:to_ary)
|
1021
|
+
if index_para?(i, accept_negative: false) || ignore_array_boundary
|
953
1022
|
(/\APlainText::/ =~ ea.class.name && defined?(ea.normalize)) ? (recursive ? ea.normalize : ea) : self.class.new(ea, recursive: recursive)
|
954
1023
|
else
|
955
|
-
raise "
|
1024
|
+
raise "Element at index ({#i}) is a Part or Array, but it should be Boundary or String."
|
1025
|
+
end
|
1026
|
+
elsif ea.respond_to?(:to_str)
|
1027
|
+
if i.even? && self.class.boundary?(ea)
|
1028
|
+
msg = "not be Boundary"
|
1029
|
+
elsif i.odd? && self.class.paragraph?(ea)
|
1030
|
+
msg = "be neither Part nor Paragraph"
|
956
1031
|
end
|
957
|
-
|
1032
|
+
raise PlainText::PartNormalizeError, sprintf("Element at index=(%d) must %s", i, msg) if msg
|
1033
|
+
|
958
1034
|
if /\APlainText::/ =~ ea.class.name
|
959
1035
|
# Paragraph or Boundary
|
960
|
-
ea.unicode_normalize
|
1036
|
+
ea.unicode_normalize # Unicode-normalized new object
|
961
1037
|
else
|
962
|
-
if index_para?(i,
|
1038
|
+
if index_para?(i, accept_negative: false)
|
963
1039
|
Paragraph.new(ea.unicode_normalize || "")
|
964
1040
|
else
|
965
1041
|
Boundary.new( ea.unicode_normalize || "")
|
@@ -979,7 +1055,7 @@ $myd = false
|
|
979
1055
|
# @raise [IndexError] if too negative index is specified.
|
980
1056
|
def normalize_index_range(rng, **kwd)
|
981
1057
|
# NOTE to developers: (0..-1).to_a returns [] (!)
|
982
|
-
arpair = [rng.begin, rng.end].to_a.map{ |i| positive_array_index_checked(i,
|
1058
|
+
arpair = [rng.begin, rng.end].to_a.map{ |i| positive_array_index_checked(i, @array, **kwd) }
|
983
1059
|
arpair[1] -= 1 if rng.exclude_end?
|
984
1060
|
(arpair[0]..arpair[1])
|
985
1061
|
end
|
@@ -1002,11 +1078,11 @@ $myd = false
|
|
1002
1078
|
# @return [Integer, NilClass] nil if an Error is raised with ignore_error being true
|
1003
1079
|
def size2extract(arg1, arg2=nil, ignore_error: false, skip_renormalize: false, **kwd)
|
1004
1080
|
begin
|
1005
|
-
if arg1.
|
1081
|
+
if arg1.respond_to? :exclude_end?
|
1006
1082
|
rng = arg1
|
1007
1083
|
rng = normalize_index_range(rng, **kwd) if !skip_renormalize
|
1008
1084
|
else
|
1009
|
-
ipos = positive_array_index_checked(arg1,
|
1085
|
+
ipos = positive_array_index_checked(arg1, @array)
|
1010
1086
|
rng = (ipos..(ipos+arg2.to_int-1))
|
1011
1087
|
end
|
1012
1088
|
return 0 if rng.begin > size-1
|
@@ -1024,48 +1100,13 @@ $myd = false
|
|
1024
1100
|
end # module PlainText
|
1025
1101
|
|
1026
1102
|
|
1027
|
-
####################################################
|
1028
|
-
# Modifies Array
|
1029
|
-
####################################################
|
1030
|
-
|
1031
|
-
class Array
|
1032
|
-
|
1033
|
-
# Original equal and plus operators of Array
|
1034
|
-
hsmethod = {
|
1035
|
-
:equal_original_b4_part? => :== ,
|
1036
|
-
# :plus_operator_original_b4_part => :+
|
1037
|
-
}
|
1038
|
-
|
1039
|
-
hsmethod.each_pair do |k, ea_orig|
|
1040
|
-
if self.method_defined?(k)
|
1041
|
-
# To Developer: If you see this message, switch the DEBUG flag on (-d option) and run it.
|
1042
|
-
warn sprintf("WARNING: Method %s#%s has been already defined, which should not be. Contact the code developer. Line %d in %s%s", self.name, k.to_s, __FILE__, __LINE__, ($DEBUG ? "\n"+caller_locations.join("\n").map{|i| " "+i} : ""))
|
1043
|
-
else
|
1044
|
-
alias_method k, ea_orig
|
1045
|
-
end
|
1046
|
-
end
|
1047
|
-
|
1048
|
-
# Equal operator modified to deal with {PlainText::Part}
|
1049
|
-
#
|
1050
|
-
# @param other [Object]
|
1051
|
-
def ==(other)
|
1052
|
-
return false if !other.class.method_defined?(:to_ary)
|
1053
|
-
%i(paras boundaries).each do |ea_m| # %i(...) defined in Ruby 2.0 and later
|
1054
|
-
return equal_original_b4_part?(other) if !other.class.method_defined?(ea_m)
|
1055
|
-
return false if !self.class.method_defined?(ea_m) || (self.public_send(ea_m) != other.public_send(ea_m)) # public_send() defined in Ruby 2.0 (1.9?) and later
|
1056
|
-
end
|
1057
|
-
true
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
end
|
1061
|
-
|
1062
1103
|
####################################################
|
1063
1104
|
# require (after the module is defined)
|
1064
1105
|
####################################################
|
1065
1106
|
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1107
|
+
require_relative 'part/paragraph'
|
1108
|
+
require_relative 'part/boundary'
|
1109
|
+
require_relative "parse_rule"
|
1069
1110
|
|
1070
1111
|
#######
|
1071
1112
|
# idea
|