Skip to content

Commit b474f5e

Browse files
committed
Merge pull request #1044 from rnubel/documentation
Increase documentation coverage
2 parents 2b39cfc + 58cd902 commit b474f5e

16 files changed

+275
-11
lines changed

lib/grape/api.rb

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,60 @@
11
module Grape
2-
# The API class is the primary entry point for
3-
# creating Grape APIs.Users should subclass this
4-
# class in order to build an API.
2+
# The API class is the primary entry point for creating Grape APIs. Users
3+
# should subclass this class in order to build an API.
54
class API
65
include Grape::DSL::API
76

87
class << self
98
attr_reader :instance
9+
10+
# A class-level lock to ensure the API is not compiled by multiple
11+
# threads simultaneously within the same process.
1012
LOCK = Mutex.new
1113

14+
# Clears all defined routes, endpoints, etc., on this API.
1215
def reset!
1316
@route_set = Rack::Mount::RouteSet.new
1417
@endpoints = []
1518
@routes = nil
1619
reset_validations!
1720
end
1821

22+
# Parses the API's definition and compiles it into an instance of
23+
# Grape::API.
1924
def compile
2025
@instance ||= new
2126
end
2227

28+
# Wipe the compiled API so we can recompile after changes were made.
2329
def change!
2430
@instance = nil
2531
end
2632

33+
# This is the interface point between Rack and Grape; it accepts a request
34+
# from Rack and ultimately returns an array of three values: the status,
35+
# the headers, and the body. See [the rack specification]
36+
# (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
2737
def call(env)
2838
LOCK.synchronize { compile } unless instance
2939
call!(env)
3040
end
3141

42+
# A non-synchronized version of ::call.
3243
def call!(env)
3344
instance.call(env)
3445
end
3546

3647
# Create a scope without affecting the URL.
3748
#
38-
# @param name [Symbol] Purely placebo, just allows to name the scope to make the code more readable.
49+
# @param _name [Symbol] Purely placebo, just allows to name the scope to
50+
# make the code more readable.
3951
def scope(_name = nil, &block)
4052
within_namespace do
4153
nest(block)
4254
end
4355
end
4456

57+
# (see #cascade?)
4558
def cascade(value = nil)
4659
if value.nil?
4760
inheritable_setting.namespace_inheritable.keys.include?(:cascade) ? !!namespace_inheritable(:cascade) : true
@@ -84,6 +97,8 @@ def inherit_settings(other_settings)
8497
end
8598
end
8699

100+
# Builds the routes from the defined endpoints, effectively compiling
101+
# this API into a usable form.
87102
def initialize
88103
@route_set = Rack::Mount::RouteSet.new
89104
add_head_not_allowed_methods_and_options_methods
@@ -94,6 +109,7 @@ def initialize
94109
@route_set.freeze
95110
end
96111

112+
# Handle a request. See Rack documentation for what `env` is.
97113
def call(env)
98114
result = @route_set.call(env)
99115
result[1].delete(Grape::Http::Headers::X_CASCADE) unless cascade?
@@ -168,6 +184,8 @@ def add_head_not_allowed_methods_and_options_methods
168184
end
169185
end
170186

187+
# Allows definition of endpoints that ignore the versioning configuration
188+
# used by the rest of your API.
171189
def without_versioning(&_block)
172190
old_version = self.class.namespace_inheritable(:version)
173191
old_version_options = self.class.namespace_inheritable(:version_options)
@@ -181,6 +199,8 @@ def without_versioning(&_block)
181199
self.class.namespace_inheritable(:version_options, old_version_options)
182200
end
183201

202+
# Allows definition of endpoints that ignore the root prefix used by the
203+
# rest of your API.
184204
def without_root_prefix(&_block)
185205
old_prefix = self.class.namespace_inheritable(:root_prefix)
186206

lib/grape/dsl/callbacks.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,44 @@
22

33
module Grape
44
module DSL
5+
# Blocks can be executed before or after every API call, using `before`, `after`,
6+
# `before_validation` and `after_validation`.
7+
#
8+
# Before and after callbacks execute in the following order:
9+
#
10+
# 1. `before`
11+
# 2. `before_validation`
12+
# 3. _validations_
13+
# 4. `after_validation`
14+
# 5. _the API call_
15+
# 6. `after`
16+
#
17+
# Steps 4, 5 and 6 only happen if validation succeeds.
518
module Callbacks
619
extend ActiveSupport::Concern
720

821
include Grape::DSL::Configuration
922

1023
module ClassMethods
24+
# Execute the given block before validation, coercion, or any endpoint
25+
# code is executed.
1126
def before(&block)
1227
namespace_stackable(:befores, block)
1328
end
1429

30+
# Execute the given block after `before`, but prior to validation or
31+
# coercion.
1532
def before_validation(&block)
1633
namespace_stackable(:before_validations, block)
1734
end
1835

36+
# Execute the given block after validations and coercions, but before
37+
# any endpoint code.
1938
def after_validation(&block)
2039
namespace_stackable(:after_validations, block)
2140
end
2241

42+
# Execute the given block after the endpoint code has run.
2343
def after(&block)
2444
namespace_stackable(:afters, block)
2545
end

lib/grape/dsl/configuration.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ module ClassMethods
1010

1111
include Grape::DSL::Settings
1212

13+
# Set or retrive the configured logger. If none was configured, this
14+
# method will create a new one, logging to stdout.
15+
# @param logger [Object] the new logger to use
1316
def logger(logger = nil)
1417
if logger
1518
global_setting(:logger, logger)
@@ -19,6 +22,39 @@ def logger(logger = nil)
1922
end
2023

2124
# Add a description to the next namespace or function.
25+
# @param description [String] descriptive string for this endpoint
26+
# or namespace
27+
# @param options [Hash] other properties you can set to describe the
28+
# endpoint or namespace. Optional.
29+
# @option options :detail [String] additional detail about this endpoint
30+
# @option options :params [Hash] param types and info. normally, you set
31+
# these via the `params` dsl method.
32+
# @option options :entity [Grape::Entity] the entity returned upon a
33+
# successful call to this action
34+
# @option options :http_codes [Array[Array]] possible HTTP codes this
35+
# endpoint may return, with their meanings, in a 2d array
36+
# @option options :named [String] a specific name to help find this route
37+
# @option options :headers [Hash] HTTP headers this method can accept
38+
# @yield a block yielding an instance context with methods mapping to
39+
# each of the above, except that :entity is also aliased as #success
40+
# and :http_codes is aliased as #failure.
41+
#
42+
# @example
43+
#
44+
# desc 'create a user'
45+
# post '/users' do
46+
# # ...
47+
# end
48+
#
49+
# desc 'find a user' do
50+
# detail 'locates the user from the given user ID'
51+
# failure [ [404, 'Couldn\'t find the given user' ] ]
52+
# success User::Entity
53+
# end
54+
# get '/user/:id' do
55+
# # ...
56+
# end
57+
#
2258
def desc(description, options = {}, &config_block)
2359
if block_given?
2460
config_class = Grape::DSL::Configuration.desc_container
@@ -40,11 +76,13 @@ def desc(description, options = {}, &config_block)
4076

4177
module_function
4278

79+
# Merge multiple layers of settings into one hash.
4380
def stacked_hash_to_hash(settings)
4481
return nil if settings.nil? || settings.blank?
4582
settings.each_with_object(ActiveSupport::OrderedHash.new) { |value, result| result.deep_merge!(value) }
4683
end
4784

85+
# Returns an object which configures itself via an instance-context DSL.
4886
def desc_container
4987
Module.new do
5088
include Grape::Util::StrictHashConfiguration.module(

lib/grape/dsl/inside_route.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,14 @@ def route
238238
env['rack.routing_args'][:route_info]
239239
end
240240

241+
# Attempt to locate the Entity class for a given object, if not given
242+
# explicitly. This is done by looking for the presence of Klass::Entity,
243+
# where Klass is the class of the `object` parameter, or one of its
244+
# ancestors.
245+
# @param object [Object] the object to locate the Entity class for
246+
# @param options [Hash]
247+
# @option options :with [Class] the explicit entity class to use
248+
# @return [Class] the located Entity class, or nil if none is found
241249
def entity_class_for_obj(object, options)
242250
entity_class = options.delete(:with)
243251

@@ -259,6 +267,8 @@ def entity_class_for_obj(object, options)
259267
entity_class
260268
end
261269

270+
# @return the representation of the given object as done through
271+
# the given entity_class.
262272
def entity_representation_for(entity_class, object, options)
263273
embeds = { env: env }
264274
embeds[:version] = env['api.version'] if env['api.version']

lib/grape/dsl/parameters.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
module Grape
44
module DSL
5+
# Defines DSL methods, meant to be applied to a ParamsScope, which define
6+
# and describe the parameters accepted by an endpoint, or all endpoints
7+
# within a namespace.
58
module Parameters
69
extend ActiveSupport::Concern
710

@@ -39,6 +42,47 @@ def use(*names)
3942
alias_method :use_scope, :use
4043
alias_method :includes, :use
4144

45+
# Require one or more parameters for the current endpoint.
46+
#
47+
# @param attrs list of parameter names, or, if :using is
48+
# passed as an option, which keys to include (:all or :none) from
49+
# the :using hash. The last key can be a hash, which specifies
50+
# options for the parameters
51+
# @option attrs :type [Class] the type to coerce this parameter to before
52+
# passing it to the endpoint. See Grape::ParameterTypes for supported
53+
# types, or use a class that defines `::parse` as a custom type
54+
# @option attrs :desc [String] description to document this parameter
55+
# @option attrs :default [Object] default value, if parameter is optional
56+
# @option attrs :values [Array] permissable values for this field. If any
57+
# other value is given, it will be handled as a validation error
58+
# @option attrs :using [Hash[Symbol => Hash]] a hash defining keys and
59+
# options, like that returned by Grape::Entity#documentation. The value
60+
# of each key is an options hash accepting the same parameters
61+
# @option attrs :except [Array[Symbol]] a list of keys to exclude from
62+
# the :using Hash. The meaning of this depends on if :all or :none was
63+
# passed; :all + :except will make the :except fields optional, whereas
64+
# :none + :except will make the :except fields required
65+
#
66+
# @example
67+
#
68+
# params do
69+
# # Basic usage: require a parameter of a certain type
70+
# requires :user_id, type: Integer
71+
#
72+
# # You don't need to specify type; String is default
73+
# requires :foo
74+
#
75+
# # Multiple params can be specified at once if they share
76+
# # the same options.
77+
# requires :x, :y, :z, type: Date
78+
#
79+
# # Nested parameters can be handled as hashes. You must
80+
# # pass in a block, within which you can use any of the
81+
# # parameters DSL methods.
82+
# requires :user, type: Hash do
83+
# requires :name, type: String
84+
# end
85+
# end
4286
def requires(*attrs, &block)
4387
orig_attrs = attrs.clone
4488

@@ -55,6 +99,10 @@ def requires(*attrs, &block)
5599
end
56100
end
57101

102+
# Allow, but don't require, one or more parameters for the current
103+
# endpoint.
104+
# @param (see #requires)
105+
# @option (see #requires)
58106
def optional(*attrs, &block)
59107
orig_attrs = attrs.clone
60108

@@ -77,24 +125,35 @@ def optional(*attrs, &block)
77125
end
78126
end
79127

128+
# Disallow the given parameters to be present in the same request.
129+
# @param attrs [*Symbol] parameters to validate
80130
def mutually_exclusive(*attrs)
81131
validates(attrs, mutual_exclusion: true)
82132
end
83133

134+
# Require exactly one of the given parameters to be present.
135+
# @param (see #mutually_exclusive)
84136
def exactly_one_of(*attrs)
85137
validates(attrs, exactly_one_of: true)
86138
end
87139

140+
# Require at least one of the given parameters to be present.
141+
# @param (see #mutually_exclusive)
88142
def at_least_one_of(*attrs)
89143
validates(attrs, at_least_one_of: true)
90144
end
91145

146+
# Require that either all given params are present, or none are.
147+
# @param (see #mutually_exclusive)
92148
def all_or_none_of(*attrs)
93149
validates(attrs, all_or_none_of: true)
94150
end
95151

96152
alias_method :group, :requires
97153

154+
# @param params [Hash] initial hash of parameters
155+
# @return hash of parameters relevant for the current scope
156+
# @api private
98157
def params(params)
99158
params = @parent.params(params) if @parent
100159
if @element

lib/grape/dsl/routing.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ def route(methods, paths = ['/'], route_options = {}, &block)
135135
end
136136
end
137137

138+
# Declare a "namespace", which prefixes all subordinate routes with its
139+
# name. Any endpoints within a namespace, or group, resource, segment,
140+
# etc., will share their parent context as well as any configuration
141+
# done in the namespace context.
142+
#
143+
# @example
144+
#
145+
# namespace :foo do
146+
# get 'bar' do
147+
# # defines the endpoint: GET /foo/bar
148+
# end
149+
# end
138150
def namespace(space = nil, options = {}, &block)
139151
if space || block_given?
140152
within_namespace do
@@ -162,6 +174,7 @@ def routes
162174
@routes ||= prepare_routes
163175
end
164176

177+
# Remove all defined routes.
165178
def reset_routes!
166179
@routes = nil
167180
end
@@ -177,6 +190,7 @@ def route_param(param, options = {}, &block)
177190
namespace(":#{param}", options, &block)
178191
end
179192

193+
# @return array of defined versions
180194
def versions
181195
@versions ||= []
182196
end

0 commit comments

Comments
 (0)