Module: PlanMyStuff::MetadataParser

Defined in:
lib/plan_my_stuff/metadata_parser.rb

Constant Summary collapse

METADATA_PATTERN =

Collapsible <details> block containing a JSON code fence. Renders visibly on GitHub (issue #58) instead of being hidden in an HTML comment.

%r{
  \A<details><summary>pms-metadata</summary>\n\n
  ```json\n(.*?)\n```\n\n
  </details>\n*
}mx
ATTACHMENTS_PATTERN =

Visible attachments block emitted after the metadata block when the metadata carries non-empty attachments (issue #70). Parse strips it so round-trips stay clean.

%r{
  \A<details><summary>attachments\ \(\d+\)</summary>\n\n
  .*?\n\n
  </details>\n*
}mx

Class Method Summary collapse

Class Method Details

.attachment_line(attachment) ⇒ String

Parameters:

  • attachment (Hash{Symbol=>String})

Returns:

  • (String)


85
86
87
88
89
90
# File 'lib/plan_my_stuff/metadata_parser.rb', line 85

def attachment_line(attachment)
  url = "https://github.com/#{attachment[:owner]}/#{attachment[:repo]}" \
    "/blob/#{attachment[:sha]}/#{attachment[:path]}"
  safe_filename = attachment[:filename].to_s.gsub(']', '\]')
  "- [#{safe_filename}](#{url})"
end

.attachments_block(metadata) ⇒ String

Renders the visible attachments block when metadata carries non-empty :attachments, otherwise returns an empty string.

Parameters:

  • metadata (Hash)

Returns:

  • (String)


73
74
75
76
77
78
79
# File 'lib/plan_my_stuff/metadata_parser.rb', line 73

def attachments_block()
  attachments = [:attachments]
  return '' if attachments.blank?

  lines = attachments.map { |a| attachment_line(a) }.join("\n")
  "<details><summary>attachments (#{attachments.size})</summary>\n\n#{lines}\n\n</details>\n\n"
end

.parse(raw_body) ⇒ Hash{Symbol => Hash, String}

Extracts metadata JSON from the raw body

Parameters:

  • raw_body (String, nil)

Returns:

  • (Hash{Symbol => Hash, String})

    :metadata (Hash, empty when absent) and :body (String)



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/plan_my_stuff/metadata_parser.rb', line 32

def parse(raw_body)
  return { metadata: {}, body: '' } if raw_body.blank?
  return { metadata: {}, body: raw_body } unless raw_body.match?(METADATA_PATTERN)

  match = raw_body.match(METADATA_PATTERN)
   = JSON.parse(match[1], symbolize_names: true)
  body = raw_body.sub(METADATA_PATTERN, '').sub(ATTACHMENTS_PATTERN, '')

  { metadata: , body: body }
rescue JSON::ParserError
  { metadata: {}, body: raw_body }
end

.serialize!(metadata, body) ⇒ String

Serializes a metadata hash and body into the stored format

Parameters:

Returns:

  • (String)

Raises:

  • (ArgumentError)

    if metadata is not a Hash or PlanMyStuff::CustomFields



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/plan_my_stuff/metadata_parser.rb', line 54

def serialize!(, body)
  if !.is_a?(Hash) && !.is_a?(PlanMyStuff::CustomFields)
    raise(ArgumentError, "metadata must be a Hash or PlanMyStuff::CustomFields, got #{.class}")
  end

  hash = .is_a?(PlanMyStuff::CustomFields) ? .to_h : 
  json = JSON.pretty_generate(hash)

  "<details><summary>pms-metadata</summary>\n\n```json\n#{json}\n```\n\n</details>\n\n" \
    "#{attachments_block(hash)}#{body}"
end