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
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
|