class MindWords

Attributes

filepath[RW]
lines[RW]

Public Class Methods

new(raws='', parent: nil, debug: false) click to toggle source
# File lib/mindwords.rb, line 25
def initialize(raws='', parent: nil, debug: false)

  @parent, @debug = parent, debug
      
  s, type = RXFHelper.read raws
  
  @filepath = raws if type == :file or type == :dfs
  lines = s.strip.gsub(/^\n/,'').lines.uniq
  lines.shift if lines.first =~ /<\?mindwords\?>/       
  
  @lines = lines.inject([]) do |r,line|
    
    # the following does 2 things:
    #      1. splits words separated by a bar (|) onto their own line
    #      2. prefixes a word with an underscore if the word is the
    #         same as the hashtag. That way it's not removed by the
    #         redundancy checker

    raw_words, raw_hashtags = line.split(/(?= #)/,2)
    words = raw_words.split(/ *\| */)
    hashtags = raw_hashtags.scan(/(?<=#)\w+/)
    
    words.each do |word| 
      
      linex = (word +  raw_hashtags)
      r << (hashtags.include?(word) ? linex.sub!(/\b#{word}\b/, '_\0') \
            : linex)
    end

    r
  end
  
end

Public Instance Methods

add(s) click to toggle source
# File lib/mindwords.rb, line 59
def add(s)
  
  @lines.concat s.strip.lines
  
end
breadcrumb() click to toggle source
element(id) click to toggle source
# File lib/mindwords.rb, line 74
def element(id)
  
  doc = Rexle.new(to_xml())
  e =  doc.root.element("//*[@id='#{id}']")
  #e.attributes[:breadcrumb].to_s if e
  
end
hashtags() click to toggle source
# File lib/mindwords.rb, line 82
def hashtags()
  @parent.attributes[:hashtags].split if @parent
end
headings() click to toggle source
# File lib/mindwords.rb, line 69
def headings()
  breadcrumb[0..-2]
end
linesplus() click to toggle source

same as lines but inludes the breadcrumb path; Helpful to identify which words don't have a breadcrumb path.

# File lib/mindwords.rb, line 95
def linesplus()
  
  to_a.map do |word, _|
    r = search word
    r ? [word, r.breadcrumb] : [r, nil]
  end
  
end
lookup(s) click to toggle source

helpful when searching for a word itself using autosuggest

# File lib/mindwords.rb, line 88
def lookup(s)
  self.to_words.keys.sort.grep /^#{s}/i
end
reflect(raws) click to toggle source

Accepts a list of words with the aim of returning a MindWords document using matched words with hashtags from the existing MindWords document.

# File lib/mindwords.rb, line 117
def reflect(raws)
  
  h = to_h
  
  missing_words = []
  
  # add the tags from the main list
  a = raws.strip.lines.map do |x| 
    if h[x.chomp] then
      [x.chomp, h[x.chomp]]
    else
      missing_words << x
      nil
    end
  end.compact

  # add any linkage words from the tags
  #
  a.map(&:last).flatten(1).each do |s|

    a << [s, h[s]] if h[s]

  end

  # remove suplicates lines and transform it into a raw mindwords format
  #
  raws3 = a.uniq.map {|s,tags| [s, tags.map {|x| '#' + x }.join(' ')].join(' ') }.join("\n")

  [MindWords.new(raws3), missing_words]
  
end
save(file=@filepath) click to toggle source
# File lib/mindwords.rb, line 104
def save(file=@filepath)
  
  return if @lines.empty?
  
  puts 'before save' if @debug
  
  File.write file, to_s()
  
end
sort() click to toggle source
# File lib/mindwords.rb, line 199
def sort()
  s = @lines.sort.join
  
  def s.to_s()
    self.lines.map do |x|
      title, hashtags = x.split(/(?=#)/,2)
      title + hashtags.chomp.brown
    end.join("\n")
  end    
  
  return s
end
sort!() click to toggle source
# File lib/mindwords.rb, line 212
def sort!()
  @lines = sort().lines
  self
end
tag_sort() click to toggle source
# File lib/mindwords.rb, line 217
def tag_sort()
  
  h = @lines.group_by  {|x| x[/#\w+/]}    
  s = h.sort.map {|key, value| value.sort }.join
  
  def s.to_s()
    self.lines.map do |x|
      title, hashtags = x.split(/(?=#)/,2)
      title + hashtags.chomp.brown
    end.join("\n")
  end
  
  return s
  
end
tag_sort!() click to toggle source
# File lib/mindwords.rb, line 233
def tag_sort!()
  @lines = tag_sort().lines
  self
end
to_a() click to toggle source
# File lib/mindwords.rb, line 238
def to_a()
  
  @lines.map do |x| 
    s, rawtags = x.split(/(?= #)/,2)
    [s, rawtags.scan(/(?<=#)\w+/)]
  end
  
end
to_h() click to toggle source
# File lib/mindwords.rb, line 247
def to_h()
  to_a.to_h
end
to_hashtags() click to toggle source
# File lib/mindwords.rb, line 251
def to_hashtags()
  @hashtags
end
to_outline(sort: true) click to toggle source
# File lib/mindwords.rb, line 255
def to_outline(sort: true)
  
  build()
  
  if sort then
    a = LineTree.new(@outline).to_a
    puts ('a: ' + a.inspect).debug if @debug 
    a2tree(tree_sort(a))
  else
    @outline
  end
  
end
Also aliased as: to_tree
to_s(colour: false) click to toggle source
# File lib/mindwords.rb, line 271
def to_s(colour: false)
  
  header = "<?mindwords?>\n\n"
  return header + @lines.map(&:chomp).join("\n") unless colour
  
  body = @lines.map do |x|
      title, hashtags = x.split(/(?=#)/,2)
      title + hashtags.chomp.brown
  end.join("\n")
  
  header + body
  
end
to_tree(sort: true)
Alias for: to_outline
to_words() click to toggle source
# File lib/mindwords.rb, line 285
def to_words()
  
  h = {}
  
  Rexle.new(to_xml).root.each_recursive do |e|
    
    h[e.attributes[:title]] = {
      breadcrumb: e.attributes[:breadcrumb], 
      hashtags: e.attributes[:hashtags]
    }
    
  end
  
  h
  
end
to_xml() click to toggle source
# File lib/mindwords.rb, line 302
def to_xml()
  build() unless @xml
  @xml
end

Private Instance Methods

a2tree(a, indent=0) click to toggle source
# File lib/mindwords.rb, line 487
def a2tree(a, indent=0)

  a.map do |row|
    title, *remaining = row
    children = remaining ? a2tree(remaining, indent+1) : ''
    ('  ' * indent) + title + "\n" + children
  end.join

end
build() click to toggle source
# File lib/mindwords.rb, line 309
def build()
  
  h = {}

  @lines.each do |line|

    title, rawtags = line.split(/(?= #)/,2)
    
    rawtags.scan(/#(\w+)/).flatten(1).each do |rawtag|
      tag = rawtag.gsub(/ +/, '_')
      h[tag] ||= []
      h[tag] << title.strip
    end

  end
  
  @hashtags = h.deep_clone.sort.map {|tag, fields| [tag, fields.sort]}.to_h

  
  a = rexlize(h)
  doc = Rexle.new(['root', {}, '', *a])

  # apply node nesting

  doc.root.elements.each do |e|
    
    doc.root.xpath('//' + e.name).each do |e2|
      
      next if e2 === e
      
      e2.parent.add e
      e2.delete
      
    end
    
  end

  
  # remove duplicates which appear in the same branch above the nested node
  rm_duplicates(doc)
  
  # remove redundant nodes (outsiders)
  # a redundant node is where all children exist in existing nested nodes

  redundants = doc.root.elements.map do |e|

    r = e.elements.all? {|x| !x.has_elements?}
    puts "%s %s" % [e.name, r] if @debug
    dups = e.elements.all? {|x| doc.root.xpath('//' + x.name).length > 1}
    puts 'dups: ' + dups.inspect if @debug
    e.backtrack.to_s if dups

  end
  
  puts 'redundants: ' + redundants.inspect if @debug

  redundants.compact.each {|x| doc.element(x).delete }
 
  node = if @parent then
    found = doc.root.element('//' + @parent.name)
    found ? found.parent : doc.root
  else
    doc.root
  end
  
  # the following removes any undescore prefix from words which were the
  # same as the hashtag
  
  node.root.each_recursive do |e|

    next unless e
    puts 'e: ' + e.inspect if @debug
    
    e.attributes[:id] = e.attributes[:id].sub(/^_/,'') if e.attributes[:id]
    e.attributes[:title] = e.attributes[:title].sub(/^_/,'') if e.attributes[:title]
    e.value = e.value.sub(/^_/,'')
    e.name = e.name.sub(/^_/,'')
    
  end    
  
  # ----
  
  @outline = treeize node
  
  node.root.each_recursive do |e|
  
    e.attributes[:id] = e.attributes[:title].downcase.gsub(/ +/,'-')      
    
    s = e.parent.attributes[:breadcrumb] ? \
        e.parent.attributes[:breadcrumb].to_s  + ' / ' : ''
    e.attributes[:breadcrumb] = s +  e.value.strip
    
    r = @lines.grep(/^#{e.attributes[:title]} #/i)
    next unless r.any?
    e.attributes[:hashtags] = r[0].scan(/(?<=#)\w+/).join(' ')

    
  end
  
  @xml = node.xml pretty: true

end
rexlize(a) click to toggle source
# File lib/mindwords.rb, line 412
def rexlize(a)
  
  a.map do |x|
   
    puts 'x: ' + x.inspect if @debug

    case x
    when String
      [x.downcase.gsub(/ +/,''),  {title: x}, x]
    when Hash
      [
        x.keys.first.downcase.gsub(/_/,' '), 
        {title: x.keys.first}, 
        x.keys.first,
       *rexlize(x.values.first)
      ]
    when Array
      [
        x.first.downcase.gsub(/_/,' '), 
        {title: x.first}, x.first, *rexlize(x.last)
      ]
    end
  end

end
rm_duplicates(doc) click to toggle source
# File lib/mindwords.rb, line 438
def rm_duplicates(doc)
  
  duplicates = []
  
  doc.root.each_recursive do |e|

    rows = e.parent.xpath('//' + e.name)
    next if rows.length < 2

    rows[0..-2].each {|e2| duplicates << e.backtrack.to_s }
  
  end

  duplicates.each do |path|
    
    puts 'pathx: ' + path.inspect if @debug
    e = doc.element(path)
    e.delete if e
    
  end   

end
tree_sort(a) click to toggle source
# File lib/mindwords.rb, line 476
def tree_sort(a)

  if a.first.is_a? Array then
    a.sort_by(&:first).map {|x|  tree_sort(x) }
  elsif a.any?
    [a.first] + tree_sort(a[1..-1])
  else
    []
  end
end
treeize(node, indent=0) click to toggle source
# File lib/mindwords.rb, line 461
def treeize(node, indent=0)

  s, *children = node.children

  lines = children.map do |e|

    puts 'e: ' + e.inspect if @debug
    if e.is_a? Rexle::Element then
      ('  ' * indent) + e.value.to_s +  "\n" + treeize(e,indent+1) 
    end
  end

  lines.join
end