hobo 0.7.2 → 0.7.3

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 (77) hide show
  1. data/bin/hobo +24 -7
  2. data/hobo_files/plugin/CHANGES.txt +501 -0
  3. data/hobo_files/plugin/generators/hobo/hobo_generator.rb +8 -6
  4. data/hobo_files/plugin/generators/hobo/templates/application.dryml +3 -0
  5. data/hobo_files/plugin/generators/hobo/templates/dryml-support.js +132 -0
  6. data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +4 -5
  7. data/hobo_files/plugin/generators/hobo_model_resource/hobo_model_resource_generator.rb +75 -0
  8. data/hobo_files/plugin/generators/hobo_model_resource/templates/controller.rb +7 -0
  9. data/hobo_files/plugin/generators/hobo_model_resource/templates/functional_test.rb +8 -0
  10. data/hobo_files/plugin/generators/hobo_model_resource/templates/helper.rb +2 -0
  11. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +30 -11
  12. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +149 -92
  13. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +0 -48
  14. data/hobo_files/plugin/init.rb +45 -13
  15. data/hobo_files/plugin/lib/action_view_extensions/base.rb +4 -3
  16. data/hobo_files/plugin/lib/active_record/association_proxy.rb +18 -0
  17. data/hobo_files/plugin/lib/active_record/association_reflection.rb +5 -0
  18. data/hobo_files/plugin/lib/active_record/has_many_association.rb +7 -11
  19. data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +8 -0
  20. data/hobo_files/plugin/lib/extensions/test_case.rb +1 -1
  21. data/hobo_files/plugin/lib/hobo.rb +38 -60
  22. data/hobo_files/plugin/lib/hobo/authentication_support.rb +1 -1
  23. data/hobo_files/plugin/lib/hobo/bundle.rb +131 -34
  24. data/hobo_files/plugin/lib/hobo/composite_model.rb +1 -1
  25. data/hobo_files/plugin/lib/hobo/controller.rb +7 -8
  26. data/hobo_files/plugin/lib/hobo/dev_controller.rb +21 -0
  27. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +14 -8
  28. data/hobo_files/plugin/lib/hobo/dryml/dryml_support_controller.rb +13 -0
  29. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +6 -7
  30. data/hobo_files/plugin/lib/hobo/dryml/template.rb +207 -73
  31. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +67 -55
  32. data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +53 -3
  33. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +75 -107
  34. data/hobo_files/plugin/lib/hobo/model.rb +236 -429
  35. data/hobo_files/plugin/lib/hobo/model_controller.rb +277 -437
  36. data/hobo_files/plugin/lib/hobo/model_router.rb +62 -29
  37. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +48 -9
  38. data/hobo_files/plugin/lib/hobo/scopes.rb +98 -0
  39. data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +31 -0
  40. data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +282 -0
  41. data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +88 -0
  42. data/hobo_files/plugin/lib/hobo/scopes/scope_reflection.rb +18 -0
  43. data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +59 -0
  44. data/hobo_files/plugin/lib/hobo/undefined.rb +2 -0
  45. data/hobo_files/plugin/lib/hobo/user.rb +31 -14
  46. data/hobo_files/plugin/lib/hobo/user_controller.rb +41 -27
  47. data/hobo_files/plugin/taglibs/core.dryml +9 -11
  48. data/hobo_files/plugin/taglibs/rapid.dryml +51 -108
  49. data/hobo_files/plugin/taglibs/rapid_editing.dryml +25 -25
  50. data/hobo_files/plugin/taglibs/rapid_forms.dryml +111 -79
  51. data/hobo_files/plugin/taglibs/rapid_generics.dryml +74 -0
  52. data/hobo_files/plugin/taglibs/rapid_navigation.dryml +23 -21
  53. data/hobo_files/plugin/taglibs/rapid_pages.dryml +83 -169
  54. data/hobo_files/plugin/taglibs/rapid_plus.dryml +16 -2
  55. data/hobo_files/plugin/taglibs/rapid_support.dryml +3 -3
  56. data/hobo_files/plugin/taglibs/rapid_user_pages.dryml +104 -0
  57. metadata +60 -55
  58. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +0 -276
  59. data/hobo_files/plugin/generators/hobo_migration/templates/migration.rb +0 -9
  60. data/hobo_files/plugin/lib/active_record/table_definition.rb +0 -34
  61. data/hobo_files/plugin/lib/extensions.rb +0 -375
  62. data/hobo_files/plugin/lib/hobo/email_address.rb +0 -12
  63. data/hobo_files/plugin/lib/hobo/enum_string.rb +0 -50
  64. data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +0 -43
  65. data/hobo_files/plugin/lib/hobo/field_spec.rb +0 -68
  66. data/hobo_files/plugin/lib/hobo/html_string.rb +0 -7
  67. data/hobo_files/plugin/lib/hobo/lazy_hash.rb +0 -40
  68. data/hobo_files/plugin/lib/hobo/markdown_string.rb +0 -11
  69. data/hobo_files/plugin/lib/hobo/migrations.rb +0 -12
  70. data/hobo_files/plugin/lib/hobo/model_queries.rb +0 -117
  71. data/hobo_files/plugin/lib/hobo/password_string.rb +0 -7
  72. data/hobo_files/plugin/lib/hobo/percentage.rb +0 -14
  73. data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +0 -78
  74. data/hobo_files/plugin/lib/hobo/proc_binding.rb +0 -32
  75. data/hobo_files/plugin/lib/hobo/text.rb +0 -3
  76. data/hobo_files/plugin/lib/hobo/textile_string.rb +0 -25
  77. data/hobo_files/plugin/lib/hobo/where_fragment.rb +0 -28
@@ -0,0 +1,88 @@
1
+ module Hobo
2
+
3
+ module Scopes
4
+
5
+ module DefinedScopeProxyExtender
6
+
7
+ attr_accessor :reflections
8
+
9
+ include AutomaticScopes
10
+
11
+ def method_missing(name, *args, &block)
12
+ if (scope = named_scope(name))
13
+ association_proxy_for_scope(name, scope, args)
14
+ elsif member_class.create_automatic_scope(name)
15
+ # create_automatic_scope returned true -- the method now exists
16
+ send(name, *args, &block)
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+
23
+ def named_scope(name)
24
+ proxy_reflection.klass.try.defined_scopes._?[name.to_sym]
25
+ end
26
+
27
+
28
+ def association_proxy_for_scope(name, scope_or_proc, args)
29
+ if scope_or_proc.is_a?(Proc)
30
+ scope = scope_or_proc.call(*args)
31
+ create_association_proxy_for_scope(name, scope)
32
+ else
33
+ # This scope is not parameterised so we can cache the
34
+ # association-proxy in an instance variable
35
+ scope = scope_or_proc
36
+ scope_ivar = "@#{name.to_s.gsub('?','')}_scope"
37
+
38
+ # Some craziness here -- calling instance_variable_get or
39
+ # set directly causes self to get loaded, hence the 'bind'
40
+ # tricks
41
+ Kernel.instance_method(:instance_variable_get).bind(self).call(scope_ivar) or
42
+ begin
43
+ assoc = create_association_proxy_for_scope(name, scope)
44
+ Kernel.instance_method(:instance_variable_set).bind(self).call(scope_ivar, assoc)
45
+ end
46
+ end
47
+ end
48
+
49
+
50
+ def create_association_proxy_for_scope(name, scope)
51
+ options = proxy_reflection.options
52
+ has_many_conditions = options[:conditions]
53
+ has_many_conditions = nil if has_many_conditions.blank?
54
+ source = proxy_reflection.source_reflection
55
+ scope_conditions = scope[:conditions]
56
+ scope_conditions = nil if scope_conditions.blank?
57
+ conditions = if has_many_conditions && scope_conditions
58
+ "(#{sanitize_sql scope_conditions}) AND (#{sanitize_sql has_many_conditions})"
59
+ else
60
+ scope_conditions || has_many_conditions
61
+ end
62
+
63
+ options = options.merge(scope).update(:class_name => proxy_reflection.klass.name,
64
+ :foreign_key => proxy_reflection.primary_key_name)
65
+ options[:conditions] = conditions unless conditions.blank?
66
+ options[:source] = source.name if source
67
+
68
+ options[:limit] = scope[:limit] if scope[:limit]
69
+ options[:order] = scope[:order] if scope[:order]
70
+ options[:include] = scope[:include] if scope[:include]
71
+
72
+ r = ScopeReflection.new(:has_many, name, options, proxy_owner.class, proxy_reflection.name)
73
+
74
+ @reflections ||= {}
75
+ @reflections[name] = r
76
+
77
+ if source
78
+ ActiveRecord::Associations::HasManyThroughAssociation
79
+ else
80
+ ActiveRecord::Associations::HasManyAssociation
81
+ end.new(proxy_owner, r)
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,18 @@
1
+ module Hobo
2
+
3
+ module Scopes
4
+
5
+ class ScopeReflection < ActiveRecord::Reflection::AssociationReflection
6
+
7
+ def initialize(macro, name, options, klass, association_name)
8
+ super(macro, name, options, klass)
9
+ @association_name = association_name
10
+ end
11
+
12
+ attr_accessor :association_name
13
+
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,59 @@
1
+ module Hobo
2
+
3
+ module Scopes
4
+
5
+ class ScopedProxy
6
+
7
+ #include AutomaticScopes
8
+
9
+ def initialize(klass, scope)
10
+ @klass = klass
11
+ @scope = scope
12
+ end
13
+
14
+
15
+ def method_missing(name, *args, &block)
16
+ if name.to_sym.in?(@klass.defined_scopes.keys) || @klass.create_automatic_scope(name)
17
+ proxy = @klass.send(name, *args)
18
+ proxy.instance_variable_set("@parent_scope", self)
19
+ proxy
20
+ else
21
+ _apply_scope { @klass.send(name, *args, &block) }
22
+ end
23
+ end
24
+
25
+ def all
26
+ self.find(:all)
27
+ end
28
+
29
+ def first
30
+ self.find(:first)
31
+ end
32
+
33
+ def member_class
34
+ @klass
35
+ end
36
+
37
+ private
38
+ def _apply_scope
39
+ if @parent_scope
40
+ @parent_scope.send(:_apply_scope) do
41
+ @scope ? @klass.send(:with_scope, :find => @scope) { yield } : yield
42
+ end
43
+ else
44
+ @scope ? @klass.send(:with_scope, :find => @scope) { yield } : yield
45
+ end
46
+ end
47
+
48
+ end
49
+ (Object.instance_methods +
50
+ Object.private_instance_methods +
51
+ Object.protected_instance_methods).each do |m|
52
+ ScopedProxy.send(:undef_method, m) unless
53
+ m.in?(%w{initialize method_missing send instance_variable_set instance_variable_get puts}) || m.starts_with?('_')
54
+
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -40,3 +40,5 @@ module Hobo
40
40
  end
41
41
 
42
42
  end
43
+
44
+
@@ -4,6 +4,12 @@ module Hobo
4
4
 
5
5
  module User
6
6
 
7
+ @user_models = []
8
+
9
+ def self.default_user_model
10
+ @user_models.first._?.constantize
11
+ end
12
+
7
13
  AUTHENTICATION_FIELDS = [:salt, :crypted_password, :remember_token, :remember_token_expires_at]
8
14
 
9
15
  # Extend the base class with AuthenticatedUser functionality
@@ -12,9 +18,12 @@ module Hobo
12
18
  # - plaintext password validation
13
19
  # - login token for rembering a login during multiple browser sessions
14
20
  def self.included(base)
21
+ @user_models << base.name
22
+
15
23
  base.extend(ClassMethods)
16
24
 
17
25
  base.class_eval do
26
+
18
27
  fields do
19
28
  crypted_password :string, :limit => 40
20
29
  salt :string, :limit => 40
@@ -22,21 +31,20 @@ module Hobo
22
31
  remember_token_expires_at :datetime
23
32
  end
24
33
 
25
- # Virtual attribute for the unencrypted password
26
- attr_accessor :password
34
+ validates_confirmation_of :password, :if => :password_required?
27
35
 
28
- validates_presence_of :password, :if => :password_required?
29
- validates_presence_of :password_confirmation, :if => :password_required?
30
- validates_confirmation_of :password, :if => :password_required?
31
-
36
+ # Virtual attributes for setting and changing the password
37
+ attr_accessor :current_password, :password, :password_confirmation, :type => :password
38
+
39
+
40
+ validate :validate_current_password_when_changing_password
41
+
32
42
  before_save :encrypt_password
33
43
 
34
44
  never_show *AUTHENTICATION_FIELDS
35
45
 
36
46
  attr_protected *AUTHENTICATION_FIELDS
37
47
 
38
- set_field_type :password => :password, :password_confirmation => :password
39
-
40
48
  password_validations
41
49
  end
42
50
  end
@@ -50,23 +58,22 @@ module Hobo
50
58
  end
51
59
 
52
60
  def login_attribute=(attr, validate=true)
53
- @login_attr = attr = attr.to_sym
61
+ @login_attribute = attr = attr.to_sym
54
62
  unless attr == :login
55
63
  alias_attribute(:login, attr)
56
- set_field_type :login => field_type(attr)
64
+ declare_attr_type(:login, attr_type(attr)) if table_exists? # this breaks if the table doesn't exist
57
65
  end
58
66
 
59
67
  if validate
60
- validates_presence_of attr
61
68
  validates_length_of attr, :within => 3..100
62
69
  validates_uniqueness_of attr, :case_sensitive => false
63
70
  end
64
71
  end
65
- attr_reader :login_attr
72
+ attr_reader :login_attribute
66
73
 
67
74
  # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
68
75
  def authenticate(login, password)
69
- u = find(:first, :conditions => ["#{@login_attr} = ?", login]) # need to get the salt
76
+ u = find(:first, :conditions => ["#{@login_attribute} = ?", login]) # need to get the salt
70
77
 
71
78
  if u && u.authenticated?(password)
72
79
  if u.respond_to?(:last_login_at) || u.respond_to?(:login_count)
@@ -125,6 +132,10 @@ module Hobo
125
132
  false
126
133
  end
127
134
 
135
+ def changing_password?
136
+ crypted_password? && (password || password_confirmation)
137
+ end
138
+
128
139
  protected
129
140
  # Before filter that encrypts the password before having it stored in the database.
130
141
  def encrypt_password
@@ -133,9 +144,15 @@ module Hobo
133
144
  self.crypted_password = encrypt(password)
134
145
  end
135
146
 
147
+
136
148
  # Is a password required for login? (or do we have an empty password?)
137
149
  def password_required?
138
- (crypted_password.blank? && password != nil) || !password.blank?
150
+ (crypted_password.blank? && password != nil) || !password.blank? || changing_password?
151
+ end
152
+
153
+
154
+ def validate_current_password_when_changing_password
155
+ changing_password? && !authenticated?(current_password) and errors.add :current_password, "is not correct"
139
156
  end
140
157
 
141
158
  end
@@ -2,15 +2,18 @@ module Hobo
2
2
 
3
3
  module UserController
4
4
 
5
- @user_models = []
6
-
7
5
  class << self
8
- attr_reader :user_models
9
-
10
6
  def included(base)
11
- base.filter_parameter_logging "password"
12
- base.skip_before_filter :login_required, :only => [:login]
13
- user_models << base.model
7
+ base.class_eval do
8
+ filter_parameter_logging "password"
9
+ skip_before_filter :login_required, :only => [:login, :signup]
10
+
11
+ include_taglib "rapid_user_pages", :plugin => "hobo"
12
+
13
+ show_action :account
14
+
15
+ alias_method_chain :hobo_update, :account_flash
16
+ end
14
17
  end
15
18
  end
16
19
 
@@ -20,9 +23,10 @@ module Hobo
20
23
 
21
24
  def logout; hobo_logout; end
22
25
 
26
+ private
27
+
23
28
  def hobo_login(options={})
24
- options = LazyHash.new(options)
25
- login_attr = model.login_attr.to_s.titleize.downcase
29
+ login_attr = model.login_attribute.to_s.titleize.downcase
26
30
  options.reverse_merge!(:success_notice => "You have logged in.",
27
31
  :failure_notice => "You did not provide a valid #{login_attr} and password.")
28
32
 
@@ -36,10 +40,12 @@ module Hobo
36
40
 
37
41
  # If supplied, a block can be used to test if this user is
38
42
  # allowed to log in (e.g. the account may be disabled)
39
- if block_given? && !yield
43
+ account_available = block_given? ? yield : true
44
+
45
+ if !account_available
40
46
  # block returned false - cancel this login
41
47
  self.current_user = old_user
42
- hobo_render(:account_disabled)
48
+ render :action => :account_disabled unless performed?
43
49
  else
44
50
  if params[:remember_me] == "1"
45
51
  current_user.remember_me
@@ -50,30 +56,21 @@ module Hobo
50
56
  end
51
57
  end
52
58
  end
53
-
54
- hobo_render unless performed?
55
59
  end
56
60
 
57
61
 
58
62
  def hobo_signup(&b)
59
63
  if request.post?
60
- @user = model.new(params[model.name.underscore])
61
- @this = @user
62
- save_and_set_status!(@user)
63
- self.current_user = @user if valid?
64
+ self.this = model.user_create(current_user, params[model.name.underscore])
65
+ self.current_user = this if valid?
64
66
  response_block(&b) or
65
67
  if valid?
66
68
  flash[:notice] ||= "Thanks for signing up!"
67
69
  redirect_back_or_default(home_page)
68
- elsif invalid?
69
- hobo_render
70
- elsif not_allowed?
71
- permission_denied
72
70
  end
73
71
  else
74
- @this = @user = model.new
72
+ self.this = model.new
75
73
  yield if block_given?
76
- hobo_render unless performed?
77
74
  end
78
75
  end
79
76
 
@@ -81,15 +78,32 @@ module Hobo
81
78
  def hobo_logout(options={})
82
79
  options = options.reverse_merge(:notice => "You have logged out.",
83
80
  :redirect_to => base_url)
84
-
85
- current_user.forget_me if logged_in?
86
- cookies.delete :auth_token
87
- reset_session
81
+
82
+ logout_current_user
88
83
  yield if block_given?
89
84
  flash[:notice] ||= options[:notice]
90
85
  redirect_back_or_default(options[:redirect_to]) unless performed?
91
86
  end
92
87
 
88
+
89
+ def hobo_update_with_account_flash(*args)
90
+ hobo_update_without_account_flash(*args) do
91
+ flash[:notice] = "Changes to your account were saved" if valid? && @this == current_user
92
+ yield if block_given?
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def logout_current_user
99
+ if logged_in?
100
+ current_user.forget_me
101
+ cookies.delete :auth_token
102
+ reset_session
103
+ self.current_user = nil
104
+ end
105
+ end
106
+
93
107
  end
94
108
 
95
109
  end
@@ -3,9 +3,9 @@
3
3
  </def>
4
4
 
5
5
 
6
- <def tag="wrap" attrs="tag, when">
7
- <% body = parameters.default %>
8
- <%= when_ ? call_tag(tag, attributes, &proc { body }) : body %>
6
+ <def tag="wrap" attrs="tag, when, parameter">
7
+ <% parameter ||= :default %>
8
+ <%= when_ ? send(tag, attributes, { parameter.to_sym => parameters[:default] }) : parameter.default %>
9
9
  </def>
10
10
 
11
11
 
@@ -15,8 +15,8 @@
15
15
  %></def>
16
16
 
17
17
 
18
- <def tag="repeat" attrs="even-odd, join"><%=
19
- if !this.blank?
18
+ <def tag="repeat" attrs="even-odd, join">
19
+ <if><%=
20
20
  if even_odd
21
21
  map_this do
22
22
  klass = [attributes[:class], cycle("even", "odd")].compact.join(' ')
@@ -31,15 +31,13 @@
31
31
  res
32
32
  end.join(join)
33
33
  end
34
- end
35
- else
36
- ""
37
- end
38
- %></def>
34
+ end %>
35
+ </if>
36
+ </def>
39
37
 
40
38
 
41
39
  <def tag="do"><%= parameters.default %></def>
42
- <def tag="with"><%= parameters.default %></def>
40
+ <def tag="with" alias-of="do"/>
43
41
 
44
42
 
45
43
  <def tag="if" attrs="test"><%=