hobo 0.8.3 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/CHANGES.txt +330 -0
  2. data/Manifest +12 -4
  3. data/Rakefile +4 -6
  4. data/dryml_generators/rapid/cards.dryml.erb +5 -1
  5. data/dryml_generators/rapid/forms.dryml.erb +8 -10
  6. data/dryml_generators/rapid/pages.dryml.erb +65 -36
  7. data/hobo.gemspec +28 -15
  8. data/lib/active_record/association_collection.rb +3 -22
  9. data/lib/hobo.rb +25 -258
  10. data/lib/hobo/accessible_associations.rb +131 -0
  11. data/lib/hobo/authentication_support.rb +15 -9
  12. data/lib/hobo/composite_model.rb +1 -1
  13. data/lib/hobo/controller.rb +7 -8
  14. data/lib/hobo/dryml.rb +9 -10
  15. data/lib/hobo/dryml/dryml_builder.rb +7 -1
  16. data/lib/hobo/dryml/dryml_doc.rb +161 -0
  17. data/lib/hobo/dryml/dryml_generator.rb +18 -9
  18. data/lib/hobo/dryml/part_context.rb +76 -42
  19. data/lib/hobo/dryml/tag_parameters.rb +1 -0
  20. data/lib/hobo/dryml/taglib.rb +2 -1
  21. data/lib/hobo/dryml/template.rb +39 -29
  22. data/lib/hobo/dryml/template_environment.rb +79 -37
  23. data/lib/hobo/dryml/template_handler.rb +66 -21
  24. data/lib/hobo/guest.rb +2 -10
  25. data/lib/hobo/hobo_helper.rb +125 -53
  26. data/lib/hobo/include_in_save.rb +0 -1
  27. data/lib/hobo/lifecycles.rb +54 -24
  28. data/lib/hobo/lifecycles/actions.rb +95 -31
  29. data/lib/hobo/lifecycles/creator.rb +18 -23
  30. data/lib/hobo/lifecycles/lifecycle.rb +86 -62
  31. data/lib/hobo/lifecycles/state.rb +1 -2
  32. data/lib/hobo/lifecycles/transition.rb +22 -28
  33. data/lib/hobo/model.rb +64 -176
  34. data/lib/hobo/model_controller.rb +67 -54
  35. data/lib/hobo/model_router.rb +5 -2
  36. data/lib/hobo/permissions.rb +397 -0
  37. data/lib/hobo/permissions/associations.rb +167 -0
  38. data/lib/hobo/scopes.rb +15 -38
  39. data/lib/hobo/scopes/association_proxy_extensions.rb +15 -5
  40. data/lib/hobo/scopes/automatic_scopes.rb +43 -18
  41. data/lib/hobo/scopes/named_scope_extensions.rb +2 -2
  42. data/lib/hobo/user.rb +10 -4
  43. data/lib/hobo/user_controller.rb +6 -5
  44. data/lib/hobo/view_hints.rb +58 -0
  45. data/rails_generators/hobo/hobo_generator.rb +7 -3
  46. data/rails_generators/hobo/templates/guest.rb +1 -13
  47. data/rails_generators/hobo_front_controller/hobo_front_controller_generator.rb +1 -1
  48. data/rails_generators/hobo_model/hobo_model_generator.rb +4 -2
  49. data/rails_generators/hobo_model/templates/hints.rb +4 -0
  50. data/rails_generators/hobo_model/templates/model.rb +8 -8
  51. data/rails_generators/hobo_model_controller/hobo_model_controller_generator.rb +10 -0
  52. data/rails_generators/hobo_model_controller/templates/controller.rb +1 -1
  53. data/rails_generators/hobo_rapid/templates/hobo-rapid.js +91 -56
  54. data/rails_generators/hobo_rapid/templates/lowpro.js +15 -15
  55. data/rails_generators/hobo_rapid/templates/reset.css +36 -3
  56. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +13 -17
  57. data/rails_generators/hobo_user_controller/templates/controller.rb +1 -1
  58. data/rails_generators/hobo_user_model/templates/model.rb +18 -16
  59. data/taglibs/core.dryml +60 -18
  60. data/taglibs/rapid.dryml +8 -401
  61. data/taglibs/rapid_core.dryml +586 -0
  62. data/taglibs/rapid_document_tags.dryml +28 -10
  63. data/taglibs/rapid_editing.dryml +92 -55
  64. data/taglibs/rapid_forms.dryml +406 -87
  65. data/taglibs/rapid_generics.dryml +1 -1
  66. data/taglibs/rapid_navigation.dryml +2 -1
  67. data/taglibs/rapid_pages.dryml +7 -16
  68. data/taglibs/rapid_plus.dryml +39 -14
  69. data/taglibs/rapid_support.dryml +1 -1
  70. data/taglibs/rapid_user_pages.dryml +14 -4
  71. data/tasks/{generate_tag_reference.rb → generate_tag_reference.rake} +49 -18
  72. data/tasks/hobo_tasks.rake +16 -0
  73. data/test/permissions/models/models.rb +134 -0
  74. data/test/permissions/models/schema.rb +55 -0
  75. data/test/permissions/models/test.sqlite3 +0 -0
  76. data/test/permissions/test_permissions.rb +436 -0
  77. metadata +27 -14
  78. data/lib/hobo/mass_assignment.rb +0 -64
  79. data/rails_generators/hobo/templates/patch_routing.rb +0 -30
  80. data/uninstall.rb +0 -1
@@ -1,6 +1,6 @@
1
1
  <def tag="card" polymorphic>
2
2
  <div class="card" param="default" merge-attrs>
3
- <header param if-content/>
3
+ <header param/>
4
4
  <div param="body" if="&all_parameters[:body]"/>
5
5
  </div>
6
6
  </def>
@@ -14,7 +14,8 @@
14
14
  </def>
15
15
 
16
16
  <def tag="nav-item">
17
- <set body="&parameters.default"/>
17
+ <% body = parameters.default
18
+ body = h(this.to_s) if body.blank? -%>
18
19
  <li class="#{'current' if (c = scope.current_navigation) && c.downcase == body.downcase.gsub(/<.*?>/, '').strip}"
19
20
  merge-attrs="&attributes - attrs_for(:a)">
20
21
  <a merge-attrs="&attributes & attrs_for(:a)"><%= body %></a>
@@ -4,15 +4,16 @@
4
4
  <head param>
5
5
  <title param><%= strip_tags full_title %></title>
6
6
  <do param="stylesheets">
7
- <stylesheet name="reset"/>
8
- <stylesheet name="hobo-rapid"/>
7
+ <stylesheet name="reset, hobo-rapid"/>
9
8
  <theme-stylesheet/>
10
- <stylesheet name="application"/>
9
+ <stylesheet name="application" param="app-stylesheet"/>
11
10
  </do>
12
11
 
13
12
  <do param="scripts">
14
- <javascript param name="prototype, effects, dragdrop, controls, lowpro, hobo-rapid, application"/>
13
+ <javascript param name="prototype, effects, dragdrop, controls, lowpro, hobo-rapid"/>
15
14
  <if-ie version="lt IE 7" param="fix-ie6"><javascript name="IE7"/></if-ie>
15
+ <do param="custom-scripts"/>
16
+ <javascript param="application-javascript" name="application"/>
16
17
  </do>
17
18
  </head>
18
19
 
@@ -23,7 +24,7 @@
23
24
  <h1 param="app-name"><a href="#{base_url}/"><app-name/></a></h1>
24
25
  <live-search param if="&defined_route? :site_search"/>
25
26
  <account-nav if="&login_url(Hobo::User.default_user_model)" param/>
26
- <main-nav param/>
27
+ <main-nav current="&title" param/>
27
28
  </header>
28
29
  <section with-flash-messages param="content"/>
29
30
  <footer class="page-footer" param/>
@@ -122,9 +123,7 @@
122
123
  </def>
123
124
 
124
125
  <def tag="stylesheet" attrs="name">
125
- <repeat with="&comma_split(name)">
126
- <%= stylesheet_link_tag name, attributes %>
127
- </repeat>
126
+ <%= stylesheet_link_tag *(comma_split(name) + [attributes]) %>
128
127
  </def>
129
128
 
130
129
 
@@ -173,11 +172,3 @@
173
172
  %><do field="&name" param="default"/><%
174
173
  end
175
174
  %></def>
176
-
177
-
178
- <def tag="or-cancel">
179
- <if test="&linkable?">or <a>Cancel</a></if>
180
- <else>
181
- <if test="&linkable?(this.class)">or <a to="&this.class">Cancel</a></if>
182
- </else>
183
- </def>
@@ -41,20 +41,6 @@
41
41
  </def>
42
42
 
43
43
 
44
- <def tag="change-password-form">
45
- <form class="change-password" param>
46
- <field-list fields="current_password, password, password_confirmation" param>
47
- <password-label:>New Password</password-label:>
48
- <password-confirmation-label:>Confirm New Password</password-confirmation-label:>
49
- </field-list>
50
-
51
- <div class="actions" param="actions">
52
- <submit label="Change Password" param/>
53
- </div>
54
- </form>
55
- </def>
56
-
57
-
58
44
  <def tag="sortable-collection" attrs="sortable-options"><%
59
45
  singular_name = this.member_class.name.underscore
60
46
  attributes[:id] ||= "#{singular_name}_ordering"
@@ -79,3 +65,42 @@
79
65
  end # FIXME: Make unobstrusive
80
66
  %>
81
67
  </def>
68
+
69
+
70
+ <def tag="preview-with-more" attrs="name">
71
+ <% name ||= collection_name.pluralize -%>
72
+ <section class="#{name.gsub(' ', '-').dasherize} preview-with-more" param="default">
73
+ <h3 param="heading"><%= name.titleize %></h3>
74
+ <a param="more">More <type-name plural lowercase/>...</a>
75
+ <collection param/>
76
+ </section>
77
+ </def>
78
+
79
+
80
+ <def tag="gravatar" attrs="size, rating">
81
+ <% size ||= 80; rating ||= 'g'; digest = Digest::MD5.hexdigest(this.email_address) -%>
82
+ <a class="gravatar"><img class="gravatar" src="http://www.gravatar.com/avatar/#{digest}?s=#{size}&r=#{rating}" merge-attrs/></a>
83
+ </def>
84
+
85
+
86
+ <def tag="live-search">
87
+ <div class="search">
88
+ <label for="search-field">Search</label><input type="search" class="live-search"/>
89
+ <spinner id="search-spinner"/>
90
+ </div>
91
+ <section class="hidden" id="search-results-panel">
92
+ <h2>Search Results</h2><div param="close-button">close</div>
93
+ <section id="search-results">&nbsp;</section>
94
+ </section>
95
+ </def>
96
+
97
+
98
+ <def tag="filter-menu" attrs="param-name, options, no-filter">
99
+ <% no_filter ||= "All" %>
100
+ <form action="&request.request_uri" method="get" class="filter-menu">
101
+ <div>
102
+ <select-menu name="&param_name" options="&options" selected="&params[param_name.gsub('-', '_')]"
103
+ first-option="&no_filter" merge-params/>
104
+ </div>
105
+ </form>
106
+ </def>
@@ -18,7 +18,7 @@
18
18
  columns + assocs
19
19
  end
20
20
  else
21
- comma_split(fields)
21
+ comma_split(fields.gsub('-', '_'))
22
22
  end
23
23
  field_names -= comma_split(skip) if skip
24
24
  field_names = field_names.select {|f| can_view?(this, f)} unless force_all
@@ -1,5 +1,7 @@
1
1
  <def tag="simple-page">
2
- <page without-live-search without-account-nav without-main-nav merge/>
2
+ <page without-live-search without-main-nav merge>
3
+ <account-nav: replace><dev-user-changer/></account-nav:>
4
+ </page>
3
5
  </def>
4
6
 
5
7
 
@@ -131,13 +133,21 @@
131
133
 
132
134
  <content: param>
133
135
  <header param="content-header">
134
- <h2><name/></h2>
136
+ <h2 param="heading"><name/></h2>
135
137
  </header>
136
138
 
137
139
  <section param="content-body">
138
140
  <error-messages param/>
139
- <h2>Change Password</h2>
140
- <change-password-form/>
141
+ <form class="change-password" param>
142
+ <field-list fields="email_address, current_password, password, password_confirmation" param>
143
+ <password-label:>New Password</password-label:>
144
+ <password-confirmation-label:>Confirm New Password</password-confirmation-label:>
145
+ </field-list>
146
+
147
+ <div class="actions" param="actions">
148
+ <submit label="Save" param/>
149
+ </div>
150
+ </form>
141
151
  </section>
142
152
  </content:>
143
153
 
@@ -1,5 +1,5 @@
1
1
  require 'fileutils'
2
- require 'hobosupport'
2
+
3
3
  ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__) + "/../lib"
4
4
 
5
5
  require 'rexml/xpath'
@@ -115,47 +115,78 @@ end
115
115
 
116
116
 
117
117
  def contents(root)
118
- tags = XPath.match(root, '/*/def')
118
+ tags = XPath.match(root, '/*/*[@tag]')
119
119
  tags.map { |tag| " * #{link_to_tag tag}\n" }.join
120
120
  end
121
121
 
122
122
 
123
123
  def doc_for_taglib(title, root)
124
- tags = XPath.match(root, '/*/def').map { |e| doc_for_tag(e) }.join("\n\n")
124
+ tags = XPath.match(root, '/*/*[@tag]').map { |e| doc_for_tag(e) }.join("\n\n")
125
125
 
126
126
  "# #{title}\n\n" + contents(root) + "\n\n" + tags
127
127
  end
128
128
 
129
- namespace :hobo do
129
+ def index_page(output_files, output_dir)
130
+ markdown = "# Tag Documentation\n\n" + output_files.map do |f|
131
+ link = f.gsub(output_dir+'/', '')
132
+ link_text = link.gsub('_', '\_').gsub(/\.html$/, '')
133
+ "* [#{link_text}](#{link})"
134
+ end.join("\n")
130
135
 
131
- desc "Generate markdown formatted reference docs automatically from DRYML taglibs"
132
- task :generate_tag_reference do
133
- gem 'maruku'
134
- require 'maruku'
136
+ html = Maruku.new(markdown).to_html
137
+
138
+ File.open("#{output_dir}/index.html", 'w') { |f| f.write(html) }
139
+ end
135
140
 
136
- src = ENV['src']
141
+ def process_directory(src, output_dir, output_format)
142
+ raise RuntimeError, "#{output_dir} is not a directory" if File.exists?(output_dir) && !File.directory?(output_dir)
137
143
 
138
- output_dir = ENV['output'] || "taglib-docs"
139
- raise RuntimeError, "#{output_dir} is not a directory" if File.exists?(output_dir) && !File.directory?(output_dir)
144
+ FileUtils.mkdir output_dir unless File.exists? output_dir
140
145
 
141
- FileUtils.mkdir output_dir unless File.exists? output_dir
146
+ dryml_files = File.directory?(src) ? Dir["#{src}/*"] : [src]
142
147
 
143
- dryml_files = File.directory?(src) ? Dir["#{src}/*"] : [src]
148
+ output_files = []
144
149
 
145
- dryml_files.each do |f|
150
+ dryml_files.each do |f|
151
+ if File.directory?(f)
152
+ output_files += process_directory(f, "#{output_dir}/#{File.basename(f)}", output_format)
153
+ elsif f =~ /\.dryml$/
146
154
  basename = File.basename(f).sub(/\.dryml$/, '')
147
155
  title = basename.titleize
148
156
 
149
157
  doc = Hobo::Dryml::Parser::Document.new(File.read(f), f)
150
158
 
151
- markdown = doc_for_taglib(title, doc)
152
- #html = Maruku.new(markdown).to_html
159
+ output = doc.restore_erb_scriptlets(doc_for_taglib(title, doc))
160
+ output = Maruku.new(output).to_html.gsub('&amp;', '&') if output_format == 'html'
153
161
 
154
- output_file = "#{output_dir}/#{basename}.markdown"
162
+ output_file = "#{output_dir}/#{basename}.#{output_format}"
155
163
  puts output_file
156
- File.open(output_file, 'w') { |f| f.write(markdown) }
164
+ File.open(output_file, 'w') { |f| f.write(output) }
165
+ output_files << output_file
157
166
  end
158
167
  end
168
+ output_files
169
+ end
170
+
171
+
172
+
173
+ namespace :hobo do
174
+
175
+ desc "Generate markdown formatted reference docs automatically from DRYML taglibs"
176
+ task :generate_tag_reference => :environment do
177
+ gem 'maruku'
178
+ require 'maruku'
179
+
180
+ src = ENV['src']
181
+
182
+ output_dir = ENV['output'] || "taglib-docs"
183
+
184
+ output_format = ENV['format'] || "markdown"
185
+
186
+ output_files = process_directory(src, output_dir, output_format)
187
+
188
+ index_page(output_files, output_dir)
189
+ end
159
190
 
160
191
  end
161
192
 
@@ -27,6 +27,22 @@ namespace :hobo do
27
27
  end
28
28
 
29
29
  end
30
+
31
+ desc "Run the DRYML generators to generate taglibs in app/views/taglibs/auto"
32
+ task :generate_taglibs => :environment do
33
+ Hobo::Dryml::DrymlGenerator.run
34
+ end
35
+
36
+ desc "Run the standard generators that the hobo command runs."
37
+ task :run_standard_generators do
38
+ exec <<-END
39
+ ruby script/generate hobo --add-routes && \
40
+ ruby script/generate hobo_rapid --import-tags && \
41
+ ruby script/generate hobo_user_model user && \
42
+ ruby script/generate hobo_user_controller user && \
43
+ ruby script/generate hobo_front_controller front --delete-index --add-routes
44
+ END
45
+ end
30
46
 
31
47
  end
32
48
 
@@ -0,0 +1,134 @@
1
+ HOBO_HOME = "#{File.dirname(__FILE__)}/../../../.."
2
+ $:.unshift "#{HOBO_HOME}/hobosupport/lib"
3
+ $:.unshift "#{HOBO_HOME}/hobofields/lib"
4
+ $:.unshift "#{HOBO_HOME}/hobo/lib"
5
+
6
+ require 'rubygems'
7
+ require 'sqlite3'
8
+ require 'activerecord'
9
+ require 'hobosupport'
10
+ require 'hobofields'
11
+ require 'hobo'
12
+
13
+ Hobo::Model.enable
14
+
15
+ module Models
16
+
17
+ extend self
18
+
19
+ HOME = File.dirname(__FILE__)
20
+
21
+ def model(name, &b)
22
+ klass = Object.const_set(name, Class.new(ActiveRecord::Base))
23
+ klass.hobo_model
24
+ klass.class_eval(&b)
25
+ klass.delete_all rescue nil
26
+ end
27
+
28
+ def user_model(name, &b)
29
+ klass = Object.const_set(name, Class.new(ActiveRecord::Base))
30
+ klass.hobo_user_model
31
+ klass.class_eval(&b)
32
+ klass.delete_all rescue nil
33
+ end
34
+
35
+ def create_database_sqlite3
36
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3",
37
+ :database => "#{HOME}/test.sqlite3",
38
+ :timeout => 5000)
39
+ end
40
+
41
+ def init
42
+ create_database_sqlite3
43
+ make_models
44
+ up, down = HoboFields::MigrationGenerator.run
45
+ ActiveRecord::Migration.class_eval(up)
46
+ end
47
+
48
+ def make_models
49
+
50
+ model :Response do
51
+ fields do
52
+ body :string
53
+ end
54
+ belongs_to :user
55
+ belongs_to :recipe
56
+ belongs_to :request
57
+ end
58
+
59
+ model :Comment do
60
+ fields do
61
+ body :string
62
+ end
63
+ belongs_to :user
64
+ belongs_to :recipe
65
+ end
66
+
67
+ model :Request do
68
+ fields do
69
+ body :string
70
+ end
71
+ belongs_to :user
72
+ has_many :responses
73
+ end
74
+
75
+ model :Recipe do
76
+ fields do
77
+ name :string
78
+ body :string
79
+ end
80
+ belongs_to :user, :creator => true
81
+ has_many :responses, :dependent => :destroy
82
+ has_many :comments, :dependent => :destroy
83
+ has_many :images, :dependent => :destroy, :accessible => true
84
+ belongs_to :code_example, :dependent => :destroy, :accessible => true
85
+ has_many :collaboratorships
86
+ has_many :collaborators, :through => :collaboratorships, :source => :user, :accessible => true
87
+
88
+ def create_permitted?; acting_user == user end
89
+ def update_permitted?; acting_user == user end
90
+ def destroy_permitted?; acting_user == user end
91
+ end
92
+
93
+ model :Collaboratorship do
94
+ belongs_to :user
95
+ belongs_to :recipe
96
+ def create_permitted?; recipe.user == acting_user end
97
+ def destroy_permitted?; recipe.user == acting_user end
98
+ end
99
+
100
+ model :Image do
101
+ fields do
102
+ name :string
103
+ end
104
+ belongs_to :recipe
105
+ delegate :user, :to => :recipe
106
+ def create_permitted?; user._?.paid_up? && user == acting_user end
107
+ def update_permitted?; user == acting_user end
108
+ def destroy_permitted?; user == acting_user end
109
+ end
110
+
111
+ model :CodeExample do
112
+ fields do
113
+ filename :string
114
+ end
115
+ end
116
+
117
+ user_model :User do
118
+ fields do
119
+ name :string
120
+ paid_up :boolean
121
+ end
122
+ has_many :recipes
123
+ has_many :comments
124
+ has_many :responses
125
+ has_many :requests
126
+
127
+ lifecycle do
128
+ state :active, :default => true
129
+ end
130
+ end
131
+
132
+ end
133
+
134
+ end
@@ -0,0 +1,55 @@
1
+ # ActiveRecord Schema for testing the Hobo permission system
2
+
3
+ ActiveRecord::Schema.define do
4
+
5
+ create_table "responses", :force => true do |t|
6
+ t.datetime "created_at"
7
+ t.datetime "updated_at"
8
+ t.integer "user_id"
9
+ t.integer "recipe_id"
10
+ t.integer "request_id"
11
+ t.text "body"
12
+ t.boolean "markdown"
13
+ end
14
+
15
+ create_table "comments", :force => true do |t|
16
+ t.text "body"
17
+ t.boolean "markdown"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ t.integer "user_id"
21
+ t.integer "recipe_id"
22
+ end
23
+
24
+ create_table "requests", :force => true do |t|
25
+ t.text "description"
26
+ t.boolean "markdown"
27
+ t.datetime "created_at"
28
+ t.datetime "updated_at"
29
+ t.integer "user_id"
30
+ t.string "subject"
31
+ end
32
+
33
+ create_table "recipes", :force => true do |t|
34
+ t.string "name"
35
+ t.text "body"
36
+ t.datetime "created_at"
37
+ t.datetime "updated_at"
38
+ t.integer "user_id"
39
+ end
40
+
41
+ create_table "users", :force => true do |t|
42
+ t.string "crypted_password", :limit => 40
43
+ t.string "salt", :limit => 40
44
+ t.string "remember_token"
45
+ t.datetime "remember_token_expires_at"
46
+ t.string "username"
47
+ t.string "email_address"
48
+ t.boolean "administrator", :default => false
49
+ t.datetime "created_at"
50
+ t.datetime "updated_at"
51
+ t.string "state", :default => "active"
52
+ t.datetime "key_timestamp"
53
+ end
54
+
55
+ end