jekyll-rp_logs 0.1.3
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 +7 -0
- data/.gitignore +9 -0
- data/.gitmodules +3 -0
- data/.themes/default/source/_config.yml.default +51 -0
- data/.themes/default/source/_includes/footer.html +23 -0
- data/.themes/default/source/_includes/head.html +13 -0
- data/.themes/default/source/_includes/header.html +27 -0
- data/.themes/default/source/_includes/rp.html +19 -0
- data/.themes/default/source/_layouts/default.html +20 -0
- data/.themes/default/source/_layouts/page.html +14 -0
- data/.themes/default/source/_layouts/post.html +15 -0
- data/.themes/default/source/_layouts/rp.html +32 -0
- data/.themes/default/source/_layouts/tag_index.html +9 -0
- data/.themes/default/source/_sass/_base.scss +204 -0
- data/.themes/default/source/_sass/_layout.scss +236 -0
- data/.themes/default/source/_sass/_rp.scss +142 -0
- data/.themes/default/source/_sass/_syntax-highlighting.scss +67 -0
- data/.themes/default/source/arcs.html +22 -0
- data/.themes/default/source/css/main.scss +64 -0
- data/.themes/default/source/index.html +23 -0
- data/.themes/default/source/js/toggle_ooc.js +93 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +92 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/jekyll-rp_logs.gemspec +30 -0
- data/lib/jekyll/rp_logs/parse_irssi_xchat.rb +47 -0
- data/lib/jekyll/rp_logs/parse_weechat.rb +46 -0
- data/lib/jekyll/rp_logs/rp_arcs.rb +69 -0
- data/lib/jekyll/rp_logs/rp_log_converter.rb +202 -0
- data/lib/jekyll/rp_logs/rp_parser.rb +114 -0
- data/lib/jekyll/rp_logs/rp_tag_index.rb +56 -0
- data/lib/jekyll/rp_logs/rp_tags.rb +107 -0
- data/lib/jekyll/rp_logs/rp_tasks.rb +57 -0
- data/lib/jekyll/rp_logs/version.rb +5 -0
- data/lib/jekyll/rp_logs.rb +18 -0
- metadata +123 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module RpLogs
|
3
|
+
|
4
|
+
class WeechatParser < RpLogs::Parser
|
5
|
+
|
6
|
+
# Add this class to the parsing dictionary
|
7
|
+
FORMAT_STR = 'weechat'
|
8
|
+
RpLogs::RpLogGenerator.add self
|
9
|
+
|
10
|
+
# Stuff
|
11
|
+
class << self
|
12
|
+
MODE = /([+%@&~!]?)/
|
13
|
+
NICK = /([\w\-\\\[\]\{\}\^\`\|]+)/
|
14
|
+
DATE_REGEXP = /(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)/
|
15
|
+
|
16
|
+
FLAGS = /((?:![A-Z]+ )*)/
|
17
|
+
JUNK = /#{DATE_REGEXP}\t<?-->?\t.*$/
|
18
|
+
EMOTE = /^#{FLAGS}#{DATE_REGEXP}\t \*\t#{NICK}\s+([^\n]*)$/
|
19
|
+
TEXT = /^#{FLAGS}#{DATE_REGEXP}\t#{MODE}#{NICK}\t([^\n]*)$/
|
20
|
+
|
21
|
+
TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S'
|
22
|
+
|
23
|
+
def parse_line(line, options = {})
|
24
|
+
case line
|
25
|
+
when JUNK
|
26
|
+
return nil
|
27
|
+
when EMOTE
|
28
|
+
date = DateTime.strptime($2, TIMESTAMP_FORMAT)
|
29
|
+
return Parser::LogLine.new(date, options, sender: $3, contents: $4, \
|
30
|
+
flags: $1, type: :rp)
|
31
|
+
when TEXT
|
32
|
+
date = DateTime.strptime($2, TIMESTAMP_FORMAT)
|
33
|
+
mode = if $3 != '' then $3 else ' ' end
|
34
|
+
return Parser::LogLine.new(date, options, sender: $4, contents: $5, \
|
35
|
+
flags: $1, type: :ooc, mode: mode)
|
36
|
+
else
|
37
|
+
# Only put text and emotes in the log
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Largely inspired by http://brizzled.clapper.org/blog/2010/12/20/some-jekyll-hacks/
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module RpLogs
|
5
|
+
|
6
|
+
# Holds arc information
|
7
|
+
class Arc
|
8
|
+
|
9
|
+
attr_accessor :name, :rps
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
# inspect types
|
13
|
+
name.strip!
|
14
|
+
@name = name
|
15
|
+
|
16
|
+
@rps = []
|
17
|
+
# potential future idea: directories for each arc
|
18
|
+
end
|
19
|
+
|
20
|
+
def <<(rp_page)
|
21
|
+
@rps << rp_page
|
22
|
+
end
|
23
|
+
|
24
|
+
def start_date
|
25
|
+
@rps.map { |rp_page| rp_page.data['start_date'] }.min
|
26
|
+
end
|
27
|
+
|
28
|
+
def end_date
|
29
|
+
@rps.map { |rp_page| rp_page.data['last_post_time'] }.max
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_arc?
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
self.name
|
38
|
+
end
|
39
|
+
|
40
|
+
def eql?(arc)
|
41
|
+
self.class.equal?(arc.class) && (self.name == arc.name) && (self.rps.equal?(arc.rps))
|
42
|
+
end
|
43
|
+
|
44
|
+
def hash
|
45
|
+
self.name.hash
|
46
|
+
end
|
47
|
+
|
48
|
+
# actually by... start.. date?
|
49
|
+
def <=>(o)
|
50
|
+
if self.class == o.class
|
51
|
+
self.name <=> o.name
|
52
|
+
else
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
self.class.name + "[" + @name + "]"
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_liquid
|
62
|
+
# Liquid wants a hash, not an object.
|
63
|
+
|
64
|
+
{ "name" => @name, "rps" => @rps }
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
require_relative 'rp_parser'
|
2
|
+
require_relative 'rp_arcs'
|
3
|
+
require_relative 'rp_tags'
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module RpLogs
|
7
|
+
|
8
|
+
# Consider renaming since it is more of a converter in practice
|
9
|
+
class RpLogGenerator < Jekyll::Generator
|
10
|
+
safe true
|
11
|
+
priority :normal
|
12
|
+
|
13
|
+
RP_KEY = "rps"
|
14
|
+
|
15
|
+
@@parsers = {}
|
16
|
+
|
17
|
+
def RpLogGenerator.add(parser)
|
18
|
+
@@parsers[parser::FORMAT_STR] = parser
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(config)
|
22
|
+
config['rp_convert'] ||= true
|
23
|
+
end
|
24
|
+
|
25
|
+
def skip_page(page, message)
|
26
|
+
@site.collections[RP_KEY].docs.delete page
|
27
|
+
print "\nSkipping #{page.path}: #{message}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_errors?(page)
|
31
|
+
# Verify that formats are specified
|
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
|
44
|
+
|
45
|
+
# Verify that tags exist
|
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
|
54
|
+
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
def generate(site)
|
59
|
+
return unless site.config['rp_convert']
|
60
|
+
@site = site
|
61
|
+
|
62
|
+
# Directory of RPs
|
63
|
+
index = site.pages.detect { |page| page.data['rp_index'] }
|
64
|
+
index.data['rps'] = {'canon' => [], 'noncanon' => []}
|
65
|
+
|
66
|
+
# Arc-style directory
|
67
|
+
arc_page = site.pages.detect { |page| page.data['rp_arcs'] }
|
68
|
+
|
69
|
+
site.data['menu_pages'] = [index, arc_page]
|
70
|
+
|
71
|
+
arcs = Hash.new { |hash, key| hash[key] = Arc.new(key) }
|
72
|
+
no_arc_rps = []
|
73
|
+
|
74
|
+
# Convert all of the posts to be pretty
|
75
|
+
# Also build up our hash of tags
|
76
|
+
site.collections[RP_KEY].docs.select { true }
|
77
|
+
.each { |page|
|
78
|
+
# because we're iterating over a selected array, we can delete from the original
|
79
|
+
begin
|
80
|
+
next if has_errors? page
|
81
|
+
|
82
|
+
page.data['rp_tags'] = page.data['rp_tags'].split(',').map { |t| Tag.new t }
|
83
|
+
|
84
|
+
# Skip if something goes wrong
|
85
|
+
next unless convertRp page
|
86
|
+
|
87
|
+
key = if page.data['canon'] then 'canon' else 'noncanon' end
|
88
|
+
# Add key for canon/noncanon
|
89
|
+
index.data['rps'][key] << page
|
90
|
+
# Add tag for canon/noncanon
|
91
|
+
page.data['rp_tags'] << (Tag.new key)
|
92
|
+
page.data['rp_tags'].sort!
|
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 $!
|
105
|
+
end
|
106
|
+
}
|
107
|
+
|
108
|
+
arcs.each_key { |key| sort_chronologically! arcs[key].rps }
|
109
|
+
combined_rps = no_arc_rps.map { |x| ['rp', x] } + arcs.values.map { |x| ['arc', x] }
|
110
|
+
combined_rps.sort_by! { |type,x|
|
111
|
+
case type
|
112
|
+
when 'rp'
|
113
|
+
x.data['start_date']
|
114
|
+
when 'arc'
|
115
|
+
x.start_date
|
116
|
+
end
|
117
|
+
}.reverse!
|
118
|
+
arc_page.data['rps'] = combined_rps
|
119
|
+
|
120
|
+
sort_chronologically! index.data['rps']['canon']
|
121
|
+
sort_chronologically! index.data['rps']['noncanon']
|
122
|
+
end
|
123
|
+
|
124
|
+
def sort_chronologically!(pages)
|
125
|
+
pages.sort_by! { |p| p.data['start_date'] }.reverse!
|
126
|
+
end
|
127
|
+
|
128
|
+
def convertRp(page)
|
129
|
+
options = get_options page
|
130
|
+
|
131
|
+
compiled_lines = []
|
132
|
+
page.content.each_line { |raw_line|
|
133
|
+
page.data['format'].each { |format|
|
134
|
+
log_line = @@parsers[format].parse_line(raw_line, options)
|
135
|
+
if log_line then
|
136
|
+
compiled_lines << log_line
|
137
|
+
break
|
138
|
+
end
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
if compiled_lines.length == 0 then
|
143
|
+
skip_page(page, "No lines were matched by any format.")
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
|
147
|
+
merge_lines! compiled_lines
|
148
|
+
stats = extract_stats compiled_lines
|
149
|
+
|
150
|
+
split_output = compiled_lines.map { |line| line.output }
|
151
|
+
|
152
|
+
page.content = split_output.join("\n")
|
153
|
+
|
154
|
+
if page.data['infer_char_tags'] then
|
155
|
+
# Turn the nicks into characters
|
156
|
+
nick_tags = stats[:nicks].map! { |n| Tag.new('char:' + n) }
|
157
|
+
page.data['rp_tags'] = (nick_tags.merge page.data['rp_tags']).to_a.sort
|
158
|
+
end
|
159
|
+
|
160
|
+
page.data['end_date'] = stats[:end_date]
|
161
|
+
page.data['start_date'] ||= stats[:start_date]
|
162
|
+
|
163
|
+
true
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_options(page)
|
167
|
+
{ :strict_ooc => page.data['strict_ooc'],
|
168
|
+
:merge_text_into_rp => page.data['merge_text_into_rp'] }
|
169
|
+
end
|
170
|
+
|
171
|
+
def merge_lines!(compiled_lines)
|
172
|
+
last_line = nil
|
173
|
+
compiled_lines.reject! { |line|
|
174
|
+
if last_line == nil then
|
175
|
+
last_line = line
|
176
|
+
false
|
177
|
+
elsif last_line.mergeable_with? line then
|
178
|
+
last_line.merge! line
|
179
|
+
# Delete the current line from output and maintain last_line
|
180
|
+
# in case we need to merge multiple times.
|
181
|
+
true
|
182
|
+
else
|
183
|
+
last_line = line
|
184
|
+
false
|
185
|
+
end
|
186
|
+
}
|
187
|
+
end
|
188
|
+
|
189
|
+
def extract_stats(compiled_lines)
|
190
|
+
nicks = Set.new
|
191
|
+
compiled_lines.each { |line|
|
192
|
+
nicks << line.sender if line.output_type == :rp
|
193
|
+
}
|
194
|
+
|
195
|
+
{ :nicks => nicks,
|
196
|
+
:end_date => compiled_lines[-1].timestamp,
|
197
|
+
:start_date => compiled_lines[0].timestamp }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module RpLogs
|
3
|
+
|
4
|
+
class Parser
|
5
|
+
FORMAT_STR = nil
|
6
|
+
|
7
|
+
class LogLine
|
8
|
+
MAX_SECONDS_BETWEEN_POSTS = 3
|
9
|
+
RP_FLAG = '!RP'
|
10
|
+
OOC_FLAG = '!OOC'
|
11
|
+
|
12
|
+
attr :timestamp, :mode, :sender, :contents
|
13
|
+
attr :flags
|
14
|
+
# Some things depend on the original type of the line (nick format)
|
15
|
+
attr :base_type
|
16
|
+
attr :output_type
|
17
|
+
attr :options
|
18
|
+
|
19
|
+
attr :last_merged_timestamp
|
20
|
+
|
21
|
+
def initialize(timestamp, options = {}, sender:, contents:, flags:, type:, mode: ' ')
|
22
|
+
@timestamp = timestamp
|
23
|
+
# Initialize to be the same as @timestamp
|
24
|
+
@last_merged_timestamp = timestamp
|
25
|
+
@mode = mode
|
26
|
+
@sender = sender
|
27
|
+
@contents = contents
|
28
|
+
@flags = flags.split(' ')
|
29
|
+
|
30
|
+
@base_type = type
|
31
|
+
@output_type = type
|
32
|
+
|
33
|
+
@options = options
|
34
|
+
|
35
|
+
# This makes it RP by default
|
36
|
+
@output_type = :rp if options[:strict_ooc]
|
37
|
+
|
38
|
+
# Check the contents for (
|
39
|
+
@output_type = :ooc if contents.strip[0] == '('
|
40
|
+
|
41
|
+
# Flags override our assumptions, always
|
42
|
+
if flags.include? RP_FLAG then
|
43
|
+
@output_type = :rp
|
44
|
+
elsif flags.include? OOC_FLAG then
|
45
|
+
@output_type = :ooc
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def output
|
50
|
+
# String used for the timestamp anchors
|
51
|
+
anchor = @timestamp.strftime('%Y-%m-%d_%H:%M:%S')
|
52
|
+
# String used when hovering over timestamps (friendly long-form)
|
53
|
+
title = @timestamp.strftime('%H:%M:%S %B %-d, %Y')
|
54
|
+
# String actually displayed on page
|
55
|
+
display = @timestamp.strftime('%H:%M')
|
56
|
+
ts_out = "<a name=\"#{anchor}\" title=\"#{title}\" href=\"##{anchor}\">#{display}</a>"
|
57
|
+
|
58
|
+
sender_out = nil
|
59
|
+
case @base_type
|
60
|
+
when :rp
|
61
|
+
sender_out = " * #{@sender}"
|
62
|
+
when :ooc
|
63
|
+
sender_out = " <#{@mode}#{@sender}>"
|
64
|
+
else
|
65
|
+
# Explode.
|
66
|
+
throw "No known type: #{@base_type}"
|
67
|
+
end
|
68
|
+
|
69
|
+
tag_class = nil
|
70
|
+
tag_close = "</p>"
|
71
|
+
case @output_type
|
72
|
+
when :rp
|
73
|
+
tag_class = "rp"
|
74
|
+
when :ooc
|
75
|
+
tag_class = "ooc"
|
76
|
+
else
|
77
|
+
# Explode.
|
78
|
+
throw "No known type: #{@output_type}"
|
79
|
+
end
|
80
|
+
tag_open = "<p class=\"#{tag_class}\">"
|
81
|
+
|
82
|
+
"#{tag_open}#{ts_out}#{sender_out} #{@contents}#{tag_close}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def mergeable_with?(next_line)
|
86
|
+
# Only merge posts close enough in time
|
87
|
+
# The difference in time between the post merged into this one, and the next post, must be less than the limit
|
88
|
+
close_enough_time = (next_line.timestamp - @last_merged_timestamp) * 24 * 60 * 60 <= MAX_SECONDS_BETWEEN_POSTS
|
89
|
+
# Only merge posts with same sender
|
90
|
+
same_sender = @sender == next_line.sender
|
91
|
+
# Only merge rp lines
|
92
|
+
is_rp = @output_type == :rp
|
93
|
+
# Merge if next post is rp, or sender has split_to_normal_text property
|
94
|
+
# Only merge if the base type was OOC... otherwise you couldn't force not merging
|
95
|
+
# Maybe a job for !NOTMERGE flag, or similar
|
96
|
+
next_line_is_rp = next_line.output_type == :rp || \
|
97
|
+
(@options[:merge_text_into_rp].include?(@sender) && next_line.base_type == :ooc)
|
98
|
+
|
99
|
+
close_enough_time && same_sender && is_rp && next_line_is_rp
|
100
|
+
end
|
101
|
+
|
102
|
+
def merge!(next_line)
|
103
|
+
@contents += ' ' + next_line.contents
|
104
|
+
@last_merged_timestamp = next_line.timestamp
|
105
|
+
end
|
106
|
+
|
107
|
+
def inspect()
|
108
|
+
"<#{@mode}#{@sender}> (#{@base_type} -> #{@output_type}) #{@content}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Again largely inspired by http://brizzled.clapper.org/blog/2010/12/20/some-jekyll-hacks/
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module RpLogs
|
5
|
+
|
6
|
+
class TagIndex < Jekyll::Page
|
7
|
+
def initialize(site, base, dir, tag, pages)
|
8
|
+
@site = site
|
9
|
+
@base = base
|
10
|
+
@dir = dir
|
11
|
+
@name = 'index.html'
|
12
|
+
|
13
|
+
self.process(@name)
|
14
|
+
# Get tag_index filename
|
15
|
+
tag_index = (site.config['rp_tag_index_layout'] || 'tag_index') + '.html'
|
16
|
+
self.read_yaml(File.join(base, '_layouts'), tag_index)
|
17
|
+
self.data['tag'] = tag # Set which tag this index is for
|
18
|
+
# Sort tagged RPs by their start date
|
19
|
+
self.data['pages'] = pages.sort_by { |p| p.data['start_date'] }
|
20
|
+
tag_title_prefix = site.config['rp_tag_title_prefix'] || 'Tag: '
|
21
|
+
self.data['title'] = "#{tag_title_prefix}#{tag}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class TagIndexGenerator < Jekyll::Generator
|
26
|
+
safe true
|
27
|
+
# Needs to run after RpLogGenerator
|
28
|
+
priority :low
|
29
|
+
|
30
|
+
def initialize(config)
|
31
|
+
config['rp_tag_index'] ||= true
|
32
|
+
config['rp_tag_dir'] ||= '/tags'
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate(site)
|
36
|
+
return unless site.config['rp_tag_index']
|
37
|
+
|
38
|
+
dir = site.config['rp_tag_dir']
|
39
|
+
tags = rps_by_tag(site)
|
40
|
+
tags.each_pair { |tag, pages|
|
41
|
+
site.pages << TagIndex.new(site, site.source, File.join(dir, tag.dir), tag, pages)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns a hash of tags => [pages with tag]
|
46
|
+
def rps_by_tag(site)
|
47
|
+
tag_ref = Hash.new { |hash, key| hash[key] = Set.new }
|
48
|
+
site.collections[RpLogGenerator::RP_KEY].docs.each { |page|
|
49
|
+
page.data['rp_tags'].each { |tag| tag_ref[tag] << page }
|
50
|
+
}
|
51
|
+
return tag_ref
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# Largely inspired by http://brizzled.clapper.org/blog/2010/12/20/some-jekyll-hacks/
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module RpLogs
|
5
|
+
|
6
|
+
TAG_NAME_MAP = {
|
7
|
+
"#" => "sharp",
|
8
|
+
"/" => "slash",
|
9
|
+
"\\" => "backslash",
|
10
|
+
" " => "_"
|
11
|
+
}
|
12
|
+
|
13
|
+
# Holds tag information
|
14
|
+
class Tag
|
15
|
+
|
16
|
+
attr_accessor :dir, :name, :type
|
17
|
+
|
18
|
+
TYPES = [:meta, :character, :general]
|
19
|
+
CHAR_FLAG = /char:(.*)/
|
20
|
+
META_TAGS = /(safe|questionable|explicit|canon|noncanon|complete|incomplete)/
|
21
|
+
|
22
|
+
TYPE_CLASSES = {
|
23
|
+
:character => ['rp-tag-character'],
|
24
|
+
:meta => ['rp-tag-meta'],
|
25
|
+
:general => []
|
26
|
+
}
|
27
|
+
|
28
|
+
def initialize(name)
|
29
|
+
# inspect types
|
30
|
+
name.strip!
|
31
|
+
if (name =~ CHAR_FLAG) == 0 then
|
32
|
+
@name = $1
|
33
|
+
@type = :character
|
34
|
+
else
|
35
|
+
@name = name.downcase
|
36
|
+
@type = @name =~ META_TAGS ? :meta : :general
|
37
|
+
end
|
38
|
+
|
39
|
+
@dir = name_to_dir(@name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
self.name
|
44
|
+
end
|
45
|
+
|
46
|
+
def eql?(tag)
|
47
|
+
self.class.equal?(tag.class) && (self.name == tag.name && self.type == tag.type)
|
48
|
+
end
|
49
|
+
|
50
|
+
def hash
|
51
|
+
self.name.hash
|
52
|
+
end
|
53
|
+
|
54
|
+
def <=>(o)
|
55
|
+
if self.class == o.class && self.type == o.type
|
56
|
+
self.name <=> o.name
|
57
|
+
elsif self.type == :character
|
58
|
+
-1
|
59
|
+
elsif o.type == :character
|
60
|
+
1
|
61
|
+
elsif self.type == :meta
|
62
|
+
-1
|
63
|
+
elsif o.type == :meta
|
64
|
+
1
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def inspect
|
71
|
+
self.class.name + "[" + @name + ", " + @dir + "]"
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_liquid
|
75
|
+
# Liquid wants a hash, not an object.
|
76
|
+
|
77
|
+
{ "name" => @name, "dir" => @dir, "classes" => self.classes }
|
78
|
+
end
|
79
|
+
|
80
|
+
def classes
|
81
|
+
TYPE_CLASSES[@type].join ' '
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Map a tag to its directory name. Certain characters are escaped,
|
87
|
+
# using the TAG_NAME_MAP constant, above.
|
88
|
+
def name_to_dir(name)
|
89
|
+
s = ""
|
90
|
+
name.each_char do |c|
|
91
|
+
if (c =~ /[-A-Za-z0-9_|\[\]]/) != nil
|
92
|
+
s += c
|
93
|
+
else
|
94
|
+
c2 = TAG_NAME_MAP[c]
|
95
|
+
if not c2
|
96
|
+
msg = "Bad character '#{c}' in tag '#{name}'"
|
97
|
+
puts("*** #{msg}")
|
98
|
+
raise Exception.new(msg)
|
99
|
+
end
|
100
|
+
s += "#{c2}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module RpLogs
|
5
|
+
class RpTasks
|
6
|
+
include Rake::DSL if defined? Rake::DSL
|
7
|
+
|
8
|
+
def copy_unless_exist(from, to, message = nil)
|
9
|
+
unless File.exist?(to)
|
10
|
+
puts message if message
|
11
|
+
cp from, to
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Octopress
|
16
|
+
def get_stdin(message)
|
17
|
+
print message
|
18
|
+
STDIN.gets.chomp
|
19
|
+
end
|
20
|
+
|
21
|
+
# Octopress
|
22
|
+
def ask(message, valid_options)
|
23
|
+
if valid_options
|
24
|
+
answer = get_stdin("#{message} #{valid_options.to_s.gsub(/"/, '').gsub(/, /,'/')} ") while !valid_options.include?(answer)
|
25
|
+
else
|
26
|
+
answer = get_stdin(message)
|
27
|
+
end
|
28
|
+
answer
|
29
|
+
end
|
30
|
+
|
31
|
+
def install_tasks
|
32
|
+
namespace :rp_logs do
|
33
|
+
|
34
|
+
directory '_rps'
|
35
|
+
|
36
|
+
desc 'Create a new Jekyll site for RP logs, with the default theme'
|
37
|
+
task :new do |args|
|
38
|
+
if File.directory?("_sass")
|
39
|
+
abort("rake aborted!") if ask("A theme is already installed, proceeding will overwrite existing non-custom files. Are you sure?", ['y', 'n']) == 'n'
|
40
|
+
end
|
41
|
+
|
42
|
+
Rake::Task[:_rps].invoke
|
43
|
+
# allow directory specification
|
44
|
+
|
45
|
+
gem_root = Gem::Specification.find_by_name("jekyll-rp_logs").gem_dir
|
46
|
+
cp_r Dir["#{gem_root}/.themes/default/source/*"], "./"
|
47
|
+
copy_unless_exist("_config.yml.default", "_config.yml")
|
48
|
+
touch "_sass/_custom-vars.scss"
|
49
|
+
touch "_sass/_custom-rules.scss"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Jekyll::RpLogs::RpTasks.new.install_tasks
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "jekyll/rp_logs/version"
|
2
|
+
require 'jekyll'
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
module RpLogs
|
6
|
+
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Require the main converter plugin first
|
11
|
+
require 'jekyll/rp_logs/rp_log_converter'
|
12
|
+
require 'jekyll/rp_logs/rp_tag_index'
|
13
|
+
|
14
|
+
# Now require all of the parsers
|
15
|
+
Gem.find_files("jekyll/rp_logs/parse*.rb").each { |path| require path }
|
16
|
+
|
17
|
+
# Require the rake tasks
|
18
|
+
require 'jekyll/rp_logs/rp_tasks'
|