class MdEdit
Attributes
phraseslookup[R]
sections[R]
Public Class Methods
new(md, debug: false, root: 'Thoughts')
click to toggle source
pass in a Markdown document or a Markdown filename
# File lib/md_edit.rb, line 19 def initialize(md, debug: false, root: 'Thoughts') @debug = debug s, @filename = if md.lines.length == 1 then File.write(md, "# #{root}\n\n") unless File.exists? md File.exists?(md) ? [File.read(md), md] : md else md end load_sections(s) end
Public Instance Methods
create(s)
click to toggle source
# File lib/md_edit.rb, line 38 def create(s) @s = @s.rstrip + "\n\n" + s.sub(/^(?=\w)/,'## ').sub(/#+ [a-z]/)\ {|x| x.upcase}.sub(/(?!=^\n)$/,"\n\n") load_sections(@s) save() :created end
delete(s)
click to toggle source
specify a heading to delete a section
# File lib/md_edit.rb, line 50 def delete(s) key = @sections.keys.grep(/#{s.downcase}/i).first old_value = @sections[key].flatten.join heading = last_heading(key) old_section = heading + old_value @s.sub!(old_section, '') load_sections(@s) save() :deleted end
find(s, heading: true)
click to toggle source
# File lib/md_edit.rb, line 95 def find(s, heading: true) key = @sections.keys\ .grep(/#{s.downcase.gsub('(','\(').gsub(')','\)')}/i).first return unless key headings = key.lines.first.split(/ > /) title = "%s %s" % ['#' * headings.length, headings.last] a = [title, @sections[key].join] heading ? a.join : a end
query(s, full_trail: false, limit: 10)
click to toggle source
# File lib/md_edit.rb, line 108 def query(s, full_trail: false, limit: 10) puts 'query() s: ' + s.inspect if @debug results = [] r = @headingslookup.q s puts 'query() r: ' + r.inspect if @debug if r and r.any? then results = if full_trail then r else r.map do |x| headings = x.split(' > ') headings.length > 1 ? headings[1..-1].join(' > ') : headings[0] end.reject(&:empty?) end end r2 = @phraseslookup.q s, search_tags: true if r2 and r2.any? then a = r2.sort_by {|x| -x.length} # attempt to remove duplicate results from the 1 section a2 = a.group_by {|x| x[/\[[^\]]+\]/]} a2.each do |k,v| s4 = v.first[/\]\s*(.*)/mi,1] index = s4 =~ /#{s}/mi s2 = make_snippet(s4, index, words: [2,2]) v[1..-1].each do |x| s5 = x[/\]\s*(.*)/,1] index2 = s5 =~ /#{s}/ if index2 then s3 = make_snippet(s5, index2, words: [2,2]) v.delete x if s2 =~ /#{s3}/ else v.delete x end end end end if a2 then h = a2.values.flatten(1).group_by {|x| x[/\[[^\]]+\]/]} phrases_found = h.to_a.flat_map do |raw_heading,v| # get rid of results which are almost duplicate (contain a # subset of text from the 1st result) phrases = v.map {|x| x[/\] +(.*)/,1]} filtered_phrases = phrases[1..-1].reject {|x| phrases[0].include? x } filtered_phrases.unshift(phrases[0]) # get rid of the top level heading from the heading trailing heading = if raw_heading =~ / > / then raw_heading[1..-2].split(' > ')[1..-1].join(' > ') else raw_heading[1..-2] end filtered_phrases.map {|phrase| "[%s] %s" % [heading, phrase] } end results.concat phrases_found if phrases_found end results.take limit end
Also aliased as: q
to_h()
click to toggle source
# File lib/md_edit.rb, line 214 def to_h() @h end
to_outline(bullets: false)
click to toggle source
# File lib/md_edit.rb, line 206 def to_outline(bullets: false) a = indentor(@s.scan(/^#+ [^\n]+/).join("\n")) .lines.map {|x| x.sub(/#+ +/,'')} bullets ? a.map{|x| x.sub(/\b/,'- ')} : a.join end
to_s()
click to toggle source
# File lib/md_edit.rb, line 218 def to_s() @s end
update(raw_value, heading: nil )
click to toggle source
update a section by heading title e.g. ## To-donn[ ] Vacuum the bedroom
# File lib/md_edit.rb, line 66 def update(raw_value, heading: nil ) value = raw_value.gsub(/\r/,'').chomp + "\n" title = (heading ? heading : value.lines.first.chomp)[/#+ +(.*)/,1] key = @sections.keys.grep(/#{title.downcase}/i).first return unless key old_value = @sections[key].flatten.join puts 'old_value: ' + old_value.inspect if @debug heading = last_heading(key) old_section = value =~ /^#+/ ? heading + old_value : old_value puts 'old_section: ' + old_section.inspect if @debug @s.sub!(old_section, value) puts '@s: ' + @s.inspect if @debug load_sections(@s) save() :updated end
Also aliased as: edit
Private Instance Methods
build_keyword_list(s, heading)
click to toggle source
returns a hash object; each key contains the heading as well as a phrase
# File lib/md_edit.rb, line 226 def build_keyword_list(s, heading) a = s.split.uniq.flat_map do |raw_word| i, pos = 0, [] w = raw_word[/\w{2,}/] next if IGNOREWORDS.include? w next unless w (pos << (s[i..-1] =~ /#{w}/i); i += pos[-1] + 1) while s[i..-1][/#{w}/i] pos[1..-1].inject([pos[0]]) {|r,x| r << r.last + x + 1 } pos.map do |x| start = x-15 start = 0 if start < 0 snippet = make_snippet(s, start) "[%s] %s | %s %s" % [heading, snippet, w.downcase, heading.scan(/\w+/).join(' ').downcase] end end a end
indentor(s)
click to toggle source
# File lib/md_edit.rb, line 258 def indentor(s) a = s.split(/(?<=\n)(?=#+)/) a.map.with_index do |x, i| # get the indentation level indent = x[/^#+/].count('#') - 1 lines = x.lines lines.first.prepend(' ' * indent) + lines[1..-1].map {|y| (' ' * indent) + ' ' + y}.join end.join end
last_heading(key)
click to toggle source
# File lib/md_edit.rb, line 274 def last_heading(key) a = key.lines.first.split(/ > /) "%s %s" % ['#' * a.length, a.last] end
load_sections(s)
click to toggle source
# File lib/md_edit.rb, line 281 def load_sections(s) @sections = parse s h = @sections.keys.inject({}) do |r,x| r.merge(x.sub(/^#+ +/,'').downcase => 5 - x.count('#')) end puts 'h: ' + h.inspect if @debug @headingslookup = PhraseLookup.new h @h = h.to_a.map {|k,v| [k.split(' > ').last, v]}.to_h @s = s phrases = @sections.flat_map do |heading, raw_value| a = raw_value.take_while {|x| x.is_a? String} next unless a and a.join.strip.length > 0 #next if a.nil? or a.join.strip.empty? build_keyword_list(a.join.strip, heading).compact.map do |s| [s, 4 - heading.count('>')] end end @phraseslookup = PhraseLookup.new phrases.compact.to_h end
make_snippet(raw_s, start, words: [2, 8])
click to toggle source
# File lib/md_edit.rb, line 309 def make_snippet(raw_s, start, words: [2, 8]) s = raw_s.gsub(/\n/,' ') take_words_behind(s[0..start], words: words[0]) + take_words(s[start+1..-1], words: words[-1]) end
parse(markdown)
click to toggle source
# File lib/md_edit.rb, line 316 def parse(markdown) s = indentor(markdown) puts "s: \n" + s if @debug a = LineTree.new(s, ignore_blank_lines: false, ignore_newline: false).to_a puts 'a: ' + a.inspect if @debug h = {} scan a, h return h end
save()
click to toggle source
# File lib/md_edit.rb, line 329 def save() File.write @filename, @s if @filename end
scan(a, h={}, trail=[])
click to toggle source
# File lib/md_edit.rb, line 333 def scan(a, h={}, trail=[]) a.map do |x| raw_head = x.first if raw_head =~ /^#/ then head = raw_head[/^[^\n]+/] fullkey = trail + [head[/#+ +(.*)/,1]] key = fullkey.join(" > ") h[key] = nil r = scan(x[1..-1], h, fullkey) h[key] = ["\n"] + r [head + "\n", r] else x.flatten.join end end end
take_words(s, words: 8)
click to toggle source
# File lib/md_edit.rb, line 360 def take_words(s, words: 8) r = s[/^(?:\S+\s+){#{words}}/m] r ? r : s end
take_words_behind(s, words: 2)
click to toggle source
# File lib/md_edit.rb, line 367 def take_words_behind(s, words: 2) r = s[/(?:\s+\S+){#{words}}$/m] r ? r : s end