hobo 1.3.3 → 1.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. data/{CHANGES.txt → CHANGES-1.3.txt} +0 -0
  2. data/CHANGES-1.4.txt +678 -0
  3. data/Rakefile +13 -3
  4. data/TODO-1.4.txt +69 -0
  5. data/VERSION +1 -1
  6. data/app/helpers/hobo_debug_helper.rb +16 -0
  7. data/app/helpers/hobo_deprecated_helper.rb +45 -0
  8. data/app/helpers/hobo_helper_base.rb +8 -0
  9. data/app/helpers/hobo_permissions_helper.rb +136 -0
  10. data/app/helpers/hobo_route_helper.rb +196 -0
  11. data/{lib/hobo/helper/translations.rb → app/helpers/hobo_translations_helper.rb} +4 -7
  12. data/{lib/hobo/helper/translations/normalizer.rb → app/helpers/hobo_translations_normalizer_helper.rb} +3 -10
  13. data/app/helpers/hobo_type_helper.rb +24 -0
  14. data/app/helpers/hobo_view_hint_helper.rb +13 -0
  15. data/hobo.gemspec +3 -3
  16. data/lib/generators/hobo/admin_subsite/admin_subsite_generator.rb +0 -9
  17. data/lib/generators/hobo/admin_subsite/templates/application.dryml +2 -0
  18. data/lib/generators/hobo/admin_subsite/templates/gitkeep +0 -0
  19. data/lib/generators/hobo/admin_subsite/templates/site.css.erb +9 -0
  20. data/lib/generators/hobo/admin_subsite/templates/site.js.erb +10 -0
  21. data/lib/generators/hobo/assets/assets_generator.rb +16 -2
  22. data/lib/generators/hobo/assets/templates/application.css +9 -0
  23. data/lib/generators/hobo/assets/templates/application.dryml.erb +0 -5
  24. data/lib/generators/hobo/assets/templates/application.js +11 -0
  25. data/lib/generators/hobo/assets/templates/front.css +10 -0
  26. data/lib/generators/hobo/assets/templates/front.js +11 -0
  27. data/lib/generators/hobo/assets/templates/front_site.dryml.erb +6 -0
  28. data/lib/generators/hobo/assets/templates/gitkeep +0 -0
  29. data/lib/generators/hobo/dev_tweaks/dev_tweaks_generator.rb +31 -0
  30. data/lib/generators/hobo/i18n/templates/hobo.en.yml +1 -1
  31. data/lib/generators/hobo/install_plugin/USAGE +3 -0
  32. data/lib/generators/hobo/install_plugin/install_plugin_generator.rb +36 -0
  33. data/lib/generators/hobo/plugin.rb +112 -0
  34. data/lib/generators/hobo/setup_wizard/setup_wizard_generator.rb +31 -14
  35. data/lib/generators/hobo/subsite.rb +16 -2
  36. data/lib/generators/hobo/subsite/templates/gitkeep +0 -0
  37. data/lib/generators/hobo/subsite/templates/site.css.erb +9 -0
  38. data/lib/generators/hobo/subsite/templates/site.js.erb +10 -0
  39. data/lib/generators/hobo/subsite_taglib/templates/taglib.dryml.erb +0 -17
  40. data/lib/generators/hobo/test_framework/test_framework_generator.rb +1 -1
  41. data/lib/hobo.rb +3 -2
  42. data/lib/hobo/controller.rb +43 -24
  43. data/lib/hobo/controller/model.rb +63 -42
  44. data/lib/hobo/controller/user_base.rb +1 -3
  45. data/lib/hobo/engine.rb +1 -1
  46. data/lib/hobo/extensions/active_record/associations/association.rb +36 -0
  47. data/lib/hobo/extensions/active_record/associations/collection.rb +10 -19
  48. data/lib/hobo/extensions/active_record/associations/proxy.rb +3 -15
  49. data/lib/hobo/extensions/active_record/associations/scope.rb +2 -2
  50. data/lib/hobo/extensions/active_record/permissions.rb +32 -38
  51. data/lib/hobo/extensions/active_record/relation_with_origin.rb +5 -5
  52. data/lib/hobo/model.rb +12 -7
  53. data/lib/hobo/model/accessible_associations.rb +8 -15
  54. data/lib/hobo/model/lifecycles/creator.rb +1 -1
  55. data/lib/hobo/model/lifecycles/transition.rb +1 -1
  56. data/lib/hobo/model/permissions.rb +4 -4
  57. data/lib/hobo/model/scopes.rb +4 -17
  58. data/lib/hobo/model/scopes/automatic_scopes.rb +5 -13
  59. data/lib/hobo/rapid/helper.rb +1 -161
  60. data/lib/hobo/rapid/taglibs/rapid.dryml +3 -17
  61. data/test/doctest/hobo/hobo_helper.rdoctest +8 -44
  62. data/{doctests → test/doctest}/hobo/lifecycles.rdoctest +0 -0
  63. data/{doctests → test/doctest}/hobo/model.rdoctest +2 -4
  64. data/{doctests → test/doctest}/hobo/multi_model_forms.rdoctest +3 -24
  65. data/{doctests → test/doctest}/hobo/scopes.rdoctest +3 -53
  66. data/test/doctest/prepare_testapp.rb +11 -0
  67. data/test/irt/generators/admin_subsite.irt +1 -19
  68. data/test/irt/generators/assets.irt +4 -9
  69. data/test/irt/generators/controller.irt +0 -3
  70. data/test/irt/generators/front_controller.irt +0 -5
  71. data/test/irt/generators/{helper.rb → irt_helper.rb} +2 -2
  72. data/test/irt/generators/model.irt +1 -12
  73. data/test/irt/generators/partials/_account_user_model_tests.rb +0 -8
  74. data/test/irt/generators/partials/_accounts_users_controller_tests.rb +0 -2
  75. data/test/irt/generators/partials/_default_user_model_tests.rb +0 -8
  76. data/test/irt/generators/partials/_default_users_controller_tests.rb +0 -2
  77. data/test/irt/generators/partials/_house_controller_tests.rb +0 -2
  78. data/test/irt/generators/partials/_house_model_tests.rb +1 -9
  79. data/test/irt/generators/partials/_subsite_taglib_admin.rb +5 -2
  80. data/test/irt/generators/partials/_subsite_taglib_admin_invite_only.rb +1 -1
  81. data/test/irt/generators/partials/_subsite_taglib_noopt.rb +2 -2
  82. data/test/irt/generators/partials/_subsite_taglib_variables.rb +0 -15
  83. data/test/irt/generators/partials/_user_mailer_tests.rb +1 -3
  84. data/test/irt/generators/resource.irt +0 -3
  85. data/test/irt/generators/subsite.irt +6 -22
  86. data/test/irt/generators/subsite_taglib.irt +0 -18
  87. data/test/irt/generators/test_framework.irt +2 -5
  88. data/test/irt/generators/user_controller.irt +0 -3
  89. data/test/irt/generators/user_mailer.irt +0 -3
  90. data/test/irt/generators/user_model.irt +0 -3
  91. data/test/irt/generators/user_resource.irt +0 -3
  92. data/test/irt/readme.txt +6 -3
  93. metadata +116 -159
  94. data/app/controllers/dev_controller.rb +0 -25
  95. data/app/views/dev/summary.dryml +0 -102
  96. data/doctests/prepare_testapp.rb +0 -8
  97. data/lib/generators/hobo/admin_subsite/templates/admin.css +0 -20
  98. data/lib/generators/hobo/rapid/USAGE +0 -3
  99. data/lib/generators/hobo/rapid/rapid_generator.rb +0 -24
  100. data/lib/generators/hobo/rapid/templates/IE7.js +0 -2
  101. data/lib/generators/hobo/rapid/templates/blank.gif +0 -0
  102. data/lib/generators/hobo/rapid/templates/hobo-rapid.css +0 -94
  103. data/lib/generators/hobo/rapid/templates/hobo-rapid.js +0 -1015
  104. data/lib/generators/hobo/rapid/templates/ie7-recalc.js +0 -166
  105. data/lib/generators/hobo/rapid/templates/lowpro.js +0 -339
  106. data/lib/generators/hobo/rapid/templates/reset.css +0 -95
  107. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/101-3B5F87-ACD3E6.png +0 -0
  108. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/30-3E547A-242E42.png +0 -0
  109. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/30-DBE1E5-FCFEF5.png +0 -0
  110. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/300-ACD3E6-fff.png +0 -0
  111. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/50-ACD3E6-fff.png +0 -0
  112. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/fieldbg.gif +0 -0
  113. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/pencil.png +0 -0
  114. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/small_close.png +0 -0
  115. data/lib/generators/hobo/rapid/templates/themes/clean/public/images/spinner.gif +0 -0
  116. data/lib/generators/hobo/rapid/templates/themes/clean/public/stylesheets/clean.css +0 -327
  117. data/lib/generators/hobo/rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +0 -102
  118. data/lib/generators/hobo/rapid/templates/themes/clean/views/clean.dryml +0 -10
  119. data/lib/hobo/helper.rb +0 -460
  120. data/lib/hobo/rapid/taglibs/rapid_core.dryml +0 -808
  121. data/lib/hobo/rapid/taglibs/rapid_document_tags.dryml +0 -56
  122. data/lib/hobo/rapid/taglibs/rapid_editing.dryml +0 -287
  123. data/lib/hobo/rapid/taglibs/rapid_forms.dryml +0 -1156
  124. data/lib/hobo/rapid/taglibs/rapid_generics.dryml +0 -48
  125. data/lib/hobo/rapid/taglibs/rapid_i18n.dryml +0 -173
  126. data/lib/hobo/rapid/taglibs/rapid_lifecycles.dryml +0 -96
  127. data/lib/hobo/rapid/taglibs/rapid_navigation.dryml +0 -108
  128. data/lib/hobo/rapid/taglibs/rapid_pages.dryml +0 -259
  129. data/lib/hobo/rapid/taglibs/rapid_plus.dryml +0 -247
  130. data/lib/hobo/rapid/taglibs/rapid_summary.dryml +0 -283
  131. data/lib/hobo/rapid/taglibs/rapid_support.dryml +0 -102
  132. data/lib/hobo/rapid/taglibs/rapid_user_pages.dryml +0 -182
  133. data/test/irt/generators/rapid.irt +0 -29
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'rake'
2
- require 'rake/rdoctask'
2
+ require 'rdoc/task'
3
3
  require 'rake/testtask'
4
4
  require 'tmpdir'
5
5
 
@@ -9,13 +9,16 @@ $:.unshift File.expand_path('../lib', __FILE__)
9
9
  $:.unshift File.expand_path('../../hobo_support/lib', __FILE__)
10
10
  $:.unshift File.expand_path('../../hobo_fields/lib', __FILE__)
11
11
  $:.unshift File.expand_path('../../dryml/lib', __FILE__)
12
+
12
13
  require 'hobo'
13
14
 
15
+ include Rake::DSL
16
+
14
17
  RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
15
18
  RUBYDOCTEST = ENV['RUBYDOCTEST'] || "#{RUBY} -S rubydoctest"
16
19
 
17
20
  GEM_ROOT = File.expand_path('../', __FILE__)
18
- TESTAPP_PATH = File.join Dir.tmpdir, 'hobo_testapp'
21
+ TESTAPP_PATH = ENV['TESTAPP_PATH'] || File.join(Dir.tmpdir, 'hobo_testapp')
19
22
  BIN = File.expand_path('../bin/hobo', __FILE__)
20
23
  require 'hobo_support/common_tasks'
21
24
  include HoboSupport::CommonTasks
@@ -37,9 +40,16 @@ Rake::TestTask.new(:test) { |t|
37
40
  namespace "test" do
38
41
  desc "Run the doctests"
39
42
  task :doctest do |t|
40
- files=Dir['doctests/**/*.rdoctest'].map {|f| File.expand_path(f)}.join(' ')
43
+ files=Dir['test/doctest/**/*.rdoctest'].map {|f| File.expand_path(f)}.join(' ')
41
44
  exit(1) if !system("#{RUBYDOCTEST} #{files}")
42
45
  end
46
+
47
+ desc "Run the irt tests"
48
+ task :irt => :prepare_testapp do |t|
49
+ chdir TESTAPP_PATH
50
+ sh %(irt #{File.expand_path('.',GEM_ROOT)})
51
+ end
52
+
43
53
  end
44
54
 
45
55
  # --- RDoc --- #
data/TODO-1.4.txt ADDED
@@ -0,0 +1,69 @@
1
+ # TODO
2
+
3
+ ## regressions
4
+
5
+ * after-submit, sortable-input-many and name-many do not work
6
+ * Hobo 1.4 breaks default_scope. If you're setting the order, you
7
+ can use Hobo's set_default_order as a stopgap although once it's
8
+ fixed please switch back to default_scope as set_default_order
9
+ is deprecated.
10
+ * remote-method-button, create-button, update-button,
11
+ transition-button: normal usages of these tags work, but they do
12
+ not work if you ask them to do AJAX
13
+ * live-search works, but it's not 'live'. You have to press return
14
+ to start the search
15
+ * remove-button, remote-method-button, create-button & update-button
16
+ used to display inline but now display as a block. In other
17
+ words, they now display one per line rather than several in a
18
+ single line.
19
+ * the rapid_summary tags have been moved out
20
+ of core Hobo into their own plugin,
21
+ https://github.com/Hobo/hobo_summary, which is not yet in a working state
22
+
23
+ ## documentation
24
+
25
+ * document themes/plugins
26
+ * FAQ
27
+ * agility
28
+ * admin subsite
29
+ * books
30
+ * ajax manual section
31
+
32
+ ## Cookbook
33
+
34
+ * captcha
35
+ * search
36
+ * actually use Hobo 1.4's new caching abilities
37
+ * auto-link tags in manual
38
+ * create fakedef manual entries for DRYML tags not in taglibs entry
39
+
40
+ ## new features that aren't "done"
41
+
42
+ * create_response: mirror update_response
43
+ * taglib cleanup
44
+ * clean_sidemenu -> plugin
45
+ * nested-cache: csrf workaround
46
+ * nested-cache: enhanced sweeper version
47
+ * monkey patch will_paginate if my patches are not upstreamed
48
+
49
+ It's quite likely that some of the new tag definitions are missing
50
+ useful id, class, merge or param attributes. This doesn't impact core
51
+ functionality, but it does limit your ability to extend the tags. If
52
+ you notice any such omissions, please let us know, it is easy to fix..
53
+
54
+ ## stuff that we really want to do
55
+
56
+ * fixup deprecation warnings
57
+ * port to Rails 3.2 and/or 4.0
58
+ * nuke any remaining prototype code
59
+ * add a sane default for non-AJAX JSON requests.
60
+ * trawl the lighthouse && pull requests
61
+ * steal the tags from Portal
62
+ * fixup hobo-contrib
63
+
64
+ ## would be nice:
65
+
66
+ * parametrize the clean theme
67
+ * create a bootstrap theme
68
+ * add theme chooser to setup wizard
69
+ * add support for has-one
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.3
1
+ 1.4.0.pre2
@@ -0,0 +1,16 @@
1
+ module HoboDebugHelper
2
+ extend HoboHelperBase
3
+ protected
4
+ def abort_with(*args)
5
+ raise args.*.pretty_inspect.join("-------\n")
6
+ end
7
+
8
+ def log_debug(*args)
9
+ return if not logger
10
+ logger.debug("\n### DRYML Debug ###")
11
+ logger.debug(args.*.pretty_inspect.join("-------\n"))
12
+ logger.debug("DRYML THIS = #{this.typed_id rescue this.inspect}")
13
+ logger.debug("###################\n")
14
+ args.first unless args.empty?
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ # as far as I can tell, these functions are no longer used. It's
2
+ # theoretically possible that they are used in user apps somewhere,
3
+ # but unlikely
4
+ module HoboDeprecatedHelper
5
+ if Rails.application.config.hobo.include_deprecated_helper
6
+ protected
7
+ def uid
8
+ @hobo_uid ||= 0
9
+ @hobo_uid += 1
10
+ end
11
+
12
+ def update_elements_class(updates)
13
+ 'update::'+comma_split(updates).join(':') unless updates.blank?
14
+ end
15
+
16
+ def js_str(s)
17
+ if s.is_a? Hobo::RawJs
18
+ s.to_s
19
+ else
20
+ "'" + s.to_s.gsub("'"){"\\'"} + "'"
21
+ end
22
+ end
23
+
24
+
25
+ def make_params_js(*args)
26
+ ("'" + make_params(*args) + "'").sub(/ \+ ''$/,'')
27
+ end
28
+
29
+
30
+ def nl_to_br(s)
31
+ s.to_s.gsub("\n", "<br/>") if s
32
+ end
33
+
34
+ def transpose_with_field(field, collection=nil)
35
+ collection ||= this
36
+ matrix = collection.map {|obj| obj.send(field) }
37
+ max_length = matrix.*.length.max
38
+ matrix = matrix.map do |a|
39
+ a + [nil] * (max_length - a.length)
40
+ end
41
+ matrix.transpose
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ module HoboHelperBase
2
+
3
+ def add_to_controller(controller)
4
+ controller.send(:include, self)
5
+ controller.hide_action(self.instance_methods)
6
+ end
7
+
8
+ end
@@ -0,0 +1,136 @@
1
+ module HoboPermissionsHelper
2
+ extend HoboHelperBase
3
+ protected
4
+
5
+ def current_user
6
+ # simple one-hit-per-request cache
7
+ @current_user ||= begin
8
+ id = session._?[:user]
9
+ (id && Hobo::Model.find_by_typed_id(id) rescue nil) || ::Guest.new
10
+ end
11
+ end
12
+
13
+
14
+ def logged_in?
15
+ !current_user.guest?
16
+ end
17
+
18
+
19
+ def can_create?(object=this)
20
+ if object.is_a?(Class) and object < ActiveRecord::Base
21
+ object = object.new
22
+ elsif (refl = object.try.proxy_reflection) && refl.macro == :has_many
23
+ if Hobo.simple_has_many_association?(object)
24
+ object = object.new
25
+ object.set_creator(current_user)
26
+ else
27
+ return false
28
+ end
29
+ end
30
+ object.creatable_by?(current_user)
31
+ end
32
+
33
+
34
+ def can_update?(object=this)
35
+ object.updatable_by?(current_user)
36
+ end
37
+
38
+
39
+ def can_edit?(*args)
40
+ object, field = if args.empty?
41
+ if this.respond_to?(:editable_by?) && !this_field_reflection
42
+ [this, nil]
43
+ elsif this_parent && this_field
44
+ [this_parent, this_field]
45
+ else
46
+ [this, nil]
47
+ end
48
+ elsif args.length == 2
49
+ args
50
+ else
51
+ [this, args.first]
52
+ end
53
+
54
+ if !field && (origin = object.try.origin)
55
+ object, field = origin, object.origin_attribute
56
+ end
57
+
58
+ object.editable_by?(current_user, field)
59
+ end
60
+
61
+
62
+ def can_delete?(object=this)
63
+ object.destroyable_by?(current_user)
64
+ end
65
+
66
+
67
+
68
+ def can_call?(*args)
69
+ method = args.last
70
+ object = args.length == 2 ? args.first : this
71
+
72
+ object.method_callable_by?(current_user, method)
73
+ end
74
+
75
+
76
+ # can_view? has special behaviour if it's passed a class or an
77
+ # association-proxy -- it instantiates the class, or creates a new
78
+ # instance "in" the association, and tests the permission of this
79
+ # object. This means the permission methods in models can't rely
80
+ # on the instance being properly initialised. But it's important
81
+ # that it works like this because, in the case of an association
82
+ # proxy, we don't want to loose the information that the object
83
+ # belongs_to the proxy owner.
84
+ def can_view?(*args)
85
+ # TODO: Man does this need a big cleanup!
86
+
87
+ if args.empty?
88
+ # if we're repeating over an array, this_field ends up with the current index. Is this useful to anybody?
89
+ if this_parent && this_field && !this_field.is_a?(Integer)
90
+ object = this_parent
91
+ field = this_field
92
+ else
93
+ object = this
94
+ end
95
+ elsif args.first.is_one_of?(String, Symbol)
96
+ object = this
97
+ field = args.first
98
+ else
99
+ object, field = args
100
+ end
101
+
102
+ if field
103
+ # Field can be a dot separated path
104
+ if field.is_a?(String) && (path = field.split(".")).length > 1
105
+ _, _, object = Dryml.get_field_path(object, path[0..-2])
106
+ field = path.last
107
+ end
108
+ elsif (origin = object.try.origin)
109
+ object, field = origin, object.origin_attribute
110
+ end
111
+
112
+ @can_view_cache ||= {}
113
+ @can_view_cache[ [object, field] ] ||=
114
+ if !object.respond_to?(:viewable_by?)
115
+ true
116
+ elsif object.viewable_by?(current_user, field)
117
+ # If possible, we also check if the current *value* of the field is viewable
118
+ if field.is_one_of?(Symbol, String) && (v = object.send(field)) && v.respond_to?(:viewable_by?)
119
+ if v.is_a?(Array)
120
+ v.new_candidate.viewable_by?(current_user, nil)
121
+ else
122
+ v.viewable_by?(current_user, nil)
123
+ end
124
+ else
125
+ true
126
+ end
127
+ else
128
+ false
129
+ end
130
+ end
131
+
132
+
133
+ def select_viewable(collection=this)
134
+ collection.select {|x| can_view?(x)}
135
+ end
136
+ end
@@ -0,0 +1,196 @@
1
+ module HoboRouteHelper
2
+ extend HoboHelperBase
3
+ protected
4
+ def base_url
5
+ "#{Rails.application.config.action_controller.relative_url_root}"
6
+ end
7
+
8
+ def controller_for(obj)
9
+ if obj.is_a? Class
10
+ obj.name.underscore.pluralize
11
+ else
12
+ obj.class.name.underscore.pluralize
13
+ end
14
+ end
15
+
16
+
17
+ def subsite
18
+ params[:controller]._?.match(/([^\/]+)\//)._?[1]
19
+ end
20
+
21
+ IMPLICIT_ACTIONS = [:index, :show, :create, :update, :destroy]
22
+
23
+ def object_url(obj, *args)
24
+ params = args.extract_options!
25
+ action = args.first._?.to_sym
26
+ options, params = params.partition_hash([:subsite, :method, :format])
27
+ options[:subsite] ||= self.subsite
28
+ subsite, method = options.get :subsite, :method
29
+
30
+ if obj.respond_to?(:member_class) && obj.respond_to?(:origin) && obj.origin
31
+ # Asking for URL of a collection, e.g. category/1/adverts or category/1/adverts/new
32
+
33
+ refl = obj.origin.class.reverse_reflection(obj.origin_attribute)
34
+ owner_name = refl.name.to_s
35
+ owner_name = owner_name.singularize if refl.macro == :has_many
36
+ if action == :new
37
+ action_path = "#{obj.origin_attribute}/new"
38
+ action = :"new_for_#{owner_name}"
39
+ elsif action.nil?
40
+ action_path = obj.origin_attribute
41
+ if method.to_s == 'post'
42
+ action = :"create_for_#{owner_name}"
43
+ else
44
+ O action = :"index_for_#{owner_name}"
45
+ end
46
+ end
47
+ klass = obj.member_class
48
+ obj = obj.origin
49
+ else
50
+ action ||= case options[:method].to_s
51
+ when 'put'; :update
52
+ when 'post'; :create
53
+ when 'delete'; :destroy
54
+ else; obj.is_a?(Class) ? :index : :show
55
+ end
56
+
57
+ if options[:method].to_s == 'post' && obj.try.new_record?
58
+ # Asking for url to post new record to
59
+ obj = obj.class
60
+ end
61
+
62
+ klass = if obj.is_a?(Class)
63
+ obj
64
+ elsif obj.respond_to?(:member_class)
65
+ obj.member_class # We get here if we're passed a scoped class
66
+ else
67
+ obj.class
68
+ end
69
+ end
70
+
71
+ if Hobo::Routes.linkable?(klass, action, options)
72
+
73
+ url = base_url_for(obj, subsite, action)
74
+ url += "/#{action_path || action}" unless action.in?(IMPLICIT_ACTIONS)
75
+
76
+ params = make_params(params)
77
+ params.blank? ? url : "#{url}?#{params}"
78
+ end
79
+ end
80
+
81
+
82
+ def linkable?(*args)
83
+ options = args.extract_options!
84
+ target = args.empty? || args.first.is_a?(Symbol) ? this : args.shift
85
+ action = args.first
86
+ return false if action.nil? && target.try.new_record?
87
+
88
+ if target.respond_to?(:member_class) && (origin = target.try.origin)
89
+ klass = origin.class
90
+ action = if action == :new
91
+ "new_#{target.origin_attribute.to_s.singularize}"
92
+ elsif action.nil?
93
+ target.origin_attribute
94
+ end
95
+ elsif target.is_a?(Class)
96
+ klass = target
97
+ action ||= :index
98
+ else
99
+ klass = target.class
100
+ action ||= :show
101
+ end
102
+
103
+ Hobo::Routes.linkable?(klass, action, options.reverse_merge(:subsite => subsite))
104
+ end
105
+
106
+ def base_url_for(object, subsite, action)
107
+ path = object.to_url_path or Hobo::Error.new("cannot create url for #{object.inspect} (#{object.class})")
108
+ "#{base_url}#{'/' + subsite unless subsite.blank?}/#{path}"
109
+ end
110
+
111
+
112
+ def recognize_page_path
113
+ # round tripping params through the router will remove
114
+ # unnecessary params
115
+ Rails.application.routes.recognize_path(params[:page_path] || url_for(params))
116
+ end
117
+
118
+ def url_for_page_path(options={})
119
+ url_for recognize_page_path.merge(options)
120
+ end
121
+
122
+ def controller_action_from_page_path
123
+ recognize_page_path.values_at(:controller,:action)
124
+ end
125
+
126
+ def defined_route?(r)
127
+ @view.respond_to?("#{r}_url")
128
+ end
129
+
130
+ def _as_params(name, obj)
131
+ if obj.is_a? Array
132
+ obj.map {|x| _as_params("#{name}[]", x)}.join("&")
133
+ elsif obj.is_a? Hash
134
+ obj.map {|k,v| _as_params("#{name}[#{k}]", v)}.join("&")
135
+ elsif obj.is_a? Hobo::RawJs
136
+ "#{name}=' + #{obj} + '"
137
+ else
138
+ v = if obj.is_one_of?(ActiveRecord::Base, Array)
139
+ "@" + typed_id(obj)
140
+ else
141
+ obj.to_s.gsub("'"){"\\'"}
142
+ end
143
+ "#{name}=#{v}"
144
+ end
145
+ end
146
+
147
+ def make_params(*hashes)
148
+ hash = {}
149
+ hashes.each {|h| hash.update(h) if h}
150
+ hash.map {|k,v| _as_params(k, v)}.join("&")
151
+ end
152
+
153
+ def current_page_url
154
+ request.fullpath.match(/^([^?]*)/)._?[1]
155
+ end
156
+
157
+ # Login url for a given user record or user class
158
+ def forgot_password_url(user_class=Hobo::Model::UserBase.default_user_model)
159
+ send("#{user_class.name.underscore}_forgot_password_url") rescue nil
160
+ end
161
+
162
+
163
+ # Login url for a given user record or user class
164
+ def login_url(user_class=Hobo::Model::UserBase.default_user_model)
165
+ send("#{user_class.name.underscore}_login_url") rescue nil
166
+ end
167
+
168
+
169
+ # Sign-up url for a given user record or user class
170
+ def signup_url(user_class=Hobo::Model::UserBase.default_user_model)
171
+ send("#{user_class.name.underscore}_signup_url") rescue nil
172
+ end
173
+
174
+
175
+ # Login url for a given user record or user class
176
+ def logout_url(user_or_class=nil)
177
+ c = if user_or_class.nil?
178
+ current_user.class
179
+ elsif user_or_class.is_a?(Class)
180
+ user_or_class
181
+ else
182
+ user_or_class.class
183
+ end
184
+ send("#{c.name.underscore}_logout_url") rescue nil
185
+ end
186
+
187
+ def new_for_current_user(model_or_assoc=nil)
188
+ model_or_assoc ||= this
189
+ if model_or_assoc.respond_to?(:new_candidate)
190
+ model_or_assoc.user_new_candidate(current_user)
191
+ else
192
+ model_or_assoc.user_new(current_user)
193
+ end
194
+ end
195
+
196
+ end