class Plotline::Import::Handlers::MarkdownFile

Constants

FILENAME_SPLIT_PATTERN
FRONT_MATTER_PATTERN
MARKDOWN_EXTENSIONS

Public Instance Methods

import(filename) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 13
def import(filename)
  log "\e[34mImporting:\e[0m #{filename}"

  date, slug = filename_to_date_and_slug(filename)

  if !File.exists?(filename) && entry = Plotline::Entry.find_by(slug: slug)
    log "  \e[31mFile removed, deleting entry\e[0m \e[32m##{entry.id}\e[0m"
    entry.destroy
    return
  end

  full_contents = File.read(filename)
  full_contents = convert_relative_image_paths(filename, full_contents)

  meta, contents = extract_metadata_from_contents(full_contents)

  if meta['type'].blank?
    raise "\e[31mMissing 'type' attribute in #{filename}\e[0m"
  end

  klass = meta.delete('type').classify.constantize
  entry = klass.find_or_initialize_by(slug: slug)

  process_image_urls(full_contents)
  update_entry(entry, meta, date, contents, full_contents)
end
supported_file?(filename) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 9
def supported_file?(filename)
  MARKDOWN_EXTENSIONS.include?(File.extname(filename).gsub('.', ''))
end

Private Instance Methods

convert_relative_image_paths(filename, contents) click to toggle source

Converts relative image paths found in markdown files to the target path in app/public

# File lib/plotline/import/handlers/markdown_file.rb, line 72
def convert_relative_image_paths(filename, contents)
  entry_file_dir = File.dirname(filename)

  contents.gsub(/(\.\.\/.+\.(?:jpe?g|gif|png|mp4|mov|wmv|avi))/) do
    absolute_path = File.expand_path(File.join(entry_file_dir, $1))
    '/uploads' + absolute_path.gsub(@runner.source_dir, '')
  end
end
dump_errors(entry) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 123
def dump_errors(entry)
  log "\e[31mERROR: #{entry.class.name} could not be saved!\e[0m"
  entry.errors.each do |attr, error|
    log "  \e[31m#{attr}:\e[0m #{error}"
  end
end
dump_log(entry, meta) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 112
def dump_log(entry, meta)
  log "\e[32m#{entry.class.name}:\e[0m"
  meta.each do |k, v|
    log "  \e[32m#{k}:\e[0m #{v}"
  end
  log "  \e[32mslug:\e[0m #{entry.slug}"
  log "  \e[32mdraft:\e[0m #{entry.draft?}"
  log "  \e[32mpublished_at:\e[0m #{entry.published_at}"
  log "  \e[32mbody:\e[0m #{entry.body[0..100].gsub("\n", " ")}..."
end
extract_metadata_from_contents(contents) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 59
def extract_metadata_from_contents(contents)
  if result = contents.match(FRONT_MATTER_PATTERN)
    contents = contents[(result[0].length)...(contents.length)]
    meta = YAML.safe_load(result[0])
  else
    meta = {}
  end

  [meta, contents]
end
filename_to_date_and_slug(filename) click to toggle source

Turns markdown filename to date and slug, e.g.:

2016-03-20_hello-world.md

results in:

['2016-03-20', 'hello-world']

If there's no date in the filename (e.g. when file is a draft), only slug will be returned and date will be nil.

# File lib/plotline/import/handlers/markdown_file.rb, line 49
def filename_to_date_and_slug(filename)
  date, slug = File.basename(filename, ".*").split(FILENAME_SPLIT_PATTERN).reject { |m| m.blank? }
  if slug.blank?
    slug = date
    date = nil
  end

  [date, slug]
end
process_image_urls(contents) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 81
def process_image_urls(contents)
  URI.extract(contents).select{ |url| url[/\.(?:jpe?g|png|gif)\b/i] }.each do |url|
    Plotline::Image.find_or_create_by(image: url)
  end
end
update_entry(entry, meta, date, contents, full_contents) click to toggle source
# File lib/plotline/import/handlers/markdown_file.rb, line 87
def update_entry(entry, meta, date, contents, full_contents)
  checksum = Digest::MD5.hexdigest(full_contents)
  if entry.checksum == checksum
    log "  File unchanged, skipping."
    return
  end

  draft = !!meta.delete('draft')
  entry.status = draft ? :draft : :published

  entry.assign_attributes(meta.merge(
    body: contents,
    checksum: checksum,
    published_at: (Date.parse(date) if date && !draft)
  ))

  dump_log(entry, meta)

  unless entry.save
    dump_errors(entry)
  end
rescue ActiveModel::UnknownAttributeError => e
  log "\e[31mERROR: #{e.message}\e[0m"
end