jekyll-rp_logs 0.1.6 → 0.2.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/.codeclimate.yml +46 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.themes/default/source/_config.yml.default +13 -3
- data/.travis.yml +9 -0
- data/CHANGELOG.md +55 -0
- data/README.md +85 -32
- data/Rakefile +42 -5
- data/jekyll-rp_logs.gemspec +6 -1
- data/lib/jekyll/rp_logs/parse_irssi_xchat.rb +35 -37
- data/lib/jekyll/rp_logs/parse_mirc.rb +40 -42
- data/lib/jekyll/rp_logs/parse_skype_12hour.rb +33 -45
- data/lib/jekyll/rp_logs/parse_skype_24hour.rb +33 -41
- data/lib/jekyll/rp_logs/parse_weechat.rb +36 -36
- data/lib/jekyll/rp_logs/rp_arcs.rb +13 -16
- data/lib/jekyll/rp_logs/rp_log_converter.rb +140 -117
- data/lib/jekyll/rp_logs/rp_logline.rb +225 -0
- data/lib/jekyll/rp_logs/rp_page.rb +63 -0
- data/lib/jekyll/rp_logs/rp_parser.rb +9 -103
- data/lib/jekyll/rp_logs/rp_tag_index.rb +18 -20
- data/lib/jekyll/rp_logs/rp_tasks.rb +5 -6
- data/lib/jekyll/rp_logs/version.rb +1 -1
- data/lib/jekyll/rp_logs.rb +4 -5
- metadata +53 -4
@@ -1,184 +1,208 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
1
|
+
require_relative "rp_parser"
|
2
|
+
require_relative "rp_logline"
|
3
|
+
require_relative "rp_page"
|
4
|
+
require_relative "rp_arcs"
|
5
|
+
require_relative "rp_tags"
|
4
6
|
|
5
7
|
module Jekyll
|
6
8
|
module RpLogs
|
7
|
-
|
8
9
|
# Consider renaming since it is more of a converter in practice
|
9
10
|
class RpLogGenerator < Jekyll::Generator
|
10
11
|
safe true
|
11
12
|
priority :normal
|
12
13
|
|
13
|
-
|
14
|
+
@parsers = {}
|
15
|
+
|
16
|
+
class << self
|
17
|
+
attr_reader :parsers, :rp_key
|
14
18
|
|
15
|
-
|
19
|
+
def add(parser)
|
20
|
+
@parsers[parser::FORMAT_STR] = parser
|
21
|
+
end
|
16
22
|
|
17
|
-
|
18
|
-
|
23
|
+
##
|
24
|
+
# Extract global settings from the config file.
|
25
|
+
# The rp directory and collection name is pulled out; it must be the
|
26
|
+
# first collection defined.
|
27
|
+
def extract_settings(config)
|
28
|
+
@rp_key = config["collections"].keys[0].freeze
|
29
|
+
end
|
19
30
|
end
|
20
31
|
|
21
32
|
def initialize(config)
|
22
|
-
|
23
|
-
|
33
|
+
# Should actually probably complain if things are undefined or missing
|
34
|
+
config["rp_convert"] = true unless config.key? "rp_convert"
|
35
|
+
|
36
|
+
RpLogGenerator.extract_settings(config)
|
37
|
+
LogLine.extract_settings(config)
|
24
38
|
|
25
|
-
|
26
|
-
@site.collections[RP_KEY].docs.delete page
|
27
|
-
print "\nSkipping #{page.path}: #{message}"
|
39
|
+
Jekyll.logger.info "Loaded jekyll-rp_logs #{RpLogs::VERSION}"
|
28
40
|
end
|
29
41
|
|
30
|
-
def
|
31
|
-
|
32
|
-
if page.data['format'].nil? || page.data['format'].length == 0 then
|
33
|
-
skip_page(page, "No formats specified")
|
34
|
-
return true
|
35
|
-
else
|
36
|
-
# Verify that the parser for each format exists
|
37
|
-
page.data['format'].each { |format|
|
38
|
-
if @@parsers[format].nil? then
|
39
|
-
skip_page(page, "Format #{format} does not exist.")
|
40
|
-
return true
|
41
|
-
end
|
42
|
-
}
|
43
|
-
end
|
42
|
+
def generate(site)
|
43
|
+
return unless site.config["rp_convert"]
|
44
44
|
|
45
|
-
|
46
|
-
if page.data['rp_tags'].nil? then
|
47
|
-
skip_page(page, "No tags specified")
|
48
|
-
return true
|
49
|
-
# Verify that arc names are in the proper format
|
50
|
-
elsif not (page.data['arc_name'].nil? || page.data['arc_name'].respond_to?('each')) then
|
51
|
-
skip_page(page, "arc_name must be blank or a YAML list")
|
52
|
-
return true
|
53
|
-
end
|
45
|
+
main_index, arc_index = extract_indexes(site)
|
54
46
|
|
55
|
-
|
47
|
+
# Pull out all the pages that are error-free
|
48
|
+
rp_pages = extract_valid_rps(site)
|
49
|
+
|
50
|
+
convert_all_pages(site, main_index, arc_index, rp_pages)
|
56
51
|
end
|
57
52
|
|
58
|
-
|
59
|
-
return unless site.config['rp_convert']
|
60
|
-
@site = site
|
53
|
+
private
|
61
54
|
|
55
|
+
##
|
56
|
+
# Convenience method for accessing the collection key name
|
57
|
+
def rp_key
|
58
|
+
self.class.rp_key
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
#
|
63
|
+
def extract_indexes(site)
|
62
64
|
# Directory of RPs
|
63
|
-
|
64
|
-
|
65
|
+
main_index = site.pages.find { |page| page.data["rp_index"] }
|
66
|
+
main_index.data["rps"] = { "canon" => [], "noncanon" => [] }
|
65
67
|
|
66
68
|
# Arc-style directory
|
67
|
-
|
69
|
+
arc_index = site.pages.find { |page| page.data["rp_arcs"] }
|
68
70
|
|
69
|
-
site.data[
|
71
|
+
site.data["menu_pages"] = [main_index, arc_index]
|
72
|
+
end
|
70
73
|
|
74
|
+
##
|
75
|
+
# Returns a list of RpLogs::Page objects that are error-free.
|
76
|
+
def extract_valid_rps(site)
|
77
|
+
site.collections[rp_key].docs.map { |p| RpLogs::Page.new(p) }
|
78
|
+
.reject do |p|
|
79
|
+
message = p.errors?(self.class.parsers)
|
80
|
+
skip_page(site, p, message) if message
|
81
|
+
message
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def convert_all_pages(site, main_index, arc_index, rp_pages)
|
71
86
|
arcs = Hash.new { |hash, key| hash[key] = Arc.new(key) }
|
72
87
|
no_arc_rps = []
|
73
88
|
|
74
89
|
# Convert all of the posts to be pretty
|
75
90
|
# Also build up our hash of tags
|
76
|
-
|
77
|
-
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
page
|
93
|
-
|
94
|
-
arc_name = page.data['arc_name']
|
95
|
-
if arc_name then
|
96
|
-
arc_name.each { |n| arcs[n] << page }
|
97
|
-
else
|
98
|
-
no_arc_rps << page
|
99
|
-
end
|
100
|
-
rescue
|
101
|
-
# Catch all for any other exception encountered when parsing a page
|
102
|
-
skip_page(page, "Error parsing #{page.path}: " + $!.inspect)
|
103
|
-
# Raise exception, so Jekyll prints backtrace if run with --trace
|
104
|
-
raise $!
|
91
|
+
rp_pages.each do |page|
|
92
|
+
begin
|
93
|
+
# Skip if something goes wrong
|
94
|
+
next unless convert_rp(site, page)
|
95
|
+
|
96
|
+
key = page[:canon] ? "canon" : "noncanon"
|
97
|
+
# Add key for canon/noncanon
|
98
|
+
main_index.data["rps"][key] << page
|
99
|
+
# Add tag for canon/noncanon
|
100
|
+
page[:rp_tags] << (Tag.new key)
|
101
|
+
page[:rp_tags].sort!
|
102
|
+
|
103
|
+
arc_name = page[:arc_name]
|
104
|
+
if arc_name && !arc_name.empty?
|
105
|
+
arc_name.each { |n| arcs[n] << page }
|
106
|
+
else
|
107
|
+
no_arc_rps << page
|
105
108
|
end
|
106
|
-
}
|
107
109
|
|
108
|
-
|
109
|
-
|
110
|
-
|
110
|
+
Jekyll.logger.info "Converted #{page.basename}"
|
111
|
+
rescue
|
112
|
+
# Catch all for any other exception encountered when parsing a page
|
113
|
+
skip_page(site, page, "Error parsing #{page.basename}: #{$ERROR_INFO.inspect}")
|
114
|
+
# Raise exception, so Jekyll prints backtrace if run with --trace
|
115
|
+
raise $ERROR_INFO
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
arcs.each_key { |key| sort_chronologically! arcs[key].rps }
|
120
|
+
combined_rps = no_arc_rps.map { |x| ["rp", x] } + arcs.values.map { |x| ["arc", x] }
|
121
|
+
combined_rps.sort_by! { |type, x|
|
111
122
|
case type
|
112
|
-
when
|
113
|
-
x
|
114
|
-
when
|
115
|
-
x.start_date
|
123
|
+
when "rp"
|
124
|
+
x[:time_line] || x[:start_date]
|
125
|
+
when "arc"
|
126
|
+
x.start_date
|
116
127
|
end
|
117
128
|
}.reverse!
|
118
|
-
|
129
|
+
arc_index.data["rps"] = combined_rps
|
119
130
|
|
120
|
-
sort_chronologically!
|
121
|
-
sort_chronologically!
|
131
|
+
sort_chronologically! main_index.data["rps"]["canon"]
|
132
|
+
sort_chronologically! main_index.data["rps"]["noncanon"]
|
122
133
|
end
|
123
134
|
|
124
|
-
def sort_chronologically!(pages)
|
125
|
-
pages
|
135
|
+
def sort_chronologically!(pages)
|
136
|
+
# Check pages for invalid time_line value
|
137
|
+
pages.each do |p|
|
138
|
+
if p[:time_line] && !p[:time_line].is_a?(Date)
|
139
|
+
Jekyll.logger.error "Malformed time_line #{p[:time_line]} in file #{p.path}"
|
140
|
+
fail "Malformed time_line date"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
# Sort pages by time_line if present or start_date otherwise
|
144
|
+
pages.sort_by! { |p| p[:time_line] || p[:start_date] }.reverse!
|
126
145
|
end
|
127
146
|
|
128
|
-
def
|
129
|
-
options =
|
147
|
+
def convert_rp(site, page)
|
148
|
+
options = page.options
|
130
149
|
|
131
150
|
compiled_lines = []
|
132
|
-
page.content.each_line { |raw_line|
|
133
|
-
page
|
134
|
-
log_line =
|
135
|
-
if log_line
|
136
|
-
compiled_lines << log_line
|
151
|
+
page.content.each_line { |raw_line|
|
152
|
+
page[:format].each { |format|
|
153
|
+
log_line = self.class.parsers[format].parse_line(raw_line, options)
|
154
|
+
if log_line
|
155
|
+
compiled_lines << log_line
|
137
156
|
break
|
138
157
|
end
|
139
158
|
}
|
140
159
|
}
|
141
160
|
|
142
|
-
if compiled_lines.length == 0
|
143
|
-
skip_page(page, "No lines were matched by any format.")
|
161
|
+
if compiled_lines.length == 0
|
162
|
+
skip_page(site, page, "No lines were matched by any format.")
|
144
163
|
return false
|
145
164
|
end
|
146
165
|
|
147
166
|
merge_lines! compiled_lines
|
148
167
|
stats = extract_stats compiled_lines
|
149
168
|
|
150
|
-
split_output = compiled_lines.map
|
151
|
-
|
169
|
+
split_output = compiled_lines.map(&:output)
|
152
170
|
page.content = split_output.join("\n")
|
153
171
|
|
154
|
-
if page
|
172
|
+
if page[:infer_char_tags]
|
155
173
|
# Turn the nicks into characters
|
156
|
-
nick_tags = stats[:nicks].map! { |n| Tag.new(
|
157
|
-
page
|
174
|
+
nick_tags = stats[:nicks].map! { |n| Tag.new("char:" + n) }
|
175
|
+
page[:rp_tags] = (nick_tags.merge page[:rp_tags]).to_a.sort
|
158
176
|
end
|
159
177
|
|
160
|
-
page
|
161
|
-
page
|
178
|
+
page[:end_date] = stats[:end_date]
|
179
|
+
page[:start_date] ||= stats[:start_date]
|
162
180
|
|
163
181
|
true
|
164
182
|
end
|
165
183
|
|
166
|
-
|
167
|
-
|
168
|
-
|
184
|
+
##
|
185
|
+
# Skip the page. Removes it from the site collection, and outputs a
|
186
|
+
# warning message saying it was skipped with the given reason.
|
187
|
+
def skip_page(site, page, message)
|
188
|
+
site.collections[rp_key].docs.delete page.page
|
189
|
+
Jekyll.logger.warn "Skipping #{page.basename}: #{message}"
|
169
190
|
end
|
170
191
|
|
192
|
+
##
|
193
|
+
# Consider moving this into Parser or RpLogs::Page
|
194
|
+
# It doesn't really belong here
|
171
195
|
def merge_lines!(compiled_lines)
|
172
196
|
last_line = nil
|
173
|
-
compiled_lines.reject! { |line|
|
174
|
-
if last_line
|
197
|
+
compiled_lines.reject! { |line|
|
198
|
+
if last_line.nil?
|
175
199
|
last_line = line
|
176
200
|
false
|
177
|
-
elsif last_line.mergeable_with? line
|
201
|
+
elsif last_line.mergeable_with? line
|
178
202
|
last_line.merge! line
|
179
|
-
# Delete the current line from output and maintain last_line
|
203
|
+
# Delete the current line from output and maintain last_line
|
180
204
|
# in case we need to merge multiple times.
|
181
|
-
true
|
205
|
+
true
|
182
206
|
else
|
183
207
|
last_line = line
|
184
208
|
false
|
@@ -186,17 +210,16 @@ module Jekyll
|
|
186
210
|
}
|
187
211
|
end
|
188
212
|
|
189
|
-
def extract_stats(compiled_lines)
|
213
|
+
def extract_stats(compiled_lines)
|
190
214
|
nicks = Set.new
|
191
|
-
compiled_lines.each { |line|
|
215
|
+
compiled_lines.each { |line|
|
192
216
|
nicks << line.sender if line.output_type == :rp
|
193
217
|
}
|
194
218
|
|
195
|
-
{ :
|
196
|
-
:
|
197
|
-
:
|
219
|
+
{ nicks: nicks,
|
220
|
+
end_date: compiled_lines[-1].timestamp,
|
221
|
+
start_date: compiled_lines[0].timestamp }
|
198
222
|
end
|
199
223
|
end
|
200
|
-
|
201
224
|
end
|
202
|
-
end
|
225
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module RpLogs
|
5
|
+
class LogLine
|
6
|
+
RP_FLAG = "!RP".freeze
|
7
|
+
OOC_FLAG = "!OOC".freeze
|
8
|
+
MERGE_FLAG = "!MERGE".freeze
|
9
|
+
SPLIT_FLAG = "!SPLIT".freeze
|
10
|
+
|
11
|
+
attr_reader :timestamp, :mode, :sender, :contents, :flags
|
12
|
+
# Some things depend on the original type of the line (nick format)
|
13
|
+
attr_reader :base_type, :output_type
|
14
|
+
attr_reader :options
|
15
|
+
|
16
|
+
# Timestamp of the most recent line this line was merged with, to allow
|
17
|
+
# merging consecutive lines each MAX_SECONDS_BETWEEN_POSTS apart
|
18
|
+
attr_reader :last_merged_timestamp
|
19
|
+
|
20
|
+
# The max number of seconds between two lines that can still be merged
|
21
|
+
@max_seconds_between_posts = 3
|
22
|
+
|
23
|
+
# All characters that can denote the beginning of an OOC line
|
24
|
+
@ooc_start_delimiters = "([".freeze
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_reader :ooc_start_delimiters, :max_seconds_between_posts
|
28
|
+
|
29
|
+
def extract_settings(config)
|
30
|
+
@max_seconds_between_posts = config.fetch("max_seconds_between_posts",
|
31
|
+
@max_seconds_between_posts)
|
32
|
+
@ooc_start_delimiters = config.fetch("ooc_start_delimiters",
|
33
|
+
@ooc_start_delimiters).freeze
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(timestamp, options = {}, sender:, contents:, flags:, type:, mode: " ")
|
38
|
+
@timestamp = timestamp
|
39
|
+
# Initialize to be the same as @timestamp
|
40
|
+
@last_merged_timestamp = timestamp
|
41
|
+
@mode = mode
|
42
|
+
@sender = sender
|
43
|
+
@contents = contents
|
44
|
+
@flags = flags.split(" ")
|
45
|
+
|
46
|
+
@base_type = type
|
47
|
+
@output_type = type
|
48
|
+
|
49
|
+
@options = options
|
50
|
+
|
51
|
+
classify
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Set derived properties of this LogLine based on various options
|
56
|
+
private def classify
|
57
|
+
# This makes it RP by default
|
58
|
+
@output_type = :rp if @options[:strict_ooc]
|
59
|
+
|
60
|
+
# Check the contents for leading ( or [
|
61
|
+
@output_type = :ooc if ooc_start_delimiters.include? @contents.strip[0]
|
62
|
+
|
63
|
+
# Flags override our assumptions, always
|
64
|
+
if @flags.include? RP_FLAG
|
65
|
+
@output_type = :rp
|
66
|
+
elsif @flags.include? OOC_FLAG
|
67
|
+
@output_type = :ooc
|
68
|
+
end
|
69
|
+
# TODO: Containing both flags should result in a warning
|
70
|
+
end
|
71
|
+
|
72
|
+
def output
|
73
|
+
tag_open, tag_close = output_tags
|
74
|
+
# Escape any HTML special characters in the input
|
75
|
+
escaped_content = CGI.escapeHTML(@contents)
|
76
|
+
"#{tag_open}#{output_timestamp}#{output_sender} #{escaped_content}#{tag_close}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def output_timestamp
|
80
|
+
# String used for the timestamp anchors
|
81
|
+
anchor = @timestamp.strftime("%Y-%m-%d_%H:%M:%S")
|
82
|
+
# String used when hovering over timestamps (friendly long-form)
|
83
|
+
title = @timestamp.strftime("%H:%M:%S %B %-d, %Y")
|
84
|
+
# String actually displayed on page
|
85
|
+
display = @timestamp.strftime("%H:%M")
|
86
|
+
"<a name=\"#{anchor}\" title=\"#{title}\" href=\"##{anchor}\">#{display}</a>"
|
87
|
+
end
|
88
|
+
|
89
|
+
def output_sender
|
90
|
+
case @base_type
|
91
|
+
when :rp
|
92
|
+
return " * #{@sender}"
|
93
|
+
when :ooc
|
94
|
+
return " <#{@mode}#{@sender}>"
|
95
|
+
else
|
96
|
+
# Explode.
|
97
|
+
fail "No known type: #{@base_type}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def output_tags
|
102
|
+
tag_class =
|
103
|
+
case @output_type
|
104
|
+
when :rp then "rp"
|
105
|
+
when :ooc then "ooc"
|
106
|
+
else # Explode.
|
107
|
+
fail "No known type: #{@output_type}"
|
108
|
+
end
|
109
|
+
tag_open = "<p class=\"#{tag_class}\">"
|
110
|
+
tag_close = "</p>"
|
111
|
+
|
112
|
+
[tag_open, tag_close]
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Check if this line can be merged with the given line. In order to be
|
117
|
+
# merged, the two lines must fulfill the following requirements:
|
118
|
+
#
|
119
|
+
# * The timestamp difference is >= 0 and <= MAX_SECONDS_BETWEEN POSTS
|
120
|
+
# (close_enough_timestamps?)
|
121
|
+
# * The lines have the same sender (same_sender?)
|
122
|
+
# * The first line has output_type :rp (rp?)
|
123
|
+
# * The next line has output_type :rp OR the sender has been specified
|
124
|
+
# as someone who splits to normal text
|
125
|
+
#
|
126
|
+
# Exceptions:
|
127
|
+
# * If the next line has the SPLIT flag, it will never be merged
|
128
|
+
# * If the next line has the MERGE flag, it will always be merged
|
129
|
+
def mergeable_with?(next_line)
|
130
|
+
# Perform the checks for the override flags
|
131
|
+
return true if next_line.merge_flag?
|
132
|
+
return false if next_line.split_flag?
|
133
|
+
mergeable_ignoring_flags?(next_line)
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Does all the rest of the checks that don't have to do with the
|
138
|
+
# override flags SPLIT_FLAG and MERGE_FLAG.
|
139
|
+
private def mergeable_ignoring_flags?(next_line)
|
140
|
+
close_enough_timestamps?(next_line) &&
|
141
|
+
same_sender?(next_line) &&
|
142
|
+
rp? &&
|
143
|
+
(next_line.rp? || next_line.possible_split_to_normal_text?)
|
144
|
+
end
|
145
|
+
|
146
|
+
def merge!(next_line)
|
147
|
+
@contents += "#{space_between_lines}#{next_line.contents}"
|
148
|
+
@last_merged_timestamp = next_line.timestamp
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Returns "" if the sender has been said to split by characters.
|
154
|
+
# Returns " " otherwise.
|
155
|
+
#
|
156
|
+
# When the sender splits by characters, adding a space will put spaces in
|
157
|
+
# the middle of words. Their spaces will be preserved at the end of lines.
|
158
|
+
private def space_between_lines
|
159
|
+
if options[:splits_by_character] &&
|
160
|
+
options[:splits_by_character].include?(@sender)
|
161
|
+
""
|
162
|
+
else
|
163
|
+
" "
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Returns true if this line has the output_type :rp
|
169
|
+
def rp?
|
170
|
+
@output_type == :rp
|
171
|
+
end
|
172
|
+
|
173
|
+
def split_flag?
|
174
|
+
@flags.include? SPLIT_FLAG
|
175
|
+
end
|
176
|
+
|
177
|
+
def merge_flag?
|
178
|
+
@flags.include? MERGE_FLAG
|
179
|
+
end
|
180
|
+
|
181
|
+
##
|
182
|
+
# Return true if this sender splits to normal text, and the line base
|
183
|
+
# type was OOC. This allows you to force a quick text post not to merge
|
184
|
+
# by flagging it !OOC.
|
185
|
+
#
|
186
|
+
# Only merge if the base type was OOC... otherwise you couldn't force not merging
|
187
|
+
# Maybe a job for !NOTMERGE flag, or similar
|
188
|
+
protected def possible_split_to_normal_text?
|
189
|
+
base_type == :ooc && @options[:merge_text_into_rp] &&
|
190
|
+
@options[:merge_text_into_rp].include?(@sender)
|
191
|
+
end
|
192
|
+
|
193
|
+
def inspect
|
194
|
+
"<#{@mode}#{@sender}> (#{@base_type} -> #{@output_type}) #{@contents}"
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
##
|
200
|
+
# Only merge posts close enough in time
|
201
|
+
# The difference in time between the post merged into this one, and
|
202
|
+
# the next post, must be less than the limit (and non-negative)
|
203
|
+
def close_enough_timestamps?(next_line)
|
204
|
+
time_diff = (next_line.timestamp - @last_merged_timestamp) * 24 * 60 * 60
|
205
|
+
time_diff >= 0 && time_diff <= max_seconds_between_posts
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Returns if these lines have the same sender
|
210
|
+
def same_sender?(next_line)
|
211
|
+
@sender == next_line.sender
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Convenience methods for accessing class instance variables
|
216
|
+
def max_seconds_between_posts
|
217
|
+
self.class.max_seconds_between_posts
|
218
|
+
end
|
219
|
+
|
220
|
+
def ooc_start_delimiters
|
221
|
+
self.class.ooc_start_delimiters
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module RpLogs
|
3
|
+
class Page
|
4
|
+
extend Forwardable
|
5
|
+
def_delegators :@page, :basename, :content, :content=, :path, :to_liquid
|
6
|
+
|
7
|
+
# Jekyll::Page object
|
8
|
+
attr_reader :page
|
9
|
+
|
10
|
+
def initialize(page)
|
11
|
+
@page = page
|
12
|
+
|
13
|
+
# If the tags exist, try to convert them to a list of Tag objects
|
14
|
+
self[:rp_tags] &&= self[:rp_tags].split(",").map { |t| Tag.new t }
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Pass the request along to the page's data hash, and allow symbols to be
|
19
|
+
# used by converting them to strings first.
|
20
|
+
def [](key)
|
21
|
+
@page.data[key.to_s]
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(key, value)
|
25
|
+
@page.data[key.to_s] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# Check this page for errors, using the provided list of supported parse
|
30
|
+
# formats
|
31
|
+
#
|
32
|
+
# Returns false if there is no error
|
33
|
+
# Returns error_message if there is an error
|
34
|
+
def errors?(supported_formats)
|
35
|
+
# Verify that formats are specified
|
36
|
+
if self[:format].nil? || self[:format].empty?
|
37
|
+
return "No formats specified"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Verify that the parser for each format exists
|
41
|
+
self[:format].each do |format|
|
42
|
+
return "Format #{format} does not exist." unless supported_formats[format]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Verify that tags exist
|
46
|
+
return "No tags specified" if self[:rp_tags].nil?
|
47
|
+
|
48
|
+
# Verify that arc names are in the proper format
|
49
|
+
if self[:arc_name] && !self[:arc_name].respond_to?("each")
|
50
|
+
return "arc_name must be blank or a YAML list"
|
51
|
+
end
|
52
|
+
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
def options
|
57
|
+
{ strict_ooc: self[:strict_ooc],
|
58
|
+
merge_text_into_rp: self[:merge_text_into_rp],
|
59
|
+
splits_by_character: self[:splits_by_character] }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|