hobo 0.8.10 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGES.txt +126 -2
  2. data/Rakefile +4 -1
  3. data/bin/hobo +1 -1
  4. data/doctest/scopes.rdoctest +11 -4
  5. data/dryml_generators/rapid/cards.dryml.erb +8 -2
  6. data/dryml_generators/rapid/forms.dryml.erb +5 -4
  7. data/dryml_generators/rapid/pages.dryml.erb +150 -65
  8. data/lib/hobo.rb +1 -1
  9. data/lib/hobo/accessible_associations.rb +2 -0
  10. data/lib/hobo/authentication_support.rb +1 -1
  11. data/lib/hobo/controller.rb +11 -3
  12. data/lib/hobo/dryml/dryml_doc.rb +1 -1
  13. data/lib/hobo/fake_initializer.rb +14 -0
  14. data/lib/hobo/hobo_helper.rb +94 -6
  15. data/lib/hobo/lifecycles.rb +17 -2
  16. data/lib/hobo/lifecycles/lifecycle.rb +1 -1
  17. data/lib/hobo/lifecycles/transition.rb +12 -4
  18. data/lib/hobo/model.rb +25 -22
  19. data/lib/hobo/model_controller.rb +42 -37
  20. data/lib/hobo/model_router.rb +11 -7
  21. data/lib/hobo/permissions.rb +12 -10
  22. data/lib/hobo/permissions/associations.rb +1 -1
  23. data/lib/hobo/static_tags +21 -0
  24. data/lib/hobo/user.rb +7 -3
  25. data/lib/hobo/user_controller.rb +7 -7
  26. data/lib/hobo/view_hints.rb +10 -3
  27. data/rails_generators/hobo/USAGE +4 -0
  28. data/rails_generators/hobo_admin_site/USAGE +16 -0
  29. data/rails_generators/hobo_front_controller/hobo_front_controller_generator.rb +11 -2
  30. data/rails_generators/hobo_front_controller/templates/controller.rb +6 -0
  31. data/rails_generators/hobo_front_controller/templates/summary.dryml +103 -0
  32. data/rails_generators/hobo_model_resource/USAGE +38 -0
  33. data/rails_generators/hobo_rapid/USAGE +3 -0
  34. data/rails_generators/hobo_rapid/templates/hobo-rapid.js +7 -3
  35. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +4 -0
  36. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +5 -0
  37. data/rails_generators/hobo_subsite/USAGE +16 -0
  38. data/rails_generators/hobo_subsite/hobo_subsite_generator.rb +1 -1
  39. data/rails_generators/hobo_user_controller/templates/controller.rb +2 -2
  40. data/rails_generators/hobo_user_model/templates/model.rb +6 -1
  41. data/taglibs/rapid.dryml +1 -0
  42. data/taglibs/rapid_core.dryml +4 -4
  43. data/taglibs/rapid_forms.dryml +29 -21
  44. data/taglibs/rapid_generics.dryml +3 -1
  45. data/taglibs/rapid_lifecycles.dryml +14 -9
  46. data/taglibs/rapid_navigation.dryml +1 -1
  47. data/taglibs/rapid_plus.dryml +1 -0
  48. data/taglibs/rapid_summary.dryml +300 -0
  49. data/taglibs/rapid_support.dryml +1 -1
  50. data/taglibs/rapid_user_pages.dryml +21 -19
  51. data/test/permissions/test_permissions.rb +1 -1
  52. metadata +12 -4
@@ -227,14 +227,14 @@ module Hobo
227
227
  def lifecycle_routes
228
228
  model::Lifecycle.creators.values.where.publishable?.*.name.each do |creator|
229
229
  linkable_route("do_#{singular}_#{creator}", "#{plural}/#{creator}", "do_#{creator}",
230
- :conditions => { :method => :post }, :format => false, :linkable_action => creator)
231
- linkable_route("#{singular}_#{creator}", "#{plural}/#{creator}", creator, :conditions => { :method => :get }, :format => false)
230
+ :conditions => { :method => :post }, :linkable_action => creator)
231
+ linkable_route("#{singular}_#{creator}", "#{plural}/#{creator}", creator, :conditions => { :method => :get })
232
232
  end
233
233
  model::Lifecycle.transitions.where.publishable?.*.name.each do |transition|
234
234
  linkable_route("do_#{singular}_#{transition}", "#{plural}/:id/#{transition}", "do_#{transition}",
235
- :conditions => { :method => :put }, :format => false, :linkable_action => transition)
235
+ :conditions => { :method => :put }, :linkable_action => transition)
236
236
  linkable_route("#{singular}_#{transition}", "#{plural}/:id/#{transition}", transition,
237
- :conditions => { :method => :get }, :format => false)
237
+ :conditions => { :method => :get })
238
238
  end
239
239
  end
240
240
 
@@ -252,9 +252,13 @@ module Hobo
252
252
  options.reverse_merge!(:controller => route_with_subsite(plural))
253
253
  name = name_with_subsite(name)
254
254
  route = route_with_subsite(route)
255
- format_route = options.delete(:format) != false
256
- map.named_route(name, route, options)
257
- map.named_route("formatted_#{name}", "#{route}.:format", options) if format_route
255
+ if HoboSupport::RAILS_AT_LEAST_23
256
+ map.named_route(name, "#{route}.:format", options)
257
+ else
258
+ # kick it old-skool
259
+ map.named_route(name, route, options)
260
+ map.named_route("formatted_#{name}", "#{route}.:format", options)
261
+ end
258
262
  true
259
263
  else
260
264
  false
@@ -46,7 +46,7 @@ module Hobo
46
46
  r.set_creator user
47
47
  yield r if block_given?
48
48
  r.user_view(user)
49
- r.send :callback, :after_user_new
49
+ r.with_acting_user(user) { r.send :callback, :after_user_new }
50
50
  end
51
51
  end
52
52
 
@@ -75,7 +75,7 @@ module Hobo
75
75
  def viewable_by?(user, attribute=nil)
76
76
  new.viewable_by?(user, attribute)
77
77
  end
78
-
78
+
79
79
  end
80
80
 
81
81
 
@@ -190,9 +190,9 @@ module Hobo
190
190
  if attribute
191
191
  attribute = attribute.to_s.sub(/\?$/, '').to_sym
192
192
 
193
- # Try the attribute-specic edit-permission method if there is one
193
+ # Try the attribute-specific edit-permission method if there is one
194
194
  if has_hobo_method?(meth = "#{attribute}_edit_permitted?")
195
- with_acting_user(user) { send(meth) }
195
+ return with_acting_user(user) { send(meth) }
196
196
  end
197
197
 
198
198
  # No setter = no edit permission
@@ -375,20 +375,22 @@ module Hobo
375
375
  end
376
376
  end
377
377
  end
378
-
378
+
379
379
  # Best. Name. Ever
380
- def deunknownify_attribute(attr)
380
+ def deunknownify_attribute(attr, remove_globals = true)
381
381
  attr = attr.to_sym
382
-
382
+
383
383
  metaclass.send :remove_method, attr
384
-
384
+
385
385
  if (refl = self.class.reflections[attr]) && refl.macro == :belongs_to
386
386
  # A belongs_to -- restore the underlying fields
387
387
  deunknownify_attribute refl.primary_key_name
388
- deunknownify_attribute refl.options[:foreign_type] if refl.options[:polymorphic]
388
+ deunknownify_attribute(refl.options[:foreign_type], false) if refl.options[:polymorphic]
389
389
  else
390
390
  # A regular field -- restore the dirty tracking methods
391
- ["#{attr}_change", "#{attr}_was", "#{attr}_changed?", :changed?, :changed, :changes].each do |m|
391
+ # if remove_globals is false, skip the top-level methods, as we have already removed them
392
+ to_remove = remove_globals ? [:changed?, :changed, :changes] : []
393
+ (["#{attr}_change", "#{attr}_was", "#{attr}_changed?"] + to_remove).each do |m|
392
394
  metaclass.send :remove_method, m.to_sym
393
395
  end
394
396
  end
@@ -84,7 +84,7 @@ module Hobo
84
84
  end
85
85
 
86
86
 
87
- def create!(attrs = nil)
87
+ def create(attrs = nil)
88
88
  klass = @reflection.klass
89
89
  user = acting_user if klass < Hobo::Model
90
90
  klass.transaction do
@@ -2,6 +2,8 @@ abbr
2
2
  acronym
3
3
  address
4
4
  applet
5
+ article
6
+ audio
5
7
  b
6
8
  basefont
7
9
  bdo
@@ -9,14 +11,20 @@ big
9
11
  blockquote
10
12
  body
11
13
  button
14
+ canvas
12
15
  caption
13
16
  center
14
17
  cite
15
18
  code
16
19
  colgroup
20
+ command
21
+ datagrid
22
+ datalist
17
23
  dd
18
24
  del
25
+ details
19
26
  dfn
27
+ dialog
20
28
  dir
21
29
  div
22
30
  dl
@@ -24,6 +32,7 @@ dt
24
32
  em
25
33
  embed
26
34
  fieldset
35
+ figure
27
36
  font
28
37
  frameset
29
38
  h1
@@ -33,6 +42,7 @@ h4
33
42
  h5
34
43
  h6
35
44
  head
45
+ hgroup
36
46
  i
37
47
  iframe
38
48
  ins
@@ -42,21 +52,30 @@ label
42
52
  legend
43
53
  li
44
54
  map
55
+ mark
45
56
  menu
57
+ meter
58
+ nav
46
59
  noframes
47
60
  noscript
48
61
  object
49
62
  ol
50
63
  optgroup
51
64
  option
65
+ output
52
66
  p
53
67
  pre
68
+ progress
54
69
  q
70
+ rp
71
+ rt
72
+ ruby
55
73
  s
56
74
  samp
57
75
  script
58
76
  select
59
77
  small
78
+ source
60
79
  span
61
80
  strike
62
81
  strong
@@ -69,9 +88,11 @@ textarea
69
88
  tfoot
70
89
  th
71
90
  thead
91
+ time
72
92
  title
73
93
  tr
74
94
  tt
75
95
  u
76
96
  ul
77
97
  var
98
+ video
@@ -37,6 +37,10 @@ module Hobo
37
37
  validate :validate_current_password_when_changing_password
38
38
 
39
39
  # Virtual attributes for setting and changing the password
40
+ # note that :password_confirmation= is also defined by
41
+ # validates_confirmation_of, so this line must follow any
42
+ # validates_confirmation_of statements.
43
+ # https://hobo.lighthouseapp.com/projects/8324-hobo/tickets/530
40
44
  attr_accessor :current_password, :password, :password_confirmation, :type => :password
41
45
 
42
46
  before_save :encrypt_password
@@ -70,7 +74,7 @@ module Hobo
70
74
  end
71
75
  end
72
76
 
73
- attr_reader :login_attribute
77
+ inheriting_cattr_reader :login_attribute
74
78
 
75
79
 
76
80
  # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
@@ -153,7 +157,7 @@ module Hobo
153
157
 
154
158
 
155
159
  def lifecycle_changing_password?
156
- lifecycle.active_step && :password.in?(lifecycle.active_step.parameters)
160
+ self.class.has_lifecycle? && lifecycle.active_step && :password.in?(lifecycle.active_step.parameters)
157
161
  end
158
162
 
159
163
  # Is a new password (and confirmation) required? (i.e. signing up or changing password)
@@ -163,7 +167,7 @@ module Hobo
163
167
 
164
168
 
165
169
  def validate_current_password_when_changing_password
166
- changing_password? && !authenticated?(current_password) and errors.add :current_password, "is not correct"
170
+ changing_password? && !authenticated?(current_password) and errors.add :current_password, ht(:hobo.messages.current_password_is_not_correct, :default["is not correct"])
167
171
  end
168
172
 
169
173
  end
@@ -57,8 +57,8 @@ module Hobo
57
57
  (redirect_to home_page; return) if logged_in?
58
58
 
59
59
  login_attr = model.login_attribute.to_s.titleize.downcase
60
- options.reverse_merge!(:success_notice => "You have logged in.",
61
- :failure_notice => "You did not provide a valid #{login_attr} and password.")
60
+ options.reverse_merge!(:success_notice => ht(:"users.messages.login.success", :default=>["You have logged in."]),
61
+ :failure_notice => ht(:"users.messages.login.error", :login=>login_attr, :default=>["You did not provide a valid #{login_attr} and password."]))
62
62
 
63
63
  if request.post?
64
64
  user = model.authenticate(params[:login], params[:password])
@@ -97,8 +97,8 @@ module Hobo
97
97
  def hobo_do_signup(&b)
98
98
  do_creator_action(:signup) do
99
99
  if valid?
100
- flash[:notice] = "Thanks for signing up!"
101
- flash[:notice] << " You must activate your account before you can log in. Please check your email." unless this.account_active?
100
+ flash[:notice] = ht(:"users.messages.signup.success", :default=>["Thanks for signing up!"])
101
+ flash[:notice] << ht(:"users.messages.signup.must_activate", :default=>[" You must activate your account before you can log in. Please check your email."]) unless this.account_active?
102
102
  end
103
103
  response_block(&b) or if valid?
104
104
  if this.account_active?
@@ -111,7 +111,7 @@ module Hobo
111
111
 
112
112
 
113
113
  def hobo_logout(options={})
114
- options = options.reverse_merge(:notice => "You have logged out.",
114
+ options = options.reverse_merge(:notice => ht(:"users.messages.logout", :default=>["You have logged out."]),
115
115
  :redirect_to => base_url)
116
116
 
117
117
  logout_current_user
@@ -136,7 +136,7 @@ module Hobo
136
136
  do_transition_action :reset_password do
137
137
  response_block(&b) or if valid?
138
138
  self.current_user = this
139
- flash[:notice] = "Your password has been reset"
139
+ flash[:notice] = ht(:"users.messages.reset_password", :default=>["Your password has been reset"])
140
140
  redirect_to home_page
141
141
  end
142
142
  end
@@ -145,7 +145,7 @@ module Hobo
145
145
 
146
146
  def hobo_update_with_account_flash(*args)
147
147
  hobo_update_without_account_flash(*args) do
148
- flash[:notice] = "Changes to your account were saved" if valid? && @this == current_user
148
+ flash[:notice] = ht(:"users.messages.update.success", :default=>["Changes to your account were saved"]) if valid? && @this == current_user
149
149
  yield if block_given?
150
150
  end
151
151
  end
@@ -18,7 +18,7 @@ module Hobo
18
18
  val
19
19
  else
20
20
  arg = if block
21
- block[*args]
21
+ instance_exec(*args, &block)
22
22
  else
23
23
  args.first
24
24
  end
@@ -43,9 +43,16 @@ module Hobo
43
43
  model < ActiveRecord::Acts::List::InstanceMethods &&
44
44
  model.new.try.scope_condition == "1 = 1" }
45
45
 
46
-
46
+ setter :inline_booleans, [] do |*args|
47
+ if args[0] == true
48
+ model.columns.select { |c| c.type == :boolean }.*.name
49
+ else
50
+ args.*.to_s
51
+ end
52
+ end
53
+
47
54
  # Accessors
48
-
55
+
49
56
  class << self
50
57
 
51
58
  def model
@@ -0,0 +1,4 @@
1
+ Description:
2
+
3
+ Adds support for the basic Hobo & DRYML system, not including
4
+ Rapid.
@@ -0,0 +1,16 @@
1
+ Description:
2
+
3
+ Creates a subsite, a namespaced section of your application.
4
+
5
+ The subsite will use app/views/taglibs/<subsite_name>_site.dryml
6
+ instead of app/views/taglibs/appplication.dryml. This allows you
7
+ to easily set different themes and choose different CSS files for
8
+ the subsite.
9
+
10
+ Controllers for the subsite are created in
11
+ app/controllers/<subsite_name>/ and views are also in their own
12
+ subdirectory. This allows you to have two different controllers
13
+ and two different sets of views for the same model.
14
+
15
+ The difference between hobo_admin_site and hobo_subsite is that
16
+ hobo_admin_site limits the subsite to use by administrators only.
@@ -35,6 +35,7 @@ class HoboFrontControllerGenerator < Rails::Generator::NamedBase
35
35
 
36
36
 
37
37
  m.template("index.dryml", File.join('app/views', class_path, file_name, "index.dryml"))
38
+ m.template("summary.dryml", File.join('app/views', class_path, file_name, "summary.dryml"))
38
39
  end
39
40
  end
40
41
 
@@ -46,8 +47,16 @@ class HoboFrontControllerGenerator < Rails::Generator::NamedBase
46
47
  routes_path = File.join(RAILS_ROOT, "config/routes.rb")
47
48
  name = full_class_path
48
49
 
49
- route = (" map.site_search 'search', :controller => '#{name}', :action => 'search'\n" +
50
- " map.root :controller => '#{name}', :action => 'index'")
50
+ root = class_nesting_depth>0 ? class_nesting.underscore : "root"
51
+
52
+ route = " map.site_search 'search', :controller => '#{name}', :action => 'search'\n"
53
+ if class_nesting_depth == 0
54
+ route+= " map.root :controller => '#{name}', :action => 'index'"
55
+ elsif class_nesting_depth == 1
56
+ route+= " map.#{class_nesting.underscore} '/#{class_nesting.underscore}', :controller => '#{name}', :action => 'index'"
57
+ else
58
+ assert false, "no support for class_nesting_depth>1"
59
+ end
51
60
 
52
61
  route_src = File.read(routes_path)
53
62
  return if route_src.include?(route)
@@ -4,6 +4,12 @@ class <%= class_name %>Controller < ApplicationController
4
4
 
5
5
  def index; end
6
6
 
7
+ def summary
8
+ if !current_user.administrator?
9
+ redirect_to user_login_path
10
+ end
11
+ end
12
+
7
13
  def search
8
14
  if params[:query]
9
15
  site_search(params[:query])
@@ -0,0 +1,103 @@
1
+ <page>
2
+ <content:>
3
+ <div class="content-body">
4
+ <h2>Application Summary</h2>
5
+
6
+ <table class="app-summary">
7
+ <tr> <th></th><th></th></tr>
8
+ <tr> <td>Application Name</td> <td><app-name/></td> </tr>
9
+ <tr> <td>Application Location</td> <td><rails-root/></td> </tr>
10
+ <tr> <td>Rails Version</td> <td><rails-version/></td> </tr>
11
+ <tr> <td>Rails Location</td> <td><rails-location/></td> </tr>
12
+ <tr> <td>Mode</td> <td><rails-env/></td> </tr>
13
+ </table>
14
+
15
+ <h3>Change Control</h3>
16
+ <table class="app-summary">
17
+ <tr> <th></th><th></th></tr>
18
+ <tr> <td>Method</td> <td><cms-method/></td> </tr>
19
+ <if test="&cms_method.strip=='git'">
20
+ <tr> <td>Version</td> <td><cms-version/></td> </tr>
21
+ <tr> <td>Date</td> <td><cms-last-commit-time/></td> </tr>
22
+ <tr> <td>Branch</td> <td><cms-branch/></td> </tr>
23
+ <tr> <td>Clean?</td> <td><cms-clean/></td></tr>
24
+ </if>
25
+ </table>
26
+
27
+
28
+ <h3>Gems</h3>
29
+ <table class="app-summary">
30
+ <with-gems>
31
+ <tr if="&first_item?"><th></th><th>Required</th><th>Installed</th><th>Status</th><th>Dependencies</th></tr>
32
+ <tr>
33
+ <td><gem-name/></td>
34
+ <td><gem-version-required/></td>
35
+ <td><gem-version/></td>
36
+ <td><gem-frozen/></td>
37
+ <td><gem-dependencies/></td>
38
+ </tr>
39
+ </with-gems>
40
+ </table>
41
+
42
+ <h3>Plugins</h3>
43
+ <table class="app-summary">
44
+ <with-plugins>
45
+ <tr if="&first_item?"><th></th><th>Location</th><th>Method</th><th>Clean?</th><th>Version</th></tr>
46
+ <tr>
47
+ <td><plugin-name/></td>
48
+ <td><plugin-location/></td>
49
+ <td><plugin-method/></td>
50
+ <td><plugin-clean/></td>
51
+ <td><plugin-version/></td>
52
+ </tr>
53
+ </with-plugins>
54
+ </table>
55
+
56
+ <h3>Environments</h3>
57
+ <table class="app-summary">
58
+ <tr><th></th><th colspan='2'>database</th></tr>
59
+ <with-environments>
60
+ <tr>
61
+ <td><environment-name /></td>
62
+ <td><database-type /></td>
63
+ <td><database-name /></td>
64
+ </tr>
65
+ </with-environments>
66
+ </table>
67
+
68
+ <h2>Models</h2>
69
+ <table class="app-summary">
70
+ <tr><th>Class</th><th>Table</th></tr>
71
+ <with-models>
72
+ <tr>
73
+ <td><model-name/></td>
74
+ <td><model-table-name/></td>
75
+ </tr>
76
+ </with-models>
77
+ </table>
78
+
79
+ <with-models>
80
+ <h3 if="&this.try.table_name"><model-name /></h3>
81
+ <table class="app-summary">
82
+ <with-model-columns>
83
+ <tr if="&first_item?"><th>Column</th><th>Type</th></tr>
84
+ <tr>
85
+ <td><model-column-name/></td>
86
+ <td><model-column-type/></td>
87
+ </tr>
88
+ </with-model-columns>
89
+ </table>
90
+ <table class="app-summary">
91
+ <with-model-associations>
92
+ <tr if="&first_item?"><th>Association</th><th>Macro</th><th>Class</th></tr>
93
+ <tr>
94
+ <td><model-association-name/></td>
95
+ <td><model-association-macro/></td>
96
+ <td><model-association-class-name/></td>
97
+ </tr>
98
+ </with-model-associations>
99
+ </table>
100
+ </with-models>
101
+ </div>
102
+ </content:>
103
+ </page>