Class: Skriptorium::Article

Inherits:
Object
  • Object
show all
Defined in:
lib/skriptorium/article.rb

Constant Summary collapse

FRONT_MATTER_RX =
/---([\s\S]*?)---/.freeze
FRONT_MATTER_LINE_RX =
/^(?<key>\w+)\s*:\s*(?<value>.*)/.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs) ⇒ Article

Returns a new instance of Article.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/skriptorium/article.rb', line 12

def initialize(attrs)
  @id = attrs[:id]
  @title = attrs.fetch(:title).to_s.strip
  @tags = attrs[:tags] || []
  @canonical_url = attrs[:canonical_url]&.strip
  @published_at = attrs[:published_at] || DateTime.now
  @cover_image = attrs[:cover_image]

  @slug = attrs[:slug]&.strip || stable_slug

  @markdown = attrs[:markdown]
  @html = attrs[:html]
  raw = attrs[:content].to_s.strip
  @content = if markdown?
               @front_matter = parse_front_matter(raw) || {}.with_indifferent_access
               raw.gsub(/---([\s\S]*?)---/, '').strip
             else
               @front_matter = {}.with_indifferent_access
               raw
             end
end

Instance Attribute Details

#canonical_urlObject (readonly)

Returns the value of attribute canonical_url.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def canonical_url
  @canonical_url
end

#contentObject (readonly)

Returns the value of attribute content.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def content
  @content
end

#cover_imageObject (readonly)

Returns the value of attribute cover_image.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def cover_image
  @cover_image
end

#idObject (readonly)

Returns the value of attribute id.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def id
  @id
end

#published_atObject (readonly)

Returns the value of attribute published_at.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def published_at
  @published_at
end

#slugObject (readonly)

Returns the value of attribute slug.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def slug
  @slug
end

#tagsObject (readonly)

Returns the value of attribute tags.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def tags
  @tags
end

#titleObject (readonly)

Returns the value of attribute title.



7
8
9
# File 'lib/skriptorium/article.rb', line 7

def title
  @title
end

Class Method Details

.parse_date(str) ⇒ Object



108
109
110
111
112
# File 'lib/skriptorium/article.rb', line 108

def self.parse_date(str)
  DateTime.parse(str) if str
rescue StandardError
  nil
end

Instance Method Details

#front_matter(key = nil) ⇒ Object



40
41
42
# File 'lib/skriptorium/article.rb', line 40

def front_matter(key = nil)
  key ? @front_matter&.fetch(key, nil) : @front_matter
end

#html?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/skriptorium/article.rb', line 53

def html?
  @html
end

#html_to_markdown(data) ⇒ Object



94
95
96
# File 'lib/skriptorium/article.rb', line 94

def html_to_markdown(data)
  ReverseMarkdown.convert(data)
end

#markdown?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/skriptorium/article.rb', line 49

def markdown?
  @markdown
end

#markdown_to_html(data) ⇒ Object



88
89
90
91
92
# File 'lib/skriptorium/article.rb', line 88

def markdown_to_html(data)
  renderer = Redcarpet::Render::HTML.new(prettify: true)
  md = Redcarpet::Markdown.new(renderer, fenced_code_blocks: true)
  md.render(data)
end

#parse_front_matter(data) ⇒ Object



98
99
100
101
102
103
104
105
106
# File 'lib/skriptorium/article.rb', line 98

def parse_front_matter(data)
  if (md_fm = data.match(FRONT_MATTER_RX))
    front_matter = md_fm[1].strip.split("\n").map do |line|
      md = line.match(FRONT_MATTER_LINE_RX)
      "#{md[:key]}: '#{md[:value]}'"
    end.join("\n")
    YAML.safe_load(front_matter).with_indifferent_access
  end
end

#same?(other) ⇒ Boolean

Returns:

  • (Boolean)


34
35
36
37
38
# File 'lib/skriptorium/article.rb', line 34

def same?(other)
  (@slug && @slug == other.slug) ||
    (@title && @title == other.title) ||
    (@canonical_url && @canonical_url == other.canonical_url)
end

#stable_slugObject



44
45
46
47
# File 'lib/skriptorium/article.rb', line 44

def stable_slug
  sl = Russian.transliterate(@title)
  sl.downcase.strip.gsub(/[\W\-_]+/, '_').gsub(/_$/, '').gsub(/^_/, '')
end

#to_htmlObject



57
58
59
# File 'lib/skriptorium/article.rb', line 57

def to_html
  html? ? @content : markdown_to_html(@content)
end

#to_markdown(fm = {}) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/skriptorium/article.rb', line 61

def to_markdown(fm = {})
  c = if markdown?
        @content
      else
        html_to_markdown(@content)
      end.strip

  header = front_matter.merge(
    {
      title: title,
      tags: [tags].flatten.compact,
      canonical_url: canonical_url,
      slug: stable_slug,
      cover_image: cover_image,
      image: cover_image,
      published_at: published_at&.strftime('%Y-%m-%d %H:%M:%S %z'),
      date: published_at&.strftime('%Y-%m-%d %H:%M:%S %z')
    }.compact.with_indifferent_access
  ).merge(fm.with_indifferent_access)

  [
    header.to_hash.sort.to_h.to_yaml.strip,
    '---',
    c
  ].join("\n")
end