hobo 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
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