public
Description: Ramaze is a simple, light and modular open-source web application framework written in Ruby.
Homepage: http://ramaze.net
Clone URL: git://github.com/manveru/ramaze.git
Click here to lend your support to: ramaze and make a donation at www.pledgie.com !
ramaze / lib / ramaze / app.rb
100644 126 lines (107 sloc) 3.751 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
module Ramaze
  # An application is a collection of controllers and options that have a
  # common name.
  # Every application has a location it dispatches from, this behaves similar
  # to Rack::URLMap.
 
  AppMap = Innate::URLMap.new
 
  def self.to(object)
    app_name = object.ancestral_trait[:app]
    App[app_name].to(object)
  end
 
  # App is the superclass for applications and acts as their prototype when it
  # comes to configuration.
  #
  # An application consists of options, a location, and a list of objects. The
  # objects are usually {Controller}s.
  #
  # The options are inherited, the basics are set in Ramaze.options, from there
  # to Ramaze::App.options, and finally into every instance of App.
  #
  # This allows to collect {Controller}s of your application into a common
  # group that can easily be used in other applications, while retaining the
  # original options.
  #
  # Every instance of {App} is mapped in {AppMap}, which is the default
  # location to #call from Rack.
  #
  # Additionally, every {App} can have custom locations for
  # root/public/view/layout directories, which allows reuse beyond directory
  # boundaries.
  #
  # In contrast to Innate, where all Nodes share the same middleware, {App}
  # also has a subset of middleware that handles serving static files, routes
  # and rewrites.
  #
  # To indicate that a {Controller} belongs to a specific application, you can
  # pass a second argument to {Controller::map}
  #
  # @example adding Controller to application
  #
  # class WikiController < Ramaze::Controller
  # map '/', :wiki
  # end
  #
  # The App instance will be created for you and if you don't use any other
  # applications in your code there is nothing else you have to do. Others can
  # now come and simply reuse your code in their own applications.
  #
  # There is some risk of name collisions if everybody calls their app `:wiki`,
  # but given that you only use one foreign app of this kind might give less
  # reason for concern.
  #
  # If you still try to use two apps with the same name, you have to be
  # careful, loading one first, renaming it, then loading the second one.
  #
  # The naming of an App has no influence on any other aspects of dispatching
  # or configuration.
  class App
    include Innate::Optioned
 
    # options not found here will be looked up in Ramaze.options
    options.dsl do
      o "Unique identifier for this application",
        :name, :pristine
    end
 
    APP_LIST = {}
 
    attr_reader :name, :location, :url_map, :options
 
    def initialize(name, location = nil)
      @name = name.to_sym
      @url_map = Innate::URLMap.new
      self.location = location if location
 
      APP_LIST[@name] = self
 
      @options = self.class.options.sub(@name)
    end
 
    def sync
      AppMap.map(location, self)
    end
 
    def location=(location)
      @location = location.to_str.freeze
      sync
    end
 
    def call(env)
      to_app.call(env)
    end
 
    def to_app
      files = Ramaze::Files.new(*public_roots)
      app = Current.new(Route.new(url_map), Rewrite.new(url_map))
      Rack::Cascade.new([files, app])
    end
 
    def map(location, object)
      url_map.map(location, object)
    end
 
    def to(object)
      return unless mapped = url_map.to(object)
      [location, mapped].join('/').squeeze('/')
    end
 
    def public_roots
      roots, publics = [*options.roots], [*options.publics]
      roots.map{|root| publics.map{|public| ::File.join(root, public) }}.flatten
    end
 
    def self.find_or_create(name, location = nil)
      location = '/' if location.nil? && name == :pristine
      self[name] || new(name, location)
    end
 
    def self.[](name)
      APP_LIST[name.to_sym]
    end
  end
end