Module: Textus::Refresh

Defined in:
lib/textus/refresh.rb

Constant Summary collapse

ACTION_TIMEOUT_SECONDS =
2

Class Method Summary collapse

Class Method Details

.call(store, key, as:) ⇒ Object

Raises:



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/textus/refresh.rb', line 7

def self.call(store, key, as:)
  mentry, path, = store.manifest.resolve(key)
  raise UsageError.new("no action declared for '#{key}'") unless mentry.action

  before_etag = File.exist?(path) ? Etag.for_file(path) : nil
  callable = store.registry.action(mentry.action)
  view = StoreView.new(store, writable: true, as: as)
  result =
    begin
      Timeout.timeout(ACTION_TIMEOUT_SECONDS) do
        callable.call(config: mentry.action_config, store: view, args: {})
      end
    rescue Timeout::Error
      raise UsageError.new("action '#{mentry.action}' exceeded #{ACTION_TIMEOUT_SECONDS}s timeout")
    rescue Textus::Error
      raise
    rescue StandardError => e
      raise UsageError.new("action '#{mentry.action}' raised: #{e.class}: #{e.message}")
    end

  normalized = normalize_action_result(result, format: mentry.format)
  envelope = store.put(
    key,
    meta: normalized[:meta],
    body: normalized[:body],
    content: normalized[:content],
    as: as,
    suppress_events: true,
  )

  change = if before_etag.nil?
             :created
           elsif envelope["etag"] == before_etag
             :unchanged
           else
             :updated
           end
  store.fire_event(:refresh, key: key, envelope: envelope, change: change) unless change == :unchanged
  envelope
end

.normalize_action_result(res, format:) ⇒ Object

Normalize the three accepted action return shapes into the store’s internal body, content representation.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/textus/refresh.rb', line 50

def self.normalize_action_result(res, format:)
  res = res.transform_keys(&:to_s) if res.is_a?(Hash)
  res ||= {}
  # Accept both legacy :frontmatter/:_meta key names from actions.
  meta_val = res["_meta"] || res["frontmatter"]
  body    = res["body"]
  content = res["content"]

  case format
  when "markdown"
    { meta: meta_val || {}, body: body.to_s, content: nil }
  when "text"
    { meta: {}, body: body.to_s, content: nil }
  when "json", "yaml"
    if !content.nil?
      { meta: meta_val || {}, body: nil, content: content }
    elsif !body.nil?
      { meta: {}, body: body.to_s, content: nil }
    else
      raise UsageError.new("action for #{format} returned neither content nor body")
    end
  else
    raise UsageError.new("unknown format #{format.inspect}")
  end
end