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/util.rb
CHANGED
@@ -47,8 +47,8 @@ module PlainText
|
|
47
47
|
# @param size_even [Boolean] if true (Def: false), the sizes of the returned arrays are guaranteed to be identical.
|
48
48
|
# @param filler [Object] if size_even: is true and if matching is performed, this filler is added at the end of the last element.
|
49
49
|
def even_odd_arrays(ary, size_even: false, filler: "")
|
50
|
-
ar_even = select.with_index { |_, i| i.even? } rescue select.each_with_index { |_, i| i.even? } # Rescue for Ruby 2.1 or earlier
|
51
|
-
ar_odd = select.with_index { |_, i| i.odd? } rescue select.each_with_index { |_, i| i.odd? } # Rescue for Ruby 2.1 or earlier
|
50
|
+
ar_even = ary.select.with_index { |_, i| i.even? } rescue ary.select.each_with_index { |_, i| i.even? } # Rescue for Ruby 2.1 or earlier
|
51
|
+
ar_odd = ary.select.with_index { |_, i| i.odd? } rescue ary.select.each_with_index { |_, i| i.odd? } # Rescue for Ruby 2.1 or earlier
|
52
52
|
if size_even && (ar_even.size != ar_odd.size)
|
53
53
|
ar_odd.push filler
|
54
54
|
raise "Should not happern." if (ar_even.size != ar_odd.size)
|
@@ -61,14 +61,15 @@ module PlainText
|
|
61
61
|
# If positive or zero, it returns i.
|
62
62
|
# If the negative index is out of range, it returns nil.
|
63
63
|
#
|
64
|
+
# @see #positive_array_index_checked
|
64
65
|
# @param i [Integer]
|
65
|
-
# @param
|
66
|
+
# @param arysize [Array, Integer] Reference Array or its size (Array#size).
|
66
67
|
# @return [Integer, NilClass] nil if out of range to the negative. Note in most cases in Ruby default, it raises IndexError. See the code of {#positive_array_index_checked}
|
67
68
|
# @raise [TypeError] if non-integer is specified.
|
68
|
-
# @raise [ArgumentError] if
|
69
|
-
def positive_array_index(i,
|
70
|
-
arysize = (
|
71
|
-
i2 = i.to_int rescue (raise TypeError, sprintf("no implicit conversion of #{i.class} into Integer (i=#{i.inspect},
|
69
|
+
# @raise [ArgumentError] if arysize is neither an Array nor Integer, or more specifically, it does not have size method or arysize.size does not return Integer or similar.
|
70
|
+
def positive_array_index(i, arysize=nil)
|
71
|
+
arysize = (arysize.respond_to?(:to_int) ? arysize.to_int : arysize.size)
|
72
|
+
i2 = i.to_int rescue (raise TypeError, sprintf("no implicit conversion of #{i.class} into Integer (i=#{i.inspect},arysize=#{arysize.inspect})"))
|
72
73
|
return i2 if i2 >= 0
|
73
74
|
ret = arysize + i2 rescue (raise ArgumentError, "Reference is neither an Array nor Integer.")
|
74
75
|
(ret < 0) ? nil : ret
|
@@ -82,20 +83,20 @@ module PlainText
|
|
82
83
|
# Wrapper for {#positive_array_index}
|
83
84
|
#
|
84
85
|
# @param index_in [Integer] Index to check and convert from. Potentially negative integer.
|
85
|
-
# @param
|
86
|
+
# @param arysize [Array, Integer] Reference Array or its size (Array#size).
|
86
87
|
# @param accept_too_big [Boolean, NilClass] if true (Default), a positive index larger than the last array index is returned as it is. If nil, the last index + 1 is accepted but raises an Exception for anything larger. If false, any index larger than the last index raises an Exception.
|
87
88
|
# @param varname [NilClass, String] Name of the variable (or nil) to be used for error messages.
|
88
89
|
# @return [Integer] Non-negative index; i.e., if index=-1 is specified for an Array with a size of 3, the returned value is 2 (the last index of it).
|
89
90
|
# @raise [IndexError] if the index is out of the range to negative.
|
90
|
-
# @raise [ArgumentError] if
|
91
|
-
def positive_array_index_checked(index_in,
|
92
|
-
# def self.positive_valid_index_for_array(index_in,
|
91
|
+
# @raise [ArgumentError] if arysize is neither an Array nor Integer, or more specifically, it does not have size method or arysize.size does not return Integer or similar.
|
92
|
+
def positive_array_index_checked(index_in, arysize, accept_too_big: true, varname: nil)
|
93
|
+
# def self.positive_valid_index_for_array(index_in, arysize, varname: nil)
|
93
94
|
errmsgs = {}
|
94
95
|
%w(of for).each do |i|
|
95
96
|
errmsgs[i] = (varname ? "." : sprintf(" %s %s.", i, varname))
|
96
97
|
end
|
97
98
|
|
98
|
-
arysize = (
|
99
|
+
arysize = (arysize.respond_to?(:to_int) ? arysize.to_int : arysize.size)
|
99
100
|
index = positive_array_index(index_in, arysize) # guaranteed to be Integer or nil (or ArgumentError)
|
100
101
|
raise IndexError, sprintf("index (%s) too small for array; minimum: -%d", index_in, arysize) if !index # Ruby default Error message (except the variable "index" as opposed to "index_in is used in the true Ruby default).
|
101
102
|
if index_in >= 0
|
data/lib/plain_text.rb
CHANGED
@@ -8,12 +8,17 @@
|
|
8
8
|
# Many of the methods work on tha basis of a line. For example, {#head} and {#tail} methods
|
9
9
|
# work like the respective UNIX-shell commands, returning a specified line at the head/tail parts of self.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
11
|
+
# Many of the methods contained directly in this module are meant to be
|
12
|
+
# included in String. Obviously, though, it is debatable if it is
|
13
|
+
# a good practice to include a third-party module in the core class.
|
14
|
+
#
|
15
|
+
# Several module functions are also available.
|
16
|
+
# This module contains a helper module function {PlainText.extend_this}, with which
|
17
|
+
# an object extends this module easily as Singleton if this module is not already included.
|
14
18
|
#
|
15
19
|
# A few methods in this module assume that {PlainText::Split} is included in String,
|
16
20
|
# which in default is the case, as soon as this file is read (by Ruby's require).
|
21
|
+
# The specification may be subject to change in the future release.
|
17
22
|
#
|
18
23
|
# @author Masa Sakano (Wise Babel Ltd)
|
19
24
|
#
|
@@ -139,7 +144,7 @@ module PlainText
|
|
139
144
|
# @param delete_asian_space [Boolean] Any spaces between, before, after Asian characters (but punctuation) are deleted, if true (Default).
|
140
145
|
# @param linehead_style [Symbol] One of +(:truncate|:delete|:none)+ (Def: :none). Determine how to handle consecutive white spaces at the beggining of each line.
|
141
146
|
# @param linetail_style [Symbol] One of +(:truncate|:delete|:markdown|:none)+ (Def: :delete). Determine how to handle consecutive white spaces at the end of each line. If +:markdown, 1 space is always deleted, and two or more spaces are truncated into two ASCII whitespaces *if* the last two spaces are ASCII whitespaces, or else untouched.
|
142
|
-
# @param firstlbs_style [Symbol, String] One of +(:truncate|:delete|:none)+ or String (Def: :
|
147
|
+
# @param firstlbs_style [Symbol, String] One of +(:truncate|:delete|:none)+ or String (Def: :delete). If +:truncate+, any linebreaks at the very beginning of self (and whitespaces in between), if exist, are truncated to a single linebreak. If String, they are, even if not exists, replaced with the specified String (such as a linebreak). If +:delete+, they are deleted. Note This option has nothing to do with the whitespaces at the beginning of the first significant line (hence the name of the option). Note if a (random) Part is given, this option only considers the first significant element of it.
|
143
148
|
# @param lastsps_style [Symbol, String] One of +(:truncate|:delete|:none|:linebreak)+ or String (Def: :truncate). If +:truncate+, any of linebreaks *AND* white spaces at the tail of self, if exist, are truncated to a single linebreak. If +:delete+, they are deleted. If String, they are, even if not exists, replaced with the specified String (such as a linebreak, in which case +lb_out+ is used as String, i.e., it guarantees only 1 linebreak to exist at the end of the String). Note if a (random) Part is given, this option only considers the last significant element of it.
|
144
149
|
# @param lb [String] Linebreak character like +\n+ etc (Default: $/). If this is one of the standard line-breaks, irregular line-breaks (for example, existence of CR when only LF should be there) are corrected.
|
145
150
|
# @param lb_out [String] Linebreak used for output (Default: +lb+)
|
@@ -185,7 +190,7 @@ module PlainText
|
|
185
190
|
# Also, deepcopy is needed, as this method is destructive.
|
186
191
|
prt = (preserve_paragraph ? prt : Part.new([prt.join])).deepcopy
|
187
192
|
end
|
188
|
-
prt.
|
193
|
+
prt.squash_boundaries! # Boundaries are squashed.
|
189
194
|
|
190
195
|
# Handles Boundary
|
191
196
|
clean_text_boundary!(prt, boundary_style: boundary_style)
|
@@ -407,7 +412,7 @@ module PlainText
|
|
407
412
|
end # self.clean_text_line_head_tail!
|
408
413
|
private_class_method :clean_text_line_head_tail!
|
409
414
|
|
410
|
-
# @param prt [PlainText
|
415
|
+
# @param prt [PlainText::Part] (see PlainText.clean_text#prt)
|
411
416
|
# @param firstlbs_style [Symbol, String] (see PlainText.clean_text#firstlbs_style)
|
412
417
|
# @param lastsps_style [Symbol, String] (see PlainText.clean_text#lastsps_style)
|
413
418
|
# @return [void]
|
@@ -419,7 +424,6 @@ module PlainText
|
|
419
424
|
lastsps_style: ,
|
420
425
|
is_debug: false
|
421
426
|
)
|
422
|
-
|
423
427
|
# Handles the beginning of the given Part.
|
424
428
|
obj = prt.first_significant_element || return
|
425
429
|
# The first significant element is either Paragraph or Background.
|
@@ -1050,8 +1054,8 @@ module PlainText
|
|
1050
1054
|
|
1051
1055
|
end # module PlainText
|
1052
1056
|
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
+
require_relative "plain_text/part"
|
1058
|
+
require_relative "plain_text/parse_rule"
|
1059
|
+
require_relative "plain_text/split"
|
1060
|
+
require_relative "plain_text/util"
|
1057
1061
|
|
data/plain_text.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'date'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{plain_text}.sub(/.*/){|c| (c == File.basename(Dir.pwd)) ? c : raise("ERROR: s.name=(#{c}) in gemspec seems wrong!")}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8".sub(/.*/){|c| fs = Dir.glob('changelog{,.*}', File::FNM_CASEFOLD); raise('More than one ChangeLog exist!') if fs.size > 1; warn("WARNING: Version(s.version=#{c}) already exists in #{fs[0]} - ok?") if fs.size == 1 && !IO.readlines(fs[0]).grep(/^\(Version: #{Regexp.quote c}\)$/).empty? ; c } # n.b., In macOS, changelog and ChangeLog are identical in default.
|
9
9
|
# s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
10
|
s.bindir = 'bin'
|
11
11
|
%w(countchar textclean head.rb tail.rb yard2md_afterclean).each do |f|
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
File.executable?(path) ? s.executables << f : raise("ERROR: Executable (#{path}) is not executable!")
|
14
14
|
end
|
15
15
|
s.authors = ["Masa Sakano"]
|
16
|
-
s.date = %q{2022-
|
16
|
+
s.date = %q{2022-09-14}.sub(/.*/){|c| (Date.parse(c) == Date.today) ? c : raise("ERROR: s.date=(#{c}) is not today!")}
|
17
17
|
s.summary = %q{Module to handle Plain-Text}
|
18
18
|
s.description = %q{This module provides utility functions and methods to handle plain text, classes Part/Paragraph/Boundary to represent the logical structure of a document and ParseRule to describe the rules to parse plain text to produce a Part-type Ruby instance. A few handy Ruby executable scripts to make use of them are included.}
|
19
19
|
# s.email = %q{abc@example.com}
|
data/test/test_plain_text.rb
CHANGED
@@ -2,11 +2,26 @@
|
|
2
2
|
|
3
3
|
# Author: M. Sakano (Wise Babel Ltd)
|
4
4
|
|
5
|
-
require 'plain_text'
|
6
|
-
|
7
5
|
$stdout.sync=true
|
8
6
|
$stderr.sync=true
|
7
|
+
|
9
8
|
# print '$LOAD_PATH=';p $LOAD_PATH
|
9
|
+
arlibbase = %w(plain_text)
|
10
|
+
|
11
|
+
arlibrelbase = arlibbase.map{|i| "../lib/"+i}
|
12
|
+
|
13
|
+
arlibrelbase.each do |elibbase|
|
14
|
+
require_relative elibbase
|
15
|
+
end # arlibbase.each do |elibbase|
|
16
|
+
|
17
|
+
print "NOTE: Running: "; p File.basename(__FILE__)
|
18
|
+
print "NOTE: Library relative paths: "; p arlibrelbase
|
19
|
+
arlibbase4full = arlibbase.map{|i| i.sub(%r@^(../)+@, "")}
|
20
|
+
puts "NOTE: Library full paths for #{arlibbase4full.inspect}: "
|
21
|
+
arlibbase4full.each do |elibbase|
|
22
|
+
ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
|
23
|
+
print elibbase+": " if ar.empty?; p ar
|
24
|
+
end
|
10
25
|
|
11
26
|
#################################################
|
12
27
|
# Unit Test
|
@@ -301,12 +316,22 @@ class TestUnitPlainText < MiniTest::Test
|
|
301
316
|
assert_equal "", PT.tail_inverse("", 3)
|
302
317
|
|
303
318
|
# Child class of String
|
319
|
+
# NOTE: In Ruby 3, a subclass of String is not respected in the methods of String:
|
320
|
+
# @see https://rubyreferences.github.io/rubychanges/3.0.html#string-always-returning-string
|
321
|
+
# NOTE: In Ruby 3, "".class.name is frozen?==true
|
304
322
|
chs = ChString.new ""
|
305
|
-
|
323
|
+
require 'rubygems' if !defined? Gem # for Ruby 1
|
324
|
+
is_ver_2 = (Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3'))
|
325
|
+
nam = (is_ver_2 ? chs.class : String).name
|
326
|
+
|
306
327
|
assert_equal "", chs
|
307
328
|
assert_equal chs, PT.tail(chs)
|
308
329
|
assert_equal nam, PT.tail(chs).class.name, nam+" <=> \n"+PT.tail(chs).class.name.inspect
|
309
|
-
|
330
|
+
if is_ver_2
|
331
|
+
assert_equal nam, PT.tail(chs.class.name)
|
332
|
+
else
|
333
|
+
assert_raises(FrozenError){ PT.tail(chs.class.name) }
|
334
|
+
end
|
310
335
|
assert_equal nam, PT.tail(chs, -100).class.name
|
311
336
|
end
|
312
337
|
|
@@ -2,12 +2,26 @@
|
|
2
2
|
|
3
3
|
# Author: M. Sakano (Wise Babel Ltd)
|
4
4
|
|
5
|
-
require 'plain_text'
|
6
|
-
require 'plain_text/parse_rule'
|
7
|
-
|
8
5
|
$stdout.sync=true
|
9
6
|
$stderr.sync=true
|
7
|
+
|
10
8
|
# print '$LOAD_PATH=';p $LOAD_PATH
|
9
|
+
arlibbase = %w(plain_text plain_text/parse_rule)
|
10
|
+
|
11
|
+
arlibrelbase = arlibbase.map{|i| "../lib/"+i}
|
12
|
+
|
13
|
+
arlibrelbase.each do |elibbase|
|
14
|
+
require_relative elibbase
|
15
|
+
end # arlibbase.each do |elibbase|
|
16
|
+
|
17
|
+
print "NOTE: Running: "; p File.basename(__FILE__)
|
18
|
+
print "NOTE: Library relative paths: "; p arlibrelbase
|
19
|
+
arlibbase4full = arlibbase.map{|i| i.sub(%r@^(../)+@, "")}
|
20
|
+
puts "NOTE: Library full paths for #{arlibbase4full.inspect}: "
|
21
|
+
arlibbase4full.each do |elibbase|
|
22
|
+
ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
|
23
|
+
print elibbase+": " if ar.empty?; p ar
|
24
|
+
end
|
11
25
|
|
12
26
|
#################################################
|
13
27
|
# Unit Test
|
@@ -2,11 +2,27 @@
|
|
2
2
|
|
3
3
|
# Author: M. Sakano (Wise Babel Ltd)
|
4
4
|
|
5
|
-
require 'plain_text'
|
6
|
-
|
7
5
|
$stdout.sync=true
|
8
6
|
$stderr.sync=true
|
7
|
+
|
9
8
|
# print '$LOAD_PATH=';p $LOAD_PATH
|
9
|
+
arlibbase = %w(plain_text)
|
10
|
+
|
11
|
+
arlibrelbase = arlibbase.map{|i| "../lib/"+i}
|
12
|
+
|
13
|
+
arlibrelbase.each do |elibbase|
|
14
|
+
require_relative elibbase
|
15
|
+
end # arlibbase.each do |elibbase|
|
16
|
+
|
17
|
+
print "NOTE: Running: "; p File.basename(__FILE__)
|
18
|
+
print "NOTE: Library relative paths: "; p arlibrelbase
|
19
|
+
arlibbase4full = arlibbase.map{|i| i.sub(%r@^(../)+@, "")}+%w(part part/paragraph part/boundary plain_text/util builtin_type part/string_type)
|
20
|
+
puts "NOTE: Library full paths for #{arlibbase4full.inspect}: "
|
21
|
+
arlibbase4full.each do |elibbase|
|
22
|
+
#ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
|
23
|
+
ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(elibbase)}(\.rb)?$/).uniq
|
24
|
+
print elibbase+": " if ar.empty?; p ar
|
25
|
+
end
|
10
26
|
|
11
27
|
#################################################
|
12
28
|
# Unit Test
|
@@ -18,6 +34,21 @@ gem "minitest"
|
|
18
34
|
require 'minitest/autorun'
|
19
35
|
# MiniTest::Unit.autorun
|
20
36
|
|
37
|
+
# NOTE: In Ruby 3, a subclass of Array is not respected in the methods of Array:
|
38
|
+
# @see https://rubyreferences.github.io/rubychanges/3.0.html#array-always-returning-array
|
39
|
+
# NOTE: In Ruby 3, "".class.name is frozen?==true
|
40
|
+
require 'rubygems' if !defined? Gem # for Ruby 1
|
41
|
+
IS_VER_2 = (Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3'))
|
42
|
+
|
43
|
+
# defines user-defined subclasses.
|
44
|
+
class PlainText::Part
|
45
|
+
class Section < self
|
46
|
+
class Subsection < self; end # It must be a child class!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
class PlainText::Part::Boundary::MyA < PlainText::Part::Boundary
|
50
|
+
end
|
51
|
+
|
21
52
|
class TestUnitPlainTextPart < MiniTest::Test
|
22
53
|
T = true
|
23
54
|
F = false
|
@@ -61,7 +92,7 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
61
92
|
assert_equal a2[2], pt2[2]
|
62
93
|
assert_equal ap2, pt2.paras
|
63
94
|
assert_equal ab2, pt2.boundaries
|
64
|
-
assert_equal a2+[""], pt2.to_a # An empty String is appended.
|
95
|
+
assert_equal a2+[""], pt2.to_a, "former=#{a2+['']} <=> #{pt2.to_a}" # An empty String is appended.
|
65
96
|
assert_operator a2, '!=', pt2
|
66
97
|
assert_operator pt2, '!=', a2
|
67
98
|
end
|
@@ -76,12 +107,19 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
76
107
|
|
77
108
|
pt11 = Pt.new(a1)
|
78
109
|
pt12 = Pt.new(ap1, ab1)
|
79
|
-
assert_equal pt11, pt12
|
110
|
+
assert_equal pt11, pt12, "pt11.inspect=#{pt11.inspect}"
|
80
111
|
pt21 = Pt.new(a2)
|
81
112
|
pt22 = Pt.new(ap2, ab2)
|
82
113
|
assert_equal pt21, pt22
|
83
114
|
end
|
84
115
|
|
116
|
+
def test_new03
|
117
|
+
assert_raises(ArgumentError){ Pt.new(?a) }
|
118
|
+
assert_raises(ArgumentError){ Pt.new(3) }
|
119
|
+
assert_raises(TypeError){ Pt.new([Pt::Boundary.new(""), Pt::Boundary.new("\n") ]) }
|
120
|
+
assert_raises(TypeError){ Pt.new([Pt::Paragraph.new(""), Pt::Paragraph.new("a")]) }
|
121
|
+
end
|
122
|
+
|
85
123
|
def test_size2extract01
|
86
124
|
a1 = ["a", "\n\n\n", "b", "\n\n\n", "c", "\n\n"]
|
87
125
|
pt1 = Pt.new(a1)
|
@@ -107,7 +145,7 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
107
145
|
assert_raises(IndexError){ pt1.send(:size2extract, (-9..-9), ignore_error: false, skip_renormalize: false) }
|
108
146
|
end
|
109
147
|
|
110
|
-
|
148
|
+
|
111
149
|
def test_equal01
|
112
150
|
a1 = ["a", "\n\n\n", "b", "\n\n\n", "c", "\n\n"]
|
113
151
|
pt1 = Pt.new(a1)
|
@@ -115,17 +153,31 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
115
153
|
pt2 = Pt.new(a2)
|
116
154
|
|
117
155
|
assert_operator pt1, '==', Pt.new(a1)
|
156
|
+
assert_operator pt1, '==', Pt.new(a1.dup)
|
157
|
+
assert_operator pt1, '==', Pt.new(pt1.deepcopy.to_a)
|
118
158
|
assert_operator a1, '==', pt1.to_a
|
119
159
|
assert_operator a1, '!=', pt1
|
120
160
|
assert_operator pt1, '!=', a1
|
121
|
-
assert_operator a1, '!=', ?a
|
122
|
-
assert_operator ?a, '!=', a1
|
123
161
|
assert_operator pt1, '!=', pt2
|
124
162
|
assert_operator pt2, '!=', pt1
|
125
163
|
assert_operator pt1, '!=', ?a
|
126
164
|
assert_operator ?a, '!=', pt1
|
127
165
|
end
|
128
166
|
|
167
|
+
def test_equal02_para_boundary
|
168
|
+
pa1 = Pt::Paragraph.new("abc")
|
169
|
+
bo1 = Pt::Boundary.new("\n\n")
|
170
|
+
assert_equal pa1, "abc"
|
171
|
+
assert_equal "abc", pa1
|
172
|
+
assert_equal pa1, Pt::Paragraph.new("abc")
|
173
|
+
assert_equal bo1, "\n\n"
|
174
|
+
assert_equal "\n\n", bo1
|
175
|
+
assert_equal bo1, Pt::Boundary.new("\n\n")
|
176
|
+
|
177
|
+
assert_respond_to pa1, :+
|
178
|
+
assert_respond_to bo1, :gsub!
|
179
|
+
end
|
180
|
+
|
129
181
|
def test_nomethoderror01
|
130
182
|
a1 = ["a", "\n\n\n", "b", "\n\n\n", "c", "\n\n"]
|
131
183
|
pt1 = Pt.new(a1)
|
@@ -154,6 +206,9 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
154
206
|
end
|
155
207
|
|
156
208
|
# Tests of [prm], [prm1, prm2], [prm1..prm2] and "equal" operator
|
209
|
+
# NOTE: In Ruby 3, a subclass of Array is not respected in the methods of Array:
|
210
|
+
# @see https://rubyreferences.github.io/rubychanges/3.0.html#array-always-returning-array
|
211
|
+
# NOTE: In Ruby 3, "".class.name is frozen?==true
|
157
212
|
def test_bracket01
|
158
213
|
a1 = ["a", "\n\n\n", "b", "\n\n\n", "c", "\n\n"]
|
159
214
|
pt1 = Pt.new(a1)
|
@@ -170,8 +225,10 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
170
225
|
assert_equal pt1.class, pt1[0, 6].class
|
171
226
|
assert_equal a1, pt1[0, 6].to_a
|
172
227
|
assert_equal a1[0, 6], pt1[0, 6].to_a
|
173
|
-
|
174
|
-
|
228
|
+
# oper = (IS_VER_2 ? :!= : :==) # Because PlainText::Part#== is redefined and pt1 is Part in Ruby 2, the following is unequal, whereas pt1 is Array in Ruby 3!
|
229
|
+
oper = :!= # In Ver.0.8, it is redefined as unequal.
|
230
|
+
assert_operator pt1[0, 6], oper, a1
|
231
|
+
assert_operator a1, oper, pt1[0, 6]
|
175
232
|
|
176
233
|
assert_equal a1[0, 2], pt1[0, 2].to_a
|
177
234
|
assert_equal a1, pt1[0, 98].to_a
|
@@ -206,7 +263,6 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
206
263
|
assert_nil pt1[98..99]
|
207
264
|
|
208
265
|
# other out-of-bounds: Empty
|
209
|
-
assert_equal Pt.new([]), pt1[2..1]
|
210
266
|
assert_equal a1[-2..2], pt1[-2..2].to_a
|
211
267
|
assert_equal a1[-2...3], pt1[-2...3].to_a
|
212
268
|
|
@@ -247,7 +303,7 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
247
303
|
|
248
304
|
assert_equal a11[4, 2], a1.slice!(4, 2)
|
249
305
|
ptp = pt1.slice!(4, 2)
|
250
|
-
assert_equal pt1.class, ptp.class
|
306
|
+
assert_equal pt1.class, ptp.class
|
251
307
|
assert_equal a11[4, 2], ptp.to_a
|
252
308
|
assert_operator a11[4, 2], :!=, ptp # PlainText::Part != Array
|
253
309
|
assert_equal a11[0..3], a1
|
@@ -341,48 +397,56 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
341
397
|
assert_equal "b\n\n", pt1[2..3].join
|
342
398
|
|
343
399
|
pt2 = pt1.dup
|
400
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
344
401
|
pt2.merge_para!(2,3,4)
|
345
402
|
assert_equal s1, pt2.join
|
346
403
|
assert_equal 8, pt2.size
|
347
404
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
348
405
|
|
349
406
|
pt2 = pt1.dup
|
407
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
350
408
|
pt2.merge_para!(2,3,4, 5)
|
351
409
|
assert_equal s1, pt2.join
|
352
|
-
assert_equal 8, pt2.size
|
410
|
+
assert_equal 8, pt2.size, "Size should be 8: pt2="+pt2.inspect
|
353
411
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
354
412
|
|
355
413
|
pt2 = pt1.dup
|
414
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
356
415
|
pt2.merge_para!(2..4)
|
357
416
|
assert_equal s1, pt2.join
|
358
417
|
assert_equal 8, pt2.size
|
359
418
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
360
419
|
|
361
420
|
pt2 = pt1.dup
|
421
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
362
422
|
pt2.merge_para!(2..5)
|
363
423
|
assert_equal s1, pt2.join
|
364
424
|
assert_equal 8, pt2.size
|
365
425
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
366
426
|
|
367
427
|
pt2 = pt1.dup
|
428
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
368
429
|
pt2.merge_para!(2...6)
|
369
430
|
assert_equal s1, pt2.join
|
370
431
|
assert_equal 8, pt2.size
|
371
432
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
372
433
|
|
373
434
|
pt2 = pt1.dup
|
435
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
374
436
|
pt2.merge_para!(2...-4)
|
375
437
|
assert_equal s1, pt2.join
|
376
438
|
assert_equal 8, pt2.size
|
377
439
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
378
440
|
|
379
441
|
pt2 = pt1.dup
|
442
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
380
443
|
pt2.merge_para!(1..2, use_para_index: true)
|
381
444
|
assert_equal s1, pt2.join
|
382
445
|
assert_equal 8, pt2.size
|
383
446
|
assert_equal "b\n\nc\n\n", pt2[2..3].join
|
384
447
|
|
385
448
|
pt2 = pt1.dup
|
449
|
+
assert_equal 10, pt2.size, "Sanity check should pass: #{pt2.inspect}"
|
386
450
|
pt2.merge_para!(8..12)
|
387
451
|
assert_equal s1, pt2.join
|
388
452
|
assert_equal 10, pt2.size
|
@@ -393,7 +457,7 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
393
457
|
s1 = "a\n\nb\n\nc\n\nd\n\ne\n\n"
|
394
458
|
# 0 1 2 3 4 5 6 7 8 9
|
395
459
|
pt1 = Pt.parse s1
|
396
|
-
|
460
|
+
|
397
461
|
pt2 = pt1.dup
|
398
462
|
assert pt2.merge_para_if{|ary,bi,bf|
|
399
463
|
ary[0] == ?b && ary[2] == ?c
|
@@ -424,9 +488,127 @@ class TestUnitPlainTextPart < MiniTest::Test
|
|
424
488
|
assert_equal s1, pt1.join
|
425
489
|
end
|
426
490
|
|
491
|
+
# subclass_name defined in /lib/plain_text/builtin_type.rb
|
492
|
+
def test_subclass_name
|
493
|
+
bo1 = Pt::Boundary::MyA.new("\n===\n")
|
494
|
+
assert_equal "Part::Boundary::MyA", bo1.subclass_name
|
495
|
+
assert_equal "Boundary::MyA", bo1.subclass_name(index_ini: 1)
|
496
|
+
assert_equal "MyA", bo1.subclass_name(index_ini: 2)
|
497
|
+
|
498
|
+
ss = PlainText::Part::Section::Subsection.new ["abc"]
|
499
|
+
assert_equal "Part::Section::Subsection", ss.subclass_name
|
500
|
+
assert_equal "Section::Subsection", ss.subclass_name(index_ini: 1)
|
501
|
+
end
|
502
|
+
|
503
|
+
def test_dup
|
504
|
+
pa1 = Pt::Paragraph.new("b")
|
505
|
+
bo1 = Pt::Boundary::MyA.new("\n===\n")
|
506
|
+
para1 = [Pt::Paragraph.new("a"), pa1, Pt::Paragraph.new("c")]
|
507
|
+
boun1 = [Pt::Boundary.new("\n"), bo1, Pt::Boundary.new("\n")]
|
508
|
+
pt1 = Pt.new(para1, boun1)
|
509
|
+
assert_equal pt1[2], pa1
|
510
|
+
refute_equal pt1[2].object_id, pa1.object_id, "New one should be given a different object_id (unicode_normalized)"
|
511
|
+
|
512
|
+
pt2 = pt1.dup
|
513
|
+
refute_equal pt1.object_id, pt2.object_id
|
514
|
+
refute_equal pt1.instance.object_id, pt2.instance.object_id
|
515
|
+
assert_equal pt1[2].object_id, pt2[2].object_id
|
516
|
+
assert_equal pt1.paras[1].object_id, pt2[2].object_id
|
517
|
+
assert_equal pt1.paras[1].object_id, pt2.paras[1].object_id
|
518
|
+
assert_equal pt1.boundaries[1].object_id, pt2.boundaries[1].object_id
|
519
|
+
|
520
|
+
pa2 = pa1.dup
|
521
|
+
assert_equal pa1, pa2
|
522
|
+
refute_equal pa1.object_id, pa2.object_id
|
523
|
+
refute_equal pa1.instance.object_id, pa2.instance.object_id
|
524
|
+
pa2.replace("x")
|
525
|
+
refute_equal pa1, pa2
|
526
|
+
|
527
|
+
bo2 = bo1.dup
|
528
|
+
assert_equal bo1, bo2
|
529
|
+
refute_equal bo1.object_id, bo2.object_id
|
530
|
+
refute_equal bo1.instance.object_id, bo2.instance.object_id
|
531
|
+
bo2.replace("x")
|
532
|
+
refute_equal bo1, bo2
|
533
|
+
end
|
534
|
+
|
535
|
+
def test_deepcopy
|
536
|
+
para1 = [Pt::Paragraph.new("a"), Pt::Paragraph.new("b"), Pt::Paragraph.new("c")]
|
537
|
+
boun1 = [Pt::Boundary.new("\n"), Pt::Boundary::MyA.new("\n===\n"), Pt::Boundary.new("\n")]
|
538
|
+
pt1 = Pt.new(para1, boun1)
|
539
|
+
pt2 = pt1.deepcopy
|
540
|
+
assert_equal pt1, pt2
|
541
|
+
assert_equal Pt::Paragraph, pt1.to_a[0].class
|
542
|
+
assert_equal Pt::Boundary, pt1.to_a[1].class
|
543
|
+
assert_equal Pt::Paragraph, pt1.to_a[2].class
|
544
|
+
assert_equal Pt::Boundary::MyA, pt1.to_a[3].class
|
545
|
+
assert_equal "Part::Boundary::MyA", pt1.to_a[3].subclass_name, "subclass_name should be equal: pt1: #{pt1.to_a[3].inspect}"
|
546
|
+
assert_equal "Part::Boundary::MyA", pt2.to_a[3].subclass_name
|
547
|
+
refute_equal pt1.object_id, pt2.object_id
|
548
|
+
refute_equal pt1.to_a[3].object_id, pt2.to_a[3].object_id
|
549
|
+
refute_equal pt1.to_a[3].to_s.object_id, pt2.to_a[3].to_s.object_id
|
550
|
+
refute_equal pt1.to_a[4].object_id, pt2.to_a[4].object_id
|
551
|
+
refute_equal pt1.to_a[4].to_s.object_id, pt2.to_a[4].to_s.object_id
|
552
|
+
end
|
553
|
+
|
554
|
+
def test_insert
|
555
|
+
a1 = ["a", "\n\n\n", "b", "\n\n\n", "c"]
|
556
|
+
pt1 = Pt.new(a1)
|
557
|
+
assert_equal 6, pt1.size, "Sanity check 1"
|
558
|
+
assert_equal a1+[""], pt1.to_a, "Sanity check 2"
|
559
|
+
pt2 = pt1.deepcopy
|
560
|
+
err = assert_raises(IndexError){ pt2.insert(-99, ?d, "\n") }
|
561
|
+
assert_raises(IndexError){ pt2.insert(-99) }
|
562
|
+
assert_match(/\btoo small for array\b/i, err.message)
|
563
|
+
assert_raises(IndexError){ pt2.insert(7, ?d, "\n") }
|
564
|
+
assert_raises(ArgumentError){ pt2.insert(-1, ?d) }
|
565
|
+
assert_raises(ArgumentError){ pt2.concat([?d]) }
|
566
|
+
assert_raises(ArgumentError){ pt2.push( ?d) }
|
567
|
+
assert_raises(ArgumentError){ pt2.insert(-1, ?d, "", ?e) }
|
568
|
+
assert_raises(TypeError){ pt2.insert(-1, Pt::Boundary.new("\n"), Pt::Paragraph.new(?d)) }
|
569
|
+
assert_raises(TypeError){ pt2.insert(-1, Pt::Paragraph.new(?d), Pt::Paragraph.new(?d)) }
|
570
|
+
assert_raises(TypeError){ pt2.insert(-2, Pt::Paragraph.new(?d), Pt::Boundary.new("\n")) }
|
571
|
+
assert_raises(TypeError){ pt2.insert(-2, Pt::Boundary.new("\n"), Pt::Boundary.new("\n")) }
|
572
|
+
assert_raises(TypeError){ pt2.insert(-2, Pt.new([?d]), Pt::Boundary.new("\n")) }
|
573
|
+
pt2 = pt1.deepcopy # required, as @array is altered.
|
574
|
+
assert_equal pt1, pt2
|
575
|
+
assert_equal pt1, pt2.insert(-1), "Insert with no second arguments should alter nothing."
|
576
|
+
assert_equal pt1, pt2.insert(0)
|
577
|
+
assert_equal pt1, pt2.insert(1)
|
578
|
+
|
579
|
+
pt2.insert(-1, ?e, "\n")
|
580
|
+
assert_equal 8, pt2.size
|
581
|
+
assert_equal [?e, "\n"], pt2.to_a[-2..-1]
|
582
|
+
assert pt2[-2].paragraph?
|
583
|
+
assert pt2[-1].boundary?
|
584
|
+
|
585
|
+
bo5 = Pt::Boundary.new("==")
|
586
|
+
pt2.insert(5, bo5, ?d)
|
587
|
+
assert_equal 10, pt2.size
|
588
|
+
assert_equal ["==", ?d, "", ?e, "\n"], pt2.to_a[-5..-1]
|
589
|
+
assert pt2[-2].paragraph?
|
590
|
+
assert pt2[-1].boundary?
|
591
|
+
assert_equal bo5, pt2[5]
|
592
|
+
assert pt2[5].boundary?
|
593
|
+
assert_equal "d", pt2[6]
|
594
|
+
assert pt2[6].paragraph?
|
595
|
+
|
596
|
+
pt2.insert(2, pt1, "")
|
597
|
+
assert_equal 12, pt2.size
|
598
|
+
assert_equal "a\n\n\na\n\n\nb\n\n\ncb\n\n\nc==de\n", pt2.join
|
599
|
+
end
|
600
|
+
|
601
|
+
def test_array_methods
|
602
|
+
a1 = ["a", "\n\n\n", "b", "\n\n\n", "c"]
|
603
|
+
pt1 = Pt.new(a1)
|
604
|
+
assert_equal 6, pt1.size
|
605
|
+
assert_equal a1+[""], pt1.to_a
|
606
|
+
assert_raises(NoMethodError){ pt1.delete_at(0) }
|
607
|
+
assert_raises(NoMethodError){ pt1 << ?d }
|
608
|
+
end
|
609
|
+
|
427
610
|
#assert ( /_rails_db\.sql$/ =~ s1.outfile )
|
428
611
|
#assert_nil fkeys
|
429
|
-
#assert_match(/^\s*ADD CONSTRAINT/ , s1.instance_eval{ @strall })
|
430
612
|
end # class TestUnitPlainTextPart < MiniTest::Test
|
431
613
|
|
432
614
|
#end # if $0 == __FILE__
|
@@ -2,11 +2,26 @@
|
|
2
2
|
|
3
3
|
# Author: M. Sakano (Wise Babel Ltd)
|
4
4
|
|
5
|
-
require 'plain_text'
|
6
|
-
|
7
5
|
$stdout.sync=true
|
8
6
|
$stderr.sync=true
|
7
|
+
|
9
8
|
# print '$LOAD_PATH=';p $LOAD_PATH
|
9
|
+
arlibbase = %w(plain_text)
|
10
|
+
|
11
|
+
arlibrelbase = arlibbase.map{|i| "../lib/"+i}
|
12
|
+
|
13
|
+
arlibrelbase.each do |elibbase|
|
14
|
+
require_relative elibbase
|
15
|
+
end # arlibbase.each do |elibbase|
|
16
|
+
|
17
|
+
print "NOTE: Running: "; p File.basename(__FILE__)
|
18
|
+
print "NOTE: Library relative paths: "; p arlibrelbase
|
19
|
+
arlibbase4full = arlibbase.map{|i| i.sub(%r@^(../)+@, "")}
|
20
|
+
puts "NOTE: Library full paths for #{arlibbase4full.inspect}: "
|
21
|
+
arlibbase4full.each do |elibbase|
|
22
|
+
ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
|
23
|
+
print elibbase+": " if ar.empty?; p ar
|
24
|
+
end
|
10
25
|
|
11
26
|
#################################################
|
12
27
|
# Unit Test
|
@@ -2,11 +2,26 @@
|
|
2
2
|
|
3
3
|
# Author: M. Sakano (Wise Babel Ltd)
|
4
4
|
|
5
|
-
require 'plain_text/util'
|
6
|
-
|
7
5
|
$stdout.sync=true
|
8
6
|
$stderr.sync=true
|
7
|
+
|
9
8
|
# print '$LOAD_PATH=';p $LOAD_PATH
|
9
|
+
arlibbase = %w(plain_text)
|
10
|
+
|
11
|
+
arlibrelbase = arlibbase.map{|i| "../lib/"+i}
|
12
|
+
|
13
|
+
arlibrelbase.each do |elibbase|
|
14
|
+
require_relative elibbase
|
15
|
+
end # arlibbase.each do |elibbase|
|
16
|
+
|
17
|
+
print "NOTE: Running: "; p File.basename(__FILE__)
|
18
|
+
print "NOTE: Library relative paths: "; p arlibrelbase
|
19
|
+
arlibbase4full = arlibbase.map{|i| i.sub(%r@^(../)+@, "")}
|
20
|
+
puts "NOTE: Library full paths for #{arlibbase4full.inspect}: "
|
21
|
+
arlibbase4full.each do |elibbase|
|
22
|
+
ar = $LOADED_FEATURES.grep(/(^|\/)#{Regexp.quote(File.basename(elibbase))}(\.rb)?$/).uniq
|
23
|
+
print elibbase+": " if ar.empty?; p ar
|
24
|
+
end
|
10
25
|
|
11
26
|
#################################################
|
12
27
|
# Unit Test
|