fragrant 0.0.1

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.
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,377 @@
1
+ require 'rack'
2
+ require 'grape'
3
+ require 'hashie'
4
+
5
+ module Grape
6
+ # An Endpoint is the proxy scope in which all routing
7
+ # blocks are executed. In other words, any methods
8
+ # on the instance level of this class may be called
9
+ # from inside a `get`, `post`, etc. block.
10
+ class Endpoint
11
+ attr_accessor :block, :options, :settings
12
+ attr_reader :env, :request
13
+
14
+ def initialize(settings, options = {}, &block)
15
+ @settings = settings
16
+ @block = block
17
+ @options = options
18
+
19
+ raise ArgumentError, "Must specify :path option." unless options.key?(:path)
20
+ options[:path] = Array(options[:path])
21
+ options[:path] = ['/'] if options[:path].empty?
22
+
23
+ raise ArgumentError, "Must specify :method option." unless options.key?(:method)
24
+ options[:method] = Array(options[:method])
25
+
26
+ options[:route_options] ||= {}
27
+ end
28
+
29
+ def routes
30
+ @routes ||= prepare_routes
31
+ end
32
+
33
+ def mount_in(route_set)
34
+ if options[:app] && options[:app].respond_to?(:endpoints)
35
+ options[:app].endpoints.each{|e| e.mount_in(route_set)}
36
+ else
37
+ routes.each do |route|
38
+ route_set.add_route(self, {
39
+ :path_info => route.route_compiled,
40
+ :request_method => route.route_method,
41
+ }, { :route_info => route })
42
+ end
43
+ end
44
+ end
45
+
46
+ def prepare_routes
47
+ routes = []
48
+ options[:method].each do |method|
49
+ options[:path].each do |path|
50
+ prepared_path = prepare_path(path)
51
+
52
+ anchor = options[:route_options][:anchor]
53
+ anchor = anchor.nil? ? true : anchor
54
+
55
+ requirements = options[:route_options][:requirements] || {}
56
+
57
+ path = compile_path(prepared_path, anchor && !options[:app], requirements)
58
+ regex = Rack::Mount::RegexpWithNamedGroups.new(path)
59
+ path_params = {}
60
+ # named parameters in the api path
61
+ named_params = regex.named_captures.map { |nc| nc[0] } - [ 'version', 'format' ]
62
+ named_params.each { |named_param| path_params[named_param] = "" }
63
+ # route parameters declared via desc or appended to the api declaration
64
+ route_params = (options[:route_options][:params] || {})
65
+ path_params.merge!(route_params)
66
+ request_method = (method.to_s.upcase unless method == :any)
67
+ routes << Route.new(options[:route_options].clone.merge({
68
+ :prefix => settings[:root_prefix],
69
+ :version => settings[:version] ? settings[:version].join('|') : nil,
70
+ :namespace => namespace,
71
+ :method => request_method,
72
+ :path => prepared_path,
73
+ :params => path_params,
74
+ :compiled => path,
75
+ })
76
+ )
77
+ end
78
+ end
79
+ routes
80
+ end
81
+
82
+ def prepare_path(path)
83
+ parts = []
84
+ parts << settings[:root_prefix] if settings[:root_prefix]
85
+ parts << ':version' if settings[:version] && settings[:version_options][:using] == :path
86
+ parts << namespace.to_s if namespace
87
+ parts << path.to_s if path && '/' != path
88
+ Rack::Mount::Utils.normalize_path(parts.join('/') + '(.:format)')
89
+ end
90
+
91
+ def namespace
92
+ Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace]}.join('/'))
93
+ end
94
+
95
+ def compile_path(prepared_path, anchor = true, requirements = {})
96
+ endpoint_options = {}
97
+ endpoint_options[:version] = /#{settings[:version].join('|')}/ if settings[:version]
98
+ endpoint_options.merge!(requirements)
99
+ Rack::Mount::Strexp.compile(prepared_path, endpoint_options, %w( / . ? ), anchor)
100
+ end
101
+
102
+ def call(env)
103
+ dup.call!(env)
104
+ end
105
+
106
+ def call!(env)
107
+ env['api.endpoint'] = self
108
+ if options[:app]
109
+ options[:app].call(env)
110
+ else
111
+ builder = build_middleware
112
+ builder.run options[:app] || lambda{|env| self.run(env) }
113
+ builder.call(env)
114
+ end
115
+ end
116
+
117
+ # The parameters passed into the request as
118
+ # well as parsed from URL segments.
119
+ def params
120
+ @params ||= Hashie::Mash.new.
121
+ deep_merge(request.params).
122
+ deep_merge(env['rack.routing_args'] || {}).
123
+ deep_merge(self.body_params)
124
+ end
125
+
126
+ # Pull out request body params if the content type matches and we're on a POST or PUT
127
+ def body_params
128
+ if ['POST', 'PUT'].include?(request.request_method.to_s.upcase) && request.content_length.to_i > 0
129
+ return case env['CONTENT_TYPE']
130
+ when 'application/json'
131
+ MultiJson.decode(request.body.read)
132
+ when 'application/xml'
133
+ MultiXml.parse(request.body.read)
134
+ else
135
+ {}
136
+ end
137
+ end
138
+
139
+ {}
140
+ end
141
+
142
+ # The API version as specified in the URL.
143
+ def version; env['api.version'] end
144
+
145
+ # End the request and display an error to the
146
+ # end user with the specified message.
147
+ #
148
+ # @param message [String] The message to display.
149
+ # @param status [Integer] the HTTP Status Code. Defaults to 403.
150
+ def error!(message, status=403)
151
+ throw :error, :message => message, :status => status
152
+ end
153
+
154
+ # Redirect to a new url.
155
+ #
156
+ # @param url [String] The url to be redirect.
157
+ # @param options [Hash] The options used when redirect.
158
+ # :permanent, default true.
159
+ def redirect(url, options = {})
160
+ merged_options = {:permanent => false }.merge(options)
161
+ if merged_options[:permanent]
162
+ status 301
163
+ else
164
+ if env['HTTP_VERSION'] == 'HTTP/1.1' && request.request_method.to_s.upcase != "GET"
165
+ status 303
166
+ else
167
+ status 302
168
+ end
169
+ end
170
+ header "Location", url
171
+ body ""
172
+ end
173
+
174
+ # Set or retrieve the HTTP status code.
175
+ #
176
+ # @param status [Integer] The HTTP Status Code to return for this request.
177
+ def status(status = nil)
178
+ if status
179
+ @status = status
180
+ else
181
+ return @status if @status
182
+ case request.request_method.to_s.upcase
183
+ when 'POST'
184
+ 201
185
+ else
186
+ 200
187
+ end
188
+ end
189
+ end
190
+
191
+ # Set an individual header or retrieve
192
+ # all headers that have been set.
193
+ def header(key = nil, val = nil)
194
+ if key
195
+ val ? @header[key.to_s] = val : @header.delete(key.to_s)
196
+ else
197
+ @header
198
+ end
199
+ end
200
+
201
+ # Set response content-type
202
+ def content_type(val)
203
+ header('Content-Type', val)
204
+ end
205
+
206
+ # Set or get a cookie
207
+ #
208
+ # @example
209
+ # cookies[:mycookie] = 'mycookie val'
210
+ # cookies['mycookie-string'] = 'mycookie string val'
211
+ # cookies[:more] = { :value => '123', :expires => Time.at(0) }
212
+ # cookies.delete :more
213
+ #
214
+ def cookies
215
+ @cookies ||= Cookies.new
216
+ end
217
+
218
+ # Allows you to define the response body as something other than the
219
+ # return value.
220
+ #
221
+ # @example
222
+ # get '/body' do
223
+ # body "Body"
224
+ # "Not the Body"
225
+ # end
226
+ #
227
+ # GET /body # => "Body"
228
+ def body(value = nil)
229
+ if value
230
+ @body = value
231
+ else
232
+ @body
233
+ end
234
+ end
235
+
236
+ # Allows you to make use of Grape Entities by setting
237
+ # the response body to the serializable hash of the
238
+ # entity provided in the `:with` option. This has the
239
+ # added benefit of automatically passing along environment
240
+ # and version information to the serialization, making it
241
+ # very easy to do conditional exposures. See Entity docs
242
+ # for more info.
243
+ #
244
+ # @example
245
+ #
246
+ # get '/users/:id' do
247
+ # present User.find(params[:id]),
248
+ # :with => API::Entities::User,
249
+ # :admin => current_user.admin?
250
+ # end
251
+ def present(object, options = {})
252
+ entity_class = options.delete(:with)
253
+
254
+ object.class.ancestors.each do |potential|
255
+ entity_class ||= (settings[:representations] || {})[potential]
256
+ end
257
+
258
+ entity_class ||= object.class.const_get(:Entity) if object.class.const_defined?(:Entity)
259
+
260
+ root = options.delete(:root)
261
+
262
+ representation = if entity_class
263
+ embeds = {:env => env}
264
+ embeds[:version] = env['api.version'] if env['api.version']
265
+ entity_class.represent(object, embeds.merge(options))
266
+ else
267
+ object
268
+ end
269
+
270
+ representation = { root => representation } if root
271
+ body representation
272
+ end
273
+
274
+ # Returns route information for the current request.
275
+ #
276
+ # @example
277
+ #
278
+ # desc "Returns the route description."
279
+ # get '/' do
280
+ # route.route_description
281
+ # end
282
+ def route
283
+ env["rack.routing_args"][:route_info]
284
+ end
285
+
286
+ protected
287
+
288
+ def run(env)
289
+ @env = env
290
+ @header = {}
291
+ @request = Rack::Request.new(@env)
292
+
293
+ self.extend helpers
294
+ cookies.read(@request)
295
+
296
+ run_filters befores
297
+
298
+ Array(settings[:validations]).each do |validator|
299
+ validator.validate!(params)
300
+ end
301
+
302
+ response_text = instance_eval &self.block
303
+ run_filters afters
304
+ cookies.write(header)
305
+
306
+ [status, header, [body || response_text]]
307
+ end
308
+
309
+ def build_middleware
310
+ b = Rack::Builder.new
311
+
312
+ b.use Rack::Head
313
+ b.use Grape::Middleware::Error,
314
+ :default_status => settings[:default_error_status] || 403,
315
+ :rescue_all => settings[:rescue_all],
316
+ :rescued_errors => aggregate_setting(:rescued_errors),
317
+ :format => settings[:error_format] || :txt,
318
+ :rescue_options => settings[:rescue_options],
319
+ :rescue_handlers => merged_setting(:rescue_handlers)
320
+
321
+ b.use Rack::Auth::Basic, settings[:auth][:realm], &settings[:auth][:proc] if settings[:auth] && settings[:auth][:type] == :http_basic
322
+ b.use Rack::Auth::Digest::MD5, settings[:auth][:realm], settings[:auth][:opaque], &settings[:auth][:proc] if settings[:auth] && settings[:auth][:type] == :http_digest
323
+ b.use Grape::Middleware::Prefixer, :prefix => settings[:root_prefix] if settings[:root_prefix]
324
+
325
+ if settings[:version]
326
+ b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]), {
327
+ :versions => settings[:version],
328
+ :version_options => settings[:version_options]
329
+ }
330
+ end
331
+
332
+ b.use Grape::Middleware::Formatter,
333
+ :format => settings[:format],
334
+ :default_format => settings[:default_format] || :txt,
335
+ :content_types => settings[:content_types]
336
+
337
+ aggregate_setting(:middleware).each do |m|
338
+ m = m.dup
339
+ block = m.pop if m.last.is_a?(Proc)
340
+ if block
341
+ b.use *m, &block
342
+ else
343
+ b.use *m
344
+ end
345
+ end
346
+
347
+ b
348
+ end
349
+
350
+ def helpers
351
+ m = Module.new
352
+ settings.stack.each{|frame| m.send :include, frame[:helpers] if frame[:helpers]}
353
+ m
354
+ end
355
+
356
+ def aggregate_setting(key)
357
+ settings.stack.inject([]) do |aggregate, frame|
358
+ aggregate += (frame[key] || [])
359
+ end
360
+ end
361
+
362
+ def merged_setting(key)
363
+ settings.stack.inject({}) do |merged, frame|
364
+ merged.merge(frame[key] || {})
365
+ end
366
+ end
367
+
368
+ def run_filters(filters)
369
+ (filters || []).each do |filter|
370
+ instance_eval &filter
371
+ end
372
+ end
373
+
374
+ def befores; aggregate_setting(:befores) end
375
+ def afters; aggregate_setting(:afters) end
376
+ end
377
+ end