padrino-core 0.8.5 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -55,7 +55,7 @@ Please help me brainstorm and fork the project if you have any ideas to contribu
55
55
 
56
56
  To install the padrino framework, simply grab the latest version from gemcutter:
57
57
 
58
- $ sudo gem install padrino --source http://gemcutter.org
58
+ $ sudo gem install padrino
59
59
 
60
60
  This will install the necessary padrino gems to get you started.
61
61
  Now you are ready to use this gem to enhance your sinatra projects or to create new Padrino applications.
@@ -301,21 +301,6 @@ within your application:
301
301
  This will instruct Padrino to autoload these files (and reload them when changes are detected). By default, the load path
302
302
  contains certain paths known to contain important files such as controllers, mailers, models, urls, and helpers.
303
303
 
304
- === Initializers
305
-
306
- Padrino also has support for 'initializers' which are important setup steps or configuration within an application
307
- that should occur during the bootup process. To construct initializers, simply add a file to the <tt>config/initializers<tt>
308
- directory following this convention:
309
-
310
- # config/initializers/example.rb
311
- module ExampleInitializer
312
- def self.registered(app)
313
- # Manipulate 'app' here to register components or adjust configuration
314
- app.set :environment, :production # just an example configuration change
315
- app.use Hassle # or even enable middleware
316
- end
317
- end
318
-
319
304
  Initializers are automatically required and 'registered' during the application startup process. Note that
320
305
  the name of the module must be the name of the file appended with 'Initializer' (i.e sample.rb => SampleInitializer)
321
306
 
data/Rakefile CHANGED
@@ -17,8 +17,8 @@ begin
17
17
  gem.add_runtime_dependency "i18n", ">= 0.3.2"
18
18
  gem.add_runtime_dependency "usher", ">= 0.6.2"
19
19
  gem.add_runtime_dependency "thor", ">= 0.13.0"
20
- gem.add_runtime_dependency "bundler", "= 0.9.5"
21
- gem.add_runtime_dependency "activesupport", ">= 2.3.5"
20
+ gem.add_runtime_dependency "bundler", "= 0.9.7"
21
+ gem.add_runtime_dependency "activesupport", "= 2.3.5"
22
22
  gem.add_development_dependency "shoulda", ">= 2.10.3"
23
23
  gem.add_development_dependency "mocha", ">= 0.9.7"
24
24
  gem.add_development_dependency "rack-test", ">= 0.5.0"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.5
1
+ 0.9.0
data/lib/padrino-core.rb CHANGED
@@ -1,6 +1,6 @@
1
- require 'usher'
2
1
  require 'sinatra/base'
3
2
 
3
+ Dir[File.dirname(__FILE__) + '/padrino-core/application/*.rb'].each {|file| require file }
4
4
  Dir[File.dirname(__FILE__) + '/padrino-core/*.rb'].each {|file| require file }
5
5
 
6
6
  # Defines our PADRINO_ENV
@@ -1,20 +1,24 @@
1
1
  module Padrino
2
2
  class ApplicationSetupError < RuntimeError #:nodoc:
3
3
  end
4
+
4
5
  ##
5
6
  # Subclasses of this become independent Padrino applications (stemming from Sinatra::Application)
6
7
  # These subclassed applications can be easily mounted into other Padrino applications as well.
7
- #
8
+ #
8
9
  class Application < Sinatra::Application
10
+ register Padrino::Routing # Support for advanced routing, controllers, url_for
11
+ register Padrino::Rendering # Support for enhanced rendering with template detection
9
12
 
10
13
  class << self
14
+
11
15
  def inherited(subclass) #:nodoc:
12
16
  CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
13
17
  subclass.default_configuration!
14
18
  Padrino.set_load_paths File.join(subclass.root, "/models")
15
19
  Padrino.require_dependencies File.join(subclass.root, "/models.rb")
16
20
  Padrino.require_dependencies File.join(subclass.root, "/models/**/*.rb")
17
- super(subclass) # Loading the subclass
21
+ super(subclass) # Loading the subclass inherited method
18
22
  subclass.default_filters!
19
23
  subclass.default_routes!
20
24
  subclass.default_errors!
@@ -25,95 +29,21 @@ module Padrino
25
29
  # This is used because putting the configuration into inherited doesn't
26
30
  # take into account overwritten app settings inside subclassed definitions
27
31
  # Only performs the setup first time application is initialized.
28
- #
32
+ #
29
33
  def new(*args, &bk)
30
34
  setup_application!
31
35
  super(*args, &bk)
32
36
  end
33
37
 
34
38
  ##
35
- # Method for organize in a better way our routes like:
36
- #
37
- # controller :admin do
38
- # get :index do; ...; end
39
- # get :show, :with => :id do; ...; end
40
- # end
41
- #
42
- # Now you can call your actions with:
43
- #
44
- # url(:admin_index) # => "/admin"
45
- # url(:admin_show, :id => 1) # "/admin/show/1"
46
- #
47
- # You can instead using named routes follow the sinatra way like:
48
- #
49
- # controller "/admin" do
50
- # get "/index" do; ...; end
51
- # get "/show/:id" do; ...; end
52
- # end
53
- #
54
- # And you can call directly these urls:
55
- #
56
- # # => "/admin"
57
- # # => "/admin/show/1"
58
- #
59
- def controller(*extensions, &block)
60
- if block_given?
61
- @_controller, original = extensions, @_controller
62
- instance_eval(&block)
63
- @_controller = original
64
- else
65
- include(*extensions) if extensions.any?
66
- end
67
- end
68
- alias :controllers :controller
69
-
70
- ##
71
- # Usher router, for fatures and configurations see: http://github.com/joshbuddy/usher
72
- #
73
- # ==== Examples
74
- #
75
- # router.add_route('/greedy/{!:greed,.*}')
76
- # router.recognize_path('/simple')
77
- #
78
- def router
79
- @router ||= Usher.new(:request_methods => [:request_method, :host, :port, :scheme],
80
- :ignore_trailing_delimiters => true,
81
- :generator => Usher::Util::Generators::URL.new)
82
- block_given? ? yield(@router) : @router
83
- end
84
- alias :urls :router
85
-
86
- ##
87
- # Instance method for url generation like:
88
- #
89
- # ==== Examples
90
- #
91
- # url(:show, :id => 1)
92
- # url(:show, :name => :test)
93
- # url("/show/:id/:name", :id => 1, :name => foo)
94
- #
95
- def url(name, *params)
96
- params.map! do |param|
97
- if param.is_a?(Hash)
98
- param[:format] = param[:format].to_s if param.has_key?(:format)
99
- param.each { |k,v| param[k] = v.to_param if v.respond_to?(:to_param) }
100
- end
101
- end
102
- url = router.generator.generate(name, *params)
103
- uri_root != "/" ? uri_root + url : url
104
- end
105
- alias :url_for :url
106
-
107
- ##
108
- # With this method we can use layout like rails do or if a block given like sinatra
109
- # By default we look in your/app/views/layouts/application.(haml|erb|etc)
110
- #
111
- # If you define:
112
- #
113
- # layout :custom
114
- #
115
- # Padrino look for your/app/views/layouts/custom.(haml|erb|etc)
116
- #
39
+ # Use layout like rails does or if a block given then like sinatra.
40
+ # If used without a block, sets the current layout for the route.
41
+ #
42
+ # By default, searches in your +app/views/layouts/application.(haml|erb|xxx)+
43
+ #
44
+ # If you define +layout :custom+ then searches for your layouts in
45
+ # +app/views/layouts/custom.(haml|erb|xxx)+
46
+ #
117
47
  def layout(name=:layout, &block)
118
48
  return super(name, &block) if block_given?
119
49
  @_layout = name
@@ -121,13 +51,14 @@ module Padrino
121
51
 
122
52
  ##
123
53
  # Reloads the application files from all defined load paths
124
- #
125
- # This method is used from our Padrino Reloader.
126
- #
54
+ #
55
+ # This method is used from our Padrino Reloader during development mode
56
+ # in order to reload the source files.
57
+ #
127
58
  # ==== Examples
128
- #
59
+ #
129
60
  # MyApp.reload!
130
- #
61
+ #
131
62
  def reload!
132
63
  reset_routes! # remove all existing user-defined application routes
133
64
  Padrino.load_dependency(self.app_file) # reload the app file
@@ -136,11 +67,11 @@ module Padrino
136
67
 
137
68
  ##
138
69
  # Resets application routes to only routes not defined by the user
139
- #
70
+ #
140
71
  # ==== Examples
141
- #
72
+ #
142
73
  # MyApp.reset_routes!
143
- #
74
+ #
144
75
  def reset_routes!
145
76
  router.reset!
146
77
  default_routes!
@@ -149,11 +80,11 @@ module Padrino
149
80
  ##
150
81
  # Setup the application by registering initializers, load paths and logger
151
82
  # Invoked automatically when an application is first instantiated
152
- #
83
+ #
153
84
  def setup_application!
154
85
  return if @_configured
155
- self.register_framework_extensions
156
86
  self.calculate_paths
87
+ self.register_framework_extensions
157
88
  self.register_initializers
158
89
  self.require_load_paths
159
90
  self.disable :logging # We need do that as default because Sinatra use commonlogger.
@@ -163,9 +94,10 @@ module Padrino
163
94
  end
164
95
 
165
96
  protected
97
+
166
98
  ##
167
99
  # Defines default settings for Padrino application
168
- #
100
+ #
169
101
  def default_configuration!
170
102
  # Overwriting Sinatra defaults
171
103
  set :app_file, caller_files.first || $0 # Assume app file is first caller
@@ -183,7 +115,6 @@ module Padrino
183
115
  set :authentication, false
184
116
  # Padrino locale
185
117
  set :locale_path, Proc.new { Dir[File.join(self.root, "/locale/**/*.{rb,yml}")] }
186
- set :auto_locale, false
187
118
  # Plugin specific
188
119
  set :padrino_mailer, defined?(Padrino::Mailer)
189
120
  set :padrino_helpers, defined?(Padrino::Helpers)
@@ -191,7 +122,7 @@ module Padrino
191
122
 
192
123
  ##
193
124
  # We need to add almost __sinatra__ images.
194
- #
125
+ #
195
126
  def default_routes!
196
127
  # images resources
197
128
  get "/__sinatra__/:image.png" do
@@ -202,7 +133,7 @@ module Padrino
202
133
 
203
134
  ##
204
135
  # This filter it's used for know the format of the request, and automatically set the content type.
205
- #
136
+ #
206
137
  def default_filters!
207
138
  before do
208
139
  request.path_info =~ /\.([^\.\/]+)$/
@@ -213,7 +144,7 @@ module Padrino
213
144
 
214
145
  ##
215
146
  # This log errors for production environments
216
- #
147
+ #
217
148
  def default_errors!
218
149
  configure :production do
219
150
  error ::Exception do
@@ -229,7 +160,7 @@ module Padrino
229
160
  ##
230
161
  # Calculates any required paths after app_file and root have been properly configured
231
162
  # Executes as part of the setup_application! method
232
- #
163
+ #
233
164
  def calculate_paths
234
165
  raise ApplicationSetupError.new("Please define 'app_file' option for #{self.name} app!") unless self.app_file
235
166
  set :views, find_view_path if find_view_path
@@ -237,19 +168,17 @@ module Padrino
237
168
  end
238
169
 
239
170
  ##
240
- # Requires the middleware and initializer modules to configure components
241
- #
171
+ # Requires the Padrino middleware
172
+ #
242
173
  def register_initializers
243
174
  use Padrino::Logger::Rack
244
175
  use Padrino::Reloader::Rack if reload?
245
176
  use Rack::Flash if flash?
246
- @initializer_path ||= Padrino.root + '/config/initializers/*.rb'
247
- Dir[@initializer_path].each { |file| register_initializer(file) }
248
177
  end
249
178
 
250
179
  ##
251
180
  # Registers all desired padrino extension helpers
252
- #
181
+ #
253
182
  def register_framework_extensions
254
183
  register Padrino::Mailer if padrino_mailer?
255
184
  register Padrino::Helpers if padrino_helpers?
@@ -258,288 +187,25 @@ module Padrino
258
187
 
259
188
  ##
260
189
  # Returns the load_paths for the application (relative to the application root)
261
- #
190
+ #
262
191
  def load_paths
263
192
  @load_paths ||= ["urls.rb", "config/urls.rb", "mailers/*.rb", "controllers/**/*.rb", "controllers.rb", "helpers/*.rb"]
264
193
  end
265
194
 
266
195
  ##
267
196
  # Requires all files within the application load paths
268
- #
197
+ #
269
198
  def require_load_paths
270
199
  load_paths.each { |path| Padrino.require_dependencies(File.join(self.root, path)) }
271
200
  end
272
201
 
273
202
  ##
274
203
  # Returns the path to the views directory from root by returning the first that is found
275
- #
204
+ #
276
205
  def find_view_path
277
206
  @view_paths = ["views"].collect { |path| File.join(self.root, path) }
278
207
  @view_paths.find { |path| Dir[File.join(path, '/**/*')].any? }
279
208
  end
280
-
281
- ##
282
- # Registers an initializer with the application
283
- # register_initializer('/path/to/initializer')
284
- #
285
- def register_initializer(file_path)
286
- Padrino.require_dependencies(file_path)
287
- file_class = File.basename(file_path, '.rb').camelize
288
- register "#{file_class}Initializer".constantize
289
- rescue NameError => e
290
- logger.error "The module '#{file_class}Initializer' (#{file_path}) didn't loaded properly!"
291
- logger.error " Initializer error was '#{e.message}'"
292
- end
293
-
294
- private
295
- ##
296
- # Rewrite default because now routes can be:
297
- #
298
- # ==== Examples
299
- #
300
- # get :index # => "/"
301
- # get :index, :map => "/" # => "/"
302
- # get :show, :map => "/show-me" # => "/show-me"
303
- # get "/foo/bar" # => "/show"
304
- # get :show, :with => :id # => "/show/:id"
305
- # get :show, :with => [:id, :name] # => "/show/:id/:name"
306
- # get :list, :respond_to => :js # => "/list.{:format,js)"
307
- # get :list, :respond_to => :any # => "/list(.:format)"
308
- # get :list, :respond_to => [:js, :json] # => "/list.{!format,js|json}"
309
- # gen :list, :respond_to => [:html, :js, :json] # => "/list(.{!format,js|json})"
310
- #
311
- def route(verb, path, options={}, &block)
312
-
313
- # We dup options so we can build HEAD request correctly
314
- options = options.dup
315
-
316
- # We need check if path is a symbol, if that it's a named route
317
- map = options.delete(:map)
318
-
319
- if path.kind_of?(Symbol)
320
- name = path # The route name
321
- path = map || "/#{path}" # The route path
322
- end
323
-
324
- if path.kind_of?(String)
325
- # Little reformats
326
- path.sub!(/\/index$/, "") # If the route end with /index we remove them
327
- path = (uri_root == "/" ? "/" : "(/)") if path.blank? # Add a trailing delimiter if empty
328
-
329
- # Now we need to parse our with params
330
- if params = options.delete(:with)
331
- path += "/" unless path =~ /\/$/
332
- path += Array(params).collect(&:inspect).join("/")
333
- end
334
-
335
- # Now we need to parse our respond_to
336
- if format = options.delete(:respond_to)
337
- path += case format
338
- when :any then "(.:format)"
339
- when Array then
340
- formats = format.dup # Prevent changes to HEAD verb
341
- container = formats.delete(:html) ? "(%s)" : "%s"
342
- match = ".{:format," + formats.collect { |f| "#{f}$" }.join("|") + "}"
343
- container % match
344
- else ".{:format,#{format}}"
345
- end
346
- end
347
-
348
- # Build our controller
349
- controller = Array(@_controller).collect(&:to_s)
350
-
351
- unless controller.empty?
352
- # Now we need to add our controller path only if not mapped directly
353
- if map.blank?
354
- controller_path = controller.join("/")
355
- path = controller_path + path
356
- end
357
- # Here we build the correct name route
358
- if name
359
- controller_name = controller.join("_")
360
- name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
361
- end
362
- end
363
-
364
- # We need to have a path that start with / in some circumstances and that don't end with /
365
- if path != "(/)" && path != "/"
366
- path = "/" + path if path !~ /^\//
367
- path.sub!(/\/$/, '')
368
- end
369
- end
370
-
371
- # Standard Sinatra requirements
372
- options[:conditions] ||= {}
373
- options[:conditions][:request_method] = verb
374
- options[:conditions][:host] = options.delete(:host) if options.key?(:host)
375
-
376
- # Because of self.options.host
377
- host_name(options.delete(:host)) if options.key?(:host)
378
-
379
- # Sinatra defaults
380
- define_method "#{verb} #{path}", &block
381
- unbound_method = instance_method("#{verb} #{path}")
382
- block =
383
- if block.arity != 0
384
- proc { unbound_method.bind(self).call(*@block_params) }
385
- else
386
- proc { unbound_method.bind(self).call }
387
- end
388
-
389
- invoke_hook(:route_added, verb, path, block)
390
-
391
- route = router.add_route(path, options).to(block)
392
- route.name(name) if name
393
- route
394
- end
395
- end # self
396
-
397
- ##
398
- # Return the request format, this is useful when we need to respond to a given content_type like:
399
- #
400
- # ==== Examples
401
- #
402
- # get :index, :respond_to => :any do
403
- # case content_type
404
- # when :js then ...
405
- # when :json then ...
406
- # when :html then ...
407
- # end
408
- # end
409
- #
410
- def content_type(type=nil, params={})
411
- type.nil? ? @_content_type : super(type, params)
412
- end
413
-
414
- ##
415
- # Instance method for url generation like:
416
- #
417
- # ==== Examples
418
- #
419
- # url(:show, :id => 1)
420
- # url(:show, :name => :test)
421
- # url("/show/:id/:name", :id => 1, :name => foo)
422
- #
423
- def url(name, *params)
424
- self.class.url(name, *params)
425
- end
426
- alias :url_for :url
427
-
428
- ##
429
- # This is mostly just a helper so request.path_info isn't changed when
430
- # serving files from the public directory
431
- #
432
- def static_file?(path_info)
433
- return if (public_dir = options.public).nil?
434
- public_dir = File.expand_path(public_dir)
435
-
436
- path = File.expand_path(public_dir + unescape(path_info))
437
- return if path[0, public_dir.length] != public_dir
438
- return unless File.file?(path)
439
- return path
440
- end
441
-
442
- private
443
-
444
- ##
445
- # Method for deliver static files, Sinatra 0.10.x or 1.0.x have this method
446
- # but for now we use this (because we need a compatibility with 0.9.x) and also
447
- # because we just have +static_file?+ method.
448
- #
449
- def static!
450
- if path = static_file?(request.path_info)
451
- send_file(path, :disposition => nil)
452
- end
453
- end
454
-
455
- ##
456
- # Compatibility with usher
457
- #
458
- def route!(base=self.class, pass_block=nil)
459
- # TODO: remove this when sinatra 1.0 will be released
460
- if Sinatra::VERSION =~ /^0\.9/
461
- # enable nested params in Rack < 1.0; allow indifferent access
462
- @params = if Rack::Utils.respond_to?(:parse_nested_query)
463
- indifferent_params(@request.params)
464
- else
465
- nested_params(@request.params)
466
- end
467
- # deliver static files
468
- static! if options.static? && (request.get? || request.head?)
469
- # perform before filters
470
- self.class.filters.each { |block| instance_eval(&block) }
471
- end
472
-
473
- # Usher
474
- if self.class.router and match = self.class.router.recognize(@request, @request.path_info)
475
- @block_params = match.params.map{|p| p.last}
476
- @params = @params ? @params.merge(match.params_as_hash) : match.params_as_hash
477
- pass_block = catch(:pass) do
478
- route_eval(&match.destination)
479
- end
480
- elsif base.superclass.respond_to?(:routes)
481
- route! base.superclass
482
- else
483
- route_missing
484
- end
485
- end
486
-
487
- ##
488
- # When we set :auto_locale, true then if we use param locale like:
489
- #
490
- # ==== Examples
491
- #
492
- # get "/:locale/some/foo" do; ...; end
493
- #
494
- # we automatically set the I18n locale to params[:locale]
495
- #
496
- def route_eval(&block)
497
- if options.auto_locale
498
- if params[:locale]
499
- I18n.locale = params[:locale].to_sym rescue options.locale
500
- end
501
- end
502
- super(&block)
503
- end
504
-
505
- ##
506
- # Hijacking the sinatra render for do three thing:
507
- #
508
- # * Use layout like rails do
509
- # * Use render 'path/to/my/template' (without symbols)
510
- # * Use render 'path/to/my/template' (with auto enegine lookup)
511
- #
512
- def render(engine, data=nil, options={}, locals={}, &block)
513
- # TODO: remove these @template_cache.respond_to?(:clear) when sinatra 1.0 will be released
514
- @template_cache.clear if Padrino.env != :production && @template_cache && @template_cache.respond_to?(:clear)
515
- # If engine is an hash we convert to json
516
- return engine.to_json if engine.is_a?(Hash)
517
- # If an engine is a string probably is a path so we try to resolve them
518
- if data.nil?
519
- data = engine.to_sym
520
- engine = resolve_template_engine(engine)
521
- end
522
- # Use layout as rails do
523
- if (options[:layout].nil? || options[:layout] == true) && !self.class.templates.has_key?(:layout)
524
- layout = self.class.instance_variable_defined?(:@_layout) ? self.class.instance_variable_get(:@_layout) : :application
525
- if layout
526
- # We look first for views/layout_name.ext then then for views/layouts/layout_name.ext
527
- options[:layout] = Dir["#{self.options.views}/#{layout}.*"].present? ? layout.to_sym : File.join('layouts', layout.to_s).to_sym
528
- logger.debug "Rendering layout #{options[:layout]}"
529
- end
530
- end
531
- super(engine, data, options, locals, &block)
532
- end
533
-
534
- ##
535
- # Returns the template engine (i.e haml) to use for a given template_path
536
- # resolve_template_engine('users/new') => :haml
537
- #
538
- def resolve_template_engine(template_path)
539
- resolved_template_path = File.join(self.options.views, template_path.to_s + ".*")
540
- template_file = Dir[resolved_template_path].first
541
- raise "Template path '#{template_path}' could not be located in views!" unless template_file
542
- template_engine = File.extname(template_file)[1..-1].to_sym
543
- end
209
+ end # Class Methods
544
210
  end # Application
545
- end # Padrino
211
+ end # Padrino
@@ -45,8 +45,7 @@ module Padrino
45
45
  app_obj.set :app_name, app_data.name
46
46
  app_obj.set :app_file, app_data.app_file unless ::File.exist?(app_obj.app_file)
47
47
  app_obj.set :root, app_data.app_root unless app_data.app_root.blank?
48
- # We need to initialize here the app.
49
- app_obj.setup_application!
48
+ app_obj.setup_application! # We need to initialize here the app.
50
49
  run app_obj
51
50
  end
52
51
  end
@@ -0,0 +1,48 @@
1
+ module Padrino
2
+ module Rendering
3
+ def self.registered(app)
4
+ app.send(:include, Padrino::Rendering)
5
+ end
6
+
7
+ private
8
+ ##
9
+ # Hijacking the sinatra render for do three thing:
10
+ #
11
+ # * Use layout like rails do
12
+ # * Use render 'path/to/my/template' (without symbols)
13
+ # * Use render 'path/to/my/template' (with auto enegine lookup)
14
+ #
15
+ def render(engine, data=nil, options={}, locals={}, &block)
16
+ # TODO: remove these @template_cache.respond_to?(:clear) when sinatra 1.0 will be released
17
+ @template_cache.clear if Padrino.env != :production && @template_cache && @template_cache.respond_to?(:clear)
18
+ # If engine is an hash we convert to json
19
+ return engine.to_json if engine.is_a?(Hash)
20
+ # If an engine is a string probably is a path so we try to resolve them
21
+ if data.nil?
22
+ data = engine.to_sym
23
+ engine = resolve_template_engine(engine)
24
+ end
25
+ # Use layout as rails do
26
+ if (options[:layout].nil? || options[:layout] == true) && !self.class.templates.has_key?(:layout)
27
+ layout = self.class.instance_variable_defined?(:@_layout) ? self.class.instance_variable_get(:@_layout) : :application
28
+ if layout
29
+ # We look first for views/layout_name.ext then then for views/layouts/layout_name.ext
30
+ options[:layout] = Dir["#{self.options.views}/#{layout}.*"].present? ? layout.to_sym : File.join('layouts', layout.to_s).to_sym
31
+ logger.debug "Rendering layout #{options[:layout]}"
32
+ end
33
+ end
34
+ super(engine, data, options, locals, &block)
35
+ end
36
+
37
+ ##
38
+ # Returns the template engine (i.e haml) to use for a given template_path
39
+ # resolve_template_engine('users/new') => :haml
40
+ #
41
+ def resolve_template_engine(template_path)
42
+ resolved_template_path = File.join(self.options.views, template_path.to_s + ".*")
43
+ template_file = Dir[resolved_template_path].first
44
+ raise "Template path '#{template_path}' could not be located in views!" unless template_file
45
+ template_engine = File.extname(template_file)[1..-1].to_sym
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,313 @@
1
+ require 'usher' unless defined?(Usher)
2
+ require 'padrino-core/support_lite' unless String.method_defined?(:blank!)
3
+
4
+ module Padrino
5
+ module Routing
6
+ def self.registered(app)
7
+ app.send(:include, Padrino::Routing)
8
+ end
9
+
10
+ def self.included(base)
11
+ base.extend Padrino::Routing::ClassMethods
12
+ end
13
+
14
+ ##
15
+ # Compatibility with usher
16
+ #
17
+ def route!(base=self.class, pass_block=nil)
18
+ # TODO: remove this when sinatra 1.0 will be released
19
+ if Sinatra::VERSION =~ /^0\.9/
20
+ # enable nested params in Rack < 1.0; allow indifferent access
21
+ can_parse_nested = Rack::Utils.respond_to?(:parse_nested_query)
22
+ @params = can_parse_nested ? indifferent_params(@request.params) : nested_params(@request.params)
23
+ # deliver static files
24
+ static! if options.static? && (request.get? || request.head?)
25
+ # perform before filters
26
+ self.class.filters.each { |block| instance_eval(&block) }
27
+ end # for sinatra = 0.9
28
+
29
+ # Usher
30
+ if self.class.router and match = self.class.router.recognize(@request, @request.path_info)
31
+ @block_params = match.params.map { |p| p.last }
32
+ @params = @params ? @params.merge(match.params_as_hash) : match.params_as_hash
33
+ pass_block = catch(:pass) do
34
+ route_eval(&match.destination)
35
+ end
36
+ elsif base.superclass.respond_to?(:routes)
37
+ route! base.superclass
38
+ else
39
+ route_missing
40
+ end
41
+ end
42
+
43
+ ##
44
+ # Instance method for url generation like:
45
+ #
46
+ # ==== Examples
47
+ #
48
+ # url(:show, :id => 1)
49
+ # url(:show, :name => :test)
50
+ # url("/show/:id/:name", :id => 1, :name => foo)
51
+ #
52
+ def url(*names)
53
+ self.class.url(*names)
54
+ end
55
+ alias :url_for :url
56
+
57
+ ##
58
+ # This is mostly just a helper so request.path_info isn't changed when
59
+ # serving files from the public directory
60
+ #
61
+ def static_file?(path_info)
62
+ return if (public_dir = options.public).nil?
63
+ public_dir = File.expand_path(public_dir)
64
+
65
+ path = File.expand_path(public_dir + unescape(path_info))
66
+ return if path[0, public_dir.length] != public_dir
67
+ return unless File.file?(path)
68
+ return path
69
+ end
70
+
71
+ ##
72
+ # Return the request format, this is useful when we need to respond to a given content_type like:
73
+ #
74
+ # ==== Examples
75
+ #
76
+ # get :index, :respond_to => :any do
77
+ # case content_type
78
+ # when :js then ...
79
+ # when :json then ...
80
+ # when :html then ...
81
+ # end
82
+ # end
83
+ #
84
+ def content_type(type=nil, params={})
85
+ type.nil? ? @_content_type : super(type, params)
86
+ end
87
+
88
+ ##
89
+ # Method for deliver static files, Sinatra 0.10.x or 1.0.x have this method
90
+ # but for now we use this (because we need a compatibility with 0.9.x) and also
91
+ # because we just have +static_file?+ method.
92
+ #
93
+ def static!
94
+ if path = static_file?(request.path_info)
95
+ send_file(path, :disposition => nil)
96
+ end
97
+ end
98
+
99
+ module ClassMethods
100
+ ##
101
+ # Method for organize in a better way our routes like:
102
+ #
103
+ # controller :admin do
104
+ # get :index do; ...; end
105
+ # get :show, :with => :id do; ...; end
106
+ # end
107
+ #
108
+ # Now you can call your actions with:
109
+ #
110
+ # url(:admin_index) # => "/admin"
111
+ # url(:admin_show, :id => 1) # "/admin/show/1"
112
+ #
113
+ # You can instead using named routes follow the sinatra way like:
114
+ #
115
+ # controller "/admin" do
116
+ # get "/index" do; ...; end
117
+ # get "/show/:id" do; ...; end
118
+ # end
119
+ #
120
+ # And you can call directly these urls:
121
+ #
122
+ # # => "/admin"
123
+ # # => "/admin/show/1"
124
+ #
125
+ def controller(*extensions, &block)
126
+ if block_given?
127
+ options = extensions.extract_options!
128
+ @_controller, original_controller = extensions, @_controller
129
+ @_parents, original_parent = options[:parent], @_parents
130
+ instance_eval(&block)
131
+ @_controller, @_parents = original_controller, original_parent
132
+ else
133
+ include(*extensions) if extensions.any?
134
+ end
135
+ end
136
+ alias :controllers :controller
137
+
138
+ ##
139
+ # Usher router, for fatures and configurations see: http://github.com/joshbuddy/usher
140
+ #
141
+ # ==== Examples
142
+ #
143
+ # router.add_route('/greedy/{!:greed,.*}')
144
+ # router.recognize_path('/simple')
145
+ #
146
+ def router
147
+ @router ||= Usher.new(:request_methods => [:request_method, :host, :port, :scheme],
148
+ :ignore_trailing_delimiters => true,
149
+ :generator => Usher::Util::Generators::URL.new)
150
+ block_given? ? yield(@router) : @router
151
+ end
152
+ alias :urls :router
153
+
154
+ ##
155
+ # Instance method for url generation like:
156
+ #
157
+ # ==== Examples
158
+ #
159
+ # url(:show, :id => 1)
160
+ # url(:show, :name => :test)
161
+ # url("/show/:id/:name", :id => 1, :name => foo)
162
+ #
163
+ def url(*names)
164
+ params = names.extract_options! # parameters is hash at end
165
+ name = names.join("_").to_sym # route name is concatenated with underscores
166
+ if params.is_a?(Hash)
167
+ params[:format] = params[:format].to_s if params.has_key?(:format)
168
+ params.each { |k,v| params[k] = v.to_param if v.respond_to?(:to_param) }
169
+ end
170
+ url = router.generator.generate(name, params)
171
+ url = uri_root + url if defined?(uri_root) && uri_root != "/"
172
+ url
173
+ end
174
+ alias :url_for :url
175
+
176
+ private
177
+
178
+ ##
179
+ # Rewrite default because now routes can be:
180
+ #
181
+ # ==== Examples
182
+ #
183
+ # get :index # => "/"
184
+ # get :index, :map => "/" # => "/"
185
+ # get :show, :map => "/show-me" # => "/show-me"
186
+ # get "/foo/bar" # => "/show"
187
+ # get :index, :parent => :user # => "/user/:user_id/index"
188
+ # get :show, :with => :id, :parent => :user # => "/user/:user_id/show/:id"
189
+ # get :show, :with => :id # => "/show/:id"
190
+ # get :show, :with => [:id, :name] # => "/show/:id/:name"
191
+ # get :list, :respond_to => :js # => "/list.{:format,js)"
192
+ # get :list, :respond_to => :any # => "/list(.:format)"
193
+ # get :list, :respond_to => [:js, :json] # => "/list.{!format,js|json}"
194
+ # get :list, :respond_to => [:html, :js, :json] # => "/list(.{!format,js|json})"
195
+ #
196
+ def route(verb, path, options={}, &block)
197
+ # We dup options so we can build HEAD request correctly
198
+ options = options.dup
199
+ # We need check if path is a symbol, if that it's a named route
200
+ map = options.delete(:map)
201
+
202
+ if path.kind_of?(Symbol) # path i.e :index or :show
203
+ name = path # The route name
204
+ path = map || path.to_s # The route path
205
+ end
206
+
207
+ if path.kind_of?(String) # path i.e "/index" or "/show"
208
+ # Now we need to parse our 'with' params
209
+ if with_params = options.delete(:with)
210
+ path = process_path_for_with_params(path, with_params)
211
+ end
212
+
213
+ # Now we need to parse our respond_to
214
+ if format_params = options.delete(:respond_to)
215
+ path = process_path_for_respond_to(path, format_params)
216
+ end
217
+
218
+ # Build our controller
219
+ controller = Array(@_controller).collect(&:to_s)
220
+
221
+ unless controller.empty?
222
+ # Now we need to add our controller path only if not mapped directly
223
+ if map.blank?
224
+ controller_path = controller.join("/")
225
+ path = File.join(controller_path, path)
226
+ end
227
+ # Here we build the correct name route
228
+ if name
229
+ controller_name = controller.join("_")
230
+ name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
231
+ end
232
+ end
233
+
234
+ # Now we need to parse our 'parent' params and parent scope
235
+ if parent_params = options.delete(:parent) || @_parents
236
+ parent_params = Array(@_parents) + Array(parent_params)
237
+ path = process_path_for_parent_params(path, parent_params)
238
+ end
239
+
240
+ # Little reformats
241
+ path.sub!(%r{\bindex$}, "") # If the route end with /index we remove them
242
+ path = (uri_root == "/" ? "/" : "(/)") if path.blank? # Add a trailing delimiter if path is empty
243
+
244
+ # We need to have a path that start with / in some circumstances and that don't end with /
245
+ if path != "(/)" && path != "/"
246
+ path = "/" + path unless path =~ %r{^/}
247
+ path.sub!(%r{/$}, '')
248
+ end
249
+
250
+ # We need to fix some differences between usher and sintra router
251
+ path.sub!(%r{/\?$}, '(/)') # '/foo/?' => '/foo(/)'
252
+ end
253
+
254
+ # Standard Sinatra requirements
255
+ options[:conditions] ||= {}
256
+ options[:conditions][:request_method] = verb
257
+ options[:conditions][:host] = options.delete(:host) if options.key?(:host)
258
+
259
+ # Because of self.options.host
260
+ host_name(options.delete(:host)) if options.key?(:host)
261
+
262
+ # Sinatra defaults
263
+ define_method "#{verb} #{path}", &block
264
+ unbound_method = instance_method("#{verb} #{path}")
265
+ block =
266
+ if block.arity != 0
267
+ proc { unbound_method.bind(self).call(*@block_params) }
268
+ else
269
+ proc { unbound_method.bind(self).call }
270
+ end
271
+
272
+ invoke_hook(:route_added, verb, path, block)
273
+ route = router.add_route(path, options).to(block)
274
+ route.name(name) if name
275
+ route
276
+ end
277
+
278
+ ##
279
+ # Processes the existing path and appends the 'with' parameters onto the route
280
+ # Used for calculating path in route method
281
+ #
282
+ def process_path_for_with_params(path, with_params)
283
+ File.join(path, Array(with_params).collect(&:inspect).join("/"))
284
+ end
285
+
286
+ ##
287
+ # Processes the existing path and prepends the 'parent' parameters onto the route
288
+ # Used for calculating path in route method
289
+ #
290
+ def process_path_for_parent_params(path, parent_params)
291
+ parent_prefix = parent_params.uniq.collect { |param| "#{param}/:#{param}_id" }.join("/")
292
+ File.join(parent_prefix, path)
293
+ end
294
+
295
+ ##
296
+ # Processes the existing path and appends the 'format' suffix onto the route
297
+ # Used for calculating path in route method
298
+ #
299
+ def process_path_for_respond_to(path, format_params)
300
+ format_suffix = case format_params
301
+ when :any then "(.:format)"
302
+ when Array then
303
+ formats = format_params.dup # Prevent changes to HEAD verb
304
+ container = formats.delete(:html) ? "(%s)" : "%s"
305
+ match = ".{:format," + formats.collect { |f| "#{f}$" }.join("|") + "}"
306
+ container % match
307
+ else ".{:format,#{format_params}}"
308
+ end
309
+ path << format_suffix
310
+ end
311
+ end
312
+ end
313
+ end
@@ -24,6 +24,8 @@ module Padrino
24
24
  #
25
25
  PADRINO_IGNORE_CALLERS.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
26
26
 
27
+ private
28
+
27
29
  ##
28
30
  # Returns the filename for the file that is the direct caller (first caller)
29
31
  #
@@ -10,7 +10,7 @@ module Padrino
10
10
  #
11
11
  # It is performing a check/reload cycle at the start of every request, but
12
12
  # also respects a cool down time, during which nothing will be done.
13
- #
13
+ #
14
14
  class Rack
15
15
  def initialize(app, cooldown = 1)
16
16
  @app = app
@@ -33,6 +33,14 @@ module Padrino
33
33
  end
34
34
  end
35
35
 
36
+ ##
37
+ # You can exclude some folders from reload its contents.
38
+ # Defaults excluded directories of Padrino.root are: test, spec, features, tmp, config, lib and public
39
+ #
40
+ def self.exclude
41
+ @_exclude ||= %w(test spec tmp features config lib public).map { |path| Padrino.root(path) }
42
+ end
43
+
36
44
  ##
37
45
  # What makes it especially suited for use in a any environment is that
38
46
  # any file will only be checked once and there will only be made one system
@@ -79,8 +87,8 @@ module Padrino
79
87
  # Search Ruby files in your +Padrino.root+ and monitor them for changes.
80
88
  #
81
89
  def rotation
82
- files = Dir[Padrino.root("/**/*.rb")]
83
- paths = [Padrino.root] # For now we set only our root.
90
+ paths = Dir[Padrino.root("*")].reject { |path| Padrino::Reloader.exclude.include?(path) || !File.directory?(path) }
91
+ files = paths.map { |path| Dir["#{path}/**/*.rb"] }.flatten
84
92
 
85
93
  files.map{ |file|
86
94
  found, stat = figure_path(file, paths)
@@ -1,19 +1,17 @@
1
1
  ##
2
- # This file load some usefull extensions from Active Support.
2
+ # This file loads certain extensions required by Padrino from ActiveSupport.
3
3
  #
4
- # Why ActiveSupport and not ours or extlib?
4
+ # Why use ActiveSupport and not our own library or extlib?
5
+ #
6
+ # 1) Writing custom method extensions needed (i.e string inflections) is not a good use of time.
7
+ # 2) Loading custom method extensions or separate gem would conflict when AR or MM has been loaded.
8
+ # 3) Datamapper is planning to move to ActiveSupport and away from extlib.
5
9
  #
6
- # We don't love so much rewite code and we don't use extlib because:
7
- #
8
- # 1) ActiveRecord need ActiveSupport
9
- # 2) MongoMapper need ActiveSuport
10
- # 3) DataMapper it's planning to migrate to ActiveSupport (see: http://wiki.github.com/datamapper/dm-core/roadmap)
11
- #
12
- # Required for Padrino to run:
10
+ # Extensions required for Padrino:
13
11
  #
14
12
  # * Class#cattr_accessor
15
13
  # * Module#alias_method_chain
16
- # * String#inflectors (classify, underscore, camelize, etc)
14
+ # * String#inflectors (classify, underscore, camelize, pluralize, etc)
17
15
  # * Array#extract_options!
18
16
  # * Object#blank?
19
17
  # * Object#present?
@@ -38,7 +36,7 @@ require 'active_support/core_ext/module'
38
36
  require 'active_support/ordered_hash'
39
37
 
40
38
  ##
41
- # Define our Ordered Hash
39
+ # Define our own OrderedHash based on AS::OrderedHash
42
40
  #
43
41
  unless defined?(SupportLite::OrderedHash)
44
42
  module SupportLite
@@ -47,7 +45,7 @@ unless defined?(SupportLite::OrderedHash)
47
45
  end
48
46
 
49
47
  ##
50
- # We new alwasy :to_params in a Hash
48
+ # Alias allowing for use of either method to get query parameters
51
49
  #
52
50
  unless Hash.method_defined?(:to_params)
53
51
  class Hash
@@ -56,6 +54,6 @@ unless Hash.method_defined?(:to_params)
56
54
  end
57
55
 
58
56
  ##
59
- # Load our locales
57
+ # Loads our locales configuration files
60
58
  #
61
59
  I18n.load_path += Dir["#{File.dirname(__FILE__)}/locale/*.yml"]
data/padrino-core.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{padrino-core}
8
- s.version = "0.8.5"
8
+ s.version = "0.9.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Padrino Team", "Nathan Esquenazi", "Davide D'Agostino", "Arthur Chiu"]
12
- s.date = %q{2010-02-18}
12
+ s.date = %q{2010-02-23}
13
13
  s.default_executable = %q{padrino}
14
14
  s.description = %q{The Padrino core gem required for use of this framework}
15
15
  s.email = %q{padrinorb@gmail.com}
@@ -27,6 +27,9 @@ Gem::Specification.new do |s|
27
27
  "bin/padrino",
28
28
  "lib/padrino-core.rb",
29
29
  "lib/padrino-core/application.rb",
30
+ "lib/padrino-core/application/mounter.rb",
31
+ "lib/padrino-core/application/rendering.rb",
32
+ "lib/padrino-core/application/routing.rb",
30
33
  "lib/padrino-core/caller.rb",
31
34
  "lib/padrino-core/cli/adapter.rb",
32
35
  "lib/padrino-core/cli/base.rb",
@@ -39,7 +42,6 @@ Gem::Specification.new do |s|
39
42
  "lib/padrino-core/locale/en.yml",
40
43
  "lib/padrino-core/locale/it.yml",
41
44
  "lib/padrino-core/logger.rb",
42
- "lib/padrino-core/mounter.rb",
43
45
  "lib/padrino-core/reloader.rb",
44
46
  "lib/padrino-core/server.rb",
45
47
  "lib/padrino-core/support_lite.rb",
@@ -80,8 +82,8 @@ Gem::Specification.new do |s|
80
82
  s.add_runtime_dependency(%q<i18n>, [">= 0.3.2"])
81
83
  s.add_runtime_dependency(%q<usher>, [">= 0.6.2"])
82
84
  s.add_runtime_dependency(%q<thor>, [">= 0.13.0"])
83
- s.add_runtime_dependency(%q<bundler>, ["= 0.9.5"])
84
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
85
+ s.add_runtime_dependency(%q<bundler>, ["= 0.9.7"])
86
+ s.add_runtime_dependency(%q<activesupport>, ["= 2.3.5"])
85
87
  s.add_development_dependency(%q<shoulda>, [">= 2.10.3"])
86
88
  s.add_development_dependency(%q<mocha>, [">= 0.9.7"])
87
89
  s.add_development_dependency(%q<rack-test>, [">= 0.5.0"])
@@ -91,8 +93,8 @@ Gem::Specification.new do |s|
91
93
  s.add_dependency(%q<i18n>, [">= 0.3.2"])
92
94
  s.add_dependency(%q<usher>, [">= 0.6.2"])
93
95
  s.add_dependency(%q<thor>, [">= 0.13.0"])
94
- s.add_dependency(%q<bundler>, ["= 0.9.5"])
95
- s.add_dependency(%q<activesupport>, [">= 2.3.5"])
96
+ s.add_dependency(%q<bundler>, ["= 0.9.7"])
97
+ s.add_dependency(%q<activesupport>, ["= 2.3.5"])
96
98
  s.add_dependency(%q<shoulda>, [">= 2.10.3"])
97
99
  s.add_dependency(%q<mocha>, [">= 0.9.7"])
98
100
  s.add_dependency(%q<rack-test>, [">= 0.5.0"])
@@ -103,8 +105,8 @@ Gem::Specification.new do |s|
103
105
  s.add_dependency(%q<i18n>, [">= 0.3.2"])
104
106
  s.add_dependency(%q<usher>, [">= 0.6.2"])
105
107
  s.add_dependency(%q<thor>, [">= 0.13.0"])
106
- s.add_dependency(%q<bundler>, ["= 0.9.5"])
107
- s.add_dependency(%q<activesupport>, [">= 2.3.5"])
108
+ s.add_dependency(%q<bundler>, ["= 0.9.7"])
109
+ s.add_dependency(%q<activesupport>, ["= 2.3.5"])
108
110
  s.add_dependency(%q<shoulda>, [">= 2.10.3"])
109
111
  s.add_dependency(%q<mocha>, [">= 0.9.7"])
110
112
  s.add_dependency(%q<rack-test>, [">= 0.5.0"])
@@ -21,7 +21,7 @@ Complex1Demo.controllers do
21
21
  end
22
22
 
23
23
  Complex2Demo.controllers do
24
- get("(/)"){ "The magick number is: 40!" } # Change only the number!!!
24
+ get("(/)"){ "The magick number is: 33!" } # Change only the number!!!
25
25
  end
26
26
 
27
27
  Padrino.load!
@@ -11,7 +11,7 @@ end
11
11
 
12
12
  SimpleDemo.controllers do
13
13
  get "/" do
14
- 'The magick number is: 12!' # Change only the number!!!
14
+ 'The magick number is: 39!' # Change only the number!!!
15
15
  end
16
16
  end
17
17
 
@@ -147,25 +147,4 @@ class TestApplication < Test::Unit::TestCase
147
147
  end
148
148
  end
149
149
  end
150
-
151
- context 'for application i18n functionality' do
152
-
153
- should 'have auto_locale disabled' do
154
- mock_app do
155
- assert !auto_locale
156
- end
157
- end
158
-
159
- should 'set locale when auto_locale is enabled' do
160
- mock_app do
161
- enable :auto_locale
162
- get("/:locale"){ I18n.locale.to_s }
163
- end
164
-
165
- %w(it de fr).each do |lang|
166
- get("/#{lang}")
167
- assert_equal lang, body
168
- end
169
- end
170
- end
171
150
  end
data/test/test_routing.rb CHANGED
@@ -12,7 +12,22 @@ class TestRouting < Test::Unit::TestCase
12
12
  assert_equal "okey", body
13
13
  end
14
14
 
15
- should 'match correcly similar paths' do
15
+ should "parse routes with question marks" do
16
+ mock_app do
17
+ get("/foo/?"){ "okey" }
18
+ post('/unauthenticated/?') { "no access" }
19
+ end
20
+ get "/foo"
21
+ assert_equal "okey", body
22
+ get "/foo/"
23
+ assert_equal "okey", body
24
+ post "/unauthenticated"
25
+ assert_equal "no access", body
26
+ post "/unauthenticated/"
27
+ assert_equal "no access", body
28
+ end
29
+
30
+ should 'match correctly similar paths' do
16
31
  mock_app do
17
32
  get("/my/:foo_id"){ params[:foo_id] }
18
33
  get("/my/:bar_id/bar"){ params[:bar_id] }
@@ -189,6 +204,26 @@ class TestRouting < Test::Unit::TestCase
189
204
  assert_equal "foo_bar_index", body
190
205
  end
191
206
 
207
+ should 'use named controllers with array routes' do
208
+ mock_app do
209
+ controller :admin do
210
+ get(:index){ "index" }
211
+ get(:show, :with => :id){ "show #{params[:id]}" }
212
+ end
213
+ controllers :foo, :bar do
214
+ get(:index){ "foo_bar_index" }
215
+ end
216
+ end
217
+ get "/admin"
218
+ assert_equal "index", body
219
+ get "/admin/show/1"
220
+ assert_equal "show 1", body
221
+ assert_equal "/admin", @app.url(:admin, :index)
222
+ assert_equal "/admin/show/1", @app.url(:admin, :show, :id => 1)
223
+ get "/foo/bar"
224
+ assert_equal "foo_bar_index", body
225
+ end
226
+
192
227
  should 'reset routes' do
193
228
  mock_app do
194
229
  get("/"){ "foo" }
@@ -214,4 +249,37 @@ class TestRouting < Test::Unit::TestCase
214
249
  assert_equal "edit 1", body
215
250
  end
216
251
 
217
- end
252
+ should "apply parent to route" do
253
+ mock_app do
254
+ controllers :project do
255
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
256
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
257
+ get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
258
+ end
259
+ end
260
+ get "/user/1/project"
261
+ assert_equal "index 1", body
262
+ get "/user/1/project/edit/2"
263
+ assert_equal "edit 2 1", body
264
+ get "/user/1/product/2/project/show/3"
265
+ assert_equal "show 3 1 2", body
266
+
267
+ end
268
+
269
+ should "apply parent to controller" do
270
+ mock_app do
271
+ controller :project, :parent => :user do
272
+ get(:index) { "index #{params[:user_id]}"}
273
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
274
+ get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
275
+ end
276
+ end
277
+ get "/user/1/project"
278
+ assert_equal "index 1", body
279
+ get "/user/1/project/edit/2"
280
+ assert_equal "edit 2 1", body
281
+ get "/user/1/product/2/project/show/3"
282
+ assert_equal "show 3 1 2", body
283
+ end
284
+
285
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: padrino-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Padrino Team
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2010-02-18 00:00:00 +01:00
15
+ date: 2010-02-23 00:00:00 -08:00
16
16
  default_executable: padrino
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -63,7 +63,7 @@ dependencies:
63
63
  requirements:
64
64
  - - "="
65
65
  - !ruby/object:Gem::Version
66
- version: 0.9.5
66
+ version: 0.9.7
67
67
  version:
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: activesupport
@@ -71,7 +71,7 @@ dependencies:
71
71
  version_requirement:
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - ">="
74
+ - - "="
75
75
  - !ruby/object:Gem::Version
76
76
  version: 2.3.5
77
77
  version:
@@ -133,6 +133,9 @@ files:
133
133
  - bin/padrino
134
134
  - lib/padrino-core.rb
135
135
  - lib/padrino-core/application.rb
136
+ - lib/padrino-core/application/mounter.rb
137
+ - lib/padrino-core/application/rendering.rb
138
+ - lib/padrino-core/application/routing.rb
136
139
  - lib/padrino-core/caller.rb
137
140
  - lib/padrino-core/cli/adapter.rb
138
141
  - lib/padrino-core/cli/base.rb
@@ -145,7 +148,6 @@ files:
145
148
  - lib/padrino-core/locale/en.yml
146
149
  - lib/padrino-core/locale/it.yml
147
150
  - lib/padrino-core/logger.rb
148
- - lib/padrino-core/mounter.rb
149
151
  - lib/padrino-core/reloader.rb
150
152
  - lib/padrino-core/server.rb
151
153
  - lib/padrino-core/support_lite.rb