orange 0.0.2
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.
- data/README.markdown +154 -0
- data/lib/orange.rb +7 -0
- data/lib/orange/application.rb +125 -0
- data/lib/orange/carton.rb +114 -0
- data/lib/orange/cartons/site_carton.rb +9 -0
- data/lib/orange/core.rb +197 -0
- data/lib/orange/magick.rb +91 -0
- data/lib/orange/middleware/access_control.rb +100 -0
- data/lib/orange/middleware/base.rb +41 -0
- data/lib/orange/middleware/database.rb +22 -0
- data/lib/orange/middleware/globals.rb +18 -0
- data/lib/orange/middleware/recapture.rb +19 -0
- data/lib/orange/middleware/rerouter.rb +13 -0
- data/lib/orange/middleware/restful_router.rb +59 -0
- data/lib/orange/middleware/route_context.rb +39 -0
- data/lib/orange/middleware/route_site.rb +51 -0
- data/lib/orange/middleware/show_exceptions.rb +78 -0
- data/lib/orange/middleware/site_load.rb +33 -0
- data/lib/orange/middleware/static.rb +81 -0
- data/lib/orange/middleware/static_file.rb +32 -0
- data/lib/orange/middleware/template.rb +61 -0
- data/lib/orange/model_resource.rb +170 -0
- data/lib/orange/packet.rb +88 -0
- data/lib/orange/resource.rb +37 -0
- data/lib/orange/resources/flex_router.rb +13 -0
- data/lib/orange/resources/mapper.rb +55 -0
- data/lib/orange/resources/page_parts.rb +54 -0
- data/lib/orange/resources/parser.rb +60 -0
- data/lib/orange/routable_resource.rb +16 -0
- data/lib/orange/stack.rb +201 -0
- data/spec/application_spec.rb +146 -0
- data/spec/carton_spec.rb +5 -0
- data/spec/core_spec.rb +231 -0
- data/spec/magick_spec.rb +89 -0
- data/spec/mock/mock_app.rb +17 -0
- data/spec/mock/mock_core.rb +2 -0
- data/spec/mock/mock_middleware.rb +13 -0
- data/spec/mock/mock_mixins.rb +19 -0
- data/spec/mock/mock_pulp.rb +24 -0
- data/spec/mock/mock_resource.rb +5 -0
- data/spec/mock/mock_router.rb +10 -0
- data/spec/model_resource_spec.rb +5 -0
- data/spec/orange_spec.rb +19 -0
- data/spec/packet_spec.rb +134 -0
- data/spec/resource_spec.rb +5 -0
- data/spec/resources/flex_router_spec.rb +5 -0
- data/spec/resources/mapper_spec.rb +5 -0
- data/spec/resources/parser_spec.rb +5 -0
- data/spec/routable_resource_spec.rb +5 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/stack_spec.rb +202 -0
- data/spec/stats.rb +182 -0
- metadata +194 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
module Orange
|
2
|
+
# By default, haml files are parsed in the context of their
|
3
|
+
# packet. This means all of instance variables and functions should
|
4
|
+
# be available to the haml parser.
|
5
|
+
class Packet
|
6
|
+
DEFAULT_HEADERS = {"Content-Type" => 'text/html'} unless defined?(DEFAULT_HEADERS)
|
7
|
+
|
8
|
+
def self.new(orange, env)
|
9
|
+
return env['orange.packet'] if env['orange.packet']
|
10
|
+
super(orange, env)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(orange, env)
|
14
|
+
@orange = orange
|
15
|
+
@env = env
|
16
|
+
@env['orange.packet'] = self
|
17
|
+
@env['orange.env'] = {} unless @env['orange.env']
|
18
|
+
@env['orange.env'][:request] = Rack::Request.new(env)
|
19
|
+
@env['orange.env'][:headers] = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key, default = false)
|
23
|
+
@env['orange.env'].has_key?(key) ? @env['orange.env'][key] : default
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, val)
|
27
|
+
@env['orange.env'][key] = val
|
28
|
+
end
|
29
|
+
|
30
|
+
def env
|
31
|
+
@env
|
32
|
+
end
|
33
|
+
|
34
|
+
def session
|
35
|
+
env['rack.session']
|
36
|
+
end
|
37
|
+
|
38
|
+
def headers
|
39
|
+
packet[:headers, {}].with_defaults(DEFAULT_HEADERS)
|
40
|
+
end
|
41
|
+
def header(key, val)
|
42
|
+
@env['orange.env'][:headers][key] = val
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_header(key, val)
|
46
|
+
header key, val
|
47
|
+
end
|
48
|
+
|
49
|
+
def content
|
50
|
+
return [packet[:content]] if packet[:content]
|
51
|
+
return []
|
52
|
+
end
|
53
|
+
|
54
|
+
def request
|
55
|
+
packet[:request]
|
56
|
+
end
|
57
|
+
|
58
|
+
def orange
|
59
|
+
@orange
|
60
|
+
end
|
61
|
+
|
62
|
+
def finish
|
63
|
+
headers = packet.headers
|
64
|
+
status = packet[:status, 200]
|
65
|
+
content = packet.content
|
66
|
+
if content.respond_to?(:to_ary)
|
67
|
+
headers["Content-Length"] = content.to_ary.
|
68
|
+
inject(0) { |len, part| len + Rack::Utils.bytesize(part) }.to_s
|
69
|
+
end
|
70
|
+
[status, headers, content]
|
71
|
+
end
|
72
|
+
|
73
|
+
def packet
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.mixin(inc)
|
78
|
+
include inc
|
79
|
+
end
|
80
|
+
|
81
|
+
def route
|
82
|
+
router = packet['route.router']
|
83
|
+
raise 'Router not found' unless router
|
84
|
+
router.route(self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'orange/core'
|
2
|
+
|
3
|
+
module Orange
|
4
|
+
# Orange Resource for being subclassed
|
5
|
+
class Resource
|
6
|
+
def initialize(*args, &block)
|
7
|
+
@options = Options.new(args, &block).hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_orange(orange, name)
|
11
|
+
@orange = orange
|
12
|
+
@my_orange_name = name
|
13
|
+
afterLoad
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.set_orange(*args)
|
18
|
+
raise 'trying to call set orange on a class (you probably need to instantiate a resource)'
|
19
|
+
end
|
20
|
+
|
21
|
+
def afterLoad
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def orange
|
26
|
+
@orange
|
27
|
+
end
|
28
|
+
|
29
|
+
def routable
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def view(packet = false)
|
34
|
+
''
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'orange/core'
|
2
|
+
|
3
|
+
module Orange
|
4
|
+
class Mapper < Resource
|
5
|
+
# Takes a packet extracts request information, then calls packet.route
|
6
|
+
def afterLoad
|
7
|
+
orange.add_pulp Pulp::Packet_Mapper
|
8
|
+
end
|
9
|
+
|
10
|
+
def route_to(packet, resource, *args)
|
11
|
+
context = packet['route.context', nil]
|
12
|
+
site = packet['route.faked_site'] ? packet['route.site_url', nil] : nil
|
13
|
+
args.unshift(resource)
|
14
|
+
args.unshift(context)
|
15
|
+
args.unshift(site)
|
16
|
+
'/'+args.compact.join('/')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Pulp::Packet_Mapper
|
21
|
+
def route_to(resource, *args)
|
22
|
+
orange[:mapper].route_to(self, resource, *args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def reroute(url, type = :real)
|
26
|
+
packet['reroute.to'] = url
|
27
|
+
packet['reroute.type'] = type
|
28
|
+
raise Reroute.new(self), 'Unhandled reroute'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class Reroute < Exception
|
34
|
+
def initialize(packet)
|
35
|
+
@packet = packet
|
36
|
+
@packet[:headers] = {"Content-Type" => 'text/html', "Location" => self.url}
|
37
|
+
@packet[:status] = 302
|
38
|
+
end
|
39
|
+
|
40
|
+
def url
|
41
|
+
case packet['reroute.type']
|
42
|
+
when :real
|
43
|
+
packet['reroute.to']
|
44
|
+
# Parsing for orange urls or something
|
45
|
+
when :orange
|
46
|
+
packet.route_to(packet['reroute.to'])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def packet
|
51
|
+
@packet
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Orange
|
2
|
+
class PageParts < Resource
|
3
|
+
def afterLoad
|
4
|
+
orange.add_pulp Orange::Pulp::PageParts
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Pulp::PageParts
|
9
|
+
|
10
|
+
def part
|
11
|
+
unless packet[:page_parts, false]
|
12
|
+
packet[:page_parts] = DefaultHash.new
|
13
|
+
packet[:page_parts].default = ''
|
14
|
+
end
|
15
|
+
packet[:page_parts]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Feels like part should be plural, no?
|
19
|
+
def parts; part; end
|
20
|
+
|
21
|
+
def admin_sidebar_link(section, *args)
|
22
|
+
args = args.extract_options!.with_defaults(:position => 0)
|
23
|
+
sidebar = part[:admin_sidebar, {}]
|
24
|
+
sidebar[section] = [] unless sidebar.has_key?(section)
|
25
|
+
sidebar[section].insert(args[:position], {:href => args[:link], :text => args[:text]})
|
26
|
+
part[:admin_sidebar] = sidebar
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_css(file, opts = {})
|
30
|
+
ie = opts[:ie] || false
|
31
|
+
mod = opts[:module] || 'public'
|
32
|
+
# module set to false gives the root assets dir
|
33
|
+
assets = File.join('assets', mod)
|
34
|
+
file = File.join('', assets, 'css', file)
|
35
|
+
if ie
|
36
|
+
part[:ie_css] = part[:ie_css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
|
37
|
+
else
|
38
|
+
part[:css] = part[:css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_js(file, opts = {})
|
43
|
+
ie = opts[:ie] || false
|
44
|
+
mod = opts[:module] || 'public'
|
45
|
+
assets = File.join('assets', mod)
|
46
|
+
file = File.join('', assets, 'js', file)
|
47
|
+
if ie
|
48
|
+
part[:ie_js] = part[:ie_js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
|
49
|
+
else
|
50
|
+
part[:js] = part[:js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'orange/core'
|
2
|
+
require 'haml'
|
3
|
+
require 'yaml'
|
4
|
+
require 'hpricot'
|
5
|
+
|
6
|
+
module Orange
|
7
|
+
class Parser < Resource
|
8
|
+
def afterLoad
|
9
|
+
orange.add_pulp Orange::Pulp::ParserPulp
|
10
|
+
end
|
11
|
+
|
12
|
+
def yaml(file)
|
13
|
+
string = File.read(file)
|
14
|
+
string.gsub!('__ORANGE__', orange.app_dir)
|
15
|
+
out = YAML::load(string)
|
16
|
+
end
|
17
|
+
|
18
|
+
def haml(file, packet, *vars, &block)
|
19
|
+
opts = vars.extract_options!
|
20
|
+
temp = opts.delete(:template)
|
21
|
+
resource = (opts[:resource] || '').downcase
|
22
|
+
opts.merge :orange => orange
|
23
|
+
|
24
|
+
templates_dir = File.join(orange.core_dir, 'templates')
|
25
|
+
views_dir = File.join(orange.core_dir, 'views')
|
26
|
+
default_dir = File.join(views_dir, 'default_resource')
|
27
|
+
|
28
|
+
string = false
|
29
|
+
string ||= read_if('templates', file) if temp
|
30
|
+
string ||= read_if(templates_dir, file) if temp
|
31
|
+
string ||= read_if('views', resource, file) if resource
|
32
|
+
string ||= read_if('views', file)
|
33
|
+
string ||= read_if(views_dir, file)
|
34
|
+
string ||= read_if(views_dir, 'default_resource', file)
|
35
|
+
raise LoadError, "Couldn't find haml file '#{file}" unless string
|
36
|
+
|
37
|
+
haml_engine = Haml::Engine.new(string)
|
38
|
+
out = haml_engine.render(packet, opts, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_if(*args)
|
42
|
+
return File.read(File.join(*args)) if File.exists?(File.join(*args))
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def hpricot(text)
|
47
|
+
Hpricot(text)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module Pulp::ParserPulp
|
52
|
+
def html(&block)
|
53
|
+
if block_given?
|
54
|
+
doc = orange[:parser].hpricot(packet[:content])
|
55
|
+
yield doc
|
56
|
+
packet[:content] = doc.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'orange/resource'
|
2
|
+
|
3
|
+
module Orange
|
4
|
+
class RoutableResource < Resource
|
5
|
+
def routable; true; end
|
6
|
+
|
7
|
+
def route(path, packet)
|
8
|
+
parts = path.split('/')
|
9
|
+
first = parts[0].respond_to?(:to_sym) ? parts.shift.to_sym : :index
|
10
|
+
new_path = parts.join('/')
|
11
|
+
if self.respond_to?(first)
|
12
|
+
packet[:content] = self.__send__(first, new_path, packet)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/orange/stack.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'orange/core'
|
2
|
+
require 'rack/builder'
|
3
|
+
module Orange
|
4
|
+
# Builds an orange stack of middleware
|
5
|
+
# Use in the rackup file as follows:
|
6
|
+
# app = Orange::Stack.new do
|
7
|
+
# stack Orange::DataMapper 'sqlite3::memory:' <= loads orange specific middleware
|
8
|
+
# use OtherMiddleware
|
9
|
+
# run SomeApp.new
|
10
|
+
# end
|
11
|
+
# run app
|
12
|
+
#
|
13
|
+
# All middleware placed inside the Orange::Stack will have access
|
14
|
+
# to the Orange Core (as long as it's been written to accept it as the second
|
15
|
+
# initialization argument) when added with the 'stack' method
|
16
|
+
#
|
17
|
+
# In general, Orange::Stack works like Rack::Builder.
|
18
|
+
class Stack
|
19
|
+
|
20
|
+
# Creates a new Orange::Stack out of the passed block.
|
21
|
+
#
|
22
|
+
# If a block is not passed, it will try to build one from scratch.
|
23
|
+
# The bare minimum will be `run app_class.new(@core)`, there are also
|
24
|
+
# other stacks that can be used.
|
25
|
+
#
|
26
|
+
# @param [Orange::Application] app_class the class of the main application
|
27
|
+
# @param [prebuilt] prebuilt the optional prebuilt stack, if one isn't passed as block
|
28
|
+
def initialize(app_class = nil, prebuilt = :none, &block)
|
29
|
+
@build = Rack::Builder.new
|
30
|
+
@core = Orange::Core.new
|
31
|
+
@auto_reload = false
|
32
|
+
@recapture = true
|
33
|
+
@main_app = app_class
|
34
|
+
if block_given?
|
35
|
+
instance_eval(&block)
|
36
|
+
else
|
37
|
+
@main_app = app_class.new(@core) unless app_class.nil?
|
38
|
+
prebuild(prebuilt)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Runs methods necessary to build a stack. Don't use if a stack
|
43
|
+
# has already been built by the initialize block.
|
44
|
+
#
|
45
|
+
# @todo Offer more choices for default stacks
|
46
|
+
def prebuild(choice)
|
47
|
+
case choice
|
48
|
+
when :none
|
49
|
+
no_recapture
|
50
|
+
run @main_app
|
51
|
+
else
|
52
|
+
no_recapture
|
53
|
+
run @main_app
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the main application instance that was added by the
|
58
|
+
# run method. Obviously won't return anything useful if the
|
59
|
+
# middleware stack hasn't been set up with an explicit exit point,
|
60
|
+
# as could be the case for a pure orange middleware stack on
|
61
|
+
# top of a different exit application (like Sinatra or Rails)
|
62
|
+
def main_app
|
63
|
+
@main_app
|
64
|
+
end
|
65
|
+
|
66
|
+
# Adds middleware using the Rack::Builder#use method
|
67
|
+
# @param [Object] middleware A class of middleware that meets rack middleware requirements
|
68
|
+
def use(middleware, *args, &block)
|
69
|
+
@build.use(middleware, *args, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Loads resources into the core using the Orange::Core#load method
|
73
|
+
#
|
74
|
+
# all args are passed on
|
75
|
+
def load(*args, &block)
|
76
|
+
orange.load(*args, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Adds Orange-aware middleware using the Rack::Builder#use method, adding
|
80
|
+
# the orange core to the args passed on
|
81
|
+
def stack(middleware, *args, &block)
|
82
|
+
@build.use(middleware, @core, *args, &block)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Set the auto_reload option, called without args, defaults to true,
|
86
|
+
# other option is to set it to false
|
87
|
+
def auto_reload!(val = true)
|
88
|
+
@auto_reload = val
|
89
|
+
end
|
90
|
+
|
91
|
+
# Shortcut for adding Orange::Middleware::ShowExceptions to the middleware
|
92
|
+
# stack
|
93
|
+
def use_exceptions
|
94
|
+
stack Orange::Middleware::ShowExceptions
|
95
|
+
end
|
96
|
+
|
97
|
+
# Turn off recapture middleware, which is normally just on top of the exit
|
98
|
+
# point
|
99
|
+
# @see Orange::Middleware::Recapture
|
100
|
+
def no_recapture
|
101
|
+
@recapture = false
|
102
|
+
end
|
103
|
+
|
104
|
+
# A shortcut for adding many of the routing middleware options
|
105
|
+
# simultaneously. Includes:
|
106
|
+
# * Orange::Middleware::Rerouter
|
107
|
+
# * Orange::Middleware::Static
|
108
|
+
# * Rack::AbstractFormat
|
109
|
+
# * Orange::Middleware::RouteSite
|
110
|
+
# * Orange::Middleware::RouteContext
|
111
|
+
#
|
112
|
+
# All of these are passed the args hash to use as they will, except
|
113
|
+
# for Rack::AbstractFormat
|
114
|
+
#
|
115
|
+
def prerouting(*args)
|
116
|
+
opts = args.extract_options!
|
117
|
+
stack Orange::Middleware::Rerouter, opts
|
118
|
+
stack Orange::Middleware::Static, opts
|
119
|
+
use Rack::AbstractFormat unless opts[:no_abstract_format]
|
120
|
+
# Must be used before non-destructive route altering done by Orange,
|
121
|
+
# since all orange stuff is non-destructive
|
122
|
+
stack Orange::Middleware::RouteSite, opts
|
123
|
+
stack Orange::Middleware::RouteContext, opts
|
124
|
+
end
|
125
|
+
|
126
|
+
# A shortcut for enabling restful routing via Orange::Middleware::RestfulRouter
|
127
|
+
#
|
128
|
+
# Any args are passed on to the middleware
|
129
|
+
def restful_routing(*args)
|
130
|
+
opts = args.extract_options!
|
131
|
+
stack Orange::Middleware::RestfulRouter, opts
|
132
|
+
end
|
133
|
+
|
134
|
+
# A shortcut to enable Rack::OpenID and Orange::Middleware::AccessControl
|
135
|
+
#
|
136
|
+
# Args will be passed on to Orange::Middleware::AccessControl
|
137
|
+
# @todo Make it so this is not dependent on the openid_dm_store gem
|
138
|
+
def openid_access_control(*args)
|
139
|
+
opts = args.extract_options!
|
140
|
+
require 'rack/openid'
|
141
|
+
require 'openid_dm_store'
|
142
|
+
|
143
|
+
use Rack::OpenID, OpenIDDataMapper::DataMapperStore.new
|
144
|
+
stack Orange::Middleware::AccessControl, opts
|
145
|
+
end
|
146
|
+
|
147
|
+
# Adds pulp to the core via the Orange::Core#add_pulp method
|
148
|
+
# @param [Orange::Mixin] mod a mixin to be included in the packet
|
149
|
+
def add_pulp(mod)
|
150
|
+
orange.add_pulp(mod)
|
151
|
+
end
|
152
|
+
|
153
|
+
# The exit point for the middleware stack,
|
154
|
+
# this method will add the Orange::Middleware::Recapture if applicable
|
155
|
+
# add the app to @main_app and then call Rack::Builder#run with the main app
|
156
|
+
def run(app, *args)
|
157
|
+
opts = args.extract_options!
|
158
|
+
if @recapture
|
159
|
+
stack Orange::Middleware::Recapture
|
160
|
+
@recapture = false
|
161
|
+
end
|
162
|
+
@main_app = app
|
163
|
+
@build.run(app)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Returns the Orange::Core
|
167
|
+
# @return [Orange::Core] The orange core
|
168
|
+
def orange
|
169
|
+
@core
|
170
|
+
end
|
171
|
+
|
172
|
+
# Passes through to Rack::Builder#map
|
173
|
+
# @todo Make this work - passing the block on to builder
|
174
|
+
# means we can't intercept anything, which will yield
|
175
|
+
# unexpected results
|
176
|
+
def map(path, &block)
|
177
|
+
raise 'not yet supported'
|
178
|
+
@build.map(path, &block)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Builds the middleware stack (or uses a cached one)
|
182
|
+
#
|
183
|
+
# If auto_reload is enabled ({#auto_reload!}), builds every time
|
184
|
+
#
|
185
|
+
# @return [Object] a full stack of middleware and the exit application,
|
186
|
+
# conforming to Rack guidelines
|
187
|
+
def app
|
188
|
+
@app = false if @auto_reload # Rebuild no matter what if autoload
|
189
|
+
@app ||= @build.to_app # Build if necessary
|
190
|
+
orange.fire(:stack_loaded, @app)
|
191
|
+
@app
|
192
|
+
end
|
193
|
+
|
194
|
+
# Sets the core and then passes on to the stack, according to standard
|
195
|
+
# rack procedure
|
196
|
+
def call(env)
|
197
|
+
env['orange.core'] = @core
|
198
|
+
app.call(env)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|