Class: Impression::Resource

Inherits:
Object
  • Object
show all
Defined in:
lib/impression/resource.rb

Overview

The ‘Resource` class represents an abstract web resource. Resources are organized in tree like structure, with the structure normally corresponding to the URL path hierarchy. Other ways of organising resources, according to other taxonomies, can be implemented as long as the resources implement the same interface as the `Resource` class, which includes the following methods:

  • ‘Resource#route` - returns the resource which should respond to the request.

  • ‘Resource#respond` - responds to the request.

Direct Known Subclasses

FileTree, RackApp

Constant Summary collapse

FIRST_PATH_SEGMENT_REGEXP =
/^(\/[^\/]+)\//.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent: nil, path:, &block) ⇒ void

Initalizes a new resource instance. If a block is given, it is used as the request handler instead of the default one, which returns ‘404 NOT FOUND`.

Parameters:

  • parent (Impression::Resource, nil) (defaults to: nil)

    the parent resource (or nil)

  • path (String)

    the resource’s relative path

  • &block (Proc)

    default request handler



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/impression/resource.rb', line 36

def initialize(parent: nil, path:, &block)
  @parent = parent
  @path = normalize_route_path(path)
  @route_regexp = @path == '/' ? nil : /^#{@path}(\/.*)?$/.freeze
  @children = {}

  @parent&.add_child(self)

  if block
    singleton_class.define_method(:call, &block)
  end
end

Instance Attribute Details

#childrenObject (readonly)

A hash mapping relative paths to child resources



27
28
29
# File 'lib/impression/resource.rb', line 27

def children
  @children
end

#parentObject (readonly)

Reference to the parent resource



21
22
23
# File 'lib/impression/resource.rb', line 21

def parent
  @parent
end

#pathObject (readonly)

The resource’s path relative to its parent



24
25
26
# File 'lib/impression/resource.rb', line 24

def path
  @path
end

Instance Method Details

#absolute_pathString

Returns the resource’s absolute path, according to its location in the resource hierarchy.

Returns:

  • (String)

    absolute path



64
65
66
# File 'lib/impression/resource.rb', line 64

def absolute_path
  @absoulte_path ||= File.join(@parent ? @parent.absolute_path : '/', @path)
end

#add_child(child) ⇒ Impression::Resource

Adds a child reference to the children map.

Parameters:

Returns:



82
83
84
85
# File 'lib/impression/resource.rb', line 82

def add_child(child)
  @children[child.path] = child
  self
end

#call(req) ⇒ void

This method returns an undefined value.

Responds to the given request by rendering a 404 Not found response.

Parameters:



100
101
102
# File 'lib/impression/resource.rb', line 100

def call(req)
  req.respond(nil, ':status' => Qeweney::Status::NOT_FOUND)
end

#each(&block) ⇒ Impression::Resource

Iterates over the resource and any of its sub-resources, passing each to the given block.

Returns:



72
73
74
75
76
# File 'lib/impression/resource.rb', line 72

def each(&block)
  block.(self)
  @children.values.each { |c| c.each(&block) }
  self
end

#html_response(html, **headers) ⇒ Object

Returns a callable that responds with HTML using the given parameters.

Parameters:

  • html (String)

    response body

  • **headers (Hash)

    additional response headers



169
170
171
# File 'lib/impression/resource.rb', line 169

def html_response(html, **headers)
  ->(req) { req.respond_html(html, **headers) }
end

#json_response(object, **headers) ⇒ Object

Returns a callable that responds with JSON using the given parameters.

Parameters:

  • object (any)

    object to be converted to JSON

  • **headers (Hash)

    additional response headers



178
179
180
# File 'lib/impression/resource.rb', line 178

def json_response(object, **headers)
  ->(req) { req.respond_json(object, **headers) }
end

#remount(parent, path) ⇒ void

This method returns an undefined value.

Remounts the resource on a different parent and path.

Parameters:

  • parent (Resource, nil)

    new parent

  • path (String)

    new path relative to new parent



54
55
56
57
58
# File 'lib/impression/resource.rb', line 54

def remount(parent, path)
  @parent&.remove_child(self)
  @parent = parent
  @path = normalize_route_path(path)
end

#remove_child(child) ⇒ Impression::Resource

Removes a child reference from the children map.

Parameters:

Returns:



91
92
93
94
# File 'lib/impression/resource.rb', line 91

def remove_child(child)
  @children.delete(child.path)
  self
end

#render_tree_to_static_files(base_path) ⇒ Impression::Resource

Renders the resource and all of its sub-resources to static files.

Parameters:

  • base_path (String)

    base path of target directory

Returns:



135
136
137
138
139
140
141
142
143
# File 'lib/impression/resource.rb', line 135

def render_tree_to_static_files(base_path)
  each do |r|
    path = File.join(base_path, r.relative_static_file_path)
    dir = File.dirname(path)
    FileUtils.mkdir_p(dir) if !File.directory?(dir)
    File.open(path, 'w') { |f| r.render_to_file(f) }
  end
  self
end

#route(req) ⇒ Impression::Resource?

Routes the request by matching self and any children against the request path, returning the target resource, or nil if there’s no match.

Parameters:

Returns:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/impression/resource.rb', line 111

def route(req)
  case (relative_path = req.match_resource_path?(@route_regexp))
  when nil
    return nil
  when '/'
    return self
  else
    # naive case
    child = @children[relative_path]
    return child.route(req) if child

    if (m = relative_path.match(FIRST_PATH_SEGMENT_REGEXP))
      child = @children[m[1]]
      return child.route(req) if child
    end

    return self
  end
end

#text_response(text, **headers) ⇒ Object

Returns a callable that responds with plain text using the given parameters.

Parameters:

  • text (String)

    response body

  • **headers (Hash)

    additional response headers



160
161
162
# File 'lib/impression/resource.rb', line 160

def text_response(text, **headers)
  ->(req) { req.respond_text(text, **headers) }
end

#to_procProc

Converts the resource to a Proc, for use as a Qeweney app.

Returns:

  • (Proc)

    web app proc



148
149
150
151
152
153
# File 'lib/impression/resource.rb', line 148

def to_proc
  ->(req) do
    resource = route(req) || self
    resource.call(req)
  end
end