131 lines
3.4 KiB
Ruby
131 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'sinatra/base'
|
|
require 'multi_json'
|
|
module Sinatra
|
|
# = Sinatra::JSON
|
|
#
|
|
# <tt>Sinatra::JSON</tt> adds a helper method, called +json+, for (obviously)
|
|
# json generation.
|
|
#
|
|
# == Usage
|
|
#
|
|
# === Classic Application
|
|
#
|
|
# In a classic application simply require the helper, and start using it:
|
|
#
|
|
# require "sinatra"
|
|
# require "sinatra/json"
|
|
#
|
|
# # define a route that uses the helper
|
|
# get '/' do
|
|
# json :foo => 'bar'
|
|
# end
|
|
#
|
|
# # The rest of your classic application code goes here...
|
|
#
|
|
# === Modular Application
|
|
#
|
|
# In a modular application you need to require the helper, and then tell the
|
|
# application you will use it:
|
|
#
|
|
# require "sinatra/base"
|
|
# require "sinatra/json"
|
|
#
|
|
# class MyApp < Sinatra::Base
|
|
#
|
|
# # define a route that uses the helper
|
|
# get '/' do
|
|
# json :foo => 'bar'
|
|
# end
|
|
#
|
|
# # The rest of your modular application code goes here...
|
|
# end
|
|
#
|
|
# === Encoders
|
|
#
|
|
# By default it will try to call +to_json+ on the object, but if it doesn't
|
|
# respond to that message, it will use its own rather simple encoder. You can
|
|
# easily change that anyways. To use +JSON+, simply require it:
|
|
#
|
|
# require 'json'
|
|
#
|
|
# The same goes for <tt>Yajl::Encoder</tt>:
|
|
#
|
|
# require 'yajl'
|
|
#
|
|
# For other encoders, besides requiring them, you need to define the
|
|
# <tt>:json_encoder</tt> setting. For instance, for the +Whatever+ encoder:
|
|
#
|
|
# require 'whatever'
|
|
# set :json_encoder, Whatever
|
|
#
|
|
# To force +json+ to simply call +to_json+ on the object:
|
|
#
|
|
# set :json_encoder, :to_json
|
|
#
|
|
# Actually, it can call any method:
|
|
#
|
|
# set :json_encoder, :my_fancy_json_method
|
|
#
|
|
# === Content-Type
|
|
#
|
|
# It will automatically set the content type to "application/json". As
|
|
# usual, you can easily change that, with the <tt>:json_content_type</tt>
|
|
# setting:
|
|
#
|
|
# set :json_content_type, :js
|
|
#
|
|
# === Overriding the Encoder and the Content-Type
|
|
#
|
|
# The +json+ helper will also take two options <tt>:encoder</tt> and
|
|
# <tt>:content_type</tt>. The values of this options are the same as the
|
|
# <tt>:json_encoder</tt> and <tt>:json_content_type</tt> settings,
|
|
# respectively. You can also pass those to the json method:
|
|
#
|
|
# get '/' do
|
|
# json({:foo => 'bar'}, :encoder => :to_json, :content_type => :js)
|
|
# end
|
|
#
|
|
module JSON
|
|
class << self
|
|
def encode(object)
|
|
::MultiJson.dump(object)
|
|
end
|
|
end
|
|
|
|
def json(object, options = {})
|
|
content_type resolve_content_type(options)
|
|
resolve_encoder_action object, resolve_encoder(options)
|
|
end
|
|
|
|
private
|
|
|
|
def resolve_content_type(options = {})
|
|
options[:content_type] || settings.json_content_type
|
|
end
|
|
|
|
def resolve_encoder(options = {})
|
|
options[:json_encoder] || settings.json_encoder
|
|
end
|
|
|
|
def resolve_encoder_action(object, encoder)
|
|
%i[encode generate].each do |method|
|
|
return encoder.send(method, object) if encoder.respond_to? method
|
|
end
|
|
raise "#{encoder} does not respond to #generate nor #encode" unless encoder.is_a? Symbol
|
|
|
|
object.__send__(encoder)
|
|
end
|
|
end
|
|
|
|
Base.set :json_encoder do
|
|
::MultiJson
|
|
end
|
|
|
|
Base.set :json_content_type, :json
|
|
|
|
# Load the JSON helpers in modular style automatically
|
|
Base.helpers JSON
|
|
end
|