Class: Tina4::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/response.rb

Constant Summary collapse

MIME_TYPES =
{
  ".html" => "text/html", ".htm" => "text/html",
  ".css" => "text/css", ".js" => "application/javascript",
  ".json" => "application/json", ".xml" => "application/xml",
  ".txt" => "text/plain", ".csv" => "text/csv",
  ".png" => "image/png", ".jpg" => "image/jpeg",
  ".jpeg" => "image/jpeg", ".gif" => "image/gif",
  ".svg" => "image/svg+xml", ".ico" => "image/x-icon",
  ".webp" => "image/webp", ".pdf" => "application/pdf",
  ".zip" => "application/zip", ".woff" => "font/woff",
  ".woff2" => "font/woff2", ".ttf" => "font/ttf",
  ".eot" => "application/vnd.ms-fontobject",
  ".mp3" => "audio/mpeg", ".mp4" => "video/mp4",
  ".webm" => "video/webm"
}.freeze
JSON_CONTENT_TYPE =

Pre-frozen header values

"application/json; charset=utf-8"
HTML_CONTENT_TYPE =
"text/html; charset=utf-8"
TEXT_CONTENT_TYPE =
"text/plain; charset=utf-8"
XML_CONTENT_TYPE =
"application/xml; charset=utf-8"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeResponse

Returns a new instance of Response.



31
32
33
34
35
36
# File 'lib/tina4/response.rb', line 31

def initialize
  @status = 200
  @headers = { "content-type" => HTML_CONTENT_TYPE }
  @body = ""
  @cookies = nil  # Lazy — most responses have no cookies
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



29
30
31
# File 'lib/tina4/response.rb', line 29

def body
  @body
end

#cookiesObject

Returns the value of attribute cookies.



29
30
31
# File 'lib/tina4/response.rb', line 29

def cookies
  @cookies
end

#headersObject

Returns the value of attribute headers.



29
30
31
# File 'lib/tina4/response.rb', line 29

def headers
  @headers
end

#statusObject

Returns the value of attribute status.



29
30
31
# File 'lib/tina4/response.rb', line 29

def status
  @status
end

Class Method Details

.auto_detect(result, response) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/tina4/response.rb', line 147

def self.auto_detect(result, response)
  case result
  when Tina4::Response
    result
  when Hash, Array
    response.json(result)
  when String
    if result.start_with?("<")
      response.html(result)
    else
      response.text(result)
    end
  when Integer
    response.status = result
    response.body = ""
    response
  when NilClass
    response.status = 204
    response.body = ""
    response
  else
    response.json(result.respond_to?(:to_hash) ? result.to_hash : { data: result.to_s })
  end
end

Instance Method Details

#add_cors_headers(origin: "*", methods: "GET, POST, PUT, PATCH, DELETE, OPTIONS", headers_list: "Content-Type, Authorization, Accept", credentials: false) ⇒ Object



125
126
127
128
129
130
131
132
133
# File 'lib/tina4/response.rb', line 125

def add_cors_headers(origin: "*", methods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
                     headers_list: "Content-Type, Authorization, Accept", credentials: false)
  @headers["access-control-allow-origin"] = origin
  @headers["access-control-allow-methods"] = methods
  @headers["access-control-allow-headers"] = headers_list
  @headers["access-control-allow-credentials"] = "true" if credentials
  @headers["access-control-max-age"] = "86400"
  self
end

#add_header(key, value) ⇒ Object



120
121
122
123
# File 'lib/tina4/response.rb', line 120

def add_header(key, value)
  @headers[key] = value
  self
end

#csv(content, filename: "export.csv", status: 200) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/tina4/response.rb', line 66

def csv(content, filename: "export.csv", status: 200)
  @status = status
  @headers["content-type"] = "text/csv"
  @headers["content-disposition"] = "attachment; filename=\"#{filename}\""
  @body = content.to_s
  self
end


116
117
118
# File 'lib/tina4/response.rb', line 116

def delete_cookie(name, path: "/")
  set_cookie(name, "", max_age: 0, path: path)
end

#file(path, content_type: nil, download: false) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/tina4/response.rb', line 81

def file(path, content_type: nil, download: false)
  unless ::File.exist?(path)
    @status = 404
    @body = "File not found"
    return self
  end
  ext = ::File.extname(path).downcase
  @headers["content-type"] = content_type || MIME_TYPES[ext] || "application/octet-stream"
  if download
    @headers["content-disposition"] = "attachment; filename=\"#{::File.basename(path)}\""
  end
  @body = ::File.binread(path)
  self
end

#html(content, status_or_opts = nil, status: nil) ⇒ Object



45
46
47
48
49
50
# File 'lib/tina4/response.rb', line 45

def html(content, status_or_opts = nil, status: nil)
  @status = status || (status_or_opts.is_a?(Integer) ? status_or_opts : 200)
  @headers["content-type"] = HTML_CONTENT_TYPE
  @body = content.to_s
  self
end

#json(data, status_or_opts = nil, status: nil) ⇒ Object



38
39
40
41
42
43
# File 'lib/tina4/response.rb', line 38

def json(data, status_or_opts = nil, status: nil)
  @status = status || (status_or_opts.is_a?(Integer) ? status_or_opts : 200)
  @headers["content-type"] = JSON_CONTENT_TYPE
  @body = data.is_a?(String) ? data : JSON.generate(data)
  self
end

#redirect(url, status: 302) ⇒ Object



74
75
76
77
78
79
# File 'lib/tina4/response.rb', line 74

def redirect(url, status: 302)
  @status = status
  @headers["location"] = url
  @body = ""
  self
end

#render(template_path, data = {}, status: 200) ⇒ Object



96
97
98
99
100
101
# File 'lib/tina4/response.rb', line 96

def render(template_path, data = {}, status: 200)
  @status = status
  @headers["content-type"] = HTML_CONTENT_TYPE
  @body = Tina4::Template.render(template_path, data)
  self
end


103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/tina4/response.rb', line 103

def set_cookie(name, value, opts = {})
  cookie = "#{name}=#{URI.encode_www_form_component(value)}"
  cookie += "; Path=#{opts[:path] || '/'}"
  cookie += "; HttpOnly" if opts.fetch(:http_only, true)
  cookie += "; Secure" if opts[:secure]
  cookie += "; SameSite=#{opts[:same_site] || 'Lax'}"
  cookie += "; Max-Age=#{opts[:max_age]}" if opts[:max_age]
  cookie += "; Expires=#{opts[:expires].httpdate}" if opts[:expires]
  @cookies ||= []
  @cookies << cookie
  self
end

#text(content, status_or_opts = nil, status: nil) ⇒ Object



52
53
54
55
56
57
# File 'lib/tina4/response.rb', line 52

def text(content, status_or_opts = nil, status: nil)
  @status = status || (status_or_opts.is_a?(Integer) ? status_or_opts : 200)
  @headers["content-type"] = TEXT_CONTENT_TYPE
  @body = content.to_s
  self
end

#to_rackObject



135
136
137
138
139
140
141
142
143
144
145
# File 'lib/tina4/response.rb', line 135

def to_rack
  # Fast path: no cookies (99% of API responses)
  if @cookies.nil? || @cookies.empty?
    return [@status, @headers, [@body.to_s]]
  end

  # Cookie path
  final_headers = @headers.dup
  final_headers["set-cookie"] = @cookies.join("\n")
  [@status, final_headers, [@body.to_s]]
end

#xml(content, status: 200) ⇒ Object



59
60
61
62
63
64
# File 'lib/tina4/response.rb', line 59

def xml(content, status: 200)
  @status = status
  @headers["content-type"] = XML_CONTENT_TYPE
  @body = content.to_s
  self
end