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.
@@ -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 ary [Array, Integer, nil] Reference Array or its size (Array#size) or nil (interpreted as self#size (untested)).
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 ary is neither an Array nor Integer, or more specifically, it does not have size method or ary.size does not return Integer or similar.
69
- def positive_array_index(i, ary=nil)
70
- arysize = (ary ? (ary.respond_to?(:to_int) ? ary.to_int : ary.size) : size)
71
- i2 = i.to_int rescue (raise TypeError, sprintf("no implicit conversion of #{i.class} into Integer (i=#{i.inspect},ary=#{ary.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 ary [Array, Integer, nil] Reference Array or its size (Array#size) or nil (interpreted as self#size (untested)).
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 ary is neither an Array nor Integer, or more specifically, it does not have size method or ary.size does not return Integer or similar.
91
- def positive_array_index_checked(index_in, ary=nil, accept_too_big: true, varname: nil)
92
- # def self.positive_valid_index_for_array(index_in, ary, varname: nil)
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 = (ary ? (ary.respond_to?(:to_int) ? ary.to_int : ary.size) : size)
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
- # Most methods in this module are meant to be included in String, except for a few module functions.
12
- # It is however debatable whether it is a good practice to include a third-party module in the core class.
13
- # This module contains a helper module function {PlainText.extend_this}, with which an object extends this module easily as Singleton if this module is not already included.
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: :default). 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.
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.squash_boundaryies! # Boundaries are squashed.
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:Part] (see PlainText.clean_text#prt)
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
- require "plain_text/part"
1054
- require "plain_text/parse_rule"
1055
- require "plain_text/split"
1056
- require "plain_text/util"
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.7".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.
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-08-25}.sub(/.*/){|c| (Date.parse(c) == Date.today) ? c : raise("ERROR: s.date=(#{c}) is not today!")}
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}
@@ -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
- nam = chs.class.name
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
- assert_equal nam, PT.tail(chs.class.name)
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
- assert_operator pt1[0, 6], :!=, a1
174
- assert_operator a1, :!=, pt1[0, 6]
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 # PlainText::Part
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