class Rticles::Document

Constants

CONTINUATION_RE
HEADING_RE
LIST_RE
NAME_RE
TOPIC_RE

Attributes

choices[RW]
insertions[RW]

Public Class Methods

create_paragraphs_from_array(document, parent, array) click to toggle source
# File lib/rticles/document.rb, line 79
def self.create_paragraphs_from_array(document, parent, array)
  array.each do |text_or_sub_array|
    case text_or_sub_array
    when String
      name = nil
      topic = nil
      continuation = false
      heading = nil
      list = false

      if name_match = text_or_sub_array.match(NAME_RE)
        text_or_sub_array = text_or_sub_array.sub(NAME_RE, '')
        name = name_match[1]
      end

      if topic_match = text_or_sub_array.match(TOPIC_RE)
        text_or_sub_array = text_or_sub_array.sub(TOPIC_RE, '')
        topic = topic_match[1]
      end

      if text_or_sub_array.match(CONTINUATION_RE)
        text_or_sub_array = text_or_sub_array.sub(CONTINUATION_RE, '')
        continuation = true
      end

      if heading_match = text_or_sub_array.match(HEADING_RE)
        text_or_sub_array = text_or_sub_array.sub(HEADING_RE, '')
        if heading_match[1].empty?
          heading = 1
        else
          heading = heading_match[1].sub(/\A#/, '').to_i
        end
      end

      if text_or_sub_array.match(LIST_RE)
        text_or_sub_array = text_or_sub_array.sub(LIST_RE, '')
        list = true
      end

      document.paragraphs.create(
        :parent_id => parent ? parent.id : nil,
        :body => text_or_sub_array,
        :name => name,
        :topic => topic,
        :heading => heading,
        :continuation => continuation,
        :list => list
      )
    when Array
      paragraphs_relation = parent ? parent.children : document.paragraphs.select{|p| p.parent_id.nil?}
      if paragraphs_relation.empty?
        raise RuntimeError, "jump in nesting at: #{text_or_sub_array.first}"
      end
      create_paragraphs_from_array(
        document,
        paragraphs_relation.last,
        text_or_sub_array
      )
    end
  end
end
from_yaml(yaml) click to toggle source
# File lib/rticles/document.rb, line 70
def self.from_yaml(yaml)
  parsed_yaml = YAML.load(yaml)
  document = self.create

  create_paragraphs_from_array(document, nil, parsed_yaml)

  document
end

Public Instance Methods

after_initialize() click to toggle source
# File lib/rticles/document.rb, line 21
def after_initialize
  set_up_insertions
  set_up_choices
end
numbering_config() click to toggle source
# File lib/rticles/document.rb, line 171
def numbering_config
  @numbering_config ||= Rticles::Numbering::Config.new
end
outline(options={}) click to toggle source
# File lib/rticles/document.rb, line 36
def outline(options={})
  options = options.with_indifferent_access
  for_display = options[:for_display]

  o = []
  top_level_paragraphs.each do |tlp|
    body = for_display ? tlp.body_for_display({:insertions => insertions, :choices => choices}.merge(options)) : tlp.body
    if body
      o.push(for_display ? tlp.body_for_display({:insertions => insertions, :choices => choices}.merge(options)) : tlp.body)
      unless tlp.children.empty?
        o.push(sub_outline(tlp, options.merge(list: tlp.list?)))
      end
    end
  end
  o
end
paragraph_for_reference(raw_reference) click to toggle source
# File lib/rticles/document.rb, line 141
def paragraph_for_reference(raw_reference)
  # TODO optimise
  Rails.logger.debug("Finding raw reference: #{raw_reference}")
  paragraphs.all.detect{|p| p.full_index == raw_reference}
end
paragraph_numbers_for_topic(topic, consolidate=false) click to toggle source
# File lib/rticles/document.rb, line 147
def paragraph_numbers_for_topic(topic, consolidate=false)
  paragraph_numbers_for_topics([topic], consolidate)
end
paragraph_numbers_for_topics(topics, consolidate=false) click to toggle source
# File lib/rticles/document.rb, line 151
def paragraph_numbers_for_topics(topics, consolidate=false)
  relevant_paragraphs = paragraphs.where(:topic => topics)
  relevant_paragraphs = relevant_paragraphs.for_choices(choices)
  # TODO Sorting by position won't work properly if the query includes
  # sub-paragraphs, but it is fine for the common case where only
  # top-level paragraphs have topics.
  # We should really be sorting by full_index, but
  # we don't have a sort function for this yet. (A naive typographical
  # sort isn't good enough.)
  relevant_paragraphs = relevant_paragraphs.order('position ASC')

  paragraph_numbers = relevant_paragraphs.map{|p| p.full_index(true, choices)}.select{|i| !i.nil?}

  if consolidate
    consolidate_paragraph_numbers(paragraph_numbers)
  else
    paragraph_numbers.join(', ')
  end
end
set_up_choices() click to toggle source
# File lib/rticles/document.rb, line 31
def set_up_choices
  self.choices ||= {}
  self.choices = choices.with_indifferent_access
end
set_up_insertions() click to toggle source
# File lib/rticles/document.rb, line 26
def set_up_insertions
  self.insertions ||= {}
  self.insertions = insertions.with_indifferent_access
end
to_html(options={}) click to toggle source
# File lib/rticles/document.rb, line 53
def to_html(options={})
  html = "<section>"
  html += Rticles::Paragraph.generate_html(top_level_paragraphs,
    {
      :insertions => insertions,
      :choices => choices,
      :numbering_config => numbering_config
    }.merge(options)
  )
  html += "</section>"
  html.html_safe
end
to_yaml() click to toggle source
# File lib/rticles/document.rb, line 66
def to_yaml
  outline.to_yaml
end

Protected Instance Methods

consolidate_paragraph_numbers(numbers) click to toggle source
# File lib/rticles/document.rb, line 177
def consolidate_paragraph_numbers(numbers)
  # numbers = numbers.sort
  consolidated_numbers = []
  current_run = []
  numbers.each do |n|
    if current_run.empty? || is_adjacent?(current_run.last, n)
      current_run.push(n)
    else
      if current_run.length == 1
        consolidated_numbers.push(current_run[0])
      else
        consolidated_numbers.push("#{current_run[0]}–#{current_run[-1]}")
      end
      current_run = [n]
    end
  end
  if current_run.length == 1
    consolidated_numbers.push(current_run[0])
  else
    consolidated_numbers.push("#{current_run[0]}–#{current_run[-1]}")
  end
  consolidated_numbers.join(', ')
end
is_adjacent?(a, b) click to toggle source
# File lib/rticles/document.rb, line 201
def is_adjacent?(a, b)
  # TODO Make this smart enough to handle sub-numbers like '2.4', '2.6'
  b.to_i == a.to_i + 1
end
sub_outline(p, options={}) click to toggle source
# File lib/rticles/document.rb, line 206
def sub_outline(p, options={})
  options = options.with_indifferent_access
  for_display = options[:for_display]

  o = []
  last_index = p.children.length - 1
  p.children.each_with_index do |c, index|
    body = for_display ? c.body_for_display({:insertions => insertions, :choices => choices}.merge(options)) : c.body
    if body
      o.push(body)
      unless c.children.empty?
        o.push(sub_outline(c, options))
      end
    end
  end
  if options[:list]
    # Add terminating punctuation to the String elements of o, but making the last one a full stop instead of a semicolon.
    final_element = true
    o.reverse_each do |p|
      if p.is_a?(String)
        if final_element
          p.sub!(/\Z/, '.')
          final_element = false
        else
          p.sub!(/\Z/, ';')
        end
      end
    end
  end
  o
end