/
json.rb
130 lines (120 loc) · 3.38 KB
/
json.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 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