hobo 0.7.2 → 0.7.3

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