Skip to content

Commit

Permalink
Methods to set content type and content (#313)
Browse files Browse the repository at this point in the history
* methods to set content type and content

* respond_with

* respond with works

* organized methods better

* allow hash or json for json response

* formatting

* small changes

* moved content_types out to constant

* tested IRL

* refactored file structure

* works after many hours

* good for now, got it working as good as it used to.

* added tests

* tests work and fixes empty headers'

* removed vestigul code


Former-commit-id: 6d2d14d
  • Loading branch information
elorest committed Nov 4, 2017
1 parent d84803e commit e25ea0a
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 10 deletions.
47 changes: 41 additions & 6 deletions spec/amber/controller/base_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -50,33 +50,68 @@ module Amber::Controller
end
end

describe "#respond_with" do
request = HTTP::Request.new("GET", "")
request.headers["Accept"] = ""
context = create_context(request)

it "respond_with html as default option" do
expected_result = "<html><body><h1>Elorest <3 Amber</h1></body></html>"
ResponsesController.new(context).index.should eq expected_result
end

it "respond_with html" do
expected_result = "<html><body><h1>Elorest <3 Amber</h1></body></html>"
context.request.headers["Accept"] = "text/html"
ResponsesController.new(context).index.should eq expected_result
end

it "responds with json" do
expected_result = %({"type":"json","name":"Amberator"})
context.request.headers["Accept"] = "application/json"
ResponsesController.new(context).index.should eq expected_result
end

it "responds with xml" do
expected_result = "<xml><body><h1>Sort of xml</h1></body></xml>"
context.request.headers["Accept"] = "application/xml"
ResponsesController.new(context).index.should eq expected_result
end

it "responds with text" do
expected_result = "Hello I'm text!"
context.request.headers["Accept"] = "text/plain"
ResponsesController.new(context).index.should eq expected_result
end
end

describe "#render" do
request = HTTP::Request.new("GET", "")
context = create_context(request)
csrf_form = form_with_csrf(Amber::Pipe::CSRF.token(context))

it "renders html from slang template" do
TestController.new(context).render_template_page.should eq page_template
RenderController.new(context).render_template_page.should eq page_template
end

it "renders partial without layout" do
TestController.new(context).render_partial.should eq partial_only
RenderController.new(context).render_partial.should eq partial_only
end

it "renders flash message" do
TestController.new(context).render_with_flash
RenderController.new(context).render_with_flash
end

it "renders html and layout from slang template" do
TestController.new(context).render_multiple_partials_in_layout.should eq layout_with_multiple_partials
RenderController.new(context).render_multiple_partials_in_layout.should eq layout_with_multiple_partials
end

it "renders html and layout from slang template" do
TestController.new(context).render_with_layout.should eq layout_with_template
RenderController.new(context).render_with_layout.should eq layout_with_template
end

it "renders a form with a csrf tag" do
TestController.new(context).render_with_csrf.should eq csrf_form
RenderController.new(context).render_with_csrf.should eq csrf_form
end
end

Expand Down
13 changes: 12 additions & 1 deletion spec/support/fixtures/controller_fixtures.cr
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class HelloController < Amber::Controller::Base
end
end

class TestController < Amber::Controller::Base
class RenderController < Amber::Controller::Base
def render_template_page
render("spec/support/sample/views/test/test.slang", layout: false)
end
Expand All @@ -82,3 +82,14 @@ class TestController < Amber::Controller::Base
render("spec/support/sample/views/test/flash.slang", layout: false)
end
end

class ResponsesController < Amber::Controller::Base
def index
respond_with do
html "<html><body><h1>Elorest <3 Amber</h1></body></html>"
json type: "json", name: "Amberator"
xml "<xml><body><h1>Sort of xml</h1></body></xml>"
text "Hello I'm text!"
end
end
end
4 changes: 2 additions & 2 deletions src/amber/controller/base.cr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
require "http"

require "./render"
require "./filters"
require "./redirect"
require "./helpers/*"

module Amber::Controller
class Base
include Render
include Helpers::Render
include Helpers::Responders
include RedirectMethods
include Callbacks
include Helpers::Tag
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Amber::Controller
module Amber::Controller::Helpers
module Render
LAYOUT = "application.slang"

Expand Down
77 changes: 77 additions & 0 deletions src/amber/controller/helpers/responders.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module Amber::Controller::Helpers
module Responders
class Content
TYPE = {html: "text/html", json: "application/json", text: "text/plain", xml: "application/xml"}
@requested_responses : Array(String)
@available_responses = Hash(String, String).new
@type : String? = nil

def initialize(@requested_responses)
end

# TODO: add JS type simlar to rails.
def html(html : String)
@available_responses[TYPE[:html]] = html; self
end

def xml(xml : String)
@available_responses[TYPE[:xml]] = xml; self
end

def json(json : String | Hash(Symbol | String, String))
@available_responses[TYPE[:json]] = json.is_a?(String) ? json : json.to_json; self
end

def json(**args : Object)
json(args.to_h)
end

def text(text : String)
@available_responses[TYPE[:text]] = text; self
end

def type
select_type.to_s
end

def body
@available_responses[type]
end

private def select_type
@type ||= begin
raise "You must define at least one response_type." if @available_responses.empty?
@requested_responses << @available_responses.keys.first
@requested_responses.find do |resp|
@available_responses.keys.includes?(resp)
end
end
end
end

private def requested_responses
req_responses = Array(String).new

if (accept = context.request.headers["Accept"]?) && !accept.empty?
accepts = accept.split(";").first?.try(&.split(/,|,\s/))
req_responses.concat(accepts) if accepts.is_a?(Array) && accepts.any?
end
req_responses
end

protected def respond_with(&block)
content = with Content.new(requested_responses) yield
if content.body
set_response(body: content.body, status_code: 200, content_type: content.type)
else
set_response(body: "Response unexceptable.", status_code: 406, content_type: Content::TYPE[:text])
end
end

private def set_response(body, status_code = 200, content_type = Content::TYPE[:html])
context.response.status_code = status_code
context.response.content_type = content_type
context.content = body
end
end
end

0 comments on commit e25ea0a

Please sign in to comment.