jekyll-rp_logs 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|