fragrant 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +6 -0
  3. data/bin/fragrant +14 -0
  4. data/lib/fragrant/address_manager.rb +80 -0
  5. data/lib/fragrant/vagrantfile_generator.rb +64 -0
  6. data/lib/fragrant.rb +323 -0
  7. data/spec/fragrant/environments_spec.rb +18 -0
  8. data/spec/fragrant/vagrantfile_generator_spec.rb +40 -0
  9. data/spec/fragrant/vms_spec.rb +26 -0
  10. data/spec/spec_helper.rb +15 -0
  11. data/vendor/grape/LICENSE +20 -0
  12. data/vendor/grape/lib/grape/api.rb +420 -0
  13. data/vendor/grape/lib/grape/cookies.rb +41 -0
  14. data/vendor/grape/lib/grape/endpoint.rb +377 -0
  15. data/vendor/grape/lib/grape/entity.rb +378 -0
  16. data/vendor/grape/lib/grape/exceptions/base.rb +17 -0
  17. data/vendor/grape/lib/grape/exceptions/validation_error.rb +10 -0
  18. data/vendor/grape/lib/grape/middleware/auth/basic.rb +30 -0
  19. data/vendor/grape/lib/grape/middleware/auth/digest.rb +30 -0
  20. data/vendor/grape/lib/grape/middleware/auth/oauth2.rb +72 -0
  21. data/vendor/grape/lib/grape/middleware/base.rb +154 -0
  22. data/vendor/grape/lib/grape/middleware/error.rb +87 -0
  23. data/vendor/grape/lib/grape/middleware/filter.rb +17 -0
  24. data/vendor/grape/lib/grape/middleware/formatter.rb +81 -0
  25. data/vendor/grape/lib/grape/middleware/prefixer.rb +21 -0
  26. data/vendor/grape/lib/grape/middleware/versioner/header.rb +59 -0
  27. data/vendor/grape/lib/grape/middleware/versioner/param.rb +44 -0
  28. data/vendor/grape/lib/grape/middleware/versioner/path.rb +42 -0
  29. data/vendor/grape/lib/grape/middleware/versioner.rb +29 -0
  30. data/vendor/grape/lib/grape/route.rb +23 -0
  31. data/vendor/grape/lib/grape/util/deep_merge.rb +23 -0
  32. data/vendor/grape/lib/grape/util/hash_stack.rb +100 -0
  33. data/vendor/grape/lib/grape/validations/coerce.rb +61 -0
  34. data/vendor/grape/lib/grape/validations/presence.rb +11 -0
  35. data/vendor/grape/lib/grape/validations/regexp.rb +13 -0
  36. data/vendor/grape/lib/grape/validations.rb +192 -0
  37. data/vendor/grape/lib/grape/version.rb +3 -0
  38. data/vendor/grape/lib/grape.rb +44 -0
  39. metadata +216 -0
@@ -0,0 +1,420 @@
1
+ require 'rack/mount'
2
+ require 'rack/auth/basic'
3
+ require 'rack/auth/digest/md5'
4
+ require 'logger'
5
+ require 'grape/util/deep_merge'
6
+
7
+ module Grape
8
+ # The API class is the primary entry point for
9
+ # creating Grape APIs.Users should subclass this
10
+ # class in order to build an API.
11
+ class API
12
+ extend Validations::ClassMethods
13
+
14
+ class << self
15
+ attr_reader :route_set
16
+ attr_reader :versions
17
+ attr_reader :routes
18
+ attr_reader :settings
19
+ attr_writer :logger
20
+ attr_reader :endpoints
21
+ attr_reader :mountings
22
+ attr_reader :instance
23
+
24
+ def logger(logger = nil)
25
+ if logger
26
+ @logger = logger
27
+ else
28
+ @logger ||= Logger.new($stdout)
29
+ end
30
+ end
31
+
32
+ def reset!
33
+ @settings = Grape::Util::HashStack.new
34
+ @route_set = Rack::Mount::RouteSet.new
35
+ @endpoints = []
36
+ @mountings = []
37
+ @routes = nil
38
+ reset_validations!
39
+ end
40
+
41
+ def compile
42
+ @instance = self.new
43
+ end
44
+
45
+ def change!
46
+ @instance = nil
47
+ end
48
+
49
+ def call(env)
50
+ compile unless instance
51
+ call!(env)
52
+ end
53
+
54
+ def call!(env)
55
+ instance.call(env)
56
+ end
57
+
58
+ # Set a configuration value for this namespace.
59
+ #
60
+ # @param key [Symbol] The key of the configuration variable.
61
+ # @param value [Object] The value to which to set the configuration variable.
62
+ def set(key, value)
63
+ settings[key.to_sym] = value
64
+ end
65
+
66
+ # Add to a configuration value for this
67
+ # namespace.
68
+ #
69
+ # @param key [Symbol] The key of the configuration variable.
70
+ # @param value [Object] The value to which to set the configuration variable.
71
+ def imbue(key, value)
72
+ settings.imbue(key, value)
73
+ end
74
+
75
+ # Define a root URL prefix for your entire
76
+ # API.
77
+ def prefix(prefix = nil)
78
+ prefix ? set(:root_prefix, prefix) : settings[:root_prefix]
79
+ end
80
+
81
+ # Specify an API version.
82
+ #
83
+ # @example API with legacy support.
84
+ # class MyAPI < Grape::API
85
+ # version 'v2'
86
+ #
87
+ # get '/main' do
88
+ # {:some => 'data'}
89
+ # end
90
+ #
91
+ # version 'v1' do
92
+ # get '/main' do
93
+ # {:legacy => 'data'}
94
+ # end
95
+ # end
96
+ # end
97
+ #
98
+ def version(*args, &block)
99
+ if args.any?
100
+ options = args.pop if args.last.is_a? Hash
101
+ options ||= {}
102
+ options = {:using => :path}.merge!(options)
103
+ @versions = versions | args
104
+ nest(block) do
105
+ set(:version, args)
106
+ set(:version_options, options)
107
+ end
108
+ end
109
+ end
110
+
111
+ # Add a description to the next namespace or function.
112
+ def desc(description, options = {})
113
+ @last_description = options.merge(:description => description)
114
+ end
115
+
116
+ # Specify the default format for the API's serializers.
117
+ # May be `:json` or `:txt` (default).
118
+ def default_format(new_format = nil)
119
+ new_format ? set(:default_format, new_format.to_sym) : settings[:default_format]
120
+ end
121
+
122
+ # Specify the format for the API's serializers.
123
+ # May be `:json` or `:txt`.
124
+ def format(new_format = nil)
125
+ new_format ? set(:format, new_format.to_sym) : settings[:format]
126
+ end
127
+
128
+ # Specify the format for error messages.
129
+ # May be `:json` or `:txt` (default).
130
+ def error_format(new_format = nil)
131
+ new_format ? set(:error_format, new_format.to_sym) : settings[:error_format]
132
+ end
133
+
134
+ # Specify additional content-types, e.g.:
135
+ # content_type :xls, 'application/vnd.ms-excel'
136
+ def content_type(key, val)
137
+ settings.imbue(:content_types, key.to_sym => val)
138
+ end
139
+
140
+ # Specify the default status code for errors.
141
+ def default_error_status(new_status = nil)
142
+ new_status ? set(:default_error_status, new_status) : settings[:default_error_status]
143
+ end
144
+
145
+ # Allows you to rescue certain exceptions that occur to return
146
+ # a grape error rather than raising all the way to the
147
+ # server level.
148
+ #
149
+ # @example Rescue from custom exceptions
150
+ # class ExampleAPI < Grape::API
151
+ # class CustomError < StandardError; end
152
+ #
153
+ # rescue_from CustomError
154
+ # end
155
+ #
156
+ # @overload rescue_from(*exception_classes, options = {})
157
+ # @param [Array] exception_classes A list of classes that you want to rescue, or
158
+ # the symbol :all to rescue from all exceptions.
159
+ # @param [Block] block Execution block to handle the given exception.
160
+ # @param [Hash] options Options for the rescue usage.
161
+ # @option options [Boolean] :backtrace Include a backtrace in the rescue response.
162
+ def rescue_from(*args, &block)
163
+ if block_given?
164
+ args.each do |arg|
165
+ imbue(:rescue_handlers, { arg => block })
166
+ end
167
+ end
168
+ imbue(:rescue_options, args.pop) if args.last.is_a?(Hash)
169
+ set(:rescue_all, true) and return if args.include?(:all)
170
+ imbue(:rescued_errors, args)
171
+ end
172
+
173
+ # Allows you to specify a default representation entity for a
174
+ # class. This allows you to map your models to their respective
175
+ # entities once and then simply call `present` with the model.
176
+ #
177
+ # @example
178
+ # class ExampleAPI < Grape::API
179
+ # represent User, :with => Entity::User
180
+ #
181
+ # get '/me' do
182
+ # present current_user # :with => Entity::User is assumed
183
+ # end
184
+ # end
185
+ #
186
+ # Note that Grape will automatically go up the class ancestry to
187
+ # try to find a representing entity, so if you, for example, define
188
+ # an entity to represent `Object` then all presented objects will
189
+ # bubble up and utilize the entity provided on that `represent` call.
190
+ #
191
+ # @param model_class [Class] The model class that will be represented.
192
+ # @option options [Class] :with The entity class that will represent the model.
193
+ def represent(model_class, options)
194
+ raise ArgumentError, "You must specify an entity class in the :with option." unless options[:with] && options[:with].is_a?(Class)
195
+ imbue(:representations, model_class => options[:with])
196
+ end
197
+
198
+ # Add helper methods that will be accessible from any
199
+ # endpoint within this namespace (and child namespaces).
200
+ #
201
+ # When called without a block, all known helpers within this scope
202
+ # are included.
203
+ #
204
+ # @param mod [Module] optional module of methods to include
205
+ # @param &block [Block] optional block of methods to include
206
+ #
207
+ # @example Define some helpers.
208
+ # class ExampleAPI < Grape::API
209
+ # helpers do
210
+ # def current_user
211
+ # User.find_by_id(params[:token])
212
+ # end
213
+ # end
214
+ # end
215
+ def helpers(new_mod = nil, &block)
216
+ if block_given? || new_mod
217
+ mod = settings.peek[:helpers] || Module.new
218
+ if new_mod
219
+ mod.class_eval do
220
+ include new_mod
221
+ end
222
+ end
223
+ mod.class_eval &block if block_given?
224
+ set(:helpers, mod)
225
+ else
226
+ mod = Module.new
227
+ settings.stack.each do |s|
228
+ mod.send :include, s[:helpers] if s[:helpers]
229
+ end
230
+ change!
231
+ mod
232
+ end
233
+ end
234
+
235
+ # Add an authentication type to the API. Currently
236
+ # only `:http_basic`, `:http_digest` and `:oauth2` are supported.
237
+ def auth(type = nil, options = {}, &block)
238
+ if type
239
+ set(:auth, {:type => type.to_sym, :proc => block}.merge(options))
240
+ else
241
+ settings[:auth]
242
+ end
243
+ end
244
+
245
+ # Add HTTP Basic authorization to the API.
246
+ #
247
+ # @param [Hash] options A hash of options.
248
+ # @option options [String] :realm "API Authorization" The HTTP Basic realm.
249
+ def http_basic(options = {}, &block)
250
+ options[:realm] ||= "API Authorization"
251
+ auth :http_basic, options, &block
252
+ end
253
+
254
+ def http_digest(options = {}, &block)
255
+ options[:realm] ||= "API Authorization"
256
+ options[:opaque] ||= "secret"
257
+ auth :http_digest, options, &block
258
+ end
259
+
260
+ def mount(mounts)
261
+ mounts = {mounts => '/'} unless mounts.respond_to?(:each_pair)
262
+ mounts.each_pair do |app, path|
263
+ if app.respond_to?(:inherit_settings)
264
+ app.inherit_settings(settings.clone)
265
+ end
266
+
267
+ endpoints << Grape::Endpoint.new(settings.clone,
268
+ :method => :any,
269
+ :path => path,
270
+ :app => app
271
+ )
272
+ end
273
+ end
274
+
275
+ # Defines a route that will be recognized
276
+ # by the Grape API.
277
+ #
278
+ # @param methods [HTTP Verb] One or more HTTP verbs that are accepted by this route. Set to `:any` if you want any verb to be accepted.
279
+ # @param paths [String] One or more strings representing the URL segment(s) for this route.
280
+ #
281
+ # @example Defining a basic route.
282
+ # class MyAPI < Grape::API
283
+ # route(:any, '/hello') do
284
+ # {:hello => 'world'}
285
+ # end
286
+ # end
287
+ def route(methods, paths = ['/'], route_options = {}, &block)
288
+ endpoint_options = {
289
+ :method => methods,
290
+ :path => paths,
291
+ :route_options => (@namespace_description || {}).deep_merge(@last_description || {}).deep_merge(route_options || {})
292
+ }
293
+ endpoints << Grape::Endpoint.new(settings.clone, endpoint_options, &block)
294
+
295
+ @last_description = nil
296
+ reset_validations!
297
+ end
298
+
299
+ def before(&block)
300
+ imbue(:befores, [block])
301
+ end
302
+
303
+ def after(&block)
304
+ imbue(:afters, [block])
305
+ end
306
+
307
+ def get(paths = ['/'], options = {}, &block); route('GET', paths, options, &block) end
308
+ def post(paths = ['/'], options = {}, &block); route('POST', paths, options, &block) end
309
+ def put(paths = ['/'], options = {}, &block); route('PUT', paths, options, &block) end
310
+ def head(paths = ['/'], options = {}, &block); route('HEAD', paths, options, &block) end
311
+ def delete(paths = ['/'], options = {}, &block); route('DELETE', paths, options, &block) end
312
+ def options(paths = ['/'], options = {}, &block); route('OPTIONS', paths, options, &block) end
313
+ def patch(paths = ['/'], options = {}, &block); route('PATCH', paths, options, &block) end
314
+
315
+ def namespace(space = nil, &block)
316
+ if space || block_given?
317
+ previous_namespace_description = @namespace_description
318
+ @namespace_description = (@namespace_description || {}).deep_merge(@last_description || {})
319
+ @last_description = nil
320
+ nest(block) do
321
+ set(:namespace, space.to_s) if space
322
+ end
323
+ @namespace_description = previous_namespace_description
324
+ else
325
+ Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace]}.join('/'))
326
+ end
327
+ end
328
+
329
+ alias_method :group, :namespace
330
+ alias_method :resource, :namespace
331
+ alias_method :resources, :namespace
332
+ alias_method :segment, :namespace
333
+
334
+ # Create a scope without affecting the URL.
335
+ #
336
+ # @param name [Symbol] Purely placebo, just allows to to name the scope to make the code more readable.
337
+ def scope(name = nil, &block)
338
+ nest(block)
339
+ end
340
+
341
+ # Apply a custom middleware to the API. Applies
342
+ # to the current namespace and any children, but
343
+ # not parents.
344
+ #
345
+ # @param middleware_class [Class] The class of the middleware you'd like
346
+ # to inject.
347
+ def use(middleware_class, *args, &block)
348
+ arr = [middleware_class, *args]
349
+ arr << block if block_given?
350
+ imbue(:middleware, [arr])
351
+ end
352
+
353
+ # Retrieve an array of the middleware classes
354
+ # and arguments that are currently applied to the
355
+ # application.
356
+ def middleware
357
+ settings.stack.inject([]){|a,s| a += s[:middleware] if s[:middleware]; a}
358
+ end
359
+
360
+ # An array of API routes.
361
+ def routes
362
+ @routes ||= prepare_routes
363
+ end
364
+
365
+ def versions
366
+ @versions ||= []
367
+ end
368
+
369
+ protected
370
+
371
+ def prepare_routes
372
+ routes = []
373
+ endpoints.each do |endpoint|
374
+ routes.concat(endpoint.routes)
375
+ end
376
+ routes
377
+ end
378
+
379
+ # Execute first the provided block, then each of the
380
+ # block passed in. Allows for simple 'before' setups
381
+ # of settings stack pushes.
382
+ def nest(*blocks, &block)
383
+ blocks.reject!{|b| b.nil?}
384
+ if blocks.any?
385
+ settings.push # create a new context to eval the follow
386
+ instance_eval &block if block_given?
387
+ blocks.each{|b| instance_eval &b}
388
+ settings.pop # when finished, we pop the context
389
+ reset_validations!
390
+ else
391
+ instance_eval &block
392
+ end
393
+ end
394
+
395
+ def inherited(subclass)
396
+ subclass.reset!
397
+ subclass.logger = logger.clone
398
+ end
399
+
400
+ def inherit_settings(other_stack)
401
+ settings.prepend other_stack
402
+ endpoints.each{|e| e.settings.prepend(other_stack)}
403
+ end
404
+ end
405
+
406
+ def initialize
407
+ @route_set = Rack::Mount::RouteSet.new
408
+ self.class.endpoints.each do |endpoint|
409
+ endpoint.mount_in(@route_set)
410
+ end
411
+ @route_set.freeze
412
+ end
413
+
414
+ def call(env)
415
+ @route_set.call(env)
416
+ end
417
+
418
+ reset!
419
+ end
420
+ end
@@ -0,0 +1,41 @@
1
+ module Grape
2
+ class Cookies
3
+
4
+ def initialize
5
+ @cookies = {}
6
+ @send_cookies = {}
7
+ end
8
+
9
+ def read(request)
10
+ request.cookies.each do |name, value|
11
+ @cookies[name.to_sym] = value
12
+ end
13
+ end
14
+
15
+ def write(header)
16
+ @cookies.select { |key, value|
17
+ @send_cookies[key.to_sym] == true
18
+ }.each { |name, value|
19
+ Rack::Utils.set_cookie_header!(
20
+ header, name, value.instance_of?(Hash) ? value : { :value => value })
21
+ }
22
+ end
23
+
24
+ def [](name)
25
+ @cookies[name]
26
+ end
27
+
28
+ def []=(name, value)
29
+ @cookies[name.to_sym] = value
30
+ @send_cookies[name.to_sym] = true
31
+ end
32
+
33
+ def each(&block)
34
+ @cookies.each(&block)
35
+ end
36
+
37
+ def delete(name)
38
+ self.[]=(name, { :value => 'deleted', :expires => Time.at(0) })
39
+ end
40
+ end
41
+ end