plain_text 0.7 → 0.8
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/.gitignore +1 -0
- data/ChangeLog +16 -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 +15 -11
- data/plain_text.gemspec +2 -2
- data/test/test_plain_text.rb +29 -4
- data/test/test_plain_text_parse_rule.rb +17 -3
- data/test/test_plain_text_part.rb +196 -14
- data/test/test_plain_text_split.rb +17 -2
- data/test/test_plain_text_util.rb +17 -2
- metadata +5 -2
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
|