Skip to content

Commit

Permalink
Updated the Tag Implication Handler to handle tags instead of strings…
Browse files Browse the repository at this point in the history
… so that tags can have stats attached to them.
  • Loading branch information
tecknojock authored and irisfofs committed Jul 17, 2017
1 parent 7224fb4 commit 3e10e34
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 25 deletions.
7 changes: 4 additions & 3 deletions lib/jekyll/rp_logs/rp_log_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def initialize(config)
RpLogGenerator.extract_settings(config)
LogLine.extract_settings(config)
Page.extract_settings(config)
Tag.extract_settings(config)

Jekyll.logger.info "Loaded jekyll-rp_logs #{RpLogs::VERSION}"
end
Expand Down Expand Up @@ -122,7 +123,7 @@ def doc.render_with_liquid?
##
# Returns a list of RpLogs::Page objects that are error-free.
def extract_valid_rps(site)
site.collections[rp_key].docs.map { |p| RpLogs::Page.new(p,site.config) }
site.collections[rp_key].docs.map { |p| RpLogs::Page.new(p) }
.reject do |p|
message = p.errors?(self.class.parsers)
skip_page(site, p, message) if message
Expand Down Expand Up @@ -161,7 +162,7 @@ def convert_page(page, site, main_index, arcs, no_arc_rps)
# Add key for canon/noncanon
main_index.data["rps"][key] << page
# Add tag for canon/noncanon
page[:rp_tags] << (Tag.new(key, site.config))
page[:rp_tags] << (Tag.new(key))
page[:rp_tags].sort!

arc_name = page[:arc_name]
Expand Down Expand Up @@ -212,7 +213,7 @@ def sort_chronologically!(pages)

def convert_rp(site, page)
msg = catch :skip_page do
page.convert_rp(self.class.parsers,site.config)
page.convert_rp(self.class.parsers)
return true
end
skip_page(site, page, msg)
Expand Down
40 changes: 31 additions & 9 deletions lib/jekyll/rp_logs/rp_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ def tag_config(config)
end
end

def initialize(page,config)
def initialize(page)
@page = page

# If the tags exist, try to convert them to a list of Tag objects
return unless self[:rp_tags].is_a?(String)
self[:rp_tags] = Tag[config, self[:rp_tags].split(",")]
self[:rp_tags] = Tag[self[:rp_tags].split(",")]
end

##
Expand All @@ -60,6 +60,28 @@ def tag_strings
tags.map(&:to_s)
end

def tag_set
if tags.uniq.length == tags.length
tags.to_set
else
tags.group_by{|i|i.to_s}.each_with_object([]){|(_,v),o|
if v.length == 1
o << v[0]
else
tag = nil
v.each_with_object{|t|
if tag
tag.update_stats! t.stats
else
tag = t
end
}
o << tag
end
}.to_set
end
end

def canon
self[:canon] ? "canon" : "noncanon"
end
Expand All @@ -68,7 +90,7 @@ def description
self[:description]
end

def convert_rp(parsers, config)
def convert_rp(parsers)
compiled_lines = convert_all_lines(parsers)

merge_lines! compiled_lines
Expand All @@ -78,7 +100,7 @@ def convert_rp(parsers, config)
split_output = compiled_lines.map(&:output)
page.content = split_output.join("\n")

update_page_properties(stats, config)
update_page_properties(stats)

true
end
Expand Down Expand Up @@ -113,8 +135,8 @@ def options

##
# Updates tags with implications and aliases.
def update_tags(config)
self[:rp_tags] = Tag[config, self.class.tag_implication_handler.update_tags(tag_strings.to_set)]
def update_tags
self[:rp_tags] = self.class.tag_implication_handler.update_tags(tag_set).to_a
self
end

Expand Down Expand Up @@ -215,13 +237,13 @@ def extract_stats(compiled_lines)
# - Adds tags based on nicks involved, if the infer_char_tags option is
# set to true.
# - Updated end and start date.
def update_page_properties(stats, config)
def update_page_properties(stats)
if self[:infer_char_tags]
# Turn the nicks into characters
nick_tags = stats[:nicks].map! { |n| Tag.new("char:#{n}",config) }
nick_tags = stats[:nicks].map! { |n| Tag.new("char:#{n}") }
self[:rp_tags] = (nick_tags.merge self[:rp_tags]).to_a.sort
end
update_tags(config)
update_tags

self[:end_date] = stats[:end_date]
self[:start_date] ||= stats[:start_date]
Expand Down
34 changes: 25 additions & 9 deletions lib/jekyll/rp_logs/rp_tag_implication_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ def initialize(config)
def update_tags(tag_set, verbose: false)
removed_tags = Set.new
loop do
previous_tags = tag_set.clone
previous_tags = tag_set.map{|t|t.to_s}

implicate_tags(tag_set, removed_tags, verbose)
alias_tags(tag_set, removed_tags)

# Break when there is no change in tags.
return tag_set if tag_set == previous_tags
return tag_set if tag_set.map{|t|t.to_s} == previous_tags
end
end

Expand All @@ -50,7 +50,7 @@ def validate_tag_rules
error_for_aliases_that_should_be_implications

# Check for loooops.
starter_tags = @tag_implications.keys.to_set.merge @tag_aliases.keys
starter_tags = Tag[@tag_implications.keys].to_set.merge Tag[@tag_aliases.keys]
update_tags(starter_tags, verbose: true)
end

Expand All @@ -61,7 +61,7 @@ def validate_tag_rules
# They can't remove tags.
def implicate_tags(tag_set, removed_tags, verbose)
until_tags_stabilize(tag_set) do |tag, to_add|
imply = @tag_implications.fetch(tag, [])
imply = @tag_implications.fetch(tag.to_s, [])

removed, imply = imply.partition { |t| removed_tags.include? t }
# It's okay if we want to imply a removed tag. Maybe?
Expand All @@ -70,7 +70,9 @@ def implicate_tags(tag_set, removed_tags, verbose)
Jekyll.logger.warn "#{tag} implies #{removed}, which #{string}. Consider implying "\
"the alised tag directly."
end


imply = Tag[imply]
imply.each{|t| t.update_stats! tag.stats}
to_add.merge imply
end
end
Expand All @@ -79,18 +81,21 @@ def implicate_tags(tag_set, removed_tags, verbose)
# Iteratively apply tag aliases until no more can be applied
def alias_tags(tag_set, removed_tags)
until_tags_stabilize(tag_set) do |tag, to_add|
next unless @tag_aliases.key? tag
aliased = @tag_aliases[tag]
next unless @tag_aliases.key? tag.to_s
aliased = @tag_aliases[tag.to_s]

# If we are trying to alias back a tag already removed, there is a
# cycle in the tag aliases and implications.
removed = aliased.find { |t| removed_tags.include? t }
error_for_cyclical_tags(tag, removed) if removed
error_for_cyclical_tags(tag.to_s, removed) if removed

# if it's already in the set, something weird happened
removed_tags << tag
removed_tags << tag.to_s
tag_set.delete tag
aliased = Tag[aliased]
aliased.each{|t| t.update_stats! tag.stats}
to_add.merge aliased
alias_loop = true
end
end

Expand All @@ -107,6 +112,7 @@ def error_for_cyclical_tags(tag, removed_tag)
# implications to add.
def until_tags_stabilize(tag_set)
tags_to_check = tag_set
alias_loop = false
loop do
# Because we use this set again as the tags to check we don't want
# to clear it.
Expand All @@ -116,6 +122,16 @@ def until_tags_stabilize(tag_set)
end

break if to_add.empty?
if alias_loop
tag_set = tag_set.to_a
to_add.each{|t|
index = tag_set.find_index{|v|v.eql? t}
if index
tag_set[index].update_stats t
end
}
tag_set = tag_set.to_set
end
tag_set.merge to_add
tags_to_check = to_add
end
Expand Down
32 changes: 28 additions & 4 deletions lib/jekyll/rp_logs/rp_tags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ module RpLogs
class Tag
include Comparable

class << self
attr_reader :char_tag_format

def extract_settings(config)
@char_tag_format = (config["char_tag_format"] || "").downcase.freeze
end
end

TYPES = [:meta, :character, :general].freeze
CHAR_FLAG = /^(char:|char-)(?<char_name>.*)/
META_TAGS = /(safe|questionable|explicit|canon|noncanon|complete|incomplete)/
Expand All @@ -31,15 +39,15 @@ class Tag

##
# Inspired by Hash, convert a list of strings to a list of Tags.
def self.[](config, *args)
args[0].map { |t| Tag.new(t,config) }
def self.[](*args)
args[0].map { |t| Tag.new(t) }
end

def initialize(name,config={"char_tag_format"=>"none"} )
def initialize(name)
# inspect types
my_name = name.strip
if CHAR_FLAG =~ my_name
case (config["char_tag_format"] || "").downcase
case @char_tag_format
when "upcase"; @name = $LAST_MATCH_INFO[:char_name].upcase
when "downcase"; @name = $LAST_MATCH_INFO[:char_name].downcase
when "capitalize_preserve"; @name = $LAST_MATCH_INFO[:char_name].gsub(/(?<![a-zA-Z])[a-zA-Z]/){|s|s.capitalize}
Expand Down Expand Up @@ -78,6 +86,22 @@ def hash
to_s.hash
end

def stats
@stats
end

##
# Update tag stats
def update_stats!(newstats)
if newstats
if @stats
@stats.merge(newstats) {|k,v1,v2|v1+v2}
else newstats
@stats = newstats
end
end
end

##
# Compares two tags. Character tags are less than meta tags, and meta
# tags are less than general tags. Two tags of the same type are compared
Expand Down

0 comments on commit 3e10e34

Please sign in to comment.