orange 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/README.markdown
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
Orange
|
2
|
+
======
|
3
|
+
|
4
|
+
Orange is intended to be a middle ground between the simplicity of Sinatra
|
5
|
+
and the power of Rails. Orange is being developed by Orange Sparkle Ball, inc
|
6
|
+
for our own use. Our main focus is on creating a super-extensible CMS
|
7
|
+
with Orange, but we're trying to make the components as reusable as possible. Our
|
8
|
+
intention is to be ready to use Orange for most client website builds by
|
9
|
+
March 2010.
|
10
|
+
|
11
|
+
**Note**: Orange is still in the alpha stage. Test coverage is lack-luster at best.
|
12
|
+
Tread carefully.
|
13
|
+
|
14
|
+
A (Theoretical) Example of Orange
|
15
|
+
=================================
|
16
|
+
|
17
|
+
_This doesn't actually work quite yet, but it's the goal we're working toward._
|
18
|
+
|
19
|
+
After installing the orange gem, create an 'app.rb'
|
20
|
+
|
21
|
+
**app.rb:**
|
22
|
+
|
23
|
+
require 'rubygems'
|
24
|
+
require 'orange'
|
25
|
+
class App < Orange::Application
|
26
|
+
end
|
27
|
+
|
28
|
+
You now have an Orange CMS that can be made by calling "App.app".
|
29
|
+
Put this line in your rackup file...
|
30
|
+
|
31
|
+
**config.ru:**
|
32
|
+
|
33
|
+
require 'app'
|
34
|
+
run App.app
|
35
|
+
|
36
|
+
Run rack however you run rack.
|
37
|
+
|
38
|
+
Look at that, a full fledged CMS in 6 lines! Not so impressive, it's all prebuilt,
|
39
|
+
right? The real question is how hard is it to customize?
|
40
|
+
|
41
|
+
I want my pages to have more than just titles and bodies. I want sidebars...
|
42
|
+
|
43
|
+
**app.rb:**
|
44
|
+
|
45
|
+
require 'rubygems'
|
46
|
+
require 'orange'
|
47
|
+
class App < Orange::Application
|
48
|
+
end
|
49
|
+
class Orange::Page
|
50
|
+
markdown :sidebar, :context => [:front]
|
51
|
+
end
|
52
|
+
|
53
|
+
We now have a sidebar that anybody can see. The backend scaffolding will adapt to allow
|
54
|
+
editing, and the front end will print it out for each page. Slap some CSS on it to make it
|
55
|
+
look like a sidebar, and tada!
|
56
|
+
|
57
|
+
Pages now have sidebars, in three lines of code and some
|
58
|
+
styling. No migrations (we rely on DataMapper's auto_upgrade functionality), no extra
|
59
|
+
files (unless we want them).
|
60
|
+
|
61
|
+
More Info
|
62
|
+
=========
|
63
|
+
|
64
|
+
Orange Philosophy
|
65
|
+
-----------------
|
66
|
+
The Orange application framework is intended to be a fully customizable CMS
|
67
|
+
capable of hosting multiple sites while maintaining Sinatra-like ease of
|
68
|
+
programming. Some core ideas behind Orange:
|
69
|
+
|
70
|
+
* Scaffolding doesn't have to be replaced if it's smart enough (most of the time)
|
71
|
+
* Put as much functionality into middleware as possible, so it can be easily reused
|
72
|
+
and remixed
|
73
|
+
* Give middleware a little more power so it's useful enough to handle more tasks
|
74
|
+
|
75
|
+
|
76
|
+
Should I Use Orange?
|
77
|
+
--------------------
|
78
|
+
Not right now, unless you want to write half the framework yourself.
|
79
|
+
|
80
|
+
|
81
|
+
When it's finished, would I want to use it?
|
82
|
+
-------------------------------------------
|
83
|
+
Depends on what you're looking for. Orange has a middleware stack intended to
|
84
|
+
be reused. If the stack has something you'd like, you could theoretically
|
85
|
+
put the middleware stack on top of Sinatra or Rails. (This hasn't actually
|
86
|
+
been tested yet.)
|
87
|
+
|
88
|
+
The full Orange application framework is intended to run
|
89
|
+
as an easily extensible CMS. We tend to think that having lots of tests
|
90
|
+
and full MVC separation just so you can add an extra type of page to the CMS
|
91
|
+
is a bit overkill. We designed this to replace ModX in our web builds for clients.
|
92
|
+
|
93
|
+
Required Gems
|
94
|
+
-------------
|
95
|
+
|
96
|
+
Make sure githubs gems can be downloaded:
|
97
|
+
|
98
|
+
$ gem sources -a http://gems.github.com
|
99
|
+
|
100
|
+
* dm-core (+ do_[sqlite3|mysql|...] )
|
101
|
+
* dm-more
|
102
|
+
* rack
|
103
|
+
* haml
|
104
|
+
* mynyml-rack-abstract-format (github)
|
105
|
+
* ruby-openid
|
106
|
+
* rack-openid
|
107
|
+
* meekish-openid_dm_store
|
108
|
+
|
109
|
+
Also, you'll need a web server of some kind and need to set it up for rack.
|
110
|
+
|
111
|
+
**Testing**
|
112
|
+
|
113
|
+
If you want to test, you'll need the following gems:
|
114
|
+
|
115
|
+
* rspec
|
116
|
+
* rack-test
|
117
|
+
|
118
|
+
Yard is also helpful for generating API docs
|
119
|
+
|
120
|
+
The following are useful rake tasks for testing purposes:
|
121
|
+
|
122
|
+
* rake test => (same as rake spec)
|
123
|
+
* rake spec => runs rspec with color enabled and spec_helper included
|
124
|
+
* rake doc => runs yardoc (no, not really necessary)
|
125
|
+
* rake clean => clear out the temporary files not included in the repo
|
126
|
+
* rake rcov => runs rspec with rcov
|
127
|
+
|
128
|
+
Programming Info
|
129
|
+
================
|
130
|
+
|
131
|
+
The basics of using the orange framework...
|
132
|
+
|
133
|
+
Terminology
|
134
|
+
-----------
|
135
|
+
|
136
|
+
* **Application**: The last stop for the packet after traversing through the middleware stack.
|
137
|
+
* **Core**: This is the core orange object, accessible from all points of the orange
|
138
|
+
system. Usually the orange instance can be called by simply using the "orange" function
|
139
|
+
* **Mixins**: Extra functionality added directly to the core. Mixins are generally for only
|
140
|
+
a couple of extra methods, anything more should probably be created as a resource.
|
141
|
+
* **Packet**: This object represents a web request coming in to the orange system.
|
142
|
+
Each request is instantiated as a packet before it is sent through the middleware stack.
|
143
|
+
* **Pulp**: Mixin added to the packet object rather than the Core.
|
144
|
+
* **Resources**: Resources are extra functionality contained within an object, accessible
|
145
|
+
from the core.
|
146
|
+
* **Stack**: The bundled collection of Orange-enhanced middleware sitting on top of the
|
147
|
+
Orange application
|
148
|
+
|
149
|
+
Pulp and Mixins
|
150
|
+
---------------
|
151
|
+
The ability to add pulp and mixins is incredibly handy because the packet and the core are
|
152
|
+
available from just about anywhere in the Orange framework. For instance, the haml parser
|
153
|
+
evaluates all local calls as if made to the packet, so adding pulp is essentially adding
|
154
|
+
functionality that is directly available to haml.
|
data/lib/orange.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
libdir = File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
3
|
+
|
4
|
+
Dir.glob(File.join(libdir, 'orange', '*.rb')).each {|f| require f }
|
5
|
+
Dir.glob(File.join(libdir, 'orange', 'cartons', '*.rb')).each {|f| require f }
|
6
|
+
Dir.glob(File.join(libdir, 'orange', 'middleware', '*.rb')).each {|f| require f }
|
7
|
+
Dir.glob(File.join(libdir, 'orange', 'resources', '*.rb')).each {|f| require f }
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Orange
|
2
|
+
# Orange::Application is the main class used for building an
|
3
|
+
# Orange App. Typically you will not initialize it directly,
|
4
|
+
# but use the app method, which returns the entire Orange
|
5
|
+
# stack, with all middleware and the Orange::Application as
|
6
|
+
# the main receiver
|
7
|
+
#
|
8
|
+
# To override the stack generated by default, you can use
|
9
|
+
# the self.stack method, which will be used to create a new
|
10
|
+
# Orange::Stack
|
11
|
+
class Application
|
12
|
+
# Initialize will set the core, and additionally accept any
|
13
|
+
# other options to be added in to the opts array
|
14
|
+
# @param [Orange::Core] core the orange core instance that this application will use
|
15
|
+
# @param [Hash] *opts the optional arguments
|
16
|
+
def initialize(core = false, *opts, &block)
|
17
|
+
@core = core
|
18
|
+
@options ||= {}
|
19
|
+
@options = Orange::Options.new(*opts, &block).hash.with_defaults(self.class.opts)
|
20
|
+
orange.register(:stack_loaded) do |s|
|
21
|
+
stack_init
|
22
|
+
end
|
23
|
+
init
|
24
|
+
end
|
25
|
+
|
26
|
+
# stack_init is ONLY called after the {#app}
|
27
|
+
# method is called, loading a stack
|
28
|
+
# (just in case the middleware stack added necessary functionality, etc)
|
29
|
+
def stack_init
|
30
|
+
end
|
31
|
+
|
32
|
+
# This method is called by initialize, subclasses should override this method
|
33
|
+
# for their own initialization needs.
|
34
|
+
#
|
35
|
+
# It will usually be better to use stack_init, which gives full access to
|
36
|
+
# the initialized stack
|
37
|
+
def init
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the orange core to be a new core
|
41
|
+
#
|
42
|
+
# Generally, the core should be set during initialization, rather
|
43
|
+
# than with this method.
|
44
|
+
# @param [Orange::Core] core the orange core instance
|
45
|
+
def set_core(core)
|
46
|
+
@core = core
|
47
|
+
end
|
48
|
+
|
49
|
+
# The standard call as required by rack. This will
|
50
|
+
# make an Orange::Packet object (if necessary) and
|
51
|
+
# then send it to the appropriate router for routing.
|
52
|
+
#
|
53
|
+
# If the :self_routing option is true (default) then
|
54
|
+
# the packet will be routed by the application if there
|
55
|
+
# is not already another class volunteering for that role.
|
56
|
+
# (Routers declare themselves in the orange
|
57
|
+
# env['route.router'] to be called by the application)
|
58
|
+
#
|
59
|
+
#
|
60
|
+
def call(env)
|
61
|
+
packet = Orange::Packet.new(@core, env)
|
62
|
+
# Set up this application as router if nothing else has
|
63
|
+
# assumed routing responsibility (for Sinatra DSL like routing)
|
64
|
+
self_routing = opts[:self_routing] || true
|
65
|
+
if (!packet['route.router'] && self_routing)
|
66
|
+
packet['route.router'] = self
|
67
|
+
end
|
68
|
+
packet.route
|
69
|
+
packet.finish
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the core
|
73
|
+
# @return [Orange::Core] the core instance set for the application
|
74
|
+
def orange
|
75
|
+
@core
|
76
|
+
end
|
77
|
+
|
78
|
+
# The default route method for the application. Must be overridden in subclasses.
|
79
|
+
#
|
80
|
+
# This method will raise a RuntimeError if not overridden.
|
81
|
+
# The intent is for the application subclass to override this method
|
82
|
+
# and use it to handle packets not routed by Stack middleware.
|
83
|
+
def route(packet)
|
84
|
+
raise 'default response from Orange::Application.route'
|
85
|
+
end
|
86
|
+
|
87
|
+
# Used to set optional values at class level. Will be merged into the options
|
88
|
+
# given at initialization time
|
89
|
+
def self.set(key, v = true)
|
90
|
+
@class_opts ||= {}
|
91
|
+
@class_opts[key] = v
|
92
|
+
end
|
93
|
+
|
94
|
+
# Gives access to class defined options.
|
95
|
+
def self.opts
|
96
|
+
@class_opts ||= {}
|
97
|
+
end
|
98
|
+
|
99
|
+
# Gives access to options for the application, both from the class and the
|
100
|
+
# instance level.
|
101
|
+
# @return [Hash] the options hash
|
102
|
+
def opts
|
103
|
+
@options
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns an instance of Orange::Stack to be run by Rack
|
107
|
+
#
|
108
|
+
# Usually, you'll call this in the rackup file: `run MyApplication.app`
|
109
|
+
def self.app
|
110
|
+
if @app.instance_of?(Proc)
|
111
|
+
Orange::Stack.new &@app # turn saved proc into a block arg
|
112
|
+
else
|
113
|
+
Orange::Stack.new self
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Changes the stack that will be used when {#app}
|
118
|
+
# is called
|
119
|
+
#
|
120
|
+
# Each call to stack overrides the previous one.
|
121
|
+
def self.stack(&block)
|
122
|
+
@app = Proc.new # pulls in the block and makes it a proc
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module Orange
|
4
|
+
class Carton
|
5
|
+
|
6
|
+
def self.as_resource
|
7
|
+
name = self.to_s
|
8
|
+
eval <<-HEREDOC
|
9
|
+
class ::#{name}_Resource < Orange::ModelResource
|
10
|
+
use #{name}
|
11
|
+
end
|
12
|
+
HEREDOC
|
13
|
+
end
|
14
|
+
|
15
|
+
# Info for
|
16
|
+
include DataMapper::Types
|
17
|
+
|
18
|
+
def self.id
|
19
|
+
include DataMapper::Resource
|
20
|
+
self.property(:id, Serial)
|
21
|
+
@scaffold_properties = []
|
22
|
+
init
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.init
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return properties that should be shown for a given context
|
29
|
+
def self.form_props(context)
|
30
|
+
@scaffold_properties.select{|p| p[:levels].include?(context) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Helper to wrap properties into admin level
|
34
|
+
def self.admin(&block)
|
35
|
+
@levels = [:admin, :orange]
|
36
|
+
instance_eval(&block)
|
37
|
+
@levels = false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Helper to wrap properties into orange level
|
41
|
+
def self.orange(&block)
|
42
|
+
@levels = [:orange]
|
43
|
+
instance_eval(&block)
|
44
|
+
@levels = false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Helper to wrap properties into front level
|
48
|
+
def self.front(&block)
|
49
|
+
@levels = [:live, :admin, :orange]
|
50
|
+
instance_eval(&block)
|
51
|
+
@levels = false
|
52
|
+
end
|
53
|
+
|
54
|
+
# Define a helper for title type database stuff
|
55
|
+
# Show in a context if wrapped in one of the helpers
|
56
|
+
def self.title(name, opts = {})
|
57
|
+
@scaffold_properties << {:name => name, :type => :title, :levels => @levels}.merge(opts) if @levels
|
58
|
+
self.property(name, String, opts)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Define a helper for fulltext type database stuff
|
62
|
+
# Show in a context if wrapped in one of the helpers
|
63
|
+
def self.fulltext(name, opts = {})
|
64
|
+
@scaffold_properties << {:name => name, :type => :fulltext, :levels => @levels, :opts => opts} if @levels
|
65
|
+
self.property(name, Text, opts)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Define a helper for input type="text" type database stuff
|
69
|
+
# Show in a context if wrapped in one of the helpers
|
70
|
+
def self.text(name, opts = {})
|
71
|
+
@scaffold_properties << {:name => name, :type => :text, :levels => @levels, :opts => opts} if @levels
|
72
|
+
self.property(name, String, opts)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Define a helper for input type="text" type database stuff
|
76
|
+
# Show in a context if wrapped in one of the helpers
|
77
|
+
def self.string(name, opts = {})
|
78
|
+
self.text(name, opts)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Override DataMapper to include context sensitivity (as set by helpers)
|
82
|
+
def self.property(name, type, opts = {})
|
83
|
+
my_type = type.to_s.downcase.to_sym
|
84
|
+
@scaffold_properties << {:name => name, :type => my_type, :levels => @levels}.merge(opts) if @levels
|
85
|
+
property(name, type, opts)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# For more generic cases, use same syntax as DataMapper
|
90
|
+
# This will make it an admin property though.
|
91
|
+
def self.admin_property(name, type, opts = {})
|
92
|
+
my_type = type.to_s.downcase.to_sym
|
93
|
+
@scaffold_properties << {:name => name, :type => my_type, :levels => [:admin, :orange]}.merge(opts)
|
94
|
+
property(name, type, opts)
|
95
|
+
end
|
96
|
+
|
97
|
+
# For more generic cases, use same syntax as DataMapper
|
98
|
+
# This will make it a front property though.
|
99
|
+
def self.front_property(name, type, opts = {})
|
100
|
+
my_type = type.to_s.downcase.to_sym
|
101
|
+
@scaffold_properties << {:name => name, :type => my_type, :levels => [:live, :admin, :orange]}.merge(opts)
|
102
|
+
property(name, type, opts)
|
103
|
+
end
|
104
|
+
|
105
|
+
# For more generic cases, use same syntax as DataMapper
|
106
|
+
# This will make it an orange property though.
|
107
|
+
def self.orange_property(name, type, opts = {})
|
108
|
+
my_type = type.to_s.downcase.to_sym
|
109
|
+
@scaffold_properties << {:name => name, :type => my_type, :levels => [:orange]}.merge(opts)
|
110
|
+
property(name, type, opts)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
data/lib/orange/core.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'rack'
|
3
|
+
require 'rack/builder'
|
4
|
+
|
5
|
+
module Orange
|
6
|
+
# Declare submodules for later use
|
7
|
+
module Pulp; end
|
8
|
+
module Mixins; end
|
9
|
+
|
10
|
+
# Allow mixins directly from Orange
|
11
|
+
def self.mixin(inc)
|
12
|
+
Core.mixin inc
|
13
|
+
end
|
14
|
+
|
15
|
+
# Allow pulp directly from Orange
|
16
|
+
def self.add_pulp(inc)
|
17
|
+
Packet.mixin inc
|
18
|
+
end
|
19
|
+
|
20
|
+
# Core is one of two main sources of interaction for Orange Applications
|
21
|
+
#
|
22
|
+
# All portions of Orange based code have access to the Core upon
|
23
|
+
# initialization. Orange allows access to individual resources,
|
24
|
+
# and also allows single point for event registration and firing.
|
25
|
+
#
|
26
|
+
# Functionality of the core can be extended by loading resources,
|
27
|
+
# or by mixins that directly affect the Core. Generally, resources
|
28
|
+
# are the less convoluted (easier to debug) way to do it.
|
29
|
+
class Core
|
30
|
+
# Sets the default options for Orange Applications
|
31
|
+
DEFAULT_CORE_OPTIONS =
|
32
|
+
{
|
33
|
+
:contexts => [:live, :admin, :orange],
|
34
|
+
:default_context => :live,
|
35
|
+
:default_resource => :not_found,
|
36
|
+
:default_database => 'sqlite3::memory:'
|
37
|
+
} unless defined?(DEFAULT_CORE_OPTIONS)
|
38
|
+
|
39
|
+
# Args will be set to the @options array.
|
40
|
+
# Block DSL style option setting also available:
|
41
|
+
#
|
42
|
+
# orange = Orange::Core.new(:optional_option => 'foo') do
|
43
|
+
# haml true
|
44
|
+
# site_name "Banana"
|
45
|
+
# custom_router MyRouterClass.new
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# orange.options[:site_name] #=> "Banana"
|
49
|
+
#
|
50
|
+
# This method calls afterLoad when it is done. Subclasses can override
|
51
|
+
# the afterLoad method for initialization needs.
|
52
|
+
def initialize(*args, &block)
|
53
|
+
@options = Options.new(*args, &block).hash.with_defaults(DEFAULT_CORE_OPTIONS)
|
54
|
+
@resources = {}
|
55
|
+
@events = {}
|
56
|
+
@file = __FILE__
|
57
|
+
load(Orange::Parser.new, :parser)
|
58
|
+
load(Orange::Mapper.new, :mapper)
|
59
|
+
load(Orange::PageParts.new, :page_parts)
|
60
|
+
afterLoad
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the orange library directory
|
65
|
+
# @return [String] the directory name indicating where the core file is
|
66
|
+
# located
|
67
|
+
def core_dir
|
68
|
+
options[:core_dir] ||= File.dirname(__FILE__)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the directory of the currently executing file (using Dir.pwd),
|
72
|
+
# can be overriden using the option :app_dir in initialization
|
73
|
+
#
|
74
|
+
# @return [String] the directory name of the currently running application
|
75
|
+
def app_dir
|
76
|
+
options[:app_dir] ||= Dir.pwd
|
77
|
+
end
|
78
|
+
|
79
|
+
# Called by initialize after finished loading
|
80
|
+
def afterLoad
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns status of a given resource by short name
|
85
|
+
# @param [Symbol] resource_name The short name of the resource
|
86
|
+
# @return [Boolean] result of has_key? in the resources list
|
87
|
+
def loaded?(resource_name)
|
88
|
+
@resources.has_key?(resource_name)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Takes an instance of a Orange::Resource subclass, sets orange
|
92
|
+
# then adds it to the orange resources
|
93
|
+
#
|
94
|
+
# It can be assigned a short name to be used for accessing later
|
95
|
+
# on. If no short name is assigned, one will be generated by downcasing
|
96
|
+
# the class name and changing it to a symbol
|
97
|
+
#
|
98
|
+
# Resources must respond to set_orange, which is automatically used to
|
99
|
+
# create a link back to the Core, and to notify the resource of its assigned
|
100
|
+
# short name.
|
101
|
+
#
|
102
|
+
# @param [Orange::Resource] resource An instance of Orange::Resource subclass
|
103
|
+
# @param [optional, Symbol, String] name A short name to assign as key in Hash
|
104
|
+
# list of resources.
|
105
|
+
# Doesn't necessarily need to be a symbol, but generally is.
|
106
|
+
# Set to the class name lowercase as a symbol by default.
|
107
|
+
def load(resource, name = false)
|
108
|
+
name = resource.class.to_s.gsub(/::/, '_').downcase.to_sym if(!name)
|
109
|
+
@resources[name] = resource.set_orange(self, name)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Convenience self for consistent naming across middleware
|
113
|
+
# @return [Orange::Core] self
|
114
|
+
def orange; self; end
|
115
|
+
|
116
|
+
# Registers interest in a callback for a named event.
|
117
|
+
#
|
118
|
+
# Event registration is stored as a hash list of events and arrays
|
119
|
+
# of procs to be executed on each event.
|
120
|
+
#
|
121
|
+
# @param [Symbol] event the name of the event registered for
|
122
|
+
# @param [optional, Integer] position the position to place the event in,
|
123
|
+
# by default goes to the front of the list. Doesn't necessarily need
|
124
|
+
# to be exact count, empty spaces in array are taken out. Forcing the
|
125
|
+
# event to be at 99 or some such position will typically make sure it
|
126
|
+
# happens last in the firing process.
|
127
|
+
# @param [Block] block The code to be executed upon event firing.
|
128
|
+
# Saved to an array of procs that are called when #fire is called.
|
129
|
+
# Block must accept one param, which is the intended to be the packet
|
130
|
+
# causing the block to fire, unless the event happens in setup.
|
131
|
+
def register(event, position = 0, &block)
|
132
|
+
if block_given?
|
133
|
+
if @events[event]
|
134
|
+
@events[event].insert(position, Proc.new)
|
135
|
+
else
|
136
|
+
@events[event] = Array.new.insert(position, Proc.new)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Fires a callback for a given packet (or other object)
|
142
|
+
#
|
143
|
+
# @param [Symbol] event name of event something has registered for
|
144
|
+
# @param [Orange::Packet, object] packet Object, generally Orange::Packet,
|
145
|
+
# causing the fire. This is passed to each Proc registered.
|
146
|
+
# @return [Boolean] returns false if nothing has been registered for the
|
147
|
+
# event, otherwise true.
|
148
|
+
def fire(event, packet)
|
149
|
+
return false unless @events[event]
|
150
|
+
@events[event].compact!
|
151
|
+
for callback in @events[event]
|
152
|
+
callback.call(packet)
|
153
|
+
end
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns options of the orange core
|
158
|
+
#
|
159
|
+
# @return [Hash] Hash of options
|
160
|
+
def options
|
161
|
+
@options
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# Accesses resources array, stored as a hash {:short_name => Resource instance,...}
|
166
|
+
#
|
167
|
+
# @param [Symbol] name the short name for the requested resource
|
168
|
+
# @return [Orange::Resource] the resource for the given short name
|
169
|
+
def [](name)
|
170
|
+
@resources[name]
|
171
|
+
end
|
172
|
+
|
173
|
+
# Includes module in the Packet class
|
174
|
+
# @param [Module] inc module to be included
|
175
|
+
def add_pulp(inc)
|
176
|
+
self.class.add_pulp inc
|
177
|
+
end
|
178
|
+
|
179
|
+
# Includes module in this class
|
180
|
+
# @param [Module] inc module to be included
|
181
|
+
def mixin(inc)
|
182
|
+
self.class.mixin inc
|
183
|
+
end
|
184
|
+
|
185
|
+
# Includes module in this class
|
186
|
+
# @param [Module] inc module to be included
|
187
|
+
def self.mixin(inc)
|
188
|
+
include inc
|
189
|
+
end
|
190
|
+
|
191
|
+
# Includes module in the Packet class
|
192
|
+
# @param [Module] inc module to be included
|
193
|
+
def self.add_pulp(inc)
|
194
|
+
Packet.mixin inc
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|