reading 0.6.0 → 0.7.0
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/bin/reading +8 -8
- data/bin/readingfile +31 -0
- data/lib/reading/config.rb +115 -148
- data/lib/reading/errors.rb +11 -64
- data/lib/reading/item/time_length.rb +138 -0
- data/lib/reading/parsing/attributes/attribute.rb +26 -0
- data/lib/reading/parsing/attributes/author.rb +15 -0
- data/lib/reading/parsing/attributes/experiences/dates_and_head_transformer.rb +106 -0
- data/lib/reading/parsing/attributes/experiences/history_transformer.rb +452 -0
- data/lib/reading/parsing/attributes/experiences/spans_validator.rb +149 -0
- data/lib/reading/parsing/attributes/experiences.rb +27 -0
- data/lib/reading/parsing/attributes/genres.rb +16 -0
- data/lib/reading/parsing/attributes/notes.rb +22 -0
- data/lib/reading/parsing/attributes/rating.rb +17 -0
- data/lib/reading/parsing/attributes/shared.rb +62 -0
- data/lib/reading/parsing/attributes/title.rb +21 -0
- data/lib/reading/parsing/attributes/variants.rb +77 -0
- data/lib/reading/parsing/csv.rb +101 -0
- data/lib/reading/parsing/parser.rb +292 -0
- data/lib/reading/parsing/rows/column.rb +131 -0
- data/lib/reading/parsing/rows/comment.rb +26 -0
- data/lib/reading/parsing/rows/compact_planned.rb +30 -0
- data/lib/reading/parsing/rows/compact_planned_columns/head.rb +60 -0
- data/lib/reading/parsing/rows/regular.rb +33 -0
- data/lib/reading/parsing/rows/regular_columns/end_dates.rb +20 -0
- data/lib/reading/parsing/rows/regular_columns/genres.rb +20 -0
- data/lib/reading/parsing/rows/regular_columns/head.rb +45 -0
- data/lib/reading/parsing/rows/regular_columns/history.rb +143 -0
- data/lib/reading/parsing/rows/regular_columns/length.rb +35 -0
- data/lib/reading/parsing/rows/regular_columns/notes.rb +32 -0
- data/lib/reading/parsing/rows/regular_columns/rating.rb +15 -0
- data/lib/reading/parsing/rows/regular_columns/sources.rb +94 -0
- data/lib/reading/parsing/rows/regular_columns/start_dates.rb +35 -0
- data/lib/reading/parsing/transformer.rb +70 -0
- data/lib/reading/util/hash_compact_by_template.rb +1 -0
- data/lib/reading/util/hash_deep_merge.rb +1 -1
- data/lib/reading/util/hash_to_struct.rb +1 -0
- data/lib/reading/util/numeric_to_i_if_whole.rb +12 -0
- data/lib/reading/util/string_truncate.rb +13 -4
- data/lib/reading/version.rb +1 -1
- data/lib/reading.rb +18 -0
- metadata +58 -41
- data/lib/reading/attribute/all_attributes.rb +0 -83
- data/lib/reading/attribute/attribute.rb +0 -25
- data/lib/reading/attribute/experiences/dates_validator.rb +0 -94
- data/lib/reading/attribute/experiences/experiences_attribute.rb +0 -74
- data/lib/reading/attribute/experiences/progress_subattribute.rb +0 -48
- data/lib/reading/attribute/experiences/spans_subattribute.rb +0 -82
- data/lib/reading/attribute/variants/extra_info_subattribute.rb +0 -44
- data/lib/reading/attribute/variants/length_subattribute.rb +0 -45
- data/lib/reading/attribute/variants/series_subattribute.rb +0 -57
- data/lib/reading/attribute/variants/sources_subattribute.rb +0 -78
- data/lib/reading/attribute/variants/variants_attribute.rb +0 -69
- data/lib/reading/csv.rb +0 -67
- data/lib/reading/line.rb +0 -23
- data/lib/reading/row/blank_row.rb +0 -23
- data/lib/reading/row/compact_planned_row.rb +0 -130
- data/lib/reading/row/regular_row.rb +0 -94
- data/lib/reading/row/row.rb +0 -88
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reading
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felipe Vogel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pastel
|
@@ -28,119 +28,136 @@ dependencies:
|
|
28
28
|
name: debug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.
|
33
|
+
version: '1.7'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.
|
40
|
+
version: '1.7'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '5.
|
47
|
+
version: '5.18'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '5.
|
54
|
+
version: '5.18'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest-reporters
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
61
|
+
version: '1.6'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
68
|
+
version: '1.6'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: pretty-diffs
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '1.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
82
|
+
version: '1.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: amazing_print
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '1.4'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '1.4'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rubycritic
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '4.7'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '4.7'
|
111
111
|
description:
|
112
112
|
email:
|
113
113
|
- fps.vogel@gmail.com
|
114
114
|
executables:
|
115
115
|
- reading
|
116
|
+
- readingfile
|
116
117
|
extensions: []
|
117
118
|
extra_rdoc_files: []
|
118
119
|
files:
|
119
120
|
- bin/reading
|
120
|
-
-
|
121
|
-
- lib/reading
|
122
|
-
- lib/reading/attribute/experiences/dates_validator.rb
|
123
|
-
- lib/reading/attribute/experiences/experiences_attribute.rb
|
124
|
-
- lib/reading/attribute/experiences/progress_subattribute.rb
|
125
|
-
- lib/reading/attribute/experiences/spans_subattribute.rb
|
126
|
-
- lib/reading/attribute/variants/extra_info_subattribute.rb
|
127
|
-
- lib/reading/attribute/variants/length_subattribute.rb
|
128
|
-
- lib/reading/attribute/variants/series_subattribute.rb
|
129
|
-
- lib/reading/attribute/variants/sources_subattribute.rb
|
130
|
-
- lib/reading/attribute/variants/variants_attribute.rb
|
121
|
+
- bin/readingfile
|
122
|
+
- lib/reading.rb
|
131
123
|
- lib/reading/config.rb
|
132
|
-
- lib/reading/csv.rb
|
133
124
|
- lib/reading/errors.rb
|
134
|
-
- lib/reading/
|
135
|
-
- lib/reading/
|
136
|
-
- lib/reading/
|
137
|
-
- lib/reading/
|
138
|
-
- lib/reading/
|
125
|
+
- lib/reading/item/time_length.rb
|
126
|
+
- lib/reading/parsing/attributes/attribute.rb
|
127
|
+
- lib/reading/parsing/attributes/author.rb
|
128
|
+
- lib/reading/parsing/attributes/experiences.rb
|
129
|
+
- lib/reading/parsing/attributes/experiences/dates_and_head_transformer.rb
|
130
|
+
- lib/reading/parsing/attributes/experiences/history_transformer.rb
|
131
|
+
- lib/reading/parsing/attributes/experiences/spans_validator.rb
|
132
|
+
- lib/reading/parsing/attributes/genres.rb
|
133
|
+
- lib/reading/parsing/attributes/notes.rb
|
134
|
+
- lib/reading/parsing/attributes/rating.rb
|
135
|
+
- lib/reading/parsing/attributes/shared.rb
|
136
|
+
- lib/reading/parsing/attributes/title.rb
|
137
|
+
- lib/reading/parsing/attributes/variants.rb
|
138
|
+
- lib/reading/parsing/csv.rb
|
139
|
+
- lib/reading/parsing/parser.rb
|
140
|
+
- lib/reading/parsing/rows/column.rb
|
141
|
+
- lib/reading/parsing/rows/comment.rb
|
142
|
+
- lib/reading/parsing/rows/compact_planned.rb
|
143
|
+
- lib/reading/parsing/rows/compact_planned_columns/head.rb
|
144
|
+
- lib/reading/parsing/rows/regular.rb
|
145
|
+
- lib/reading/parsing/rows/regular_columns/end_dates.rb
|
146
|
+
- lib/reading/parsing/rows/regular_columns/genres.rb
|
147
|
+
- lib/reading/parsing/rows/regular_columns/head.rb
|
148
|
+
- lib/reading/parsing/rows/regular_columns/history.rb
|
149
|
+
- lib/reading/parsing/rows/regular_columns/length.rb
|
150
|
+
- lib/reading/parsing/rows/regular_columns/notes.rb
|
151
|
+
- lib/reading/parsing/rows/regular_columns/rating.rb
|
152
|
+
- lib/reading/parsing/rows/regular_columns/sources.rb
|
153
|
+
- lib/reading/parsing/rows/regular_columns/start_dates.rb
|
154
|
+
- lib/reading/parsing/transformer.rb
|
139
155
|
- lib/reading/util/blank.rb
|
140
156
|
- lib/reading/util/hash_array_deep_fetch.rb
|
141
157
|
- lib/reading/util/hash_compact_by_template.rb
|
142
158
|
- lib/reading/util/hash_deep_merge.rb
|
143
159
|
- lib/reading/util/hash_to_struct.rb
|
160
|
+
- lib/reading/util/numeric_to_i_if_whole.rb
|
144
161
|
- lib/reading/util/string_remove.rb
|
145
162
|
- lib/reading/util/string_truncate.rb
|
146
163
|
- lib/reading/version.rb
|
@@ -167,8 +184,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
184
|
- !ruby/object:Gem::Version
|
168
185
|
version: '0'
|
169
186
|
requirements: []
|
170
|
-
rubygems_version: 3.4.
|
187
|
+
rubygems_version: 3.4.9
|
171
188
|
signing_key:
|
172
189
|
specification_version: 4
|
173
|
-
summary:
|
190
|
+
summary: Parses a CSV reading log.
|
174
191
|
test_files: []
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require_relative "attribute"
|
2
|
-
require_relative "variants/variants_attribute"
|
3
|
-
require_relative "experiences/experiences_attribute"
|
4
|
-
|
5
|
-
module Reading
|
6
|
-
class Row
|
7
|
-
using Util::StringRemove
|
8
|
-
using Util::HashArrayDeepFetch
|
9
|
-
|
10
|
-
# The simpler attributes are collected below. The more complex attributes
|
11
|
-
# are separated into their own files.
|
12
|
-
|
13
|
-
class RatingAttribute < Attribute
|
14
|
-
def parse
|
15
|
-
return nil unless columns[:rating]
|
16
|
-
|
17
|
-
rating = columns[:rating].strip
|
18
|
-
return nil if rating.empty?
|
19
|
-
|
20
|
-
Integer(rating, exception: false) ||
|
21
|
-
Float(rating, exception: false) ||
|
22
|
-
(raise InvalidRatingError, "Invalid rating")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class AuthorAttribute < Attribute
|
27
|
-
def parse
|
28
|
-
item_head
|
29
|
-
.remove(/\A#{config.deep_fetch(:csv, :regex, :formats)}/)
|
30
|
-
.match(/.+(?=#{config.deep_fetch(:csv, :short_separator)})/)
|
31
|
-
&.to_s
|
32
|
-
&.strip
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class TitleAttribute < Attribute
|
37
|
-
def parse
|
38
|
-
if item_head.end_with?(config.deep_fetch(:csv, :short_separator).rstrip)
|
39
|
-
raise InvalidHeadError, "Missing title? Head column ends in a separator"
|
40
|
-
end
|
41
|
-
|
42
|
-
item_head
|
43
|
-
.remove(/\A#{config.deep_fetch(:csv, :regex, :formats)}/)
|
44
|
-
.remove(/.+#{config.deep_fetch(:csv, :short_separator)}/)
|
45
|
-
.remove(/#{config.deep_fetch(:csv, :long_separator)}.+\z/)
|
46
|
-
.strip
|
47
|
-
.presence || (raise InvalidHeadError, "Missing title")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
class GenresAttribute < Attribute
|
52
|
-
def parse
|
53
|
-
return nil unless columns[:genres]
|
54
|
-
|
55
|
-
columns[:genres]
|
56
|
-
.split(config.deep_fetch(:csv, :separator))
|
57
|
-
.map(&:strip)
|
58
|
-
.map(&:downcase)
|
59
|
-
.map(&:presence)
|
60
|
-
.compact.presence
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
class NotesAttribute < Attribute
|
65
|
-
def parse
|
66
|
-
return nil unless columns[:public_notes]
|
67
|
-
|
68
|
-
columns[:public_notes]
|
69
|
-
.presence
|
70
|
-
&.chomp
|
71
|
-
&.remove(/#{config.deep_fetch(:csv, :long_separator).rstrip}\s*\z/)
|
72
|
-
&.split(config.deep_fetch(:csv, :long_separator))
|
73
|
-
&.map { |string|
|
74
|
-
{
|
75
|
-
blurb?: !!string.delete!(config.deep_fetch(:csv, :blurb_emoji)),
|
76
|
-
private?: !!string.delete!(config.deep_fetch(:csv, :private_emoji)),
|
77
|
-
content: string.strip,
|
78
|
-
}
|
79
|
-
}
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Reading
|
2
|
-
class Row
|
3
|
-
# A base class that contains behaviors common to ___Attribute classes.
|
4
|
-
class Attribute
|
5
|
-
private attr_reader :item_head, :columns, :config
|
6
|
-
|
7
|
-
# @param item_head [String] see Row#item_heads for a definition.
|
8
|
-
# @param columns [Array<String>] the CSV row split into columns.
|
9
|
-
# @param config [Hash]
|
10
|
-
def initialize(item_head: nil, columns: nil, config:)
|
11
|
-
unless item_head || columns
|
12
|
-
raise ArgumentError, "Either item_head or columns must be given to an Attribute."
|
13
|
-
end
|
14
|
-
|
15
|
-
@item_head = item_head
|
16
|
-
@columns = columns
|
17
|
-
@config = config
|
18
|
-
end
|
19
|
-
|
20
|
-
def parse
|
21
|
-
raise NotImplementedError, "#{self.class} should have implemented #{__method__}"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
module Reading
|
2
|
-
# Methods to validate dates. This does not cover all the ways dates can be
|
3
|
-
# invalid, just the ones not covered by ExperiencesAttribute during parsing.
|
4
|
-
module DatesValidator
|
5
|
-
using Util::HashArrayDeepFetch
|
6
|
-
|
7
|
-
class << self
|
8
|
-
# Checks the dates in the given experiences hash, and raises an error at
|
9
|
-
# the first invalid date found.
|
10
|
-
# @param experiences [Array<Hash>]
|
11
|
-
# @param config [Hash]
|
12
|
-
def validate(experiences, config)
|
13
|
-
validate_dates_started_are_in_order(experiences) if dates_started_column?(config)
|
14
|
-
validate_dates_finished_are_in_order(experiences) if dates_finished_column?(config)
|
15
|
-
validate_experiences_of_same_variant_do_not_overlap(experiences) if both_date_columns?(config)
|
16
|
-
validate_spans_are_in_order_and_not_overlapping(experiences)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def dates_started_column?(config)
|
22
|
-
config.deep_fetch(:csv, :enabled_columns).include?(:dates_started)
|
23
|
-
end
|
24
|
-
|
25
|
-
def dates_finished_column?(config)
|
26
|
-
config.deep_fetch(:csv, :enabled_columns).include?(:dates_finished)
|
27
|
-
end
|
28
|
-
|
29
|
-
def both_date_columns?(config)
|
30
|
-
dates_started_column?(config) && dates_finished_column?(config)
|
31
|
-
end
|
32
|
-
|
33
|
-
def validate_dates_started_are_in_order(experiences)
|
34
|
-
experiences
|
35
|
-
.filter { |exp| exp[:spans].any? }
|
36
|
-
.map { |exp| exp[:spans].first[:dates].begin }
|
37
|
-
.each_cons(2) do |a, b|
|
38
|
-
if (a.nil? && b.nil?) || (a && b && a > b )
|
39
|
-
raise InvalidDateError, "Dates started are not in order"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def validate_dates_finished_are_in_order(experiences)
|
45
|
-
experiences
|
46
|
-
.filter { |exp| exp[:spans].any? }
|
47
|
-
.map { |exp| exp[:spans].last[:dates].end }
|
48
|
-
.each_cons(2) do |a, b|
|
49
|
-
if (a.nil? && b.nil?) || (a && b && a > b )
|
50
|
-
raise InvalidDateError, "Dates finished are not in order"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def validate_experiences_of_same_variant_do_not_overlap(experiences)
|
56
|
-
experiences
|
57
|
-
.group_by { |exp| exp[:variant_index] }
|
58
|
-
.each do |_variant_index, exps|
|
59
|
-
exps.filter { |exp| exp[:spans].any? }.each_cons(2) do |a, b|
|
60
|
-
a_metaspan = a[:spans].first[:dates].begin..a[:spans].last[:dates].end
|
61
|
-
b_metaspan = b[:spans].first[:dates].begin..b[:spans].last[:dates].end
|
62
|
-
if a_metaspan.cover?(b_metaspan.begin || a_metaspan.begin || a_metaspan.end) ||
|
63
|
-
b_metaspan.cover?(a_metaspan.begin || b_metaspan.begin || b_metaspan.end)
|
64
|
-
raise InvalidDateError, "Experiences are overlapping"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def validate_spans_are_in_order_and_not_overlapping(experiences)
|
71
|
-
experiences
|
72
|
-
.filter { |exp| exp[:spans].any? }
|
73
|
-
.each do |exp|
|
74
|
-
exp[:spans]
|
75
|
-
.map { |span| span[:dates] }
|
76
|
-
.each do |dates|
|
77
|
-
if dates.begin && dates.end && dates.begin > dates.end
|
78
|
-
raise InvalidDateError, "A date range is backward"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
.each_cons(2) do |a, b|
|
82
|
-
if a.begin > b.begin || a.end > b.end
|
83
|
-
raise InvalidDateError, "Dates are not in order"
|
84
|
-
end
|
85
|
-
if a.cover?(b.begin || a.begin || a.end) ||
|
86
|
-
b.cover?(a.begin || b.begin || b.end)
|
87
|
-
raise InvalidDateError, "Dates are overlapping"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require_relative "spans_subattribute"
|
2
|
-
require_relative "progress_subattribute"
|
3
|
-
require_relative "dates_validator"
|
4
|
-
require "date"
|
5
|
-
|
6
|
-
module Reading
|
7
|
-
class Row
|
8
|
-
class ExperiencesAttribute < Attribute
|
9
|
-
using Util::HashArrayDeepFetch
|
10
|
-
using Util::HashDeepMerge
|
11
|
-
|
12
|
-
def parse
|
13
|
-
started, finished = dates_split(columns)
|
14
|
-
|
15
|
-
experiences_with_dates = started.map.with_index { |entry, i|
|
16
|
-
variant_index = variant_index(entry)
|
17
|
-
spans_attr = SpansSubattribute.new(date_entry: entry, dates_finished: finished, date_index: i, variant_index:, columns:, config:)
|
18
|
-
|
19
|
-
{
|
20
|
-
spans: spans_attr.parse || template.fetch(:spans),
|
21
|
-
group: group(entry) || template.fetch(:group),
|
22
|
-
variant_index: variant_index || template.fetch(:variant_index)
|
23
|
-
}
|
24
|
-
}.presence
|
25
|
-
|
26
|
-
if experiences_with_dates
|
27
|
-
# Raises an error if any sequence of dates does not make sense.
|
28
|
-
DatesValidator.validate(experiences_with_dates, config)
|
29
|
-
|
30
|
-
return experiences_with_dates
|
31
|
-
else
|
32
|
-
if prog = ProgressSubattribute.new(columns:, config:).parse_head
|
33
|
-
return [template.deep_merge(spans: [{ progress: prog }] )]
|
34
|
-
else
|
35
|
-
return nil
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def template
|
43
|
-
@template ||= config.deep_fetch(:item, :template, :experiences).first
|
44
|
-
end
|
45
|
-
|
46
|
-
def dates_split(columns)
|
47
|
-
dates_finished = columns[:dates_finished]&.presence
|
48
|
-
&.split(config.deep_fetch(:csv, :separator))&.map(&:strip) || []
|
49
|
-
# Don't use #has_key? because simply checking for nil covers the
|
50
|
-
# case where dates_started is the last column and omitted.
|
51
|
-
started_column_exists = columns[:dates_started]&.presence
|
52
|
-
|
53
|
-
dates_started =
|
54
|
-
if started_column_exists
|
55
|
-
columns[:dates_started]&.presence&.split(config.deep_fetch(:csv, :separator))&.map(&:strip)
|
56
|
-
else
|
57
|
-
[""] * dates_finished.count
|
58
|
-
end
|
59
|
-
|
60
|
-
[dates_started, dates_finished]
|
61
|
-
end
|
62
|
-
|
63
|
-
def group(entry)
|
64
|
-
entry.match(config.deep_fetch(:csv, :regex, :group_experience))&.captures&.first
|
65
|
-
end
|
66
|
-
|
67
|
-
def variant_index(date_entry)
|
68
|
-
match = date_entry.match(config.deep_fetch(:csv, :regex, :variant_index))
|
69
|
-
|
70
|
-
(match&.captures&.first&.to_i || 1) - 1
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module Reading
|
2
|
-
class Row
|
3
|
-
class ProgressSubattribute
|
4
|
-
using Util::HashArrayDeepFetch
|
5
|
-
|
6
|
-
private attr_reader :date_entry, :variant_index, :columns, :config
|
7
|
-
|
8
|
-
# @param date_entry [String] the entry in Dates Started.
|
9
|
-
# @param variant_index [Integer] the variant index, for getting length for default amount.
|
10
|
-
# @param columns [Array<String>]
|
11
|
-
# @param config [Hash]
|
12
|
-
def initialize(date_entry: nil, variant_index: nil, columns:, config:)
|
13
|
-
@date_entry = date_entry
|
14
|
-
@variant_index = variant_index
|
15
|
-
@columns = columns
|
16
|
-
@config = config
|
17
|
-
end
|
18
|
-
|
19
|
-
def parse
|
20
|
-
progress(date_entry) || progress(columns[:head])
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse_head
|
24
|
-
progress(columns[:head])
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def progress(str)
|
30
|
-
prog = str.match(config.deep_fetch(:csv, :regex, :progress))
|
31
|
-
|
32
|
-
if prog
|
33
|
-
if prog_percent = prog[:percent]&.to_i
|
34
|
-
return prog_percent / 100.0
|
35
|
-
elsif prog_time = prog[:time]
|
36
|
-
return prog_time
|
37
|
-
elsif prog_pages = prog[:pages]&.to_i
|
38
|
-
return prog_pages
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
dnf = str.match(config.deep_fetch(:csv, :regex, :dnf))&.captures&.first
|
43
|
-
return 0 if dnf
|
44
|
-
nil
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
module Reading
|
2
|
-
class Row
|
3
|
-
class SpansSubattribute
|
4
|
-
using Util::HashArrayDeepFetch
|
5
|
-
|
6
|
-
private attr_reader :date_entry, :dates_finished, :date_index, :variant_index, :columns, :config
|
7
|
-
|
8
|
-
# @param date_entry [String] the entry in Dates Started.
|
9
|
-
# @param dates_finished [Array<String>] the entries in Dates Finished.
|
10
|
-
# @param date_index [Integer] the index of the entry.
|
11
|
-
# @param variant_index [Integer] the variant index, for getting length for default amount.
|
12
|
-
# @param columns [Array<String>]
|
13
|
-
# @param config [Hash]
|
14
|
-
def initialize(date_entry:, dates_finished:, date_index:, variant_index:, columns:, config:)
|
15
|
-
@date_entry = date_entry
|
16
|
-
@dates_finished = dates_finished
|
17
|
-
@date_index = date_index
|
18
|
-
@variant_index = variant_index
|
19
|
-
@columns = columns
|
20
|
-
@config = config
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse
|
24
|
-
started = date_started(date_entry)
|
25
|
-
finished = date_finished(dates_finished, date_index)
|
26
|
-
return [] if started.nil? && finished.nil?
|
27
|
-
|
28
|
-
progress_attr = ProgressSubattribute.new(date_entry:, variant_index:, columns:, config:)
|
29
|
-
progress = progress_attr.parse
|
30
|
-
|
31
|
-
[{
|
32
|
-
dates: started..finished || template.fetch(:dates),
|
33
|
-
amount: length || template.fetch(:amount),
|
34
|
-
progress: progress || (1.0 if finished) || template.fetch(:progress),
|
35
|
-
name: template.fetch(:name),
|
36
|
-
favorite?: template.fetch(:favorite?),
|
37
|
-
}]
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def template
|
43
|
-
@template ||= config.deep_fetch(:item, :template, :experiences, 0, :spans).first
|
44
|
-
end
|
45
|
-
|
46
|
-
def date_started(date_entry)
|
47
|
-
dates = date_entry.scan(config.deep_fetch(:csv, :regex, :date))
|
48
|
-
raise InvalidDateError, "Conjoined dates" if dates.count > 1
|
49
|
-
raise InvalidDateError, "Missing or incomplete date" if date_entry.present? && dates.empty?
|
50
|
-
|
51
|
-
date_str = dates.first
|
52
|
-
Date.parse(date_str) if date_str
|
53
|
-
rescue Date::Error
|
54
|
-
raise InvalidDateError, "Unparsable date"
|
55
|
-
end
|
56
|
-
|
57
|
-
def date_finished(dates_finished, date_index)
|
58
|
-
return nil if dates_finished.nil?
|
59
|
-
|
60
|
-
date_str = dates_finished[date_index]&.presence
|
61
|
-
Date.parse(date_str) if date_str
|
62
|
-
rescue Date::Error
|
63
|
-
if date_str.match?(config.deep_fetch(:csv, :regex, :date))
|
64
|
-
raise InvalidDateError, "Unparsable date"
|
65
|
-
else
|
66
|
-
raise InvalidDateError, "Missing or incomplete date"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def length
|
71
|
-
sources_str = columns[:sources]&.presence || " "
|
72
|
-
bare_variant = sources_str
|
73
|
-
.split(config.deep_fetch(:csv, :regex, :formats_split))
|
74
|
-
.dig(variant_index)
|
75
|
-
&.split(config.deep_fetch(:csv, :long_separator))
|
76
|
-
&.first
|
77
|
-
length_attr = LengthSubattribute.new(bare_variant:, columns:, config:)
|
78
|
-
length_attr.parse
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Reading
|
2
|
-
class Row
|
3
|
-
class ExtraInfoSubattribute
|
4
|
-
using Util::HashArrayDeepFetch
|
5
|
-
|
6
|
-
private attr_reader :item_head, :variant_with_extras, :config
|
7
|
-
|
8
|
-
# @param item_head [String] see Row#item_heads for a definition.
|
9
|
-
# @param variant_with_extras [String] the full variant string.
|
10
|
-
# @param config [Hash]
|
11
|
-
def initialize(item_head:, variant_with_extras: nil, config:)
|
12
|
-
@item_head = item_head
|
13
|
-
@variant_with_extras = variant_with_extras
|
14
|
-
@config = config
|
15
|
-
end
|
16
|
-
|
17
|
-
def parse
|
18
|
-
(
|
19
|
-
Array(extra_info(item_head)) +
|
20
|
-
Array(extra_info(variant_with_extras))
|
21
|
-
).presence
|
22
|
-
end
|
23
|
-
|
24
|
-
def parse_head
|
25
|
-
extra_info(item_head)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def template
|
31
|
-
config.deep_fetch(:item, :template, :variants, 0, :series).first
|
32
|
-
end
|
33
|
-
|
34
|
-
def extra_info(str)
|
35
|
-
separated = str.split(config.deep_fetch(:csv, :long_separator))
|
36
|
-
separated.delete_at(0) # everything before the extra info
|
37
|
-
separated.reject { |str|
|
38
|
-
str.start_with?("#{config.deep_fetch(:csv, :series_prefix)} ") ||
|
39
|
-
str.match(config.deep_fetch(:csv, :regex, :series_volume))
|
40
|
-
}.presence
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|