hobo 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGES.txt +41 -0
  2. data/Manifest +1 -5
  3. data/Rakefile +10 -3
  4. data/bin/hobo +38 -15
  5. data/dryml_generators/rapid/cards.dryml.erb +7 -7
  6. data/dryml_generators/rapid/pages.dryml.erb +52 -24
  7. data/hobo.gemspec +42 -322
  8. data/init.rb +0 -7
  9. data/lib/active_record/association_collection.rb +9 -0
  10. data/lib/hobo.rb +13 -14
  11. data/lib/hobo/accessible_associations.rb +32 -7
  12. data/lib/hobo/authentication_support.rb +1 -1
  13. data/lib/hobo/controller.rb +5 -7
  14. data/lib/hobo/dryml.rb +9 -2
  15. data/lib/hobo/dryml/dryml_builder.rb +11 -12
  16. data/lib/hobo/dryml/dryml_doc.rb +22 -24
  17. data/lib/hobo/dryml/dryml_generator.rb +41 -4
  18. data/lib/hobo/dryml/part_context.rb +5 -3
  19. data/lib/hobo/dryml/template.rb +7 -7
  20. data/lib/hobo/dryml/template_environment.rb +11 -22
  21. data/lib/hobo/dryml/template_handler.rb +94 -25
  22. data/lib/hobo/find_for.rb +2 -2
  23. data/lib/hobo/hobo_helper.rb +21 -21
  24. data/lib/hobo/include_in_save.rb +9 -5
  25. data/lib/hobo/lifecycles/transition.rb +2 -2
  26. data/lib/hobo/model.rb +11 -61
  27. data/lib/hobo/model_controller.rb +28 -29
  28. data/lib/hobo/model_router.rb +12 -13
  29. data/lib/hobo/permissions.rb +47 -37
  30. data/lib/hobo/permissions/associations.rb +1 -1
  31. data/lib/hobo/scopes/association_proxy_extensions.rb +5 -6
  32. data/lib/hobo/scopes/automatic_scopes.rb +7 -4
  33. data/lib/hobo/tasks/rails.rb +4 -0
  34. data/lib/hobo/user.rb +0 -1
  35. data/lib/hobo/user_controller.rb +3 -1
  36. data/lib/hobo/view_hints.rb +17 -3
  37. data/rails_generators/hobo/hobo_generator.rb +1 -0
  38. data/rails_generators/hobo_front_controller/templates/functional_test.rb +1 -11
  39. data/rails_generators/hobo_front_controller/templates/index.dryml +1 -6
  40. data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
  41. data/rails_generators/hobo_rapid/templates/hobo-rapid.css +3 -2
  42. data/rails_generators/hobo_rapid/templates/hobo-rapid.js +24 -15
  43. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +17 -12
  44. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +6 -2
  45. data/rails_generators/hobo_rapid/templates/themes/clean/views/clean.dryml +2 -2
  46. data/rails_generators/hobo_user_model/templates/forgot_password.erb +2 -2
  47. data/rails_generators/hobo_user_model/templates/model.rb +2 -2
  48. data/taglibs/rapid.dryml +3 -2
  49. data/taglibs/rapid_core.dryml +21 -16
  50. data/taglibs/rapid_document_tags.dryml +1 -1
  51. data/taglibs/rapid_editing.dryml +7 -10
  52. data/taglibs/rapid_forms.dryml +115 -26
  53. data/taglibs/rapid_generics.dryml +13 -3
  54. data/taglibs/rapid_lifecycles.dryml +18 -1
  55. data/taglibs/rapid_navigation.dryml +50 -61
  56. data/taglibs/rapid_pages.dryml +103 -19
  57. data/taglibs/rapid_plus.dryml +54 -6
  58. data/taglibs/rapid_support.dryml +38 -1
  59. data/taglibs/rapid_user_pages.dryml +17 -5
  60. data/test/permissions/models/models.rb +24 -12
  61. data/test/permissions/models/test.sqlite3 +0 -0
  62. metadata +6 -15
  63. data/lib/extensions/test_case.rb +0 -129
  64. data/lib/hobo/composite_model.rb +0 -73
  65. data/lib/hobo/model_support.rb +0 -44
  66. data/tasks/fix_dryml.rake +0 -143
  67. data/tasks/generate_tag_reference.rake +0 -192
  68. data/test/dryml/complilation_test.rb +0 -261
@@ -193,7 +193,7 @@ module Hobo::Dryml
193
193
  def set_element(el)
194
194
  assigns = el.attributes.map do |name, value|
195
195
  next if name.in?(SPECIAL_ATTRIBUTES)
196
- dryml_exception("invalid name in <set>", el) unless name =~ /^#{DRYML_NAME}(\.#{DRYML_NAME})*$/
196
+ dryml_exception("invalid name in <set> (remember to use '-' rather than '_')", el) unless name =~ /^#{DRYML_NAME}(\.#{DRYML_NAME})*$/
197
197
  "#{ruby_name name} = #{attribute_to_ruby(value)}; "
198
198
  end.join
199
199
  code = apply_control_attributes("begin; #{assigns}; end", el)
@@ -203,7 +203,7 @@ module Hobo::Dryml
203
203
 
204
204
  def set_scoped_element(el)
205
205
  variables = el.attributes.map do |name, value|
206
- dryml_exception("invalid name in <set-scoped>", el) unless name =~ DRYML_NAME_RX
206
+ dryml_exception("invalid name in <set-scoped> (remember to use '-' rather than '_')", el) unless name =~ DRYML_NAME_RX
207
207
  ":#{ruby_name name} => #{attribute_to_ruby(value)} "
208
208
  end
209
209
  "<% scope.new_scope(#{variables * ', '}) { #{tag_newlines(el)} %>#{children_to_erb(el)}<% } %>"
@@ -367,7 +367,7 @@ module Hobo::Dryml
367
367
  # reproduce any line breaks in the start-tag so that line numbers are preserved
368
368
  tag_newlines(el) + "%>" +
369
369
  wrap_tag_method_body_with_metadata(children_to_erb(el)) +
370
- "<% _erbout; end"
370
+ "<% output_buffer; end"
371
371
  end
372
372
 
373
373
 
@@ -576,7 +576,7 @@ module Hobo::Dryml
576
576
  end
577
577
 
578
578
  call = apply_control_attributes(call, el)
579
- call = maybe_make_part_call(el, "<% _output(#{call}) %>")
579
+ call = maybe_make_part_call(el, "<% concat(#{call}) %>")
580
580
  wrap_tag_call_with_metadata(el, call)
581
581
  end
582
582
 
@@ -678,7 +678,7 @@ module Hobo::Dryml
678
678
  def before_parameter_tag_hash_item(name, el, metadata_name)
679
679
  param_name = get_param_name(el)
680
680
  dryml_exception("param declaration not allowed on 'before' parameters", el) if param_name
681
- content = children_to_erb(el) + "<% _output(#{param_restore_local_name(name)}.call({}, {})) %>"
681
+ content = children_to_erb(el) + "<% concat(#{param_restore_local_name(name)}.call({}, {})) %>"
682
682
  ":#{ruby_name name}_replacement => #{replace_parameter_proc(el, metadata_name, content)}"
683
683
  end
684
684
 
@@ -686,7 +686,7 @@ module Hobo::Dryml
686
686
  def after_parameter_tag_hash_item(name, el, metadata_name)
687
687
  param_name = get_param_name(el)
688
688
  dryml_exception("param declaration not allowed on 'after' parameters", el) if param_name
689
- content = "<% _output(#{param_restore_local_name(name)}.call({}, {})) %>" + children_to_erb(el)
689
+ content = "<% concat(#{param_restore_local_name(name)}.call({}, {})) %>" + children_to_erb(el)
690
690
  ":#{ruby_name name}_replacement => #{replace_parameter_proc(el, metadata_name, content)}"
691
691
  end
692
692
 
@@ -851,7 +851,7 @@ module Hobo::Dryml
851
851
  end
852
852
 
853
853
  output_tag = "element(:#{el.name}, #{attrs}, new_context { %>#{body}<% })"
854
- "<% _output(" + apply_control_attributes(output_tag, el) + ") %>"
854
+ "<% concat(" + apply_control_attributes(output_tag, el) + ") %>"
855
855
  end
856
856
  end
857
857
 
@@ -240,24 +240,13 @@ module Hobo::Dryml
240
240
  end
241
241
 
242
242
 
243
- def _erbout
244
- @_erb_output
245
- end
246
-
247
-
248
- def _output(s)
249
- @_erb_output.concat(s)
250
- end
251
-
252
-
253
243
  def new_context
254
- ctx = [ @_erb_output,
255
- @_this, @_this_parent, @_this_field, @_this_type,
256
- @_form_field_path ]
257
- @_erb_output = ""
244
+ ctx = [ @_this, @_this_parent, @_this_field, @_this_type,
245
+ @_form_field_path, @_form_field_paths_by_object ]
258
246
  @_this_type = nil
259
- res = yield
260
- @_erb_output, @_this, @_this_parent, @_this_field, @_this_type, @_form_field_path = ctx
247
+ res = nil
248
+ @view.with_output_buffer { res = yield }
249
+ @_this, @_this_parent, @_this_field, @_this_type, @_form_field_path, @_form_field_paths_by_object = ctx
261
250
  res.to_s
262
251
  end
263
252
 
@@ -374,7 +363,7 @@ module Hobo::Dryml
374
363
 
375
364
 
376
365
  def call_tag_parameter_with_default_content(the_tag, attributes, default_content, overriding_content_proc)
377
- if the_tag.is_a?(String, Symbol) && the_tag.to_s.in?(Hobo.static_tags)
366
+ if the_tag.is_one_of?(String, Symbol) && the_tag.to_s.in?(Hobo.static_tags)
378
367
  body = if overriding_content_proc
379
368
  new_context { overriding_content_proc.call(proc { default_content._?.call(nil) }) }
380
369
  elsif default_content
@@ -451,7 +440,7 @@ module Hobo::Dryml
451
440
 
452
441
  default_content = parameters[:default]
453
442
 
454
- if the_tag.is_a?(String, Symbol) && the_tag.to_s.in?(Hobo.static_tags)
443
+ if the_tag.is_one_of?(String, Symbol) && the_tag.to_s.in?(Hobo.static_tags)
455
444
  body = if overriding_default_content
456
445
  new_context { overriding_default_content.call(proc { default_content.call(nil) if default_content }) }
457
446
  elsif default_content
@@ -470,7 +459,7 @@ module Hobo::Dryml
470
459
  parameters = parameters.merge(:default => d)
471
460
  end
472
461
 
473
- if the_tag.is_a?(String, Symbol)
462
+ if the_tag.is_one_of?(String, Symbol)
474
463
  # It's a defined DRYML tag
475
464
  send(the_tag, attributes, parameters)
476
465
  else
@@ -508,7 +497,7 @@ module Hobo::Dryml
508
497
  params[:default] =
509
498
  if general_parameters[:default]
510
499
  proc do |default|
511
- overriding_default.call(proc { new_context { _output(general_parameters[:default].call(default)) } } )
500
+ overriding_default.call(proc { new_context { concat(general_parameters[:default].call(default)) } } )
512
501
  end
513
502
  else
514
503
  proc do |default|
@@ -598,8 +587,8 @@ module Hobo::Dryml
598
587
  else
599
588
  "<#{name}#{attr_string}>#{content}</#{name}>"
600
589
  end
601
- if block && eval("defined? _erbout", block.binding) # in erb context
602
- _output(res)
590
+ if block_called_from_erb? block
591
+ concat res
603
592
  else
604
593
  res
605
594
  end
@@ -60,24 +60,41 @@ module ActionController
60
60
  text = call_dryml_tag(tag, attributes)
61
61
  text && render({:text => text, :layout => false }.merge(options))
62
62
  end
63
-
64
-
63
+
65
64
  # DRYML fallback tags -- monkey patch this method to attempt to render a tag if there's no template
66
- def render_for_file_with_dryml(template_path, status = nil, layout = nil, locals = {})
67
- render_for_file_without_dryml(template_path, status, layout, locals)
68
- rescue ActionView::MissingTemplate => ex
69
- # Try to use a DRYML <page> tag instead
70
- tag_name = @dryml_fallback_tag || "#{File.basename(template_path).dasherize}-page"
71
-
72
- text = call_dryml_tag(tag_name)
73
- if text
74
- render_for_text text, status
65
+ def render_for_file_with_dryml(template, status = nil, layout = nil, locals = {})
66
+ # in rails 2.2, "template" is actually "template_path"
67
+
68
+ # if we're passed a MissingTemplateWrapper, see if there's a
69
+ # dryml tag that will render the page
70
+ if template.respond_to? :original_template_path
71
+ # this is the Rails 2.3 path
72
+ tag_name = @dryml_fallback_tag || "#{File.basename(template.original_template_path).dasherize}-page"
73
+
74
+ text = call_dryml_tag(tag_name)
75
+ if text
76
+ return render_for_text text, status
77
+ else
78
+ template.raise_wrapped_exception
79
+ end
75
80
  else
76
- raise ex
81
+ begin
82
+ result = render_for_file_without_dryml(template, status, layout, locals)
83
+ rescue ActionView::MissingTemplate => ex
84
+ # this is the Rails 2.2 path
85
+ tag_name = @dryml_fallback_tag || "#{File.basename(template).dasherize}-page"
86
+
87
+ text = call_dryml_tag(tag_name)
88
+ if text
89
+ return render_for_text text, status
90
+ else
91
+ raise ex
92
+ end
93
+ end
77
94
  end
78
95
  end
79
96
  alias_method_chain :render_for_file, :dryml
80
-
97
+
81
98
  end
82
99
  end
83
100
 
@@ -96,22 +113,74 @@ class ActionView::Template
96
113
  # from trying to compile our template. DRYML templates are each compiled as a class, not just a method,
97
114
  # so the support for compiling templates that Rails provides is innadequate.
98
115
  def render_dryml(view, local_assigns = {})
99
- stack = view.instance_variable_get(:@_render_stack)
100
- stack.push(self)
116
+ if view.instance_variable_defined?(:@_render_stack)
117
+ # Rails 2.2
118
+ stack = view.instance_variable_get(:@_render_stack)
119
+ stack.push(self)
120
+
121
+ # This is only used for TestResponse to set rendered_template
122
+ unless is_a?(ActionView::InlineTemplate) || view.instance_variable_get(:@_first_render)
123
+ view.instance_variable_set(:@_first_render, self)
124
+ end
101
125
 
102
- # This is only used for TestResponse to set rendered_template
103
- unless is_a?(ActionView::InlineTemplate) || view.instance_variable_get(:@_first_render)
104
- view.instance_variable_set(:@_first_render, self)
126
+ view.send(:_evaluate_assigns_and_ivars)
127
+ view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
128
+
129
+ result = Hobo::Dryml::TemplateHandler.new.render_for_rails22(self, view, local_assigns)
130
+
131
+ stack.pop
132
+ result
133
+ else
134
+ # Rails 2.3
135
+ compile(local_assigns)
136
+
137
+ view.with_template self do
138
+ view.send(:_evaluate_assigns_and_ivars)
139
+ view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
140
+
141
+ Hobo::Dryml::TemplateHandler.new.render_for_rails22(self, view, local_assigns)
142
+ end
105
143
  end
144
+ end
145
+
146
+ end
106
147
 
107
- view.send(:_evaluate_assigns_and_ivars)
108
- view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
148
+ # this is only used in Rails 2.3
149
+ class MissingTemplateWrapper
150
+ attr_reader :original_template_path
151
+
152
+ def initialize(exception, path)
153
+ @exception = exception
154
+ @original_template_path = path
155
+ end
109
156
 
110
- result = Hobo::Dryml::TemplateHandler.new.render_for_rails22(self, view, local_assigns)
157
+ def method_missing(*args)
158
+ raise @exception
159
+ end
111
160
 
112
- stack.pop
113
- result
161
+ def render
162
+ raise @exception
114
163
  end
164
+ end
115
165
 
116
- end
117
-
166
+
167
+ module ActionView
168
+ class PathSet < Array
169
+ # this is only used by Rails 2.3
170
+ def find_template_with_dryml(original_template_path, format = nil, html_fallback = true)
171
+ begin
172
+ find_template_without_dryml(original_template_path, format, html_fallback)
173
+ rescue ActionView::MissingTemplate => ex
174
+ # instead of throwing the exception right away, hand back a
175
+ # time bomb instead. It'll blow if mishandled...
176
+ return MissingTemplateWrapper.new(ex, original_template_path)
177
+ end
178
+ end
179
+
180
+ if instance_methods.include? "find_template"
181
+ # only rails 2.3 has this function
182
+ alias_method_chain :find_template, :dryml
183
+ end
184
+ end
185
+ end
186
+
@@ -33,13 +33,13 @@ module Hobo
33
33
  # result
34
34
  # end
35
35
  #}
36
-
36
+
37
37
  self.class.class_eval %{
38
38
  def #{name}
39
39
  Hobo::FindFor::Finder.new(self, '#{name}', :#{collection_name}, :#{anchor_association_name})
40
40
  end
41
41
  }
42
-
42
+
43
43
  return send(name, *args)
44
44
  end
45
45
  end
@@ -124,7 +124,7 @@ module Hobo
124
124
  elsif obj.is_a? Hobo::RawJs
125
125
  "#{name}=' + #{obj} + '"
126
126
  else
127
- v = if obj.is_a?(ActiveRecord::Base) or obj.is_a?(Array)
127
+ v = if obj.is_one_of?(ActiveRecord::Base, Array)
128
128
  "@" + typed_id(obj)
129
129
  else
130
130
  obj.to_s.gsub("'"){"\\'"}
@@ -286,7 +286,7 @@ module Hobo
286
286
  else
287
287
  object = this
288
288
  end
289
- elsif args.first.is_a?(String, Symbol)
289
+ elsif args.first.is_one_of?(String, Symbol)
290
290
  object = this
291
291
  field = args.first
292
292
  else
@@ -305,11 +305,11 @@ module Hobo
305
305
 
306
306
  @can_view_cache ||= {}
307
307
  @can_view_cache[ [object, field] ] ||=
308
- if !object.respond_to?(:viewable_by)
308
+ if !object.respond_to?(:viewable_by?)
309
309
  true
310
310
  elsif object.viewable_by?(current_user, field)
311
311
  # If possible, we also check if the current *value* of the field is viewable
312
- if field.is_a?(Symbol, String) && (v = object.send(field)) && v.respond_to?(:viewable_by?)
312
+ if field.is_one_of?(Symbol, String) && (v = object.send(field)) && v.respond_to?(:viewable_by?)
313
313
  v.viewable_by?(current_user, nil)
314
314
  else
315
315
  true
@@ -320,7 +320,6 @@ module Hobo
320
320
  end
321
321
 
322
322
 
323
-
324
323
  def select_viewable(collection=this)
325
324
  collection.select {|x| can_view?(x)}
326
325
  end
@@ -351,7 +350,7 @@ module Hobo
351
350
 
352
351
 
353
352
  def param_name_for(path)
354
- field_path = field_path.to_s.split(".") if field_path.is_a?(String, Symbol)
353
+ field_path = field_path.to_s.split(".") if field_path.is_one_of?(String, Symbol)
355
354
  attrs = path.rest.map{|part| "[#{part.to_s.sub /\?$/, ''}]"}.join
356
355
  "#{path.first}#{attrs}"
357
356
  end
@@ -382,7 +381,11 @@ module Hobo
382
381
 
383
382
  def new_for_current_user(model_or_assoc=nil)
384
383
  model_or_assoc ||= this
385
- model_or_assoc.user_new(current_user)
384
+ if model_or_assoc.respond_to?(:new_candidate)
385
+ model_or_assoc.user_new_candidate(current_user)
386
+ else
387
+ model_or_assoc.user_new(current_user)
388
+ end
386
389
  end
387
390
 
388
391
 
@@ -439,6 +442,7 @@ module Hobo
439
442
  result
440
443
  end
441
444
 
445
+
442
446
  def linkable?(*args)
443
447
  options = args.extract_options!
444
448
  target = args.empty? || args.first.is_a?(Symbol) ? this : args.shift
@@ -462,37 +466,33 @@ module Hobo
462
466
  Hobo::ModelRouter.linkable?(klass, action, options.reverse_merge(:subsite => subsite))
463
467
  end
464
468
 
469
+
465
470
  def css_data(name, *args)
466
471
  "#{name.to_s.dasherize}::#{args * '::'}"
467
472
  end
468
-
469
-
470
- # Convenience helper for the default app
473
+
471
474
 
472
- # FIXME: this should interrogate the routes to find index methods, not the models
473
- def front_models
474
- Hobo::Model.all_models.select {|m| linkable?(m) }
475
- end
476
-
475
+ # --- ViewHint Helpers --- #
477
476
 
478
- def this_field_name
479
- this_parent.class.view_hints.field_name(this_field)
477
+ def this_field_name
478
+ this_parent.class.try.view_hints.try.field_name(this_field) || this_field
480
479
  end
481
480
 
482
481
  def this_field_help
483
- this_parent.class.view_hints.field_help[this_field.to_sym]
482
+ this_parent.class.try.view_hints.try.field_help[this_field.to_sym]
484
483
  end
485
484
 
486
485
 
487
- # debugging support
486
+ # --- Debugging Helpers ---- #
488
487
 
489
488
  def abort_with(*args)
490
- raise args.map{|arg| PP.pp(arg, "")}.join("-------\n")
489
+ raise args.*.pretty_inspect.join("-------\n")
491
490
  end
492
491
 
493
492
  def log_debug(*args)
493
+ return if not logger
494
494
  logger.debug("\n### DRYML Debug ###")
495
- logger.debug(args.map {|a| PP.pp(a, "")}.join("-------\n"))
495
+ logger.debug(args.*.pretty_inspect.join("-------\n"))
496
496
  logger.debug("DRYML THIS = #{this.typed_id rescue this.inspect}")
497
497
  logger.debug("###################\n")
498
498
  args.first unless args.empty?
@@ -19,10 +19,13 @@ module Hobo
19
19
  added = false
20
20
  records.each do |record|
21
21
  # we want to call valid? on each one, but only add the error to self once
22
- unless record.valid?
23
- unless added
24
- errors.add association, "..."
25
- added = true
22
+
23
+ record.with_acting_user(acting_user) do
24
+ unless record.valid?
25
+ unless added
26
+ errors.add association, "..."
27
+ added = true
28
+ end
26
29
  end
27
30
  end
28
31
  end
@@ -35,7 +38,8 @@ module Hobo
35
38
  if included_in_save
36
39
  included_in_save.each_pair do |association, records|
37
40
  records.each do |record|
38
- record.save_without_validation # This means without transactions too
41
+ # save_without_validation means without transactions too
42
+ record.with_acting_user(acting_user) { record.save_without_validation }
39
43
  end
40
44
  end
41
45
  end
@@ -20,7 +20,7 @@ module Hobo
20
20
 
21
21
 
22
22
  def extract_attributes(attributes)
23
- update_attributes = options.fetch(:update, [])
23
+ update_attributes = options.fetch(:params, [])
24
24
  attributes & update_attributes
25
25
  end
26
26
 
@@ -50,7 +50,7 @@ module Hobo
50
50
 
51
51
 
52
52
  def parameters
53
- options[:update] || []
53
+ options[:params] || []
54
54
  end
55
55
 
56
56