textrepo 0.5.1 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b504229bd3ea2416e0a85cb8903fe0903b6f045a8a2549857a2b1b296f35e32a
4
- data.tar.gz: baaf7776505e0c430d9c540d88e78847eebc406612b5f9c2cb11ba20c5f3371d
3
+ metadata.gz: 0032a2287829a2a4beb5d2561a99f716a04d6d6ea5a2d99da93fed6dfb187eff
4
+ data.tar.gz: 3af5842649ea9db629117699d44941742104aec93d35b87378d729b8d020ec98
5
5
  SHA512:
6
- metadata.gz: cb90a5d324536e0c2ba8f87c93923ba19bae2c835f31445f9d0f3701110f37598f44a638b496ac992dab30ea03f82643591ea807623a93bd0afdfa52505595ac
7
- data.tar.gz: 1affcd1ff8cce4b3374610791ba733d5d5c8fd1d8b90adb5030725752c84c0f671d4ee9b6ca7f4539ebc2171baf1d2c92b9eb530dc84eed14d477df98729154e
6
+ metadata.gz: 8048e13e77c8aa8be78444b4c3e18aa955636434fb7f15f205f37b039f4c94122515f4481b3a4881923bb37661f8de968e2c80b8bf8fa2d9a101cf19ab7f9341
7
+ data.tar.gz: 5d1aeda6151c09f0c9249aa6b6d2800f54749b5a1a5050a21e1d56bb1562e4935c5b0755b92be070164acb108db7c7db488a03e0ca4d99c3493adc1b3879f55d
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
  ## [Unreleased]
8
8
  Nothing to record here.
9
9
 
10
+ ## [0.5.6] - 2020-11-11
11
+ ### Add
12
+ - Change `Repository` to enumerable.
13
+ - add `#each` method to `Repository`, then include `Enumerable`.
14
+ - Add "-H" option to some searcher default options.
15
+
16
+ ## [0.5.5] - 2020-11-10
17
+ ### Add
18
+ - Add more methods for `Timestamp` class.
19
+ - most of them are delegated to Time class
20
+ - some of them are useful to manipulate `Timestamp` object as
21
+ `String`.
22
+
23
+ ## [0.5.4] - 2020-11-05
24
+ ### Add
25
+ - Add a feature for `Repository#update` to keep timestamp unchanged
26
+ - add the third argument as:
27
+ - `Repository#update(timestamp, text, keep_stamp = false)`
28
+
29
+ ## [0.5.3] - 2020-11-03
30
+ ### Changed
31
+ - Fix issue #38: fix typo in code for FileSystemRepository.
32
+
33
+ ## [0.5.2] - 2020-11-03
34
+ ### Changed
35
+ - Fix issue #34:
36
+ - fix FileSystemRepository#entries to accept "yyyymo" pattern as a
37
+ Timestamp pattern.
38
+ - Fix issue #33: fix typo in the doc for FileSystemRepository.new.
39
+ - Fix issue #31: unfriendly error message of Timestamp.parse_s.
40
+
10
41
  ## [0.5.1] - 2020-11-02
11
42
  ### Changed
12
43
  - Fix issue #28.
@@ -22,15 +22,26 @@ module Textrepo
22
22
 
23
23
  # :stopdoc:
24
24
  module ErrMsg
25
- UNKNOWN_REPO_TYPE = 'unknown type for repository: %s'
26
- DUPLICATE_TIMESTAMP = 'duplicate timestamp: %s'
27
- EMPTY_TEXT = 'empty text'
28
- MISSING_TIMESTAMP = 'missing timestamp: %s'
25
+ ARGUMENT_RANGE = "argument out of range: %s"
26
+ UNKNOWN_REPO_TYPE = "unknown type for repository: %s"
27
+ DUPLICATE_TIMESTAMP = "duplicate timestamp: %s"
28
+ EMPTY_TEXT = "empty text"
29
+ MISSING_TIMESTAMP = "missing timestamp: %s"
29
30
  INVALID_TIMESTAMP_STRING = "invalid string as timestamp: %s"
30
31
  INVALID_SEARCH_RESULT = "invalid result by searcher: %s"
31
32
  end
32
33
  # :startdoc:
33
34
 
35
+ ##
36
+ # An error raised if argument is out of range for Timestamp class.
37
+
38
+ class ArgumentRangeError < Error
39
+ def initialize(arg)
40
+ super(ErrMsg::ARGUMENT_RANGE % arg)
41
+ end
42
+ end
43
+
44
+
34
45
  ##
35
46
  # An error raised if unknown type was specified as the repository
36
47
  # type.
@@ -67,9 +67,10 @@ module Textrepo
67
67
  # were not defined in `conf`.
68
68
  #
69
69
  # Be careful to set `:searcher_options`, it must be to specify the
70
- # searcher behavior equivalent to `grep` with "-inR". The default
71
- # value for the searcher options is defined for BSD grep (default
72
- # grep on macOS), GNU grep, and ripgrep (aka rg). They are:
70
+ # searcher behavior equivalent to `grep` with "-inRE". The
71
+ # default values for the searcher options is defined for BSD grep
72
+ # (default grep on macOS), GNU grep, and ripgrep (aka rg). They
73
+ # are:
73
74
  #
74
75
  # "grep" => ["-i", "-n", "-R", "-E"]
75
76
  # "egrep" => ["-i", "-n", "-R"]
@@ -77,7 +78,7 @@ module Textrepo
77
78
  # "gegrep" => ["-i", "-n", "-R"]
78
79
  # "rg" => ["-S", "-n", "--no-heading", "--color", "never"]
79
80
  #
80
- # If use those 3 searchers, it is not recommended to set
81
+ # If use those searchers, it is not recommended to set
81
82
  # `:searcher_options`. The default value works well in
82
83
  # `textrepo`.
83
84
  #
@@ -129,30 +130,32 @@ module Textrepo
129
130
  end
130
131
 
131
132
  ##
132
- # Updates the file content in the repository. A new timestamp
133
- # will be attached to the text.
133
+ # Updates the file content in the repository. A new Timestamp
134
+ # object will be attached to the text. Then, returns the new
135
+ # Timestamp object.
136
+ #
137
+ # When true is passed as the third argument, keeps the Timestamp
138
+ # unchanged, though updates the content. Then, returns the given
139
+ # Timestamp object.
134
140
  #
135
141
  # See the documentation of Repository#update to know about errors
136
142
  # and constraints of this method.
137
143
  #
138
144
  # :call-seq:
139
- # update(Timestamp, Array) -> Timestamp
145
+ # update(Timestamp, Array, true or false) -> Timestamp
140
146
 
141
- def update(timestamp, text)
147
+ def update(timestamp, text, keep_stamp = false)
142
148
  raise EmptyTextError if text.empty?
143
149
  raise MissingTimestampError, timestamp unless exist?(timestamp)
144
150
 
145
151
  # does nothing if given text is the same in the repository one
146
152
  return timestamp if read(timestamp) == text
147
153
 
148
- # the text must be stored with the new timestamp
149
- new_stamp = Timestamp.new(Time.now)
150
- write_text(abspath(new_stamp), text)
151
-
152
- # delete the original text file in the repository
153
- FileUtils.remove_file(abspath(timestamp))
154
+ stamp = keep_stamp ? timestamp : Timestamp.new(Time.now)
155
+ write_text(abspath(stamp), text)
156
+ FileUtils.remove_file(abspath(timestamp)) unless keep_stamp
154
157
 
155
- new_stamp
158
+ stamp
156
159
  end
157
160
 
158
161
  ##
@@ -186,7 +189,7 @@ module Textrepo
186
189
  if exist?(stamp)
187
190
  results << stamp
188
191
  end
189
- when 0, "yyyymoddhhmiss".size, "yyyymodd".size
192
+ when 0, "yyyymoddhhmiss".size, "yyyymodd".size, "yyyymo".size
190
193
  results += find_entries(stamp_pattern)
191
194
  when 4 # "yyyy" or "modd"
192
195
  pat = nil
@@ -314,20 +317,7 @@ module Textrepo
314
317
  def invoke_searcher_for_entries(searcher, pattern, entries)
315
318
  output = []
316
319
 
317
- num_of_entries = entries.size
318
- if num_of_entries == 1
319
- # If the search taget is one file, the output needs special
320
- # treatment.
321
- file = abspath(entries[0])
322
- o, s = Open3.capture2(searcher, *find_searcher_options(searcher),
323
- pattern, file)
324
- if s.success? && (! o.empty)
325
- output += o.lines.map { |line|
326
- # add filename at the beginning of the search result line
327
- [file, line.chomp].join(":")
328
- }
329
- end
330
- elsif num_of_entries > LIMIT_OF_FILES
320
+ if entries.size > LIMIT_OF_FILES
331
321
  output += invoke_searcher_for_entries(searcher, pattern, entries[0..(LIMIT_OF_FILES - 1)])
332
322
  output += invoke_searcher_for_entries(searcher, pattern, entries[LIMIT_OF_FILES..-1])
333
323
  else
@@ -337,7 +327,7 @@ module Textrepo
337
327
  files = find_files(entries)
338
328
  o, s = Open3.capture2(searcher, *find_searcher_options(searcher),
339
329
  pattern, *files)
340
- if s.success? && (! o.empty)
330
+ if s.success? && (! o.empty?)
341
331
  output += o.lines.map(&:chomp)
342
332
  end
343
333
  end
@@ -346,14 +336,16 @@ module Textrepo
346
336
  end
347
337
 
348
338
  SEARCHER_OPTS = {
349
- # case insensitive, print line number, recursive search, work as egrep
350
- "grep" => ["-i", "-n", "-R", "-E"],
351
- # case insensitive, print line number, recursive search
352
- "egrep" => ["-i", "-n", "-R"],
353
- # case insensitive, print line number, recursive search, work as gegrep
354
- "ggrep" => ["-i", "-n", "-R", "-E"],
355
- # case insensitive, print line number, recursive search
356
- "gegrep" => ["-i", "-n", "-R"],
339
+ # grep option meaning:
340
+ # - "-i": case insensitive,
341
+ # - "-n": print line number,
342
+ # - "-H": print file name,
343
+ # - "-R": recursive search,
344
+ # - "-E": work as egrep
345
+ "grep" => ["-i", "-n", "-H", "-R", "-E"],
346
+ "egrep" => ["-i", "-n", "-H", "-R"],
347
+ "ggrep" => ["-i", "-n", "-H", "-R", "-E"],
348
+ "gegrep" => ["-i", "-n", "-H", "-R"],
357
349
  # smart case, print line number, no color
358
350
  "rg" => ["-S", "-n", "--no-heading", "--color", "never"],
359
351
  }
@@ -1,6 +1,8 @@
1
1
  module Textrepo
2
2
  class Repository
3
3
 
4
+ include Enumerable
5
+
4
6
  ##
5
7
  # Repository type. It specifies which concrete repository class
6
8
  # will instantiated. For example, the type `:file_system` specifies
@@ -44,11 +46,16 @@ module Textrepo
44
46
 
45
47
  ##
46
48
  # Updates the content with given text in the repository, which is
47
- # associated to the given timestamp. Returns the timestamp newly
48
- # generated during the execution.
49
+ # associated to the given Timestamp object. Returns the Timestamp
50
+ # newly generated during the execution.
51
+ #
52
+ # When true is passed as the third argument, keeps the Timestamp
53
+ # unchanged, though updates the content. Then, returns the given
54
+ # Timestamp object.
49
55
  #
50
- # If the given Timestamp is not existed as a Timestamp attached to
51
- # text in the repository, raises MissingTimestampError.
56
+ # If the given Timestamp object is not existed as a Timestamp
57
+ # attached to text in the repository, raises
58
+ # MissingTimestampError.
52
59
  #
53
60
  # If the given text is empty, raises EmptyTextError.
54
61
  #
@@ -56,9 +63,9 @@ module Textrepo
56
63
  # does nothing. Returns the given timestamp itself.
57
64
  #
58
65
  # :call-seq:
59
- # update(Timestamp, Array) -> Timestamp
66
+ # update(Timestamp, Array, true or false) -> Timestamp
60
67
 
61
- def update(timestamp, text); timestamp; end
68
+ def update(timestamp, text, keep_stamp = false); timestamp; end
62
69
 
63
70
  ##
64
71
  # Deletes the content in the repository, which is associated to
@@ -120,6 +127,65 @@ module Textrepo
120
127
 
121
128
  def search(pattern, stamp_pattern = nil); []; end
122
129
 
130
+ ##
131
+ # Calls the given block once for each pair of timestamp and text
132
+ # in self, passing those pair as parameter. Returns the
133
+ # repository itself.
134
+ #
135
+ # If no block is given, an Enumerator is returned.
136
+
137
+ def each(&block)
138
+ if block.nil?
139
+ entries.lazy.map { |timestamp| pair(timestamp) }.to_enum(:each)
140
+ else
141
+ entries.each { |timestamp| yield pair(timestamp) }
142
+ self
143
+ end
144
+ end
145
+
146
+ alias each_pair each
147
+
148
+ ##
149
+ # Calls the given block once for each timestamp in self, passing
150
+ # the timestamp as a parameter. Returns the repository itself.
151
+ #
152
+ # If no block is given, an Enumerator is returned.
153
+
154
+ def each_key(&block)
155
+ if block.nil?
156
+ entries.to_enum(:each)
157
+ else
158
+ entries.each(&block)
159
+ end
160
+ end
161
+
162
+ alias each_timestamp each_key
163
+
164
+ ##
165
+ # Calls the given block once for each timestamp in self, passing
166
+ # the text as a parameter. Returns the repository itself.
167
+ #
168
+ # If no block is given, an Enumerator is returned.
169
+
170
+ def each_value(&block)
171
+ if block.nil?
172
+ entries.lazy.map { |timestamp| read(timestamp) }.to_enum(:each)
173
+ else
174
+ entries.each { |timestamp| yield read(timestamp) }
175
+ end
176
+ end
177
+
178
+ alias each_text each_value
179
+
180
+ # :stopdoc:
181
+
182
+ private
183
+
184
+ def pair(timestamp)
185
+ [timestamp, read(timestamp)]
186
+ end
187
+
188
+ # :startdoc:
123
189
  end
124
190
 
125
191
  require_relative 'file_system_repository'
@@ -1,3 +1,5 @@
1
+ require "forwardable"
2
+
1
3
  module Textrepo
2
4
  ##
3
5
  # Timestamp is generated from a Time object. It converts a time to
@@ -18,6 +20,7 @@ module Textrepo
18
20
 
19
21
  class Timestamp
20
22
  include Comparable
23
+ extend Forwardable
21
24
 
22
25
  ##
23
26
  # Time object which generates the Timestamp object.
@@ -29,16 +32,28 @@ module Textrepo
29
32
 
30
33
  attr_reader :suffix
31
34
 
35
+ ##
36
+ # String object which is regarded as a value of Timestamp object.
37
+ # The value is generated from @time and @suffix.
38
+
39
+ attr_reader :str
40
+
32
41
  ##
33
42
  # Creates a Timestamp object from a Time object. In addition, an
34
43
  # Integer can be passed as a suffix use.
35
44
  #
45
+ # Since Textrepo adapts 1 second as the time resolution, the
46
+ # subsec part of a given time will be ignored.
47
+ #
36
48
  # :call-seq:
37
49
  # new(Time, Integer = nil) -> Timestamp
38
50
 
39
51
  def initialize(time, suffix = nil)
40
- @time = time
52
+ raise ArgumentRangeError, suffix unless is_valid_suffix?(suffix)
53
+ parts = [:year, :mon, :day, :hour, :min, :sec].map{ |s| time.send(s) }
54
+ @time = Time.new(*parts)
41
55
  @suffix = suffix
56
+ @str = time_to_str(@time, @suffix)
42
57
  end
43
58
 
44
59
  def <=>(other) # :nodoc:
@@ -51,19 +66,257 @@ module Textrepo
51
66
  end
52
67
 
53
68
  ##
54
- # Generate an obvious time string.
69
+ # Generates an obvious time string.
55
70
  #
56
71
  # %Y %m %d %H %M %S suffix
57
72
  # "2020-12-30 12:34:56 (0 | nil)" -> "20201230123456"
58
73
  # "2020-12-30 12:34:56 (7)" -> "20201230123456_007"
59
74
 
60
75
  def to_s
76
+ @str
77
+ end
78
+
79
+ alias to_str to_s
80
+
81
+ # :stopdoc:
82
+
83
+ # delegators to Time object
84
+
85
+ def_instance_delegators :@time, :year, :mon, :day, :hour, :min, :sec
86
+ def_instance_delegators :@time, :wday, :monday?, :tuesday?, :wednesday?, :thursday?, :friday?, :saturday?, :sunday?
87
+ def_instance_delegators :@time, :asctime, :ctime, :strftime
88
+ def_instance_delegators :@time, :subsec, :nsec, :usec
89
+ def_instance_delegators :@time, :tv_nsec, :tv_sec, :tv_usec
90
+ def_instance_delegators :@time, :to_f, :to_i, :to_r
91
+ def_instance_delegators :@time, :yday, :mday
92
+ def_instance_delegators :@time, :month
93
+
94
+ # :startdoc:
95
+
96
+ def hash # :nodoc:
97
+ @str[0, 14].to_i * 1000 + @suffix.to_i
98
+ end
99
+
100
+ def eql?(other) # :nodoc:
101
+ other.is_a?(Timestamp) && @time == other.time && @suffix == other.suffix
102
+ end
103
+
104
+ ##
105
+ # Returns a new Timestamp object which is given seconds ahead.
106
+ # Even if the suffix is not nil, the new Timestamp object will
107
+ # always have nil as its suffix.
108
+ #
109
+ # :call-seq:
110
+ # +(Integer) -> Timestamp
111
+
112
+ def +(seconds)
113
+ Timestamp.new(@time + seconds, nil)
114
+ end
115
+
116
+ ##
117
+ # Returns difference of seconds between self and an argument. If
118
+ # the argument is an Integer object, returns a new Timestamp
119
+ # object which is the given seconds behind.
120
+ #
121
+ # Even if the suffix is not nil, the new Timestamp object will
122
+ # always have nil as its suffix.
123
+ #
124
+ # :call-seq:
125
+ # -(Time) -> Float
126
+ # -(Timetamp) -> Float
127
+ # -(Integer) -> Timestamp
128
+
129
+ def -(arg)
130
+ case arg
131
+ when Time
132
+ @time - arg
133
+ when Timestamp
134
+ @time - arg.time
135
+ when Integer
136
+ Timestamp.new(@time - arg, nil)
137
+ when NilClass
138
+ raise TypeError, "can't convert nil into an exact number"
139
+ else
140
+ raise ArgumentError, arg
141
+ end
142
+ end
143
+
144
+ ##
145
+ # Generates an array contains components of the Timestamp object.
146
+ # Components means "year", "mon", "day", "hour", "min", "sec", and
147
+ # "suffix".
148
+
149
+ def to_a
150
+ a = [:year, :mon, :day, :hour, :min, :sec, :suffix].map { |s| self.send(s) }
151
+ a.delete_at(-1) if a[-1].nil?
152
+ a
153
+ end
154
+
155
+ # :stopdoc:
156
+
157
+ # delegators to String object
158
+
159
+ def_instance_delegators :@str, :size, :length
160
+ def_instance_delegators :@str, :include?, :match, :match?
161
+
162
+ # :startdoc:
163
+
164
+ ##
165
+ # Returns a character or sub-string specified with args.
166
+ #
167
+ # Following type of objects could be used as args:
168
+ #
169
+ # - Integer : specifies an index
170
+ # - Integer, Integer : specified an start index and length of sub-string
171
+ # - Range : specified range of sub-string
172
+ # - Symbol : specified a type of part
173
+ #
174
+ # Following symbols could be specified:
175
+ #
176
+ # - :year
177
+ # - :mon, or :month
178
+ # - :day
179
+ # - :hour
180
+ # - :min
181
+ # - :sec
182
+ # - :suffix
183
+ #
184
+ # :call-seq:
185
+ # self[nth as Integer] -> String | nil
186
+ # self[nth as Integer, len as Integer] -> String | nil
187
+ # self[range as Range] -> String
188
+ # self[symbol as Symbol] -> String
189
+
190
+ def [](*args)
191
+ raise ArgumentError, "wrong number of arguments (given %s, execpted 1..2)" % args.size unless (1..2).include?(args.size)
192
+
193
+ arg = args[0]
194
+ case arg
195
+ when Symbol, String
196
+ key = arg.to_sym
197
+ if key == :suffix
198
+ @suffix.nil? ? nil : FMTSTRS[key] % @suffix
199
+ elsif FMTSTRS.keys.include?(key)
200
+ @time.strftime(FMTSTRS[key])
201
+ else
202
+ nil
203
+ end
204
+ else
205
+ @str[*args]
206
+ end
207
+ end
208
+
209
+ alias slice []
210
+
211
+ ##
212
+ # Returns a Timestamp object which has a next Time object.
213
+ #
214
+ # If true was passed as an argument, use incremented suffix as
215
+ # base instead of a next Time object.
216
+ #
217
+ # For example,
218
+ #
219
+ # "20201110160100" -> "20201110160101" (false as arg)
220
+ # "20201110160100" -> "20201110160100_001" (true as arg)
221
+ # "20201110160200_001" -> "20201110160201" (false as arg)
222
+ # "20201110160200_001" -> "20201110160200_002" (true as arg)
223
+ #
224
+ # If suffix was 999 before call this method, raises
225
+ # ArgumentRangeError.
226
+
227
+ def next(use_suffix = nil)
228
+ if use_suffix
229
+ Timestamp.new(@time, increase_suffix(@suffix.to_i, 1))
230
+ else
231
+ Timestamp.new(@time + 1, nil)
232
+ end
233
+ end
234
+
235
+ alias succ next
236
+
237
+ ##
238
+ # Updates the time value to a next Time destructively. See the
239
+ # document for Timestamp#next for more details.
240
+ #
241
+ # If suffix was 999 before call this method, raises
242
+ # ArgumentRangeError.
243
+
244
+ def next!(use_suffix = nil)
245
+ if use_suffix
246
+ @suffix = increase_suffix(@suffix.to_i, 1)
247
+ else
248
+ @time += 1
249
+ @suffix = nil
250
+ end
251
+ @str = time_to_str(@time, @suffix)
252
+ self
253
+ end
254
+
255
+ alias succ! next!
256
+
257
+ ##
258
+ # Splits the timestamp string into array of time parts, such as
259
+ # year, month, day, hour, minute, and second. Then, returns the
260
+ # array.
261
+ #
262
+ # When a block was passed, it would apply to each part of the
263
+ # array. Then, returns self.
264
+
265
+ def split(_ = $;, _ = 0, &blk)
266
+ parts = Timestamp.split_stamp(@str)
267
+ if blk.nil?
268
+ parts
269
+ else
270
+ parts.each { |p| yield p }
271
+ self
272
+ end
273
+ end
274
+
275
+ # :stopdoc:
276
+
277
+ def initialize_copy(_)
278
+ @time = @time.dup
279
+ @suffix = @suffix
280
+ @str = @str.dup
281
+ end
282
+
283
+ def freeze; @time.freeze; @suffix.freeze; @str.freeze; end
284
+ def taint; @time.taint; @suffix.taint; @str.taint; end
285
+ def untaint; @time.untaint; @suffix.untaint; @str.untaint; end
286
+
287
+ private
288
+
289
+ def is_valid_suffix?(suffix)
290
+ suffix.nil? || (0..999).include?(suffix)
291
+ end
292
+
293
+ def increase_suffix(suffix, num)
294
+ increased = suffix + num
295
+ raise ArgumentRangeError, suffix unless is_valid_suffix?(increased)
296
+ increased
297
+ end
298
+
299
+ def time_to_str(time, suffix = nil)
61
300
  s = @time.strftime("%Y%m%d%H%M%S")
62
301
  s += "_#{"%03u" % @suffix}" unless @suffix.nil? || @suffix == 0
63
302
  s
64
303
  end
65
304
 
305
+ FMTSTRS = {
306
+ :year => "%Y", :mon => "%m", :month => "%m", :day => "%d",
307
+ :hour => "%H", :min => "%M", :sec => "%S", :suffix => "%03u",
308
+ }
309
+
310
+ # :startdoc:
66
311
  class << self
312
+
313
+ ##
314
+ # Returns a Timestamp object generated from the current time.
315
+
316
+ def now(suffix = nil)
317
+ Timestamp.new(Time.now, suffix)
318
+ end
319
+
67
320
  ##
68
321
  # Splits a string which represents a timestamp into components.
69
322
  # Each component represents a part of constructs to instantiate
@@ -79,7 +332,8 @@ module Textrepo
79
332
  raise InvalidTimestampStringError, stamp_str if stamp_str.nil?
80
333
  # yyyy mo dd hh mi ss sfx
81
334
  a = [0..3, 4..5, 6..7, 8..9, 10..11, 12..13, 15..17].map {|r| stamp_str[r]}
82
- a[-1].nil? ? a[0..-2] : a
335
+ a.delete_at(-1) if a[-1].nil?
336
+ a
83
337
  end
84
338
 
85
339
  ##
@@ -98,10 +352,17 @@ module Textrepo
98
352
  ye, mo, da, ho, mi, se, sfx = split_stamp(stamp_str).map(&:to_i)
99
353
  Timestamp.new(Time.new(ye, mo, da, ho, mi, se), sfx)
100
354
  rescue InvalidTimestampStringError, ArgumentError => _
101
- raise InvalidTimestampStringError, stamp_str
355
+ emsg = if stamp_str.nil?
356
+ "(nil)"
357
+ elsif stamp_str.empty?
358
+ "(empty string)"
359
+ else
360
+ stamp_str
361
+ end
362
+ raise InvalidTimestampStringError, emsg
102
363
  end
103
364
  end
104
-
105
365
  end
366
+
106
367
  end
107
368
  end
@@ -1,3 +1,3 @@
1
1
  module Textrepo
2
- VERSION = '0.5.1'
2
+ VERSION = '0.5.6'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textrepo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - mnbi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-02 00:00:00.000000000 Z
11
+ date: 2020-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler