hobo 0.7.2 → 0.7.3

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.
Files changed (77) hide show
  1. data/bin/hobo +24 -7
  2. data/hobo_files/plugin/CHANGES.txt +501 -0
  3. data/hobo_files/plugin/generators/hobo/hobo_generator.rb +8 -6
  4. data/hobo_files/plugin/generators/hobo/templates/application.dryml +3 -0
  5. data/hobo_files/plugin/generators/hobo/templates/dryml-support.js +132 -0
  6. data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +4 -5
  7. data/hobo_files/plugin/generators/hobo_model_resource/hobo_model_resource_generator.rb +75 -0
  8. data/hobo_files/plugin/generators/hobo_model_resource/templates/controller.rb +7 -0
  9. data/hobo_files/plugin/generators/hobo_model_resource/templates/functional_test.rb +8 -0
  10. data/hobo_files/plugin/generators/hobo_model_resource/templates/helper.rb +2 -0
  11. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +30 -11
  12. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +149 -92
  13. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +0 -48
  14. data/hobo_files/plugin/init.rb +45 -13
  15. data/hobo_files/plugin/lib/action_view_extensions/base.rb +4 -3
  16. data/hobo_files/plugin/lib/active_record/association_proxy.rb +18 -0
  17. data/hobo_files/plugin/lib/active_record/association_reflection.rb +5 -0
  18. data/hobo_files/plugin/lib/active_record/has_many_association.rb +7 -11
  19. data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +8 -0
  20. data/hobo_files/plugin/lib/extensions/test_case.rb +1 -1
  21. data/hobo_files/plugin/lib/hobo.rb +38 -60
  22. data/hobo_files/plugin/lib/hobo/authentication_support.rb +1 -1
  23. data/hobo_files/plugin/lib/hobo/bundle.rb +131 -34
  24. data/hobo_files/plugin/lib/hobo/composite_model.rb +1 -1
  25. data/hobo_files/plugin/lib/hobo/controller.rb +7 -8
  26. data/hobo_files/plugin/lib/hobo/dev_controller.rb +21 -0
  27. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +14 -8
  28. data/hobo_files/plugin/lib/hobo/dryml/dryml_support_controller.rb +13 -0
  29. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +6 -7
  30. data/hobo_files/plugin/lib/hobo/dryml/template.rb +207 -73
  31. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +67 -55
  32. data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +53 -3
  33. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +75 -107
  34. data/hobo_files/plugin/lib/hobo/model.rb +236 -429
  35. data/hobo_files/plugin/lib/hobo/model_controller.rb +277 -437
  36. data/hobo_files/plugin/lib/hobo/model_router.rb +62 -29
  37. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +48 -9
  38. data/hobo_files/plugin/lib/hobo/scopes.rb +98 -0
  39. data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +31 -0
  40. data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +282 -0
  41. data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +88 -0
  42. data/hobo_files/plugin/lib/hobo/scopes/scope_reflection.rb +18 -0
  43. data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +59 -0
  44. data/hobo_files/plugin/lib/hobo/undefined.rb +2 -0
  45. data/hobo_files/plugin/lib/hobo/user.rb +31 -14
  46. data/hobo_files/plugin/lib/hobo/user_controller.rb +41 -27
  47. data/hobo_files/plugin/taglibs/core.dryml +9 -11
  48. data/hobo_files/plugin/taglibs/rapid.dryml +51 -108
  49. data/hobo_files/plugin/taglibs/rapid_editing.dryml +25 -25
  50. data/hobo_files/plugin/taglibs/rapid_forms.dryml +111 -79
  51. data/hobo_files/plugin/taglibs/rapid_generics.dryml +74 -0
  52. data/hobo_files/plugin/taglibs/rapid_navigation.dryml +23 -21
  53. data/hobo_files/plugin/taglibs/rapid_pages.dryml +83 -169
  54. data/hobo_files/plugin/taglibs/rapid_plus.dryml +16 -2
  55. data/hobo_files/plugin/taglibs/rapid_support.dryml +3 -3
  56. data/hobo_files/plugin/taglibs/rapid_user_pages.dryml +104 -0
  57. metadata +60 -55
  58. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +0 -276
  59. data/hobo_files/plugin/generators/hobo_migration/templates/migration.rb +0 -9
  60. data/hobo_files/plugin/lib/active_record/table_definition.rb +0 -34
  61. data/hobo_files/plugin/lib/extensions.rb +0 -375
  62. data/hobo_files/plugin/lib/hobo/email_address.rb +0 -12
  63. data/hobo_files/plugin/lib/hobo/enum_string.rb +0 -50
  64. data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +0 -43
  65. data/hobo_files/plugin/lib/hobo/field_spec.rb +0 -68
  66. data/hobo_files/plugin/lib/hobo/html_string.rb +0 -7
  67. data/hobo_files/plugin/lib/hobo/lazy_hash.rb +0 -40
  68. data/hobo_files/plugin/lib/hobo/markdown_string.rb +0 -11
  69. data/hobo_files/plugin/lib/hobo/migrations.rb +0 -12
  70. data/hobo_files/plugin/lib/hobo/model_queries.rb +0 -117
  71. data/hobo_files/plugin/lib/hobo/password_string.rb +0 -7
  72. data/hobo_files/plugin/lib/hobo/percentage.rb +0 -14
  73. data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +0 -78
  74. data/hobo_files/plugin/lib/hobo/proc_binding.rb +0 -32
  75. data/hobo_files/plugin/lib/hobo/text.rb +0 -3
  76. data/hobo_files/plugin/lib/hobo/textile_string.rb +0 -25
  77. data/hobo_files/plugin/lib/hobo/where_fragment.rb +0 -28
@@ -52,12 +52,45 @@ module Hobo::Dryml
52
52
  attr_accessor
53
53
 
54
54
  for attr in [:erb_binding, :part_contexts, :view_name,
55
- :this, :this_parent, :this_field, :this_type,
55
+ :this, :this_parent, :this_field,
56
56
  :form_field_path, :form_this, :form_field_names]
57
57
  class_eval "def #{attr}; @_#{attr}; end"
58
58
  end
59
59
 
60
60
 
61
+ # The type of this, or when this is nil, the type that would be expected in the current field
62
+ def this_type
63
+ @_this_type ||= if this == false || this == true
64
+ Hobo::Boolean
65
+ elsif this
66
+ this.class
67
+ elsif this_parent && this_field && (parent_class = this_parent.class).respond_to?(:attr_type)
68
+ type = parent_class.attr_type(this_field)
69
+ if type.is_a?(ActiveRecord::Reflection::AssociationReflection)
70
+ reflection = type
71
+ if reflection.macro == :has_many
72
+ Array
73
+ elsif reflection.options[:polymorphic]
74
+ # All we know is that it will be some active-record type
75
+ ActiveRecord::Base
76
+ else
77
+ reflection.klass
78
+ end
79
+ else
80
+ type
81
+ end
82
+ else
83
+ # Nothing to go on at all
84
+ Object
85
+ end
86
+ end
87
+
88
+
89
+ def this_field_reflection
90
+ this_parent && this_field && this_parent.class.respond_to?(:reflections) && this_parent.class.reflections[this_field.to_sym]
91
+ end
92
+
93
+
61
94
  def attrs_for(name)
62
95
  self.class.tag_attrs[name.to_sym]
63
96
  end
@@ -95,51 +128,50 @@ module Hobo::Dryml
95
128
  end
96
129
 
97
130
 
98
- def this_field_dom_id
99
- if this_parent && this_field
100
- Hobo.dom_id(this_parent, this_field)
101
- else
102
- Hobo.dom_id(this)
131
+ def dom_id(object=nil, attribute=nil)
132
+ if object.nil?
133
+ # nothing passed -- use context
134
+ if this_parent && this_field
135
+ object, attribute = this_parent, this_field
136
+ else
137
+ object = this
138
+ end
103
139
  end
104
- end
105
-
106
-
107
- def context_id
108
- if this_parent and this_parent.is_a?(ActiveRecord::Base) and this_field
109
- this_field_dom_id
110
- elsif this.respond_to?(:typed_id)
111
- this.typed_id
112
- elsif this.is_a?(Array) and !this.respond_to?(:proxy_reflection)
113
- "nil"
140
+
141
+ id = object.try.typed_id
142
+ if id
143
+ attribute ? "#{id}_#{attribute}" : id
114
144
  else
115
- Hobo.dom_id(this)
145
+ "nil"
116
146
  end
117
147
  end
118
-
119
148
 
120
- def call_part(dom_id, part_name, part_this=nil, *locals)
149
+
150
+ def call_part(part_node_id, part_name, part_this=nil, *locals)
121
151
  res = ''
122
152
  if part_this
123
153
  new_object_context(part_this) do
124
- @_part_contexts[dom_id] = PartContext.new(part_name, context_id, locals)
154
+ @_part_contexts[part_node_id] = PartContext.new(part_name, dom_id, locals)
125
155
  res = send("#{part_name}_part", *locals)
126
156
  end
127
157
  else
128
158
  new_context do
129
- @_part_contexts[dom_id] = PartContext.new(part_name, context_id, locals)
159
+ @_part_contexts[part_node_id] = PartContext.new(part_name, dom_id, locals)
130
160
  res = send("#{part_name}_part", *locals)
131
161
  end
132
162
  end
133
163
  res
134
164
  end
165
+
135
166
 
136
167
  def call_polymorphic_tag(name, *args)
168
+ name = name.to_s.gsub('-', '_')
137
169
  type = args.first.is_a?(Class) ? args.shift : nil
138
170
  attributes, parameters = args
139
171
 
140
172
  tag = find_polymorphic_tag(name, type)
141
173
  if tag != name
142
- send(tag, attributes, parameters || {})
174
+ send(tag, attributes || {}, parameters || {})
143
175
  else
144
176
  nil
145
177
  end
@@ -147,18 +179,7 @@ module Hobo::Dryml
147
179
 
148
180
 
149
181
  def find_polymorphic_tag(name, call_type=nil)
150
- call_type ||= case this_type
151
- when ActiveRecord::Reflection::AssociationReflection
152
- # Don't blow up with non-existent polymorphic types
153
- return name if this_type.options[:polymorphic] && !Object.const_defined?(this_type.class_name)
154
- this_type.klass
155
- when Array
156
- this.member_class
157
- else
158
- this_type
159
- end
160
-
161
- call_type = TrueClass if call_type == FalseClass
182
+ call_type ||= (this.is_a?(Array) && this.respond_to?(:member_class) && this.try.member_class) || this_type
162
183
 
163
184
  while true
164
185
  if call_type == ActiveRecord::Base || call_type == Object
@@ -192,8 +213,9 @@ module Hobo::Dryml
192
213
  def new_context
193
214
  ctx = [ @_erb_output,
194
215
  @_this, @_this_parent, @_this_field, @_this_type,
195
- @_form_field_path]
216
+ @_form_field_path ]
196
217
  @_erb_output = ""
218
+ @_this_type = nil
197
219
  res = yield
198
220
  @_erb_output, @_this, @_this_parent, @_this_field, @_this_type, @_form_field_path = ctx
199
221
  res.to_s
@@ -202,14 +224,7 @@ module Hobo::Dryml
202
224
 
203
225
  def new_object_context(new_this)
204
226
  new_context do
205
- @_this_parent,@_this_field,@_this_type = if new_this.respond_to?(:proxy_reflection)
206
- refl = new_this.proxy_reflection
207
- [new_this.proxy_owner, refl.name, refl]
208
- else
209
- # In dryml, TrueClass is the 'boolean' class
210
- t = new_this.class == FalseClass ? TrueClass : new_this.class
211
- [nil, nil, t]
212
- end
227
+ @_this_parent, @_this_field = [new_this.origin, new_this.origin_attribute] if new_this.respond_to?(:origin)
213
228
  @_this = new_this
214
229
  yield
215
230
  end
@@ -226,17 +241,7 @@ module Hobo::Dryml
226
241
  [field_path]
227
242
  end
228
243
  parent, field, obj = Hobo.get_field_path(tag_this || this, path)
229
-
230
- type = if parent.class.respond_to?(:field_type) && field_type = parent.class.field_type(field)
231
- field_type
232
- elsif obj == false
233
- # In dryml, TrueClass is the 'boolean' class
234
- TrueClass
235
- else
236
- obj.class
237
- end
238
-
239
- @_this, @_this_parent, @_this_field, @_this_type = obj, parent, field, type
244
+ @_this, @_this_parent, @_this_field = obj, parent, field
240
245
  @_form_field_path += path if @_form_field_path
241
246
  yield
242
247
  end
@@ -432,7 +437,14 @@ module Hobo::Dryml
432
437
  def render_tag(tag_name, attributes)
433
438
  method_name = tag_name.gsub('-', '_')
434
439
  if respond_to?(method_name)
435
- (send(method_name, attributes) + part_contexts_storage_tag).strip
440
+ res = (send(method_name, attributes) + part_contexts_storage_tag).strip
441
+
442
+ # TODO: Temporary hack to get the dryml metadata comments in the right place
443
+ if RAILS_ENV == "development"
444
+ res.gsub(/^(.*?)(<!DOCTYPE.*?>).*?(<html.*?>)/m, "\\2\\3\\1")
445
+ else
446
+ res
447
+ end
436
448
  else
437
449
  false
438
450
  end
@@ -8,12 +8,62 @@ module Hobo::Dryml
8
8
 
9
9
  def render(src, local_assigns)
10
10
  renderer = Hobo::Dryml.page_renderer(@view, local_assigns.keys)
11
- s = renderer.render_page(@view.assigns["this"] || local_assigns[:this], local_assigns)
12
- # Important to strip whitespace, or the browser hangs around for ages (FF2)
11
+ this = @view.instance_variable_set("@this", @view.controller.send(:dryml_context) || local_assigns[:this])
12
+ s = renderer.render_page(this, local_assigns)
13
13
 
14
- s.strip
14
+ # Important to strip whitespace, or the browser hangs around for ages (FF2)
15
+ s = s.strip
16
+
17
+ # TODO: Temporary hack to get the dryml metadata comments in the right place
18
+ if RAILS_ENV == "development"
19
+ s.gsub(/^(.*?)(<!DOCTYPE.*?>).*?(<html.*?>)/m, "\\2\\3\\1")
20
+ else
21
+ s
22
+ end
15
23
  end
16
24
 
17
25
  end
18
26
 
19
27
  end
28
+
29
+ module ActionController
30
+
31
+
32
+ class Base
33
+
34
+ def dryml_context
35
+ @this
36
+ end
37
+
38
+ def dryml_fallback_tag(tag_name)
39
+ @dryml_fallback_tag = tag_name
40
+ end
41
+
42
+ def render_tag(tag, options={}, render_options={})
43
+ add_variables_to_assigns
44
+
45
+ if options[:with]
46
+ @this = options[:with] unless options[:field]
47
+ else
48
+ options[:with] = dryml_context
49
+ end
50
+
51
+ text = Hobo::Dryml.render_tag(@template, tag, options)
52
+ text && render({:text => text, :layout => false }.merge(render_options))
53
+ end
54
+
55
+ def render_for_file_with_dryml(template_path, *args)
56
+ if template_path !~ /^\// && # not an absolute path (e.g. an exception ERB template)
57
+ !template_exists?(template_path) && # no template available in app/views
58
+ tag_name = @dryml_fallback_tag || "#{File.basename(template_path).dasherize}-page"
59
+
60
+ # The template was missing, try to use a DRYML <page> tag instead
61
+ render_tag(tag_name) or raise ActionController::MissingTemplate, "Missing template #{template_path}.html.erb in view path #{RAILS_ROOT}/app/views"
62
+ else
63
+ render_for_file_without_dryml(template_path, *args)
64
+ end
65
+ end
66
+ alias_method_chain :render_for_file, :dryml
67
+
68
+ end
69
+ end
@@ -40,66 +40,51 @@ module Hobo
40
40
  def subsite
41
41
  params[:controller].match(/([^\/]+)\//)._?[1]
42
42
  end
43
+
44
+
45
+ IMPLICIT_ACTIONS = [:index, :show, :create, :update, :destroy]
43
46
 
44
-
45
- def object_url(*args)
47
+ def object_url(obj, *args)
46
48
  params = args.extract_options!
47
- obj, action = args
48
- action &&= action.to_s
49
-
50
- controller_name = controller_for(obj)
51
-
52
- subsite = params[:subsite] || self.subsite
49
+ action = args.first._?.to_sym
50
+ options, params = params.partition_hash([:subsite, :method, :format])
51
+ options[:subsite] ||= self.subsite
53
52
 
54
- # TODO - what if you want if_available as a query param?
55
- if_available = params.delete(:if_available)
56
- return nil if if_available &&
57
- ((action.nil? && obj.respond_to?(:typed_id) && !linkable?(obj.class, :show, :subsite => subsite)) ||
58
- (action.nil? && obj.is_a?(Class) && !linkable?(obj, :index, :subsite => subsite)))
59
-
60
- base = subsite.blank? ? base_url : "/#{subsite}#{base_url}"
61
-
62
- parts = if obj.is_a? Class
63
- [base, controller_name]
64
-
65
- elsif obj.is_a? Hobo::CompositeModel
66
- [base, controller_name, obj.to_param]
67
-
68
- elsif obj.is_a? ActiveRecord::Base
69
- if obj.new_record?
70
- [base, controller_name]
71
- else
72
- raise HoboError.new("invalid object url: new for existing object") if action == "new"
73
-
74
- klass = obj.class
75
- id = if klass.id_name?
76
- obj.id_name(true)
77
- else
78
- obj.to_param
79
- end
80
-
81
- [base, controller_name, id]
82
- end
83
-
84
- elsif obj.is_a? Array # warning - this breaks if we use `case/when Array`
85
- owner = obj.proxy_owner
86
- new_model = obj.proxy_reflection.klass
87
- [object_url(owner), obj.proxy_reflection.name]
88
-
89
- else
90
- raise HoboError.new("cannot create url for #{obj.inspect} (#{obj.class})")
91
- end
92
- url = parts.join("/")
53
+ if obj.respond_to?(:origin)
54
+ # Asking for URL of a collection, e.g. category/1/adverts or category/1/adverts/new
55
+ if action == :new
56
+ action_path = "#{obj.origin_attribute}/new"
57
+ action = "new_#{obj.origin_attribute.to_s.singularize}"
58
+ elsif action.nil?
59
+ action = obj.origin_attribute
60
+ end
61
+ obj = obj.origin
62
+
63
+ else
64
+ action ||= case options[:method].to_s
65
+ when 'put'; :update
66
+ when 'post'; :create
67
+ when 'delete'; :destroy
68
+ else; obj.is_a?(Class) ? :index : :show
69
+ end
93
70
 
94
- case action
95
- when nil # do nothing
96
- when "destroy" then params["_method"] = "DELETE"
97
- when "update" then params["_method"] = "PUT"
98
- else url += "/#{action}"
71
+ if action == :create && obj.try.new_record?
72
+ # Asking for url to post new record to
73
+ obj = obj.class
74
+ end
99
75
  end
76
+
77
+ klass = obj.is_a?(Class) ? obj : obj.class
78
+ if Hobo::ModelRouter.linkable?(klass, action, options)
79
+
80
+ path = obj.to_url_path or HoboError.new("cannot create url for #{obj.inspect} (#{obj.class})")
81
+ url = "#{base_url}#{'/' + subsite unless subsite.blank?}/#{path}"
100
82
 
101
- params = make_params(params - [:subsite])
102
- params.blank? ? url : "#{url}?#{params}"
83
+ url += "/#{action_path || action}" unless action.in?(IMPLICIT_ACTIONS)
84
+
85
+ params = make_params(params)
86
+ params.blank? ? url : "#{url}?#{params}"
87
+ end
103
88
  end
104
89
 
105
90
 
@@ -127,31 +112,16 @@ module Hobo
127
112
  hash.map {|k,v| _as_params(k, v)}.join("&")
128
113
  end
129
114
 
130
-
131
- def dom_id(*args)
132
- if args.length == 0
133
- Hobo.dom_id(this)
134
- else
135
- Hobo.dom_id(*args)
136
- end
137
- rescue ArgumentError
138
- ""
139
- end
140
-
141
115
 
142
116
  def type_id(type=nil)
143
- type ||= this.is_a?(Class) ? this : this_type
144
- type == NilClass ? "" : Hobo.type_id(type || this.class)
117
+ type ||= (this.is_a?(Class) && this) || this_type || this.class
118
+ HoboFields.to_name(type) || type.name.underscore.gsub("/", "__")
145
119
  end
146
-
120
+
147
121
 
148
122
  def type_and_field(*args)
149
- if args.empty?
150
- this_parent && this_field && "#{Hobo.type_id(this_parent.class)}_#{this_field}"
151
- else
152
- type, field = args
153
- "#{Hobo.type_id(type)}_#{field}"
154
- end
123
+ type, field = args.empty? ? [this_parent.class, this_field] : args
124
+ "#{type.typed_id}_#{field}" if type.respond_to?(:typed_id)
155
125
  end
156
126
 
157
127
 
@@ -203,8 +173,8 @@ module Hobo
203
173
  else
204
174
  object, field = args.length == 2 ? args : [this, args.first]
205
175
 
206
- if !field and object.respond_to?(:proxy_reflection)
207
- Hobo.can_edit?(current_user, object.proxy_owner, object.proxy_reflection.name)
176
+ if !field && object.respond_to?(:origin)
177
+ Hobo.can_edit?(current_user, object.origin, object.origin_attribute)
208
178
  else
209
179
  Hobo.can_edit?(current_user, object, field)
210
180
  end
@@ -225,12 +195,14 @@ module Hobo
225
195
  object = this
226
196
  end
227
197
  end
228
-
229
- if !field and object.respond_to?(:proxy_reflection)
230
- Hobo.can_view?(current_user, object.proxy_owner, object.proxy_reflection.name)
231
- else
232
- Hobo.can_view?(current_user, object, field)
233
- end
198
+
199
+ @can_view_cache ||= {}
200
+ @can_view_cache[ [object, field] ] ||=
201
+ if !field && object.respond_to?(:origin)
202
+ Hobo.can_view?(current_user, object.origin, object.origin_attribute)
203
+ else
204
+ Hobo.can_view?(current_user, object, field)
205
+ end
234
206
  end
235
207
 
236
208
 
@@ -272,8 +244,8 @@ module Hobo
272
244
 
273
245
  def param_name_for_this(foreign_key=false)
274
246
  return "" unless form_this
275
- name = if foreign_key and this_type.respond_to?(:macro) and this_type.macro == :belongs_to
276
- param_name_for(form_this, form_field_path[0..-2] + [this_type.primary_key_name])
247
+ name = if foreign_key && (refl = this_field_reflection) && refl.macro == :belongs_to
248
+ param_name_for(form_this, form_field_path[0..-2] + [refl.primary_key_name])
277
249
  else
278
250
  param_name_for(form_this, form_field_path)
279
251
  end
@@ -282,21 +254,10 @@ module Hobo
282
254
  end
283
255
 
284
256
 
285
- def selector_type
286
- if this.is_a? ActiveRecord::Base
287
- this.class
288
- elsif this.respond_to? :member_class
289
- this.member_class
290
- elsif this == @this
291
- @model
292
- end
293
- end
294
-
295
-
296
257
  def transpose_with_field(field, collection=nil)
297
258
  collection ||= this
298
259
  matrix = collection.map {|obj| obj.send(field) }
299
- max_length = matrix.every(:length).max
260
+ max_length = matrix.*.length.max
300
261
  matrix = matrix.map do |a|
301
262
  a + [nil] * (max_length - a.length)
302
263
  end
@@ -306,9 +267,7 @@ module Hobo
306
267
 
307
268
  def new_for_current_user(model_or_assoc=nil)
308
269
  model_or_assoc ||= this
309
- record = model_or_assoc.new
310
- record.set_creator(current_user)
311
- record
270
+ model_or_assoc.user_new(current_user)
312
271
  end
313
272
 
314
273
 
@@ -338,8 +297,12 @@ module Hobo
338
297
 
339
298
 
340
299
  # Sign-up url for a given user record or user class
341
- def signup_url(user_or_class)
342
- c = user_or_class.is_a?(Class) ? user_or_class : user_or_class.class
300
+ def signup_url(user_or_class=nil)
301
+ c = case user_or_class
302
+ when Class; user_or_class
303
+ when nil; Hobo::User.default_user_model
304
+ else user_or_class
305
+ end
343
306
  send("#{c.name.underscore}_signup_url") rescue nil
344
307
  end
345
308
 
@@ -366,23 +329,28 @@ module Hobo
366
329
  target = args.empty? || args.first.is_a?(Symbol) ? this : args.shift
367
330
  action = args.first
368
331
 
369
- if target.is_a?(Class)
332
+ if (origin = target.try.origin)
333
+ klass = origin.class
334
+ action = if action == :new
335
+ "new_#{target.origin_attribute.to_s.singularize}"
336
+ elsif action.nil?
337
+ target.origin_attribute
338
+ end
339
+ elsif target.is_a?(Class)
370
340
  klass = target
371
341
  action ||= :index
372
- elsif target.respond_to?(:member_class)
373
- klass = target.member_class
374
- action ||= :show
375
342
  else
376
343
  klass = target.class
377
344
  action ||= :show
378
345
  end
379
346
 
380
- Hobo::ModelRouter.linkable?(subsite, klass, action.to_sym)
347
+ Hobo::ModelRouter.linkable?(klass, action, options.reverse_merge(:subsite => subsite))
381
348
  end
382
349
 
383
350
 
384
351
  # Convenience helper for the default app
385
352
 
353
+ # FIXME: this should interrogate the routes to find index methods, not the models
386
354
  def front_models
387
355
  Hobo.models.select {|m| linkable?(m) && !(m < Hobo::User)}
388
356
  end
@@ -398,7 +366,7 @@ module Hobo
398
366
  def log_debug(*args)
399
367
  logger.debug("\n### DRYML Debug ###")
400
368
  logger.debug(args.map {|a| PP.pp(a, "")}.join("-------\n"))
401
- logger.debug("DRYML THIS = #{Hobo.dom_id(this) rescue this.inspect}")
369
+ logger.debug("DRYML THIS = #{this.typed_id rescue this.inspect}")
402
370
  logger.debug("###################\n")
403
371
  args.first unless args.empty?
404
372
  end