hobo 0.7.4 → 0.7.5

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 (45) hide show
  1. data/bin/hobo +0 -6
  2. data/hobo_files/plugin/CHANGES.txt +103 -0
  3. data/hobo_files/plugin/Rakefile +2 -0
  4. data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
  5. data/hobo_files/plugin/generators/hobo_rapid/templates/IE7.js +2 -0
  6. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +28 -12
  7. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/{application.css → clean.css} +10 -9
  8. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +1 -1
  9. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/views/{application.dryml → clean.dryml} +0 -0
  10. data/hobo_files/plugin/init.rb +7 -3
  11. data/hobo_files/plugin/lib/hobo.rb +3 -1
  12. data/hobo_files/plugin/lib/hobo/bundle.rb +24 -14
  13. data/hobo_files/plugin/lib/hobo/dryml.rb +5 -1
  14. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +1 -1
  15. data/hobo_files/plugin/lib/hobo/dryml/parser/base_parser.rb +11 -10
  16. data/hobo_files/plugin/lib/hobo/dryml/parser/document.rb +37 -10
  17. data/hobo_files/plugin/lib/hobo/dryml/template.rb +5 -22
  18. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +1 -1
  19. data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +10 -2
  20. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +7 -0
  21. data/hobo_files/plugin/lib/hobo/model.rb +18 -13
  22. data/hobo_files/plugin/lib/hobo/model_controller.rb +45 -54
  23. data/hobo_files/plugin/lib/hobo/model_router.rb +8 -1
  24. data/hobo_files/plugin/lib/hobo/scopes.rb +3 -4
  25. data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +3 -0
  26. data/hobo_files/plugin/taglib-docs/core.markdown +165 -0
  27. data/hobo_files/plugin/taglib-docs/rapid.markdown +677 -0
  28. data/hobo_files/plugin/taglib-docs/rapid_document_tags.markdown +240 -0
  29. data/hobo_files/plugin/taglib-docs/rapid_editing.markdown +418 -0
  30. data/hobo_files/plugin/taglib-docs/rapid_forms.markdown +562 -0
  31. data/hobo_files/plugin/taglib-docs/rapid_generics.markdown +187 -0
  32. data/hobo_files/plugin/taglib-docs/rapid_navigation.markdown +214 -0
  33. data/hobo_files/plugin/taglib-docs/rapid_pages.markdown +530 -0
  34. data/hobo_files/plugin/taglib-docs/rapid_plus.markdown +65 -0
  35. data/hobo_files/plugin/taglib-docs/rapid_support.markdown +50 -0
  36. data/hobo_files/plugin/taglib-docs/rapid_user_pages.markdown +129 -0
  37. data/hobo_files/plugin/taglibs/rapid.dryml +2 -2
  38. data/hobo_files/plugin/taglibs/rapid_forms.dryml +7 -22
  39. data/hobo_files/plugin/taglibs/rapid_generics.dryml +14 -12
  40. data/hobo_files/plugin/taglibs/rapid_navigation.dryml +5 -4
  41. data/hobo_files/plugin/taglibs/rapid_pages.dryml +5 -1
  42. data/hobo_files/plugin/tasks/fix_dryml.rake +1 -1
  43. data/hobo_files/plugin/tasks/generate_tag_reference.rb +162 -0
  44. data/hobo_files/plugin/tasks/hobo_tasks.rake +17 -0
  45. metadata +46 -5
@@ -2,20 +2,47 @@ module Hobo::Dryml::Parser
2
2
 
3
3
  class Document < REXML::Document
4
4
 
5
- attr_accessor :default_attribute_value
6
-
7
- def initialize(source=nil, context={})
8
- super(nil, context)
5
+ def initialize(source, path)
6
+ super(nil)
7
+
8
+ # Replace <%...%> scriptlets with xml-safe references into a hash of scriptlets
9
+ @scriptlets = {}
10
+ source = source.gsub(/<%(.*?)%>/m) do
11
+ _, scriptlet = *Regexp.last_match
12
+ id = @scriptlets.size + 1
13
+ @scriptlets[id] = scriptlet
14
+ newlines = "\n" * scriptlet.count("\n")
15
+ "[![DRYML-ERB#{id}#{newlines}]!]"
16
+ end
17
+
18
+
19
+ @reference_src = "<dryml_page>" + source + "</dryml_page>"
20
+ rex_src = Hobo::Dryml::Parser::Source.new(@reference_src)
21
+
9
22
  @elements = Hobo::Dryml::Parser::Elements.new(self)
10
- if source.kind_of? Document
11
- @context = source.context
12
- super source
13
- else
14
- build( source )
15
- end
23
+ build(rex_src)
24
+
25
+ rescue REXML::ParseException => e
26
+ raise DrymlSyntaxError, "File: #{path}\n#{e}"
27
+ end
28
+
29
+
30
+ def element_line_num(el)
31
+ offset = el.source_offset
32
+ @reference_src[0..offset].count("\n") + 1
33
+ end
34
+
35
+
36
+ def default_attribute_value
37
+ "&true"
16
38
  end
17
39
 
40
+
41
+ def restore_erb_scriptlets(src)
42
+ src.gsub(/\[!\[DRYML-ERB(\d+)\s*\]!\]/m) {|s| "<%#{@scriptlets[$1.to_i]}%>" }
43
+ end
18
44
 
45
+
19
46
  private
20
47
  def build( source )
21
48
  Hobo::Dryml::Parser::TreeParser.new( source, self ).parse
@@ -89,30 +89,14 @@ module Hobo::Dryml
89
89
 
90
90
 
91
91
  def process_src
92
- # Replace <%...%> scriptlets with xml-safe references into a hash of scriptlets
93
- @scriptlets = {}
94
- src = @src.gsub(/<%(.*?)%>/m) do
95
- _, scriptlet = *Regexp.last_match
96
- id = @scriptlets.size + 1
97
- @scriptlets[id] = scriptlet
98
- newlines = "\n" * scriptlet.count("\n")
99
- "[![HOBO-ERB#{id}#{newlines}]!]"
100
- end
101
-
102
- @xmlsrc = "<dryml_page>" + src + "</dryml_page>"
103
- begin
104
- @doc = Hobo::Dryml::Parser::Document.new(Hobo::Dryml::Parser::Source.new(@xmlsrc))
105
- rescue REXML::ParseException => e
106
- raise DrymlSyntaxError, "File: #{@template_path}\n#{e}"
107
- end
108
- @doc.default_attribute_value = "&true"
109
-
110
- restore_erb_scriptlets(children_to_erb(@doc.root))
92
+ @doc = Hobo::Dryml::Parser::Document.new(@src, @template_path)
93
+ result = children_to_erb(@doc.root)
94
+ restore_erb_scriptlets(result)
111
95
  end
112
96
 
113
97
 
114
98
  def restore_erb_scriptlets(src)
115
- src.gsub(/\[!\[HOBO-ERB(\d+)\s*\]!\]/m) {|s| "<%#{@scriptlets[$1.to_i]}%>" }
99
+ @doc.restore_erb_scriptlets(src)
116
100
  end
117
101
 
118
102
 
@@ -896,8 +880,7 @@ module Hobo::Dryml
896
880
  end
897
881
 
898
882
  def element_line_num(el)
899
- offset = el.source_offset
900
- @xmlsrc[0..offset].count("\n") + 1
883
+ @doc.element_line_num(el)
901
884
  end
902
885
 
903
886
  def tag_newlines(el)
@@ -455,7 +455,7 @@ module Hobo::Dryml
455
455
  res = (send(method_name, attributes) + part_contexts_javascripts).strip
456
456
 
457
457
  # TODO: Temporary hack to get the dryml metadata comments in the right place
458
- if RAILS_ENV == "development"
458
+ if false && RAILS_ENV == "development"
459
459
  res.gsub(/^(.*?)(<!DOCTYPE.*?>).*?(<html.*?>)/m, "\\2\\3\\1")
460
460
  else
461
461
  res
@@ -39,16 +39,24 @@ module ActionController
39
39
  @dryml_fallback_tag = tag_name
40
40
  end
41
41
 
42
- def render_tag(tag, options={}, render_options={})
42
+
43
+ def call_dryml_tag(tag, options={})
43
44
  add_variables_to_assigns
44
45
 
46
+ # TODO: Figure out what this bit is all about :-)
45
47
  if options[:with]
46
48
  @this = options[:with] unless options[:field]
47
49
  else
48
50
  options[:with] = dryml_context
49
51
  end
50
52
 
51
- text = Hobo::Dryml.render_tag(@template, tag, options)
53
+ Hobo::Dryml.render_tag(@template, tag, options)
54
+ end
55
+
56
+
57
+ # TODO: This is namespace polution, should be called render_dryml_tag
58
+ def render_tag(tag, options={}, render_options={})
59
+ text = call_dryml_tag(tag, options)
52
60
  text && render({:text => text, :layout => false }.merge(render_options))
53
61
  end
54
62
 
@@ -8,6 +8,13 @@ module Hobo
8
8
  end
9
9
 
10
10
  protected
11
+
12
+
13
+ def uid
14
+ @hobo_uid ||= 0
15
+ @hobo_uid += 1
16
+ end
17
+
11
18
 
12
19
  def current_user
13
20
  # simple one-hit-per-request cache
@@ -78,8 +78,6 @@ module Hobo
78
78
  send("find_by_#{name_attribute}", *args)
79
79
  end
80
80
 
81
- alias_method :[], :named
82
-
83
81
 
84
82
  def field_added(name, type, args, options)
85
83
  self.name_attribute = name.to_sym if options.delete(:name)
@@ -291,17 +289,20 @@ module Hobo
291
289
 
292
290
 
293
291
  def manage_join_records(association)
294
- through = reflections[association].through_reflection
295
- source = reflections[association].source_reflection
296
292
 
297
293
  method = "manage_join_records_for_#{association}"
298
294
  after_save method
299
295
  class_eval %{
300
296
  def #{method}
301
- current = #{through.name}.*.#{source.name}
302
- to_delete = current - #{association}
303
- to_add = #{association} - current
304
- #{through.klass.name}.delete_all(["#{through.primary_key_name} = ? and #{source.primary_key_name} in (?)",
297
+ assigned = #{association}.dup
298
+ current = #{association}.reload
299
+
300
+ through = #{association}.proxy_reflection.through_reflection
301
+ source = #{association}.proxy_reflection.source_reflection
302
+
303
+ to_delete = current - assigned
304
+ to_add = assigned - current
305
+ through.klass.delete_all(["\#{through.primary_key_name} = ? and \#{source.primary_key_name} in (?)",
305
306
  self.id, to_delete.*.id]) if to_delete.any?
306
307
  to_add.each { |record| #{association} << record }
307
308
  end
@@ -363,7 +364,7 @@ module Hobo
363
364
 
364
365
 
365
366
  def user_view(user, field=nil)
366
- raise PermissionDeniedError unless Hobo.can_view?(user, self, field)
367
+ raise PermissionDeniedError, self.inspect unless Hobo.can_view?(user, self, field)
367
368
  end
368
369
 
369
370
 
@@ -511,9 +512,13 @@ module Hobo
511
512
 
512
513
  def convert_associated_records_for_mass_assignment(reflection, value)
513
514
  if reflection.macro.in?([:belongs_to, :has_one])
514
- if value.is_a?(String) && value.starts_with?('@')
515
- # TODO: This @foo_1 feature is rarely (never?) used - get rid of it
516
- Hobo.object_from_dom_id(value[1..-1])
515
+ if value.is_a?(String)
516
+ if value.starts_with?('@')
517
+ # TODO: This @foo_1 feature is rarely (never?) used - get rid of it
518
+ Hobo.object_from_dom_id(value[1..-1])
519
+ else
520
+ reflection.klass.named(value)
521
+ end
517
522
  else
518
523
  value
519
524
  end
@@ -521,7 +526,7 @@ module Hobo
521
526
  if reflection.klass.try.name_attribute
522
527
  value.map do |x|
523
528
  if x.is_a?(String)
524
- reflection.klass[x] unless x.blank?
529
+ reflection.klass.named(x) unless x.blank?
525
530
  else
526
531
  x
527
532
  end
@@ -6,7 +6,7 @@ module Hobo
6
6
 
7
7
  VIEWLIB_DIR = "taglibs"
8
8
 
9
- PAGINATE_FORMATS = [ Mime::HTML, Mime::ALL ]
9
+ DONT_PAGINATE_FORMATS = [ Mime::CSV, Mime::YAML, Mime::JSON, Mime::XML, Mime::ATOM, Mime::RSS ]
10
10
 
11
11
  READ_ONLY_ACTIONS = [:index, :show]
12
12
  WRITE_ONLY_ACTIONS = [:create, :update, :destroy]
@@ -17,9 +17,12 @@ module Hobo
17
17
  def included(base)
18
18
  base.class_eval do
19
19
  @auto_actions ||= {}
20
+
21
+ inheriting_cattr_reader :web_methods => [], :show_actions => [], :index_actions => []
20
22
 
21
23
  extend ClassMethods
22
24
 
25
+
23
26
  helper_method :model, :current_user
24
27
  before_filter :set_no_cache_headers
25
28
 
@@ -30,7 +33,6 @@ module Hobo
30
33
  alias_method_chain :render, :hobo_model
31
34
 
32
35
  end
33
- base.template_path_cache = {}
34
36
 
35
37
  Hobo::Controller.included_in_class(base)
36
38
  end
@@ -42,25 +44,12 @@ module Hobo
42
44
 
43
45
  attr_writer :model
44
46
 
45
- attr_accessor :template_path_cache
46
-
47
- def web_methods
48
- @web_methods ||= superclass.respond_to?(:web_methods) ? superclass.web_methods : []
49
- end
50
-
51
-
52
- def show_actions
53
- @show_actions ||= superclass.respond_to?(:show_actions) ? superclass.show_actions : []
54
- end
55
-
56
-
57
- def index_actions
58
- @index_actions ||= superclass.respond_to?(:index_actions) ? superclass.index_actions : []
59
- end
60
-
61
-
62
47
  def collections
63
- # By default, all has_many associations are published
48
+ # FIXME The behaviour here is weird if the superclass does
49
+ # define collections *and* this class adds some more. The
50
+ # added ones won't be published
51
+
52
+ # by default By default, all has_many associations are published
64
53
  @collections ||= if superclass.respond_to?(:collections)
65
54
  superclass.collections
66
55
  else
@@ -74,10 +63,15 @@ module Hobo
74
63
  end
75
64
 
76
65
 
77
- def autocomplete_for(field, options={})
78
- options = options.reverse_merge(:limit => 15)
79
- index_action "complete_#{field}" do
80
- hobo_completions(model.limit(options[:limit]).send("#{field}_contains", params[:query]))
66
+ def autocomplete(name, options={}, &block)
67
+ options = options.dup
68
+ field = options.delete(:field) || name
69
+ if block
70
+ index_action "complete_#{name}", &block
71
+ else
72
+ index_action "complete_#{name}" do
73
+ hobo_completetions name, model, options
74
+ end
81
75
  end
82
76
  end
83
77
 
@@ -121,7 +115,7 @@ module Hobo
121
115
  end
122
116
  end
123
117
 
124
- @auto_actions -= except_actions
118
+ @auto_actions -= except_actions.flatten
125
119
 
126
120
  def_auto_actions
127
121
  end
@@ -255,10 +249,8 @@ module Hobo
255
249
  # --- Action implementation helpers --- #
256
250
 
257
251
 
258
- def find_instance(*args)
259
- options = args.extract_options!
260
- id = args.first || params[:id]
261
- model.user_find(current_user, id, options)
252
+ def find_instance(options={})
253
+ model.user_find(current_user, params[:id], options)
262
254
  end
263
255
 
264
256
 
@@ -279,17 +271,20 @@ module Hobo
279
271
  end
280
272
 
281
273
 
282
- def destination_after_submit(record=nil)
274
+ def destination_after_submit(record=nil, destroyed=false)
283
275
  record ||= this
284
276
 
277
+ after_submit = params[:after_submit]
278
+
285
279
  # The after_submit post parameter takes priority
286
- params[:after_submit] ||
280
+ (after_submit == "stay-here" ? :back : after_submit) ||
281
+
287
282
 
288
283
  # Then try the record's show page
289
- object_url(@this) ||
284
+ (!destroyed && object_url(@this)) ||
290
285
 
291
286
  # Then the show page of the 'owning' object if there is one
292
- (@this.class.default_dependent_on && object_url(@this.send(@this.class.default_dependent_on))) ||
287
+ (!destroyed && (@this.class.default_dependent_on && object_url(@this.send(@this.class.default_dependent_on)))) ||
293
288
 
294
289
  # Last try - the index page for this model
295
290
  object_url(@this.class) ||
@@ -312,21 +307,14 @@ module Hobo
312
307
 
313
308
 
314
309
  def request_requires_pagination?
315
- # Internet explorer has a penchant for saying it would mostly
316
- # like an image, if you clicked on an image link
317
- request.format.in?(PAGINATE_FORMATS) || request.format.to_s =~ %r(image/)
310
+ request.format.not_in?(DONT_PAGINATE_FORMATS)
318
311
  end
319
312
 
320
313
 
321
314
  def find_or_paginate(finder, options)
322
315
  options = options.reverse_merge(:paginate => request_requires_pagination?)
323
- do_pagination = options.delete(:paginate)
316
+ do_pagination = options.delete(:paginate) && finder.respond_to?(:paginate)
324
317
 
325
- if do_pagination && !finder.respond_to?(:paginate)
326
- do_pagination = false
327
- logger.warn "Hobo::ModelController: Pagination is not available. To enable, please install will_paginate or a duck-type compatible paginator"
328
- end
329
-
330
318
  if do_pagination
331
319
  finder.paginate(options.reverse_merge(:page => params[:page] || 1))
332
320
  else
@@ -388,7 +376,7 @@ module Hobo
388
376
  if valid?
389
377
  respond_to do |wants|
390
378
  wants.html { redirect_to destination_after_submit }
391
- wants.js { hobo_ajax_response || render(:text => "") }
379
+ wants.js { hobo_ajax_response || render(:nothing => true) }
392
380
  end
393
381
  else
394
382
  respond_to do |wants|
@@ -404,7 +392,7 @@ module Hobo
404
392
  def hobo_update(*args, &b)
405
393
  options = args.extract_options!
406
394
 
407
- self.this ||= args.first || find_instance
395
+ self.this = args.first || find_instance
408
396
  changes = options[:attributes] || attribute_parameters
409
397
  this.user_save_changes(current_user, changes)
410
398
 
@@ -428,7 +416,7 @@ module Hobo
428
416
  wants.js do
429
417
  if in_place_edit_field
430
418
  # Decreasingly hacky support for the scriptaculous in-place-editor
431
- new_val = Hobo::Dryml.render_tag(@template, "view", :field => in_place_edit_field, :no_wrapper => true)
419
+ new_val = call_dryml_tag("view", :field => in_place_edit_field, :no_wrapper => true)
432
420
  hobo_ajax_response(this, :new_field_value => new_val)
433
421
  else
434
422
  hobo_ajax_response(this)
@@ -451,7 +439,7 @@ module Hobo
451
439
 
452
440
  def hobo_destroy(*args, &b)
453
441
  options = args.extract_options!
454
- self.this ||= args.first || find_instance
442
+ self.this = args.first || find_instance
455
443
  this.user_destroy(current_user)
456
444
  flash[:notice] = "The #{model.name.titleize.downcase} was deleted" unless request.xhr?
457
445
  destroy_response(&b)
@@ -461,7 +449,7 @@ module Hobo
461
449
  def destroy_response(&b)
462
450
  response_block(&b) or
463
451
  respond_to do |wants|
464
- wants.html { redirect_to(:action => "index") }
452
+ wants.html { redirect_to destination_after_submit(this, true) }
465
453
  wants.js { hobo_ajax_response || render(:nothing => true) }
466
454
  end
467
455
  end
@@ -490,9 +478,12 @@ module Hobo
490
478
  end
491
479
 
492
480
 
493
- def hobo_completions(finder)
481
+ def hobo_completions(attribute, finder, options={})
482
+ options = options.reverse_merge(:limit => 10, :param => :query)
483
+ finder = finder.limit(options[:limit]) unless finder.scope(:find, :limit)
484
+ finder = finder.send("#{attribute}_contains", params[options[:param]])
494
485
  items = finder.find(:all)
495
- render :text => "<ul>\n" + items.map {|i| "<li>#{i.send(attr)}</li>\n"}.join + "</ul>"
486
+ render :text => "<ul>\n" + items.map {|i| "<li>#{i.send(attribute)}</li>\n"}.join + "</ul>"
496
487
  end
497
488
 
498
489
 
@@ -506,11 +497,11 @@ module Hobo
506
497
 
507
498
 
508
499
  # --- Response helpers --- #
509
-
510
500
 
511
501
  def permission_denied(error)
512
- if respond_to? :permission_denied_response
513
- permission_denied_response
502
+ self.this = nil # Otherwise this gets sent user_view
503
+ if :permission_denied.in?(superclass.instance_methods)
504
+ super
514
505
  else
515
506
  respond_to do |wants|
516
507
  wants.html do
@@ -529,8 +520,8 @@ module Hobo
529
520
 
530
521
 
531
522
  def not_found(error)
532
- if respond_to? :not_found_response
533
- not_found_response
523
+ if :not_found_response.in?(superclass.instance_methods)
524
+ super
534
525
  elsif render_tag("not-found-page", {}, :status => 404)
535
526
  # cool
536
527
  else