Class: Utopia::Content::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/utopia/content/middleware.rb

Overview

A middleware which serves dynamically generated content based on markup files.

Constant Summary collapse

CONTENT_NAMESPACE =
"content".freeze
UTOPIA_NAMESPACE =
"utopia".freeze
CONTENT_TAG_NAME =
"utopia:content".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, root: Utopia::default_root, namespaces: {}) ⇒ Middleware

Returns a new instance of Middleware.

Parameters:

  • root (String) (defaults to: Utopia::default_root)

    The content root where pages will be generated from.

  • namespaces (Hash<String,Library>) (defaults to: {})

    Tag namespaces for dynamic tag lookup.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/utopia/content/middleware.rb', line 28

def initialize(app, root: Utopia::default_root, namespaces: {})
  @app = app
  @root = root
  
  @template_cache = Concurrent::Map.new
  @node_cache = Concurrent::Map.new
  
  @links = Links.new(@root)
  
  @namespaces = namespaces
  
  # Default content namespace for dynamic path based lookup:
  @namespaces[CONTENT_NAMESPACE] ||= self.method(:content_tag)
  
  # The core namespace for utopia specific functionality:
  @namespaces[UTOPIA_NAMESPACE] ||= Tags
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



56
57
58
# File 'lib/utopia/content/middleware.rb', line 56

def root
  @root
end

Instance Method Details

#call(env) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/utopia/content/middleware.rb', line 103

def call(env)
  request = Rack::Request.new(env)
  path = Path.create(request.path_info)
  
  # Check if the request is to a non-specific index. This only works for requests with a given name:
  basename = path.basename
  directory_path = File.join(@root, path.dirname.components, basename)
  
  # If the request for /foo/bar is actually a directory, rewrite it to /foo/bar/index:
  if File.directory? directory_path
    index_path = [basename, INDEX]
    
    return [307, {HTTP::LOCATION => path.dirname.join(index_path).to_s}, []]
  end
  
  locale = env[Localization::CURRENT_LOCALE_KEY]
  if link = @links.for(path, locale)
    if response = self.respond(link, request)
      return response
    end
  end
  
  return @app.call(env)
end

#fetch_template(path) ⇒ Object



63
64
65
66
67
# File 'lib/utopia/content/middleware.rb', line 63

def fetch_template(path)
  @template_cache.fetch_or_store(path.to_s) do
    XRB::Template.load_file(path)
  end
end

#freezeObject



46
47
48
49
50
51
52
53
54
# File 'lib/utopia/content/middleware.rb', line 46

def freeze
  return self if frozen?
  
  @root.freeze
  @namespaces.values.each(&:freeze)
  @namespaces.freeze
  
  super
end

TODO we should remove this method and expose ‘@links` directly.



59
60
61
# File 'lib/utopia/content/middleware.rb', line 59

def links(path, **options)
  @links.index(path, **options)
end

#lookup_node(path, locale = nil) ⇒ Object

Parameters:

  • path (Path)

    the request path is an absolute uri path, e.g. ‘/foo/bar`. If an xnode file exists on disk for this exact path, it is instantiated, otherwise nil.



79
80
81
82
83
# File 'lib/utopia/content/middleware.rb', line 79

def lookup_node(path, locale = nil)
  resolve_link(
    @links.for(path, locale)
  )
end

#lookup_tag(qualified_name, node) ⇒ Object

Look up a named tag such as ‘<entry />` or `<content:page>…`



70
71
72
73
74
75
76
# File 'lib/utopia/content/middleware.rb', line 70

def lookup_tag(qualified_name, node)
  namespace, name = XRB::Tag.split(qualified_name)
  
  if library = @namespaces[namespace]
    library.call(name, node)
  end
end


85
86
87
88
89
90
91
# File 'lib/utopia/content/middleware.rb', line 85

def resolve_link(link)
  if full_path = link&.full_path(@root)
    if File.exist?(full_path)
      return Node.new(self, link.path, link.path, full_path)
    end
  end
end

#respond(link, request) ⇒ Object



93
94
95
96
97
98
99
100
101
# File 'lib/utopia/content/middleware.rb', line 93

def respond(link, request)
  if node = resolve_link(link)
    attributes = request.env.fetch(VARIABLES_KEY, {}).to_hash
    
    return node.process!(request, attributes)
  elsif redirect_uri = link[:uri]
    return [307, {HTTP::LOCATION => redirect_uri}, []]
  end
end