orange-core 0.7.0 → 0.7.1
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 +5 -4
- data/lib/orange-core/carton.rb +53 -1
- data/lib/orange-core/core.rb +28 -4
- data/lib/orange-core/magick.rb +9 -0
- data/lib/orange-core/middleware/loader.rb +7 -5
- data/lib/orange-core/middleware/rerouter.rb +1 -1
- data/lib/orange-core/middleware/restful_router.rb +3 -3
- data/lib/orange-core/resource.rb +1 -0
- data/lib/orange-core/resources/mapper.rb +1 -0
- data/lib/orange-core/resources/model_resource.rb +10 -1
- data/lib/orange-core/resources/parser.rb +3 -1
- data/lib/orange-core/resources/scaffold.rb +24 -3
- data/lib/orange-core/stack.rb +1 -1
- data/lib/orange-core/views/default_resource/create.haml +1 -1
- data/lib/orange-core/views/default_resource/edit.haml +4 -1
- data/lib/orange-core/views/default_resource/show.haml +4 -1
- data/lib/orange-core/views/default_resource/table_row.haml +4 -1
- data/spec/orange-core/carton_spec.rb +2 -2
- data/spec/orange-core/core_spec.rb +18 -0
- data/spec/orange-core/mock/mock_carton.rb +3 -0
- data/spec/orange-core/stack_spec.rb +2 -2
- metadata +5 -5
data/README.markdown
CHANGED
@@ -36,19 +36,19 @@ Should I Use Orange?
|
|
36
36
|
|
37
37
|
Sinatra is probably better for this kind of thing. It's perfect for creating quick web apps based on RESTful
|
38
38
|
ideals. Or perhaps use a Sinatra clone built on Orange, so you can incorporate orange plugins and built in
|
39
|
-
database support...
|
39
|
+
database support... But [orange-juice](http://github.com/therabidbanana/orange-juice) was written for orange 0.5, so it's a bit behind. Hopefully it will be updated soon.
|
40
40
|
|
41
41
|
"I want to create a powerful web application that needs to be rock solid and use a
|
42
42
|
well-tested foundation"
|
43
43
|
|
44
|
-
|
44
|
+
This is where Ruby on Rails shines, it's a well supported, thoroughly tested framework
|
45
45
|
for building web applications that gives you everything you need for the lifecycle of your
|
46
|
-
application
|
46
|
+
application.
|
47
47
|
|
48
48
|
"I want to deploy a website on Ruby that has some dynamic elements, maybe allowing me
|
49
49
|
to create my own plugin without jumping through too many hoops."
|
50
50
|
|
51
|
-
|
51
|
+
This is what orange was designed for - we're building it to be able to quickly deploy
|
52
52
|
websites that can have a Ruby base without the heavy-weight Ruby on Rails backend, but also
|
53
53
|
without feeling like you have to start from scratch like it feels in Sinatra.
|
54
54
|
|
@@ -60,6 +60,7 @@ orange-core tries to stay light on the dependencies.
|
|
60
60
|
|
61
61
|
* dm-core (+ dm-[sqlite3|mysql|...]-adapter )
|
62
62
|
* dm-migrations
|
63
|
+
* tilt
|
63
64
|
* rack
|
64
65
|
* haml
|
65
66
|
* crack
|
data/lib/orange-core/carton.rb
CHANGED
@@ -22,7 +22,7 @@ module Orange
|
|
22
22
|
# class and just include DataMapper::Resource. All carton methods are to
|
23
23
|
# improve scaffolding capability.
|
24
24
|
class Carton
|
25
|
-
SCAFFOLD_OPTIONS = [:display_name, :levels] unless defined?(SCAFFOLD_OPTIONS)
|
25
|
+
SCAFFOLD_OPTIONS = [:display_name, :levels, :related_to, :wrap_tag] unless defined?(SCAFFOLD_OPTIONS)
|
26
26
|
extend ClassInheritableAttributes
|
27
27
|
cattr_accessor :scaffold_properties
|
28
28
|
|
@@ -51,6 +51,7 @@ module Orange
|
|
51
51
|
|
52
52
|
# Return properties that should be shown for a given context
|
53
53
|
def self.form_props(context = :live, mode = :any)
|
54
|
+
self.scaffold_properties ||= []
|
54
55
|
self.scaffold_properties.select{|p| should_use?(p, context, mode) }
|
55
56
|
end
|
56
57
|
|
@@ -92,6 +93,10 @@ module Orange
|
|
92
93
|
self.property(name, dm_type, opts)
|
93
94
|
end
|
94
95
|
|
96
|
+
def self.relationship_scaffold(name, type, opts)
|
97
|
+
self.scaffold_properties << {:name => name, :type => type, :levels => @levels, :lazy => false, :relationship => true}.merge(opts) if @levels || opts.has_key?(:levels)
|
98
|
+
end
|
99
|
+
|
95
100
|
# Define a helper for title type database stuff
|
96
101
|
# Show in a context if wrapped in one of the helpers
|
97
102
|
def self.title(name, opts = {})
|
@@ -116,6 +121,12 @@ module Orange
|
|
116
121
|
add_scaffold(name, :time, Time, opts)
|
117
122
|
end
|
118
123
|
|
124
|
+
|
125
|
+
# Show in a context if wrapped in one of the helpers
|
126
|
+
def self.number(name, opts = {})
|
127
|
+
add_scaffold(name, :number, Float, opts)
|
128
|
+
end
|
129
|
+
|
119
130
|
# Define a helper for fulltext type database stuff
|
120
131
|
# Show in a context if wrapped in one of the helpers
|
121
132
|
def self.fulltext(name, opts = {})
|
@@ -134,12 +145,45 @@ module Orange
|
|
134
145
|
add_scaffold(name, :text, String, opts)
|
135
146
|
end
|
136
147
|
|
148
|
+
# Define a helper for belongs_to stuff
|
149
|
+
def self.belongs(name, model, opts = {})
|
150
|
+
relationship_scaffold(name, :belongs, opts.with_defaults(:related_to => model))
|
151
|
+
opts = opts.delete_if{|k,v| SCAFFOLD_OPTIONS.include?(k)} # DataMapper doesn't like arbitrary opts
|
152
|
+
self.belongs_to(name, model, opts)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Define a helper for has_one
|
156
|
+
def self.has_one(name, model, opts = {})
|
157
|
+
relationship_scaffold(name, :has_one, opts.with_defaults(:related_to => model))
|
158
|
+
opts = opts.delete_if{|k,v| SCAFFOLD_OPTIONS.include?(k)} # DataMapper doesn't like arbitrary opts
|
159
|
+
self.has(1, name, model, opts)
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# Define a helper for has_many
|
164
|
+
def self.has_many(name, model, opts = {})
|
165
|
+
relationship_scaffold(name, :has_many, opts.with_defaults(:related_to => model))
|
166
|
+
opts = opts.delete_if{|k,v| SCAFFOLD_OPTIONS.include?(k)} # DataMapper doesn't like arbitrary opts
|
167
|
+
self.has(n, name, model, opts)
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# Define a helper for has_many
|
172
|
+
def self.has_and_belongs_to_many(name, model, opts = {})
|
173
|
+
relationship_scaffold(name, :has_and_belongs_to_many, opts.with_defaults(:related_to => model))
|
174
|
+
opts = opts.delete_if{|k,v| SCAFFOLD_OPTIONS.include?(k)} # DataMapper doesn't like arbitrary opts
|
175
|
+
opts.with_defaults!({:through => DataMapper::Resource})
|
176
|
+
self.has(n, name, model, opts)
|
177
|
+
end
|
178
|
+
|
179
|
+
|
137
180
|
# Define a helper for type database stuff
|
138
181
|
# Show in a context if wrapped in one of the helpers
|
139
182
|
def self.expose(name, opts = {})
|
140
183
|
self.scaffold_properties << {:name => name, :type => :text, :levels => @levels, :opts => opts} if @levels
|
141
184
|
end
|
142
185
|
|
186
|
+
|
143
187
|
# Define a helper for input type="text" type database stuff
|
144
188
|
# Show in a context if wrapped in one of the helpers
|
145
189
|
def self.string(name, opts = {})
|
@@ -177,6 +221,14 @@ module Orange
|
|
177
221
|
add_scaffold(name, my_type, type, opts)
|
178
222
|
end
|
179
223
|
|
224
|
+
def scaffold_name
|
225
|
+
titles = self.class.scaffold_properties.select{|p| p[:type] == :title}
|
226
|
+
return __send__(titles.first[:name]) if(self.respond_to?(titles.first[:name]))
|
227
|
+
return title if(self.respond_to?(:title))
|
228
|
+
return name if(self.respond_to?(:name))
|
229
|
+
return "#{self.class.to_s} ##{id}"
|
230
|
+
end
|
231
|
+
|
180
232
|
def to_s
|
181
233
|
<<-DOC
|
182
234
|
{"class": "#{self.class.to_s}", "id": "#{self.id}"}
|
data/lib/orange-core/core.rb
CHANGED
@@ -40,6 +40,18 @@ module Orange
|
|
40
40
|
Packet.mixin inc
|
41
41
|
end
|
42
42
|
|
43
|
+
# Automatically load and require resources, cartons, and middleware
|
44
|
+
def self.autoload!
|
45
|
+
Dir.glob(File.join('cartons', '*.rb')).each { |f| require f }
|
46
|
+
Dir.glob(File.join('resources', '*.rb')).each { |f| require f }
|
47
|
+
Dir.glob(File.join('middleware', '*.rb')).each { |f| require f }
|
48
|
+
@required = true
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.autoloaded?
|
52
|
+
@required || false
|
53
|
+
end
|
54
|
+
|
43
55
|
# Core is one of two main sources of interaction for Orange Applications
|
44
56
|
#
|
45
57
|
# All portions of Orange based code have access to the Core upon
|
@@ -72,13 +84,13 @@ module Orange
|
|
72
84
|
# This method calls afterLoad when it is done. Subclasses can override
|
73
85
|
# the afterLoad method for initialization needs.
|
74
86
|
def initialize(*args, &block)
|
75
|
-
@options = Mash.new(Options.new(*args, &block).hash.with_defaults(DEFAULT_CORE_OPTIONS))
|
76
87
|
@resources = {}
|
77
88
|
@application = false
|
78
89
|
@stack = false
|
79
90
|
@middleware = []
|
80
91
|
@events = {}
|
81
92
|
@file = __FILE__
|
93
|
+
@options = Mash.new(Orange::Options.new(self, *args, &block).hash.with_defaults(DEFAULT_CORE_OPTIONS))
|
82
94
|
load(Orange::Parser.new, :parser)
|
83
95
|
load(Orange::Mapper.new, :mapper)
|
84
96
|
load(Orange::Scaffold.new, :scaffold)
|
@@ -127,7 +139,7 @@ module Orange
|
|
127
139
|
# @param [Symbol] resource_name The short name of the resource
|
128
140
|
# @return [Boolean] result of has_key? in the resources list
|
129
141
|
def loaded?(resource_name)
|
130
|
-
@resources.has_key?(resource_name)
|
142
|
+
@resources.has_key?(resource_name) && (!@resources[resource_name].blank?)
|
131
143
|
end
|
132
144
|
|
133
145
|
# Takes an instance of a Orange::Resource subclass, sets orange
|
@@ -140,6 +152,9 @@ module Orange
|
|
140
152
|
# Resources must respond to set_orange, which is automatically used to
|
141
153
|
# create a link back to the Core, and to notify the resource of its assigned
|
142
154
|
# short name.
|
155
|
+
#
|
156
|
+
# 0.7 Feature - Passing a Carton class instead of an Orange::Resource instance
|
157
|
+
# will call Carton#as_resource and then load the ModelResource for that carton
|
143
158
|
#
|
144
159
|
# @param [Orange::Resource] resource An instance of Orange::Resource subclass
|
145
160
|
# @param [optional, Symbol, String] name A short name to assign as key in Hash
|
@@ -147,11 +162,20 @@ module Orange
|
|
147
162
|
# Doesn't necessarily need to be a symbol, but generally is.
|
148
163
|
# Set to the class name lowercase as a symbol by default.
|
149
164
|
def load(resource, name = false)
|
165
|
+
if(resource.instance_of?(Class) && (resource < Orange::Carton))
|
166
|
+
carton = resource # Resource isn't really ar resource
|
167
|
+
carton.as_resource
|
168
|
+
resource_class = Object.const_get("#{carton.to_s}_Resource")
|
169
|
+
resource = resource_class.new
|
170
|
+
name = carton.to_s.gsub(/::/, '_').downcase.to_sym if(!name)
|
171
|
+
end
|
150
172
|
name = resource.orange_name if(!name)
|
151
|
-
name = resource.class.to_s.gsub(/::/, '_').downcase.to_sym if(!name)
|
173
|
+
name = resource.class.to_s.gsub(/::/, '_').downcase.to_sym if(!name)
|
152
174
|
@resources[name] = resource.set_orange(self, name)
|
153
175
|
end
|
154
176
|
|
177
|
+
|
178
|
+
|
155
179
|
# Takes an instance of Orange::Middleware::Base subclass and
|
156
180
|
# keeps it for later. This way we can provide introspection into the
|
157
181
|
# middleware instances (useful for calling stack_init on them)
|
@@ -229,7 +253,7 @@ module Orange
|
|
229
253
|
#
|
230
254
|
# @return [Mash] Hash-like mash of options
|
231
255
|
def options(*args, &block)
|
232
|
-
@options.merge(Options.new(*args, &block).hash) if (args.size > 0 || block_given?)
|
256
|
+
@options.merge(Options.new(self, *args, &block).hash) if (args.size > 0 || block_given?)
|
233
257
|
@options
|
234
258
|
end
|
235
259
|
|
data/lib/orange-core/magick.rb
CHANGED
@@ -139,6 +139,7 @@ module Orange
|
|
139
139
|
# so this should be used with caution.
|
140
140
|
class Ignore
|
141
141
|
def blank?; true; end
|
142
|
+
def include?(*args); false; end
|
142
143
|
def method_missing(name, *args, &block)
|
143
144
|
return self
|
144
145
|
end
|
@@ -148,6 +149,7 @@ module Orange
|
|
148
149
|
class Options
|
149
150
|
|
150
151
|
def initialize(*options, &block)
|
152
|
+
@core = options.first if(options.size > 0 && options.first.kind_of?(Orange::Core))
|
151
153
|
@options = options.extract_options!
|
152
154
|
@options ||= {}
|
153
155
|
instance_eval(&block) if block_given?
|
@@ -156,11 +158,18 @@ module Orange
|
|
156
158
|
def hash
|
157
159
|
@options
|
158
160
|
end
|
161
|
+
|
162
|
+
# Load needs fixing up.
|
163
|
+
def load(*args)
|
164
|
+
@core.load(*args)
|
165
|
+
end
|
159
166
|
|
160
167
|
def method_missing(key, *args)
|
161
168
|
return (@options[key.to_s.gsub(/\?$/, '').to_sym].eql?(true)) if key.to_s.match(/\?$/)
|
162
169
|
if args.empty?
|
163
170
|
@options[key.to_sym]
|
171
|
+
elsif(@core && @core.respond_to?(key.to_sym))
|
172
|
+
@core.__send__(key, *args)
|
164
173
|
elsif(key.to_s.match(/\=$/))
|
165
174
|
@options[key.to_s.gsub(/\=$/, '').to_sym] = (args.size == 1 ? args.first : args)
|
166
175
|
else
|
@@ -2,12 +2,14 @@ require 'orange-core/middleware/base'
|
|
2
2
|
module Orange::Middleware
|
3
3
|
class Loader < Base
|
4
4
|
def init(*args)
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
unless Orange.autoloaded?
|
6
|
+
Dir.glob(File.join(orange.app_dir, 'resources', '*.rb')).each do |f|
|
7
|
+
require f
|
8
|
+
orange.load Orange::Inflector.constantize(Orange::Inflector.camelize(File.basename(f, '.rb'))).new
|
9
|
+
end
|
10
|
+
Dir.glob(File.join(orange.app_dir, 'cartons', '*.rb')).each { |f| require f }
|
11
|
+
Dir.glob(File.join(orange.app_dir, 'middleware', '*.rb')).each { |f| require f }
|
8
12
|
end
|
9
|
-
Dir.glob(File.join(orange.app_dir, 'cartons', '*.rb')).each { |f| require f }
|
10
|
-
Dir.glob(File.join(orange.app_dir, 'middleware', '*.rb')).each { |f| require f }
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -40,7 +40,7 @@ module Orange
|
|
40
40
|
packet['reroute.to']
|
41
41
|
# Parsing for orange urls or something
|
42
42
|
when :orange
|
43
|
-
packet.route_to(packet['reroute.to'], *packet['reroute.args', []])
|
43
|
+
"http://"+packet.env['HTTP_HOST']+packet.route_to(packet['reroute.to'], *packet['reroute.args', []])
|
44
44
|
else
|
45
45
|
packet['reroute.to']
|
46
46
|
end
|
@@ -47,13 +47,13 @@ module Orange::Middleware
|
|
47
47
|
pad = parts.shift
|
48
48
|
if !parts.empty?
|
49
49
|
resource = parts.shift
|
50
|
-
if orange.loaded?(resource.to_sym) && (!nested_in || orange[nested_in].nests.keys.include?(resource.to_sym))
|
50
|
+
if orange.loaded?(resource.to_sym) && (!nested_in || orange[nested_in, true].nests.keys.include?(resource.to_sym))
|
51
51
|
return_parts[:resource] = resource.to_sym
|
52
52
|
if !parts.empty?
|
53
53
|
second = parts.shift
|
54
54
|
if second =~ /^\d+$/
|
55
55
|
return_parts[:resource_id] = second
|
56
|
-
if !(parts.empty? || orange[resource.to_sym].nests.keys.include?(parts.first.to_sym))
|
56
|
+
if !(parts.empty? || orange[resource.to_sym, true].nests.keys.include?(parts.first.to_sym))
|
57
57
|
return_parts[:resource_action] = parts.shift.to_sym
|
58
58
|
else
|
59
59
|
return_parts[:resource_action] = :show
|
@@ -88,7 +88,7 @@ module Orange::Middleware
|
|
88
88
|
new_path = parts[:remainder]
|
89
89
|
nested = my_parts.last[:resource]
|
90
90
|
end
|
91
|
-
my_parts
|
91
|
+
packet['route.route_parts'] = my_parts
|
92
92
|
end
|
93
93
|
|
94
94
|
def should_route?(packet, parts)
|
data/lib/orange-core/resource.rb
CHANGED
@@ -38,7 +38,7 @@ module Orange
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def nests
|
41
|
-
self.class.nests
|
41
|
+
self.class.nests || {}
|
42
42
|
end
|
43
43
|
|
44
44
|
# Allows the resource to nest inside other resources
|
@@ -163,6 +163,7 @@ module Orange
|
|
163
163
|
no_reroute = opts.delete(:no_reroute)
|
164
164
|
if packet.request.post? || !opts.blank?
|
165
165
|
params = opts.with_defaults(opts.delete(:params) || packet.request.params[@my_orange_name.to_s] || {})
|
166
|
+
params = params_parse(packet, :new, params)
|
166
167
|
before = beforeNew(packet, params)
|
167
168
|
obj = onNew(packet, params) if before
|
168
169
|
afterNew(packet, obj, params) if before
|
@@ -172,6 +173,12 @@ module Orange
|
|
172
173
|
obj || false
|
173
174
|
end
|
174
175
|
|
176
|
+
def params_parse(packet, mode, params)
|
177
|
+
props = model_class.form_props(packet['route.context'], :any)
|
178
|
+
params.each{|k,v| params[k] = nil if(k.to_s =~ /_id$/ && v.blank?)}
|
179
|
+
params
|
180
|
+
end
|
181
|
+
|
175
182
|
# A callback for the actual new item event
|
176
183
|
def onNew(packet, opts = {})
|
177
184
|
model_class.new(opts)
|
@@ -225,6 +232,7 @@ module Orange
|
|
225
232
|
my_id = opts.delete(:resource_id) || packet['route.resource_id']
|
226
233
|
m = opts.delete(:model) || model_class.get(my_id)
|
227
234
|
params = opts.with_defaults(opts.delete(:params) || packet.request.params[@my_orange_name.to_s] || {})
|
235
|
+
params = params_parse(packet, :save, params)
|
228
236
|
if m
|
229
237
|
before = beforeSave(packet, m, params)
|
230
238
|
onSave(packet, m, params) if before
|
@@ -298,6 +306,7 @@ module Orange
|
|
298
306
|
|
299
307
|
# Exposed method for helping the RestfulRouter class.
|
300
308
|
def exposed(packet)
|
309
|
+
self.class.exposed_actions ||= {:all => [:show, :list], :admin => :all, :orange => :all}
|
301
310
|
all = self.class.exposed_actions[:all]
|
302
311
|
all = [all] unless all.is_a?(Array)
|
303
312
|
context = self.class.exposed_actions[packet['route.context']]
|
@@ -66,9 +66,11 @@ module Orange
|
|
66
66
|
end unless string
|
67
67
|
|
68
68
|
# Check for default resource views
|
69
|
+
string ||= read_if_exists('views', 'default_resource', context+"."+file) if context
|
69
70
|
string ||= read_if_exists('views', 'default_resource', file)
|
70
71
|
@view_dirs.reverse_each do |views_dir|
|
71
|
-
string ||= read_if_exists(views_dir, 'default_resource', file) if
|
72
|
+
string ||= read_if_exists(views_dir, 'default_resource', context+"."+file) if context
|
73
|
+
string ||= read_if_exists(views_dir, 'default_resource', file)
|
72
74
|
end unless string
|
73
75
|
raise LoadError, "Couldn't find haml file '#{file}'" unless string
|
74
76
|
|
@@ -12,11 +12,13 @@ module Orange
|
|
12
12
|
end
|
13
13
|
@scaffold_types = {}
|
14
14
|
add_scaffold_type(:boolean) do |name, val, opts|
|
15
|
+
opts = opts.with_defaults({:wrap_tag => 'p'})
|
15
16
|
if opts[:show]
|
16
17
|
val ? "true" : "false"
|
17
18
|
else
|
18
19
|
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
20
|
ret = "<label for=''>#{opts[:display_name]}</label><br />" + ret if opts[:label]
|
21
|
+
ret = "<#{opts[:wrap_tag]}>#{ret}</#{opts[:wrap_tag]}>" if opts[:wrap_tag]
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -27,12 +29,13 @@ module Orange
|
|
27
29
|
|
28
30
|
def scaffold_attribute(packet, prop, model_name, *args)
|
29
31
|
args = args.extract_options!
|
30
|
-
args.with_defaults
|
32
|
+
args = args.with_defaults({:packet => packet, :value => '', :label => false, :show => false, :wrap_tag => 'p'})
|
31
33
|
val = args[:value]
|
32
34
|
label = args[:label]
|
33
35
|
show = args[:show]
|
34
36
|
name = prop[:name]
|
35
37
|
human_readable_name = name.to_s.split('_').each{|w| w.capitalize!}.join(' ')
|
38
|
+
relationship = prop[:relationship]
|
36
39
|
display_name = prop[:display_name] || human_readable_name
|
37
40
|
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
41
|
unless show
|
@@ -51,15 +54,33 @@ module Orange
|
|
51
54
|
when :date
|
52
55
|
val.gsub!('"', '"')
|
53
56
|
ret = "<input class=\"date\" type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
|
57
|
+
when :belongs
|
58
|
+
val_id = val.blank? ? nil : val.id
|
59
|
+
vals = Object.const_get(prop[:related_to]).all
|
60
|
+
vals = vals.map{|obj| "<option value=\"#{obj.id}\"#{val_id && val_id == obj.id ? 'selected=\'selected\'' : ''}>#{obj.scaffold_name}</option>"}.join("\n")
|
61
|
+
ret = "<select name=\"#{model_name}[#{name}_id]\">#{prop[:required] ? '' : '<option value="">None</option>'}#{vals}</select>"
|
62
|
+
when :has_one
|
63
|
+
ret = ""
|
64
|
+
args[:wrap_tag] = false
|
65
|
+
when :has_many
|
66
|
+
ret = ""
|
67
|
+
args[:wrap_tag] = false
|
68
|
+
when :has_and_belongs_to_many
|
69
|
+
ret = ""
|
70
|
+
args[:wrap_tag] = false
|
71
|
+
when :number
|
72
|
+
val = val.to_s
|
73
|
+
ret = "<input class=\"number\" type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
|
54
74
|
else
|
55
75
|
val.gsub!('"', '"')
|
56
76
|
ret = "<input type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
|
57
77
|
end
|
58
|
-
ret = "<label for=''>#{display_name}</label><br />" + ret if label
|
78
|
+
ret = "<label for=''>#{display_name}</label><br />" + ret if label && !ret.blank?
|
79
|
+
ret = "<#{args[:wrap_tag]}>#{ret}</#{args[:wrap_tag]}>" if args[:wrap_tag]
|
59
80
|
else
|
60
81
|
case prop[:type]
|
61
82
|
when :title
|
62
|
-
ret = "<
|
83
|
+
ret = "<h1 class='#{model_name}-#{name}'>#{val}</h3>"
|
63
84
|
when :text
|
64
85
|
ret = "<p class='#{model_name}-#{name}'>#{val}</p>"
|
65
86
|
when :fulltext
|
data/lib/orange-core/stack.rb
CHANGED
@@ -94,7 +94,7 @@ module Orange
|
|
94
94
|
# Shortcut for adding Orange::Middleware::ShowExceptions to the middleware
|
95
95
|
# stack
|
96
96
|
def use_exceptions
|
97
|
-
stack Orange::Middleware::ShowExceptions
|
97
|
+
stack Orange::Middleware::ShowExceptions unless ENV['RACK_ENV'] == 'production'
|
98
98
|
end
|
99
99
|
|
100
100
|
# Alias for use_exceptions
|
@@ -1,4 +1,4 @@
|
|
1
1
|
%form{:action => "#{packet.route_to(model_name, 'new')}", :method => 'post', :"accept-charset" => "UTF-8"}
|
2
2
|
- for prop in props
|
3
|
-
|
3
|
+
!~ view_attribute(prop, model_name, :label => true)
|
4
4
|
%input{:type => 'submit', :value => 'Save New Item'}
|
@@ -3,7 +3,10 @@
|
|
3
3
|
= orange[:sitemap, true].sitemap_links(packet, {:slug_me => orange[:sitemap, true].slug_for(model, props)})
|
4
4
|
%form{:action => packet.route_to(model_name, model[:id], 'save'), :method => 'post', :"accept-charset" => "UTF-8"}
|
5
5
|
- for prop in props
|
6
|
-
|
6
|
+
- if(prop[:relationship])
|
7
|
+
!~ view_attribute(prop, model_name, :label => true, :value => model.__send__(prop[:name]), :model => model)
|
8
|
+
- else
|
9
|
+
!~ view_attribute(prop, model_name, :label => true, :value => model.attribute_get(prop[:name]), :model => model)
|
7
10
|
%input{:type => 'submit', :value => 'Save Changes'}
|
8
11
|
- else
|
9
12
|
%p Couldn't find the item you're looking for.
|
@@ -1,4 +1,7 @@
|
|
1
1
|
- if model
|
2
2
|
%div{ :class => model_name}
|
3
3
|
- for prop in props
|
4
|
-
|
4
|
+
- if(prop[:relationship])
|
5
|
+
!~ view_attribute(prop, model_name, :show => true, :value => model.__send__(prop[:name]), :model => model)
|
6
|
+
- else
|
7
|
+
!~ view_attribute(prop, model_name, :show => true, :value => model.attribute_get(prop[:name]), :model => model)
|
@@ -1,7 +1,10 @@
|
|
1
1
|
- if model
|
2
2
|
%tr
|
3
3
|
- for prop in props
|
4
|
-
|
4
|
+
- if(prop[:relationship])
|
5
|
+
%td= [:belongs, :has_one].include?(prop[:type]) ? (model.__send__(prop[:name]) ? model.__send__(prop[:name]).scaffold_name : "") : ""
|
6
|
+
- else
|
7
|
+
%td= model.attribute_get(prop[:name]).to_s[0..150]
|
5
8
|
%td.actions
|
6
9
|
= form_link('Delete', route_to(model_name, model.id, 'delete'), 'Are you sure you want to delete this?', {:method => 'delete'})
|
7
10
|
%a{:href => route_to(model_name, model.id, 'edit')} Edit
|
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe Orange::Carton do
|
4
4
|
it "should call property with :id, Serial on #self.id" do
|
5
|
-
MockCartonBlank.should_receive(:property).with(:id, DataMapper::
|
5
|
+
MockCartonBlank.should_receive(:property).with(:id, DataMapper::Property::Serial)
|
6
6
|
MockCartonBlank.id
|
7
7
|
end
|
8
8
|
|
@@ -120,7 +120,7 @@ describe Orange::Carton do
|
|
120
120
|
end
|
121
121
|
|
122
122
|
it "should call property on fulltext" do
|
123
|
-
MockCarton.should_receive(:property).with(an_instance_of(Symbol), DataMapper::
|
123
|
+
MockCarton.should_receive(:property).with(an_instance_of(Symbol), DataMapper::Property::Text, anything())
|
124
124
|
MockCarton.fulltext(:cudge)
|
125
125
|
end
|
126
126
|
|
@@ -3,6 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
describe Orange::Core do
|
4
4
|
before(:all) do
|
5
5
|
class Orange::Core; attr_reader :resources, :events, :file; end;
|
6
|
+
class MockCartonForCore < Orange::Carton; end;
|
6
7
|
end
|
7
8
|
|
8
9
|
it "should allow core mixin via class mixin method" do
|
@@ -139,6 +140,14 @@ describe Orange::Core do
|
|
139
140
|
c.options.should_not have_key(:opt_3)
|
140
141
|
end
|
141
142
|
|
143
|
+
it "should allow passthrough of options (for load method)" do
|
144
|
+
c= Orange::Core.new(:opt_1 => true) do
|
145
|
+
opt_2 true
|
146
|
+
load Orange::ModelResource.new, :foo
|
147
|
+
end
|
148
|
+
c[:foo].should be_an_instance_of(Orange::ModelResource)
|
149
|
+
end
|
150
|
+
|
142
151
|
it "should have a mash options hash" do
|
143
152
|
c= Orange::Core.new(:opt_1 => true, "opt_4" => 'banana'){ opt_2 true }
|
144
153
|
c.options.should be_an_instance_of(Mash)
|
@@ -177,6 +186,15 @@ describe Orange::Core do
|
|
177
186
|
c.resources.should have_key(:mock_one)
|
178
187
|
end
|
179
188
|
|
189
|
+
it "should say a resource is loaded after calling load for carton" do
|
190
|
+
c= Orange::Core.new
|
191
|
+
MockCartonForCore.should < Orange::Carton
|
192
|
+
c.load(MockCartonForCore, :mock_one)
|
193
|
+
c.should be_loaded(:mock_one)
|
194
|
+
c.resources.should have_key(:mock_one)
|
195
|
+
c[:mock_one].model_class.should == MockCartonForCore
|
196
|
+
end
|
197
|
+
|
180
198
|
it "should return self on orange" do
|
181
199
|
c= Orange::Core.new
|
182
200
|
c.orange.should eql(c)
|
@@ -160,7 +160,7 @@ describe Orange::Stack do
|
|
160
160
|
end
|
161
161
|
x.middlewarez.should have(1).middlewares
|
162
162
|
x.prerouting
|
163
|
-
x.middlewarez.should have(
|
163
|
+
x.middlewarez.should have(10).middlewares
|
164
164
|
x.middlewarez.select{|y| y.instance_of?(Orange::Middleware::AbstractFormat)}.should_not be_empty
|
165
165
|
x.middlewarez.select{|y| y.instance_of?(Orange::Middleware::RouteSite)}.should_not be_empty
|
166
166
|
end
|
@@ -188,7 +188,7 @@ describe Orange::Stack do
|
|
188
188
|
end
|
189
189
|
x.middlewarez.should have(1).middlewares
|
190
190
|
x.prerouting(:no_abstract_format => true)
|
191
|
-
x.middlewarez.should have(
|
191
|
+
x.middlewarez.should have(9).middlewares
|
192
192
|
x.middlewarez.select{|y| y.instance_of?(Orange::Middleware::AbstractFormat)}.should be_empty
|
193
193
|
x.middlewarez.select{|y| y.instance_of?(Orange::Middleware::RouteSite)}.should_not be_empty
|
194
194
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
8
|
+
- 1
|
9
|
+
version: 0.7.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- David Haslem
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-27 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -110,7 +110,7 @@ dependencies:
|
|
110
110
|
type: :development
|
111
111
|
version_requirements: *id007
|
112
112
|
description: Orange is a Ruby framework for building managed websites with code as simple as Sinatra
|
113
|
-
email:
|
113
|
+
email: david@orangesparkleball.com
|
114
114
|
executables: []
|
115
115
|
|
116
116
|
extensions: []
|
@@ -161,7 +161,7 @@ files:
|
|
161
161
|
- lib/orange-core/views/not_found/404.haml
|
162
162
|
- README.markdown
|
163
163
|
has_rdoc: true
|
164
|
-
homepage: http://github.com/
|
164
|
+
homepage: http://github.com/orange-project/orange-core
|
165
165
|
licenses: []
|
166
166
|
|
167
167
|
post_install_message: |
|