hobo 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/hobo_files/plugin/CHANGES.txt +220 -23
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +18 -25
- data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +20 -15
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +3 -3
- data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +3 -3
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.css +1 -2
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +21 -4
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/images/fieldbg.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/images/spinner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +154 -26
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +144 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +1 -1
- data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +1 -1
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +8 -11
- data/hobo_files/plugin/init.rb +0 -2
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +0 -9
- data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +0 -10
- data/hobo_files/plugin/lib/hobo.rb +57 -44
- data/hobo_files/plugin/lib/hobo/bundle.rb +222 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +2 -5
- data/hobo_files/plugin/lib/hobo/dryml.rb +8 -7
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +10 -21
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +107 -80
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +27 -20
- data/hobo_files/plugin/lib/hobo/enum_string.rb +1 -1
- data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +7 -0
- data/hobo_files/plugin/lib/hobo/guest.rb +4 -0
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +37 -9
- data/hobo_files/plugin/lib/hobo/model.rb +79 -17
- data/hobo_files/plugin/lib/hobo/model_controller.rb +59 -60
- data/hobo_files/plugin/lib/hobo/model_router.rb +16 -4
- data/hobo_files/plugin/lib/hobo/rapid_helper.rb +2 -1
- data/hobo_files/plugin/lib/hobo/user.rb +10 -7
- data/hobo_files/plugin/lib/hobo/user_controller.rb +6 -6
- data/hobo_files/plugin/{tags → taglibs}/core.dryml +5 -4
- data/hobo_files/plugin/{tags → taglibs}/rapid.dryml +54 -7
- data/hobo_files/plugin/{tags → taglibs}/rapid_document_tags.dryml +0 -0
- data/hobo_files/plugin/{tags → taglibs}/rapid_editing.dryml +4 -2
- data/hobo_files/plugin/{tags → taglibs}/rapid_forms.dryml +1 -4
- data/hobo_files/plugin/{tags → taglibs}/rapid_navigation.dryml +1 -2
- data/hobo_files/plugin/taglibs/rapid_pages.dryml +411 -0
- data/hobo_files/plugin/{tags → taglibs}/rapid_plus.dryml +0 -0
- data/hobo_files/plugin/{tags → taglibs}/rapid_support.dryml +9 -6
- data/hobo_files/plugin/tasks/fix_dryml.rake +0 -1
- metadata +16 -14
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid_ui.css +0 -167
- data/hobo_files/plugin/lib/hobo/plugins.rb +0 -75
- data/hobo_files/plugin/tags/rapid_pages.dryml +0 -341
data/hobo_files/plugin/init.rb
CHANGED
@@ -24,15 +24,6 @@ module ActiveRecord::Associations
|
|
24
24
|
end
|
25
25
|
|
26
26
|
|
27
|
-
def include?(record)
|
28
|
-
if loaded?
|
29
|
-
target.include?(record)
|
30
|
-
else
|
31
|
-
(r = find(record.id)) && r == record rescue false
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
27
|
def member_class
|
37
28
|
proxy_reflection.klass
|
38
29
|
end
|
@@ -2,16 +2,6 @@ module ActiveRecord::Associations
|
|
2
2
|
|
3
3
|
class HasManyThroughAssociation
|
4
4
|
|
5
|
-
def include?(record)
|
6
|
-
return false unless record.is_a? ActiveRecord::Base
|
7
|
-
|
8
|
-
if loaded?
|
9
|
-
target.include?(record)
|
10
|
-
else
|
11
|
-
!!find_by_id(record.id)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
5
|
def member_class
|
16
6
|
proxy_reflection.klass
|
17
7
|
end
|
@@ -47,7 +47,7 @@ module Hobo
|
|
47
47
|
|
48
48
|
def models
|
49
49
|
unless @models_loaded
|
50
|
-
Dir.entries("#{RAILS_ROOT}/app/models/").
|
50
|
+
Dir.entries("#{RAILS_ROOT}/app/models/").each do |f|
|
51
51
|
f =~ /^[a-zA-Z_][a-zA-Z0-9_]*\.rb$/ and f.sub(/.rb$/, '').camelize.constantize
|
52
52
|
end
|
53
53
|
@models_loaded = true
|
@@ -111,7 +111,8 @@ module Hobo
|
|
111
111
|
|
112
112
|
def find_by_search(query)
|
113
113
|
sql = Hobo.models.map do |model|
|
114
|
-
if model.superclass == ActiveRecord::Base # filter out STI subclasses
|
114
|
+
if model.superclass == ActiveRecord::Base && # filter out STI subclasses
|
115
|
+
ModelRouter.linkable?(nil, model, :show) # filter out non-linkables
|
115
116
|
cols = model.search_columns
|
116
117
|
if cols.blank?
|
117
118
|
nil
|
@@ -208,54 +209,66 @@ module Hobo
|
|
208
209
|
|
209
210
|
|
210
211
|
def can_edit?(person, object, field)
|
211
|
-
|
212
|
-
return false
|
212
|
+
# Can't view implies can't edit
|
213
|
+
return false if !can_view?(person, object, field)
|
213
214
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
elsif object.has_hobo_method?("#{field}_editable_by?")
|
222
|
-
object.send("#{field}_editable_by?", person)
|
215
|
+
if field.nil?
|
216
|
+
if respond_to?(:editable_by?)
|
217
|
+
object.editable_by?(person)
|
218
|
+
else
|
219
|
+
object.updatable_by?(person, nil)
|
220
|
+
end
|
221
|
+
|
223
222
|
else
|
224
|
-
|
225
|
-
|
223
|
+
setter = "#{field.to_s.sub /\?$/, ''}="
|
224
|
+
return false if !object.respond_to?(setter)
|
226
225
|
|
227
|
-
|
228
|
-
return false if refl._?.macro == :has_many
|
226
|
+
refl = object.class.reflections[field.to_sym] if object.is_a?(ActiveRecord::Base)
|
229
227
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
begin
|
234
|
-
# Setting the undefined value can sometimes result in an
|
235
|
-
# UndefinedAccessError. In that case we have no choice but
|
236
|
-
# return false.
|
237
|
-
new.send(setter, if current == true
|
238
|
-
false
|
239
|
-
elsif current == false
|
240
|
-
true
|
241
|
-
elsif refl and refl.macro == :belongs_to
|
242
|
-
Hobo::Undefined.new(refl.klass)
|
243
|
-
else
|
244
|
-
Hobo::Undefined.new
|
245
|
-
end)
|
246
|
-
rescue Hobo::UndefinedAccessError
|
247
|
-
raise HoboError, ("#{object.class.name}##{field} does not support undefined assignements, " +
|
248
|
-
"define editable_by?(user, field)")
|
249
|
-
end
|
228
|
+
# has_one and polymorphic associations are not editable (for now)
|
229
|
+
return false if refl and (refl.options[:polymorphic] or refl.macro == :has_one)
|
250
230
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
231
|
+
if object.has_hobo_method?("#{field}_editable_by?")
|
232
|
+
object.send("#{field}_editable_by?", person)
|
233
|
+
elsif object.has_hobo_method?(:editable_by?)
|
234
|
+
check_permission(:edit, person, object)
|
235
|
+
else
|
236
|
+
# Fake an edit test by setting the field in question to
|
237
|
+
# Hobo::Undefined and then testing for update permission
|
238
|
+
|
239
|
+
# This technique is not suitable for has_many associations
|
240
|
+
return false if refl._?.macro == :has_many
|
241
|
+
|
242
|
+
current = object.send(field)
|
243
|
+
new = object.duplicate
|
244
|
+
|
245
|
+
begin
|
246
|
+
# Setting the undefined value can sometimes result in an
|
247
|
+
# UndefinedAccessError. In that case we have no choice but
|
248
|
+
# return false.
|
249
|
+
new.send(setter, if current == true
|
250
|
+
false
|
251
|
+
elsif current == false
|
252
|
+
true
|
253
|
+
elsif refl and refl.macro == :belongs_to
|
254
|
+
Hobo::Undefined.new(refl.klass)
|
255
|
+
else
|
256
|
+
Hobo::Undefined.new
|
257
|
+
end)
|
258
|
+
rescue Hobo::UndefinedAccessError
|
259
|
+
raise HoboError, ("#{object.class.name}##{field} does not support undefined assignements, " +
|
260
|
+
"define editable_by?(user, field)")
|
261
|
+
end
|
262
|
+
|
263
|
+
begin
|
264
|
+
if object.new_record?
|
265
|
+
check_permission(:create, person, new)
|
266
|
+
else
|
267
|
+
check_permission(:update, person, object, new)
|
268
|
+
end
|
269
|
+
rescue Hobo::UndefinedAccessError
|
270
|
+
false
|
256
271
|
end
|
257
|
-
rescue Hobo::UndefinedAccessError
|
258
|
-
false
|
259
272
|
end
|
260
273
|
end
|
261
274
|
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'extensions'
|
2
|
+
|
3
|
+
module ::Hobo
|
4
|
+
|
5
|
+
class Bundle
|
6
|
+
|
7
|
+
@bundles = HashWithIndifferentAccess.new
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
attr_accessor :bundles, :plugin
|
12
|
+
|
13
|
+
def inherited(base)
|
14
|
+
filename = caller[0].match(/^(.*):\d+/)[1]
|
15
|
+
dirname = filename.match(%r(^.*/plugins/[^/]+))[0]
|
16
|
+
base.plugin = File.basename(dirname)
|
17
|
+
|
18
|
+
base.meta_eval do
|
19
|
+
attr_accessor :models, :controllers
|
20
|
+
end
|
21
|
+
|
22
|
+
base.models = []
|
23
|
+
base.controllers = []
|
24
|
+
|
25
|
+
eval_ruby_files(base, "#{dirname}/models")
|
26
|
+
eval_ruby_files(base, "#{dirname}/controllers")
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def bundle_model(name, &block)
|
31
|
+
models << [name, block]
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def bundle_model_controller(model_name, &block)
|
36
|
+
controllers << [model_name, block]
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def eval_ruby_files(base, dir)
|
43
|
+
Dir["#{dir}/*.rb"].each do |f|
|
44
|
+
base.instance_eval(File.read(f), f, 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(*args)
|
51
|
+
options = defaults.with_indifferent_access
|
52
|
+
options.update(args.extract_options!)
|
53
|
+
|
54
|
+
self.name = args.first || self.class.name.match(/[^:]+$/)[0].underscore
|
55
|
+
Bundle.bundles[name] = self
|
56
|
+
|
57
|
+
@renames, @options = separate_renames(options)
|
58
|
+
|
59
|
+
includes
|
60
|
+
|
61
|
+
create_models
|
62
|
+
create_controllers
|
63
|
+
|
64
|
+
init
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_accessor :renames, :options, :name
|
68
|
+
|
69
|
+
# optionally overridden by the bundle subclass
|
70
|
+
def includes; end
|
71
|
+
def init; end
|
72
|
+
def defaults; {}; end
|
73
|
+
|
74
|
+
|
75
|
+
def plugin
|
76
|
+
self.class.plugin
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def create_models
|
81
|
+
self.class.models.each do |name, block|
|
82
|
+
klass = make_class(new_name_for(name), ActiveRecord::Base) do
|
83
|
+
hobo_model
|
84
|
+
end
|
85
|
+
klass.class_eval(&block)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def create_controllers
|
91
|
+
bundle = self
|
92
|
+
self.class.controllers.each do |model_name, block|
|
93
|
+
klass = make_class("#{new_name_for(model_name).to_s.pluralize}Controller", ApplicationController) do
|
94
|
+
hobo_model_controller
|
95
|
+
end
|
96
|
+
klass.class_eval(&block)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def make_class(name, base_class, &b)
|
102
|
+
bundle = self
|
103
|
+
klass = Class.new(base_class) do
|
104
|
+
# Nasty hack because blocks can't take blocks
|
105
|
+
# Roll on Ruby 1.9
|
106
|
+
def self.feature(name, &block)
|
107
|
+
_feature(name, block)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
klass.meta_def(:bundle) do
|
112
|
+
bundle
|
113
|
+
end
|
114
|
+
|
115
|
+
klass.meta_def(:_feature) do |feature, block|
|
116
|
+
has_feature = bundle.options[feature]
|
117
|
+
if has_feature
|
118
|
+
define_method("features_#{feature}?") { true }
|
119
|
+
meta_def("features_#{feature}?") { true }
|
120
|
+
block.call if block
|
121
|
+
else
|
122
|
+
define_method("features_#{feature}?") { false }
|
123
|
+
meta_def("features_#{feature}?") { false }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
silence_warnings { Object.const_set(name, klass) }
|
127
|
+
|
128
|
+
klass.meta_def :method_missing do |name, *args|
|
129
|
+
if name.to_s =~ /^_.*_$/
|
130
|
+
bundle.magic_option(name)
|
131
|
+
else
|
132
|
+
super
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
klass.class_eval(&b) if b
|
137
|
+
klass
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
def new_name_for(name)
|
142
|
+
while renames.has_key?(name)
|
143
|
+
name = renames[name]
|
144
|
+
name2 = name.to_s.gsub(/_.*?_/) { |s| new_name_for(s[1..-2]) }
|
145
|
+
|
146
|
+
# Make sure symbols stay symbols
|
147
|
+
name = name.is_a?(Symbol) ? name2.to_sym : name2
|
148
|
+
end
|
149
|
+
name
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def separate_renames(options)
|
154
|
+
simple_options, renames = HashWithIndifferentAccess.new, HashWithIndifferentAccess.new
|
155
|
+
options.each do |k, v|
|
156
|
+
if k.to_s =~ /^[A-Z]/
|
157
|
+
renames[k] = v.to_s
|
158
|
+
renames[k.to_s.underscore] = v.to_s.underscore.to_sym
|
159
|
+
renames[k.to_s.underscore.pluralize] = v.to_s.underscore.pluralize.to_sym
|
160
|
+
else
|
161
|
+
simple_options[k] = v
|
162
|
+
end
|
163
|
+
end
|
164
|
+
[renames, simple_options]
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def customize(name, &block)
|
169
|
+
new_name_for(name).to_s.constantize.class_eval(&block)
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
def method_missing(name, *args)
|
174
|
+
if name.to_s =~ /^_.*_$/
|
175
|
+
magic_option(name)
|
176
|
+
else
|
177
|
+
super
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
# Returns the option value or renamed class name from a 'magic'
|
183
|
+
# name like _foo_ or _MyFoo_
|
184
|
+
def magic_option(name)
|
185
|
+
option_name = name.to_s[1..-2]
|
186
|
+
if option_name == "bundle"
|
187
|
+
self.name
|
188
|
+
elsif options.has_key?(option_name)
|
189
|
+
options[option_name]
|
190
|
+
else
|
191
|
+
new_name_for(option_name)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def optional_bundle(*args)
|
197
|
+
local_options = args.extract_options!
|
198
|
+
class_name, option_name = args
|
199
|
+
option_name ||= class_name.to_s.underscore
|
200
|
+
_include_bundle(class_name, option_name, local_options) if self.options[option_name]
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
def include_bundle(*args)
|
205
|
+
local_options = args.extract_options!
|
206
|
+
class_name, option_name = args
|
207
|
+
option_name ||= class_name.to_s.underscore
|
208
|
+
_include_bundle(class_name, option_name, local_options)
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
def _include_bundle(class_name, option_name, local_options)
|
213
|
+
external_options = self.options[option_name]
|
214
|
+
external_options = {} if external_options.nil? || external_options == true
|
215
|
+
name = "#{self.name}_#{option_name}"
|
216
|
+
class_name.to_s.constantize.new(name, external_options.merge(local_options).merge(renames))
|
217
|
+
self.options["#{option_name}_bundle"] = name
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
@@ -32,12 +32,9 @@ module Hobo
|
|
32
32
|
attr_reader :included_taglibs
|
33
33
|
|
34
34
|
def include_taglib(src, options={})
|
35
|
-
@included_taglibs <<
|
36
|
-
'plugins/' + options[:from_plugin] + '/taglibs/' + src
|
37
|
-
else
|
38
|
-
src.to_s
|
39
|
-
end
|
35
|
+
@included_taglibs << options.merge(:src => src)
|
40
36
|
end
|
37
|
+
|
41
38
|
end
|
42
39
|
|
43
40
|
|
@@ -24,8 +24,8 @@ module Hobo
|
|
24
24
|
|
25
25
|
EMPTY_PAGE = "[tag-page]"
|
26
26
|
|
27
|
-
APPLICATION_TAGLIB = "taglibs/application"
|
28
|
-
CORE_TAGLIB
|
27
|
+
APPLICATION_TAGLIB = { :src => "taglibs/application" }
|
28
|
+
CORE_TAGLIB = { :src => "core", :plugin => "hobo" }
|
29
29
|
|
30
30
|
DEFAULT_IMPORTS = [Hobo::HoboHelper, ApplicationHelper]
|
31
31
|
|
@@ -61,10 +61,11 @@ module Hobo
|
|
61
61
|
page ||= view.instance_variable_get('@hobo_template_path')
|
62
62
|
|
63
63
|
prepare_view!(view)
|
64
|
-
included_taglibs = ([subsite_taglib(page)] + controller_taglibs(
|
64
|
+
included_taglibs = ([subsite_taglib(page)] + controller_taglibs(view.controller.class)).compact
|
65
65
|
|
66
66
|
if page.ends_with?(EMPTY_PAGE)
|
67
|
-
controller_class = controller_class_for(page)
|
67
|
+
# DELETE ME: controller_class = controller_class_for(page)
|
68
|
+
controller_class = view.controller.class
|
68
69
|
@tag_page_renderer_classes[controller_class.name] ||=
|
69
70
|
make_renderer_class("", page, local_names, DEFAULT_IMPORTS, included_taglibs)
|
70
71
|
@tag_page_renderer_classes[controller_class.name].new(page, view)
|
@@ -87,14 +88,14 @@ module Hobo
|
|
87
88
|
end
|
88
89
|
|
89
90
|
|
91
|
+
# TODO: Delete this - not needed (use view.controller.class)
|
90
92
|
def controller_class_for(page)
|
91
93
|
controller, view = Controller.controller_and_view_for(page)
|
92
94
|
"#{controller.camelize}Controller".constantize
|
93
95
|
end
|
94
96
|
|
95
97
|
|
96
|
-
def controller_taglibs(
|
97
|
-
controller_class = controller_class_for(page)
|
98
|
+
def controller_taglibs(controller_class)
|
98
99
|
(controller_class.respond_to?(:included_taglibs) && controller_class.included_taglibs) || []
|
99
100
|
end
|
100
101
|
|
@@ -103,7 +104,7 @@ module Hobo
|
|
103
104
|
parts = page.split("/")
|
104
105
|
if parts.length == 3
|
105
106
|
subsite = parts.first
|
106
|
-
"taglibs/#{subsite}" if File.exists?("#{RAILS_ROOT}/app/views/taglibs/#{subsite}.dryml")
|
107
|
+
{ :src => "taglibs/#{subsite}" } if File.exists?("#{RAILS_ROOT}/app/views/taglibs/#{subsite}.dryml")
|
107
108
|
end
|
108
109
|
end
|
109
110
|
|