toast 0.9.5 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +171 -86
- data/config/routes.rb +1 -27
- data/lib/generators/toast/USAGE +1 -0
- data/lib/generators/toast/templates/toast-api.rb.erb +10 -0
- data/lib/generators/toast/toast_generator.rb +9 -0
- data/lib/toast/canonical_request.rb +179 -0
- data/lib/toast/collection_request.rb +161 -0
- data/lib/toast/config_dsl/association.rb +72 -0
- data/lib/toast/config_dsl/base.rb +50 -0
- data/lib/toast/config_dsl/collection.rb +45 -0
- data/lib/toast/config_dsl/common.rb +38 -0
- data/lib/toast/config_dsl/default_handlers.rb +83 -0
- data/lib/toast/config_dsl/expose.rb +176 -0
- data/lib/toast/config_dsl/settings.rb +35 -0
- data/lib/toast/config_dsl/single.rb +15 -0
- data/lib/toast/config_dsl/via_verb.rb +49 -0
- data/lib/toast/config_dsl.rb +60 -225
- data/lib/toast/engine.rb +19 -30
- data/lib/toast/errors.rb +41 -0
- data/lib/toast/http_range.rb +17 -0
- data/lib/toast/plural_assoc_request.rb +285 -0
- data/lib/toast/rack_app.rb +133 -0
- data/lib/toast/request_helpers.rb +134 -0
- data/lib/toast/single_request.rb +66 -0
- data/lib/toast/singular_assoc_request.rb +207 -0
- data/lib/toast/version.rb +2 -2
- data/lib/toast.rb +100 -1
- metadata +83 -116
- data/app/controller/toast_controller.rb +0 -103
- data/lib/toast/active_record_extensions.rb +0 -85
- data/lib/toast/association.rb +0 -219
- data/lib/toast/collection.rb +0 -139
- data/lib/toast/record.rb +0 -123
- data/lib/toast/resource.rb +0 -175
- data/lib/toast/single.rb +0 -89
data/lib/toast/resource.rb
DELETED
@@ -1,175 +0,0 @@
|
|
1
|
-
module Toast
|
2
|
-
|
3
|
-
class ResourceNotFound < Exception; end
|
4
|
-
class MethodNotAllowed < Exception; end
|
5
|
-
class PayloadInvalid < Exception; end
|
6
|
-
class Conflict < Exception; end
|
7
|
-
class PayloadFormatError < Exception; end
|
8
|
-
class UnsupportedMediaType < Exception; end
|
9
|
-
class RequestedVersionNotDefined < Exception; end
|
10
|
-
class ResourceNotAcceptable < Exception; end
|
11
|
-
class BadRequest < Exception; end
|
12
|
-
|
13
|
-
# Represents a resource. There are following resource types as sub classes:
|
14
|
-
# Record, Collection, Association, Single
|
15
|
-
class Resource
|
16
|
-
|
17
|
-
attr_accessor :prefered_media_type, :base_uri, :payload_content_type
|
18
|
-
|
19
|
-
def initialize
|
20
|
-
raise 'ToastResource#new: use #build to create an instance'
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.build params, request
|
24
|
-
resource_name = params[:resource]
|
25
|
-
id = params[:id]
|
26
|
-
subresource_name = params[:subresource]
|
27
|
-
format = params[:format]
|
28
|
-
|
29
|
-
begin
|
30
|
-
|
31
|
-
# determine model
|
32
|
-
model = get_class_by_resource_name resource_name
|
33
|
-
|
34
|
-
# determine config for representation
|
35
|
-
# config_in: cosumed representation
|
36
|
-
# config_out: produced representation
|
37
|
-
config_out = model.toast_config request.accept_media_types.prefered
|
38
|
-
config_in = model.toast_config request.media_type
|
39
|
-
|
40
|
-
# ... or in case of an association request
|
41
|
-
config_assoc_src = model.toast_config request.headers["Assoc-source-type"] # ?
|
42
|
-
|
43
|
-
# base URI for returned object
|
44
|
-
base_uri = request.base_url + request.script_name +
|
45
|
-
(config_out.namespace ? "/" + config_out.namespace : "")
|
46
|
-
|
47
|
-
# decide which sub resource type
|
48
|
-
rsc = if id.nil? and config_out.singles.include?(subresource_name)
|
49
|
-
Toast::Single.new(model, subresource_name, params.clone, config_in, config_out)
|
50
|
-
elsif id.nil?
|
51
|
-
Toast::Collection.new(model, subresource_name, params.clone, config_in, config_out)
|
52
|
-
elsif subresource_name.nil?
|
53
|
-
Toast::Record.new(model, id, format, params.clone, config_in, config_out)
|
54
|
-
elsif (config_assoc_src && config_assoc_src.exposed_associations.include?(subresource_name))
|
55
|
-
|
56
|
-
# determine associated model
|
57
|
-
assoc_model =
|
58
|
-
model.reflect_on_all_associations.detect{|a| a.name.to_s == subresource_name}.klass
|
59
|
-
|
60
|
-
# determine config for representation of assoc. model
|
61
|
-
assoc_config_out = assoc_model.toast_config request.accept_media_types.prefered
|
62
|
-
assoc_config_in = assoc_model.toast_config request.media_type
|
63
|
-
|
64
|
-
# change base URI to associated record
|
65
|
-
base_uri = request.base_url + request.script_name +
|
66
|
-
(assoc_config_out.namespace ? "/" + assoc_config_out.namespace : "")
|
67
|
-
|
68
|
-
|
69
|
-
Toast::Association.new(model, id, subresource_name, params.clone, format, config_assoc_src,
|
70
|
-
assoc_model, assoc_config_in, assoc_config_out)
|
71
|
-
|
72
|
-
else
|
73
|
-
raise ResourceNotFound
|
74
|
-
end
|
75
|
-
|
76
|
-
# set base to be prepended to URIs
|
77
|
-
rsc.base_uri = base_uri
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
rsc
|
82
|
-
rescue NameError
|
83
|
-
raise ResourceNotFound
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.get_class_by_resource_name name
|
88
|
-
begin
|
89
|
-
model = name.singularize.classify.constantize # raises NameError
|
90
|
-
|
91
|
-
unless ((model.superclass == ActiveRecord::Base) and model.is_resourceful_model?)
|
92
|
-
raise ResourceNotFound
|
93
|
-
end
|
94
|
-
|
95
|
-
model
|
96
|
-
|
97
|
-
rescue NameError
|
98
|
-
raise ResourceNotFound
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def apply method, payload, payload_media_type, link_path_info
|
103
|
-
case method
|
104
|
-
when "PUT","POST"
|
105
|
-
if link_path_info
|
106
|
-
self.link link_path_info
|
107
|
-
else
|
108
|
-
self.send(method.downcase, payload, payload_media_type)
|
109
|
-
end
|
110
|
-
when "DELETE"
|
111
|
-
if link_path_info
|
112
|
-
self.unlink link_path_info
|
113
|
-
else
|
114
|
-
self.delete
|
115
|
-
end
|
116
|
-
when "GET"
|
117
|
-
self.get
|
118
|
-
else
|
119
|
-
raise MethodNotAllowed
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
def uri_fields record, in_collection=false
|
125
|
-
out = {}
|
126
|
-
|
127
|
-
exposed_assoc =
|
128
|
-
in_collection ? record.class.toast_config.in_collection.exposed_associations :
|
129
|
-
record.class.toast_config.exposed_associations
|
130
|
-
|
131
|
-
exposed_assoc.each do |assoc|
|
132
|
-
out[assoc] = "#{self.base_uri}#{record.uri_path}/#{assoc}"
|
133
|
-
end
|
134
|
-
|
135
|
-
out["self"] = self.base_uri + record.uri_path
|
136
|
-
|
137
|
-
out
|
138
|
-
end
|
139
|
-
|
140
|
-
|
141
|
-
def paginate_query config, relation_name, relation, params
|
142
|
-
|
143
|
-
if pagination = config.paginations[relation_name] and params[:page] =~ /\d+/
|
144
|
-
|
145
|
-
raise Toast::BadRequest.new("Page 0 not defined. Paging starts with 1") if params[:page].to_i == 0
|
146
|
-
|
147
|
-
ps = pagination[:page_size].to_i
|
148
|
-
total = relation.count
|
149
|
-
|
150
|
-
page = params[:page].to_i
|
151
|
-
total_pages = (total/ps) + (total%ps == 0 ? 0 : 1)
|
152
|
-
|
153
|
-
pagination_info = {:total => total}
|
154
|
-
|
155
|
-
if total_pages > 0
|
156
|
-
|
157
|
-
if page > total_pages
|
158
|
-
pagination_info[:prev] = total_pages
|
159
|
-
else
|
160
|
-
pagination_info[:prev] = page - 1 unless page == 1
|
161
|
-
pagination_info[:next] = page + 1 if page < total_pages
|
162
|
-
end
|
163
|
-
|
164
|
-
pagination_info[:last] = total_pages
|
165
|
-
else
|
166
|
-
pagination_info[:last] = 1
|
167
|
-
end
|
168
|
-
|
169
|
-
[relation.limit(ps).offset((page-1) * ps), pagination_info]
|
170
|
-
else
|
171
|
-
[relation, nil]
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
data/lib/toast/single.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
module Toast
|
2
|
-
|
3
|
-
# A Single resource is queried without an ID, by custom class methods
|
4
|
-
# or scopes of the model or ActiveRecord single finders like:
|
5
|
-
# first, last
|
6
|
-
|
7
|
-
# The single resource name must be a class method of the model and
|
8
|
-
# must return nil or an instance.
|
9
|
-
|
10
|
-
# GET is the only allowed verb. To make changes the URI with ID has
|
11
|
-
# to be used.
|
12
|
-
class Single < Resource
|
13
|
-
|
14
|
-
attr_reader :model
|
15
|
-
|
16
|
-
def initialize model, subresource_name, params, config_in, config_out
|
17
|
-
@config_in = config_in
|
18
|
-
@config_out = config_out
|
19
|
-
|
20
|
-
unless @config_out.singles.include? subresource_name
|
21
|
-
raise ResourceNotFound
|
22
|
-
end
|
23
|
-
|
24
|
-
@model = model
|
25
|
-
@params = params
|
26
|
-
@format = params[:format]
|
27
|
-
|
28
|
-
unless @model.respond_to?(subresource_name)
|
29
|
-
raise "Toast Error: Cannot find class method '#{@model}.#{subresource_name}', which is configured in 'acts_as_resource > singles'."
|
30
|
-
end
|
31
|
-
|
32
|
-
@record = if @config_out.pass_params_to.include?(subresource_name)
|
33
|
-
if @model.method(subresource_name).arity != 1
|
34
|
-
raise "Toast Error: Class method '#{@model}.#{subresource_name}' must accept one parameter, as configured by 'acts_as_resource > pass_params_to'."
|
35
|
-
end
|
36
|
-
@model.send(subresource_name, @params)
|
37
|
-
else
|
38
|
-
if(@model.method(subresource_name).arity < -1 or
|
39
|
-
@model.method(subresource_name).arity > 0)
|
40
|
-
raise "Toast Error: Class method '#{@model}.#{subresource_name}' must be callable w/o parameters"
|
41
|
-
end
|
42
|
-
@model.send(subresource_name)
|
43
|
-
end
|
44
|
-
|
45
|
-
raise ResourceNotFound if @record.nil?
|
46
|
-
end
|
47
|
-
|
48
|
-
def get
|
49
|
-
case @format
|
50
|
-
when "html"
|
51
|
-
{
|
52
|
-
:template => "resources/#{model.to_s.underscore}",
|
53
|
-
:locals => { model.to_s.pluralize.underscore.to_sym => @record }
|
54
|
-
}
|
55
|
-
when "json"
|
56
|
-
{
|
57
|
-
:json => @record.represent( @config_out.exposed_attributes,
|
58
|
-
@config_out.exposed_associations,
|
59
|
-
@base_uri,
|
60
|
-
@config_out.media_type),
|
61
|
-
:status => :ok
|
62
|
-
}
|
63
|
-
else
|
64
|
-
raise ResourceNotFound
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
def put
|
70
|
-
raise MethodNotAllowed
|
71
|
-
end
|
72
|
-
|
73
|
-
def post payload
|
74
|
-
raise MethodNotAllowed
|
75
|
-
end
|
76
|
-
|
77
|
-
def delete
|
78
|
-
raise MethodNotAllowed
|
79
|
-
end
|
80
|
-
|
81
|
-
def link l
|
82
|
-
raise MethodNotAllowed
|
83
|
-
end
|
84
|
-
|
85
|
-
def unlink l
|
86
|
-
raise MethodNotAllowed
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|