orange-core 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/README.markdown +145 -0
  2. data/lib/orange-core.rb +8 -0
  3. data/lib/orange-core/application.rb +132 -0
  4. data/lib/orange-core/assets/css/exceptions.css +50 -0
  5. data/lib/orange-core/assets/js/exceptions.js +44 -0
  6. data/lib/orange-core/carton.rb +178 -0
  7. data/lib/orange-core/core.rb +266 -0
  8. data/lib/orange-core/magick.rb +270 -0
  9. data/lib/orange-core/middleware/base.rb +96 -0
  10. data/lib/orange-core/middleware/database.rb +45 -0
  11. data/lib/orange-core/middleware/four_oh_four.rb +45 -0
  12. data/lib/orange-core/middleware/globals.rb +17 -0
  13. data/lib/orange-core/middleware/loader.rb +13 -0
  14. data/lib/orange-core/middleware/rerouter.rb +53 -0
  15. data/lib/orange-core/middleware/restful_router.rb +99 -0
  16. data/lib/orange-core/middleware/route_context.rb +39 -0
  17. data/lib/orange-core/middleware/route_site.rb +51 -0
  18. data/lib/orange-core/middleware/show_exceptions.rb +80 -0
  19. data/lib/orange-core/middleware/static.rb +67 -0
  20. data/lib/orange-core/middleware/static_file.rb +32 -0
  21. data/lib/orange-core/middleware/template.rb +60 -0
  22. data/lib/orange-core/packet.rb +232 -0
  23. data/lib/orange-core/plugin.rb +172 -0
  24. data/lib/orange-core/resource.rb +96 -0
  25. data/lib/orange-core/resources/mapper.rb +36 -0
  26. data/lib/orange-core/resources/model_resource.rb +228 -0
  27. data/lib/orange-core/resources/not_found.rb +10 -0
  28. data/lib/orange-core/resources/page_parts.rb +68 -0
  29. data/lib/orange-core/resources/parser.rb +113 -0
  30. data/lib/orange-core/resources/routable_resource.rb +16 -0
  31. data/lib/orange-core/resources/scaffold.rb +106 -0
  32. data/lib/orange-core/stack.rb +226 -0
  33. data/lib/orange-core/templates/exceptions.haml +111 -0
  34. data/lib/orange-core/views/default_resource/create.haml +4 -0
  35. data/lib/orange-core/views/default_resource/edit.haml +9 -0
  36. data/lib/orange-core/views/default_resource/list.haml +10 -0
  37. data/lib/orange-core/views/default_resource/show.haml +4 -0
  38. data/lib/orange-core/views/default_resource/table_row.haml +7 -0
  39. data/lib/orange-core/views/not_found/404.haml +2 -0
  40. data/spec/orange-core/application_spec.rb +183 -0
  41. data/spec/orange-core/carton_spec.rb +136 -0
  42. data/spec/orange-core/core_spec.rb +248 -0
  43. data/spec/orange-core/magick_spec.rb +96 -0
  44. data/spec/orange-core/middleware/base_spec.rb +38 -0
  45. data/spec/orange-core/middleware/globals_spec.rb +3 -0
  46. data/spec/orange-core/middleware/rerouter_spec.rb +3 -0
  47. data/spec/orange-core/middleware/restful_router_spec.rb +3 -0
  48. data/spec/orange-core/middleware/route_context_spec.rb +3 -0
  49. data/spec/orange-core/middleware/route_site_spec.rb +3 -0
  50. data/spec/orange-core/middleware/show_exceptions_spec.rb +3 -0
  51. data/spec/orange-core/middleware/static_file_spec.rb +3 -0
  52. data/spec/orange-core/middleware/static_spec.rb +3 -0
  53. data/spec/orange-core/mock/mock_app.rb +16 -0
  54. data/spec/orange-core/mock/mock_carton.rb +43 -0
  55. data/spec/orange-core/mock/mock_core.rb +2 -0
  56. data/spec/orange-core/mock/mock_middleware.rb +25 -0
  57. data/spec/orange-core/mock/mock_mixins.rb +19 -0
  58. data/spec/orange-core/mock/mock_model_resource.rb +47 -0
  59. data/spec/orange-core/mock/mock_pulp.rb +24 -0
  60. data/spec/orange-core/mock/mock_resource.rb +26 -0
  61. data/spec/orange-core/mock/mock_router.rb +10 -0
  62. data/spec/orange-core/orange_spec.rb +19 -0
  63. data/spec/orange-core/packet_spec.rb +203 -0
  64. data/spec/orange-core/resource_spec.rb +96 -0
  65. data/spec/orange-core/resources/mapper_spec.rb +5 -0
  66. data/spec/orange-core/resources/model_resource_spec.rb +246 -0
  67. data/spec/orange-core/resources/parser_spec.rb +5 -0
  68. data/spec/orange-core/resources/routable_resource_spec.rb +5 -0
  69. data/spec/orange-core/spec_helper.rb +53 -0
  70. data/spec/orange-core/stack_spec.rb +232 -0
  71. data/spec/stats.rb +182 -0
  72. metadata +227 -0
@@ -0,0 +1,10 @@
1
+ require 'orange-core/resource'
2
+ module Orange
3
+ class NotFound < Orange::Resource
4
+ call_me :not_found
5
+ def route(packet)
6
+ packet[:content] = orange[:parser].haml("404.haml", packet, :resource => self)
7
+ packet[:status] = 404
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,68 @@
1
+ require 'orange-core/resource'
2
+ module Orange
3
+ class PageParts < Resource
4
+ def afterLoad
5
+ orange.add_pulp Orange::Pulp::PageParts
6
+ end
7
+
8
+ def part(packet)
9
+ unless packet[:page_parts, false]
10
+ packet[:page_parts] = DefaultHash.new
11
+ packet[:page_parts].default = ''
12
+ end
13
+ packet[:page_parts]
14
+ end
15
+
16
+
17
+ def add_css(packet, file, opts = {})
18
+ ie = opts[:ie] || false
19
+ mod = opts[:module] || 'public'
20
+ # module set to false gives the root assets dir
21
+ assets = File.join('assets', mod)
22
+ file = File.join('', assets, 'css', file)
23
+ unless packet[:css_files, []].include?(file)
24
+ if ie
25
+ part(packet)[:ie_css] = part(packet)[:ie_css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
26
+ else
27
+ part(packet)[:css] = part(packet)[:css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
28
+ end
29
+ packet[:css_files] ||= []
30
+ packet[:css_files].insert((opts[:position] ? opts[:position] : -1), file)
31
+ end
32
+ end
33
+
34
+ def add_js(packet, file, opts = {})
35
+ ie = opts[:ie] || false
36
+ mod = opts[:module] || 'public'
37
+ assets = File.join('assets', mod)
38
+ file = File.join('', assets, 'js', file)
39
+ unless packet[:js_files, []].include?(file)
40
+ if ie
41
+ part(packet)[:ie_js] = part(packet)[:ie_js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
42
+ else
43
+ part(packet)[:js] = part(packet)[:js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
44
+ end
45
+ packet[:js_files] ||= []
46
+ packet[:js_files].insert((opts[:position] ? opts[:position] : -1), file)
47
+ end
48
+ end
49
+ end
50
+
51
+ module Pulp::PageParts
52
+ def part
53
+ orange[:page_parts].part(packet)
54
+ end
55
+
56
+ # Feels like part should be plural, no?
57
+ def parts; part; end
58
+
59
+
60
+ def add_css(file, opts = {})
61
+ orange[:page_parts].add_css(packet, file, opts)
62
+ end
63
+
64
+ def add_js(file, opts = {})
65
+ orange[:page_parts].add_js(packet, file, opts)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,113 @@
1
+ require 'orange-core/core'
2
+ require 'haml'
3
+ require 'yaml'
4
+ require 'crack'
5
+
6
+ module Orange
7
+ class Parser < Resource
8
+ def afterLoad
9
+ orange.add_pulp Orange::Pulp::ParserPulp
10
+ @template_dirs = [File.join(orange.core_dir, 'templates')]
11
+ @view_dirs = [File.join(orange.core_dir, 'views')]
12
+ Orange.plugins.each{|p| @template_dirs << p.templates if p.has_templates? }
13
+ Orange.plugins.each{|p| @view_dirs << p.views if p.has_views? }
14
+ end
15
+
16
+ def yaml(file)
17
+ return nil unless File.exists?(file)
18
+ string = File.read(file)
19
+ string.gsub!('__ORANGE__', orange.app_dir)
20
+ out = YAML::load(string)
21
+ end
22
+
23
+ def haml(file, packet_binding, *vars, &block)
24
+
25
+ opts = vars.extract_options!
26
+ # Initial info
27
+ temp = opts.delete(:template)
28
+ opts[:resource_name] = opts[:resource].orange_name.to_s if
29
+ opts[:resource] && opts[:resource].respond_to?(:orange_name)
30
+ resource = (opts[:resource_name] || '').downcase
31
+
32
+ if packet_binding.is_a? Orange::Packet
33
+ context = packet_binding['route.context'].to_s
34
+ unless temp
35
+ packet_binding['parser.haml-templates'] ||= {}
36
+ haml_engine = packet_binding['parser.haml-templates']["#{context}-#{resource}-#{file}"] || false
37
+ end
38
+ end
39
+ unless haml_engine
40
+ opts.merge :orange => orange
41
+
42
+ string = false
43
+ if temp
44
+ string ||= read_if_exists('templates', file)
45
+ @template_dirs.each do |templates_dir|
46
+ string ||= read_if_exists(templates_dir, file)
47
+ end unless string
48
+ end
49
+
50
+ if context
51
+ #Check for context specific overrides
52
+ string ||= read_if_exists('views', resource, context+"."+file) if resource
53
+ string ||= read_if_exists('views', context+"."+file)
54
+ @view_dirs.each do |views_dir|
55
+ string ||= read_if_exists(views_dir, resource, context+"."+file) if resource
56
+ string ||= read_if_exists(views_dir, context+"."+file)
57
+ end unless string
58
+ end
59
+
60
+ # Check for standard views
61
+ string ||= read_if_exists('views', resource, file) if resource
62
+ string ||= read_if_exists('views', file)
63
+ @view_dirs.each do |views_dir|
64
+ string ||= read_if_exists(views_dir, resource, file) if resource
65
+ string ||= read_if_exists(views_dir, file)
66
+ end unless string
67
+
68
+ # Check for default resource views
69
+ string ||= read_if_exists('views', 'default_resource', file)
70
+ @view_dirs.each do |views_dir|
71
+ string ||= read_if_exists(views_dir, 'default_resource', file) if resource
72
+ end unless string
73
+ raise LoadError, "Couldn't find haml file '#{file}'" unless string
74
+
75
+ haml_engine = Haml::Engine.new(string)
76
+ if packet_binding.is_a? Orange::Packet
77
+ packet_binding['parser.haml-templates']["#{context}-#{resource}-#{file}"] = haml_engine
78
+ end
79
+ end
80
+ out = haml_engine.render(packet_binding, opts, &block)
81
+ end
82
+
83
+ def read_if_exists(*args)
84
+ return File.read(File.join(*args)) if File.exists?(File.join(*args))
85
+ false
86
+ end
87
+
88
+ def hpricot(text)
89
+ require 'hpricot'
90
+ Hpricot(text)
91
+ end
92
+
93
+ def xml(text)
94
+ Crack::XML.parse(text)
95
+ end
96
+
97
+ def json(text)
98
+ Crack::JSON.parse(text)
99
+ end
100
+ end
101
+
102
+ module Pulp::ParserPulp
103
+ def html(&block)
104
+ if block_given?
105
+ unless(packet[:content].blank?)
106
+ doc = orange[:parser].hpricot(packet[:content])
107
+ yield doc
108
+ packet[:content] = doc.to_s
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,16 @@
1
+ require 'orange-core/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
@@ -0,0 +1,106 @@
1
+ require 'orange-core/core'
2
+
3
+ module Orange
4
+ class Scaffold < Resource
5
+ # Load the scaffold helpers
6
+ def afterLoad
7
+ orange.add_pulp Pulp::ScaffoldHelpers
8
+ Packet.meta_methods(/view_([a-zA-Z_]+)/) do |packet, match, args|
9
+ model = args.shift
10
+ args = args.extract_with_defaults(:mode => match[1].to_sym)
11
+ packet.view(model, args)
12
+ end
13
+ @scaffold_types = {}
14
+ add_scaffold_type(:boolean) do |name, val, opts|
15
+ if opts[:show]
16
+ val ? "true" : "false"
17
+ else
18
+ ret = "<input type='hidden' name='#{opts[:model_name]}[#{name}]' value='0' /><input type='checkbox' name='#{opts[:model_name]}[#{name}]' value='1' #{'checked="checked"' if (val && val != '')}/>"
19
+ ret = "<label for=''>#{opts[:display_name]}</label><br />" + ret if opts[:label]
20
+ end
21
+ end
22
+ end
23
+
24
+ def add_scaffold_type(type, &block)
25
+ @scaffold_types[type] = Proc.new
26
+ end
27
+
28
+ def scaffold_attribute(packet, prop, model_name, *args)
29
+ args = args.extract_options!
30
+ args.with_defaults!({:packet => packet, :value => '', :label => false, :show => false})
31
+ val = args[:value]
32
+ label = args[:label]
33
+ show = args[:show]
34
+ name = prop[:name]
35
+ human_readable_name = name.to_s.split('_').each{|w| w.capitalize!}.join(' ')
36
+ display_name = prop[:display_name] || human_readable_name
37
+ return @scaffold_types[prop[:type]].call(name, val, args.with_defaults!(:display_name => display_name, :model_name => model_name)) if @scaffold_types.has_key?(prop[:type])
38
+ unless show
39
+ case prop[:type]
40
+ when :title
41
+ val.gsub!('"', '&quot;')
42
+ ret = "<input class=\"title\" type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
43
+ when :text
44
+ val.gsub!('"', '&quot;')
45
+ ret = "<input type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
46
+ when :fulltext
47
+ ret = "<textarea name='#{model_name}[#{name}]'>#{val}</textarea>"
48
+ when :boolean
49
+ human_readable_name = human_readable_name + '?'
50
+ ret = "<input type='hidden' name='#{model_name}[#{name}]' value='0' /><input type='checkbox' name='#{model_name}[#{name}]' value='1' #{'checked="checked"' if (val && val != '')}/>"
51
+ when :date
52
+ val.gsub!('"', '&quot;')
53
+ ret = "<input class=\"date\" type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
54
+ else
55
+ val.gsub!('"', '&quot;')
56
+ ret = "<input type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
57
+ end
58
+ ret = "<label for=''>#{display_name}</label><br />" + ret if label
59
+ else
60
+ case prop[:type]
61
+ when :title
62
+ ret = "<h3 class='#{model_name}-#{name}'>#{val}</h3>"
63
+ when :text
64
+ ret = "<p class='#{model_name}-#{name}'>#{val}</p>"
65
+ when :fulltext
66
+ ret = "<div class='#{model_name}-#{name}'>#{val}</div>"
67
+ else
68
+ ret = "<div class='#{model_name}-#{name}'>#{val}</div>"
69
+ end
70
+ end
71
+ return ret
72
+ end
73
+ end
74
+
75
+ module Pulp::ScaffoldHelpers
76
+ # Creates a button that appears to be a link but
77
+ # does form submission with custom method (_method param in POST)
78
+ # This is to avoid issues of a destructive get.
79
+ # @param [String] text link text to show
80
+ # @param [String] link the actual href value of the link
81
+ # @param [String, false] confirm text of the javascript confirm (false for none [default])
82
+ # @param [optional, Array] args array of optional arguments, only opts[:method] defined
83
+ # @option opts [String] method method name (Should be 'DELETE', 'PUT' or 'POST')
84
+ def form_link(text, link, confirm = false, opts = {})
85
+ text = "<img src='#{opts[:img]}' alt='#{text}' />" if opts[:img]
86
+ css = opts[:class]? opts[:class] : 'form_button_link'
87
+ meth = (opts[:method]? "<input type='hidden' name='_method' value='#{opts[:method]}' />" : '')
88
+ if confirm
89
+ "<form action='#{link}' method='post' class='mini' onsubmit='return confirm(\"#{confirm}\")'><button class='link_button'><a href='#' class='#{css}'>#{text}</a></button>#{meth}</form>"
90
+ else
91
+ "<form action='#{link}' method='post' class='mini'><button class='link_button'><a href='#' class='#{css}'>#{text}</a></button>#{meth}</form>"
92
+ end
93
+ end
94
+
95
+ # Calls view for an orange resource.
96
+ def view(model_name, *args)
97
+ orange[model_name].view(self, *args)
98
+ end
99
+
100
+ # Returns a scaffolded attribute
101
+ def view_attribute(prop, model_name, *args)
102
+ orange[:scaffold].scaffold_attribute(self, prop, model_name, *args)
103
+ end
104
+ end
105
+
106
+ end
@@ -0,0 +1,226 @@
1
+ require 'orange-core/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 [Orange::Core] core the orange core
28
+ # @param [Symbol] prebuilt the optional prebuilt stack, if one isn't passed as block
29
+ def initialize(app_class = nil, core = false, prebuilt = :none, &block)
30
+ @build = Rack::Builder.new
31
+ @core = core || Orange::Core.new
32
+ @core.stack = self # Set a back reference in the core.
33
+ @auto_reload = false
34
+ @app = false
35
+ @middleware = []
36
+ @recapture = true
37
+ @main_app = app_class
38
+ if block_given?
39
+ instance_eval(&block)
40
+ else
41
+ @main_app = app_class.new(@core) unless app_class.nil?
42
+ prebuild(prebuilt)
43
+ end
44
+ end
45
+
46
+ # Runs methods necessary to build a stack. Don't use if a stack
47
+ # has already been built by the initialize block.
48
+ #
49
+ # @todo Offer more choices for default stacks
50
+ def prebuild(choice)
51
+ case choice
52
+ when :none
53
+ run @main_app
54
+ else
55
+ run @main_app
56
+ end
57
+ end
58
+
59
+ # Returns the main application instance that was added by the
60
+ # run method. Obviously won't return anything useful if the
61
+ # middleware stack hasn't been set up with an explicit exit point,
62
+ # as could be the case for a pure orange middleware stack on
63
+ # top of a different exit application (like Sinatra or Rails)
64
+ def main_app
65
+ @main_app
66
+ end
67
+
68
+ # Adds middleware using the Rack::Builder#use method
69
+ # @param [Object] middleware A class of middleware that meets rack middleware requirements
70
+ def use(middleware, *args, &block)
71
+ @build.use(middleware, *args, &block)
72
+ end
73
+
74
+ # Loads resources into the core using the Orange::Core#load method
75
+ #
76
+ # all args are passed on
77
+ def load(*args, &block)
78
+ orange.load(*args, &block)
79
+ end
80
+
81
+ # Adds Orange-aware middleware using the Rack::Builder#use method, adding
82
+ # the orange core to the args passed on
83
+ def stack(middleware, *args, &block)
84
+ @build.use(middleware, @core, *args, &block)
85
+ end
86
+
87
+ # Set the auto_reload option, called without args, defaults to true,
88
+ # other option is to set it to false
89
+ def auto_reload!(val = true)
90
+ @auto_reload = val
91
+ end
92
+
93
+ # Shortcut for adding Orange::Middleware::ShowExceptions to the middleware
94
+ # stack
95
+ def use_exceptions
96
+ stack Orange::Middleware::ShowExceptions
97
+ end
98
+
99
+ # Alias for use_exceptions
100
+ def show_exceptions
101
+ use_exceptions
102
+ end
103
+
104
+ # Turn off recapture middleware, which is normally just on top of the exit
105
+ # point
106
+ # @see Orange::Middleware::Recapture
107
+ def no_recapture
108
+ @recapture = false
109
+ end
110
+
111
+ # A shortcut for adding many of the routing middleware options
112
+ # simultaneously. Includes:
113
+ # * Orange::Middleware::Rerouter
114
+ # * Orange::Middleware::Static
115
+ # * Rack::AbstractFormat
116
+ # * Orange::Middleware::RouteSite
117
+ # * Orange::Middleware::RouteContext
118
+ #
119
+ # All of these are passed the args hash to use as they will, except
120
+ # for Rack::AbstractFormat
121
+ #
122
+ def prerouting(*args)
123
+ opts = args.extract_options!
124
+ stack Orange::Middleware::Globals
125
+ stack Orange::Middleware::Loader
126
+ stack Orange::Middleware::Rerouter, opts.dup
127
+ stack Orange::Middleware::Static, opts.dup
128
+ use Rack::AbstractFormat unless opts[:no_abstract_format]
129
+ # Must be used before non-destructive route altering done by Orange,
130
+ # since all orange stuff is non-destructive
131
+ stack Orange::Middleware::RouteSite, opts.dup
132
+ stack Orange::Middleware::RouteContext, opts.dup
133
+ stack Orange::Middleware::Database
134
+ Orange.plugins.each{|p| p.middleware(:prerouting).each{|m| stack m, opts.dup} if p.has_middleware?}
135
+ end
136
+
137
+ # A shortcut for routing via Orange::Middleware::RestfulRouter and any plugins
138
+ #
139
+ # Any args are passed on to the middleware
140
+ def routing(opts ={})
141
+ stack Orange::Middleware::RestfulRouter, opts.dup
142
+ Orange.plugins.each{|p| p.middleware(:routing).each{|m| stack m, opts.dup} if p.has_middleware?}
143
+ end
144
+
145
+ def postrouting(opts ={})
146
+ Orange.plugins.each{|p| p.middleware(:postrouting).each{|m| stack m, opts.dup} if p.has_middleware?}
147
+ stack Orange::Middleware::Template
148
+ stack Orange::Middleware::FourOhFour, opts.dup # Last ditch, send route to 404 page.
149
+ end
150
+
151
+ def responders(opts ={})
152
+ Orange.plugins.each{|p| p.middleware(:responders).each{|m| stack m, opts.dup} if p.has_middleware?}
153
+ end
154
+
155
+ # # A shortcut to enable Rack::OpenID and Orange::Middleware::AccessControl
156
+ # #
157
+ # # Args will be passed on to Orange::Middleware::AccessControl
158
+ # def openid_access_control(*args)
159
+ # opts = args.extract_options!
160
+ #
161
+ # end
162
+
163
+ # Adds pulp to the core via the Orange::Core#add_pulp method
164
+ # @param [Orange::Mixin] mod a mixin to be included in the packet
165
+ def add_pulp(mod)
166
+ orange.add_pulp(mod)
167
+ end
168
+
169
+ # The exit point for the middleware stack,
170
+ # add the app to @main_app and then call Rack::Builder#run with the main app
171
+ def run(app, *args)
172
+ opts = args.extract_options!
173
+ @main_app = app
174
+ @build.run(app)
175
+ end
176
+
177
+ # Returns the Orange::Core
178
+ # @return [Orange::Core] The orange core
179
+ def orange
180
+ @core
181
+ end
182
+
183
+ # Passes through to Rack::Builder#map
184
+ # @todo Make this work - passing the block on to builder
185
+ # means we can't intercept anything, which will yield
186
+ # unexpected results
187
+ def map(path, &block)
188
+ raise 'not yet supported'
189
+ @build.map(path, &block)
190
+ end
191
+
192
+ # Builds the middleware stack (or uses a cached one)
193
+ #
194
+ # If auto_reload is enabled ({#auto_reload!}), builds every time
195
+ #
196
+ # @return [Object] a full stack of middleware and the exit application,
197
+ # conforming to Rack guidelines
198
+ def app
199
+ if @auto_reload
200
+ orange.fire(:stack_reloading, @app) if orange.stack # Alert we are rebuilding
201
+ @app = false # Rebuild no matter what if autoload
202
+ end
203
+ unless @app
204
+ @app = do_build # Build if necessary
205
+ orange.fire(:stack_loaded, @app)
206
+ end
207
+ @app
208
+ end
209
+
210
+ def do_build
211
+ @build.to_app
212
+ end
213
+
214
+ # Sets the core and then passes on to the stack, according to standard
215
+ # rack procedure
216
+ def call(env)
217
+ env['orange.core'] = @core
218
+ app.call(env)
219
+ end
220
+
221
+ # Debug helping
222
+ def inspect
223
+ "#<Orange::Stack:0x#{self.object_id.to_s(16)} @build=#{@build.inspect}, @core=#{@core.inspect}>"
224
+ end
225
+ end
226
+ end