dry_crud 0.6.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README.rdoc +41 -36
  2. data/Rakefile +51 -43
  3. data/VERSION +1 -1
  4. data/lib/generators/dry_crud/USAGE +1 -0
  5. data/lib/generators/dry_crud/dry_crud_generator.rb +20 -0
  6. data/{rails_generators → lib/generators}/dry_crud/templates/INSTALL +4 -3
  7. data/{rails_generators → lib/generators}/dry_crud/templates/app/controllers/crud_controller.rb +31 -9
  8. data/lib/generators/dry_crud/templates/app/controllers/render_inheritable.rb +152 -0
  9. data/{rails_generators → lib/generators}/dry_crud/templates/app/helpers/crud_helper.rb +4 -4
  10. data/{rails_generators/dry_crud/templates/lib → lib/generators/dry_crud/templates/app/helpers}/standard_form_builder.rb +0 -0
  11. data/{rails_generators → lib/generators}/dry_crud/templates/app/helpers/standard_helper.rb +81 -76
  12. data/{rails_generators/dry_crud/templates/lib → lib/generators/dry_crud/templates/app/helpers}/standard_table_builder.rb +45 -46
  13. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/crud/_attrs.html.erb +0 -0
  14. data/lib/generators/dry_crud/templates/app/views/crud/_form.html.erb +1 -0
  15. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/crud/_list.html.erb +0 -0
  16. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/crud/edit.html.erb +1 -1
  17. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/crud/index.html.erb +1 -1
  18. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/crud/new.html.erb +1 -1
  19. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/crud/show.html.erb +1 -1
  20. data/{rails_generators → lib/generators}/dry_crud/templates/app/views/layouts/crud.html.erb +1 -0
  21. data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +10 -0
  22. data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.erb +4 -0
  23. data/{rails_generators → lib/generators}/dry_crud/templates/public/stylesheets/crud.css +5 -5
  24. data/{rails_generators → lib/generators}/dry_crud/templates/test/crud_test_model.rb +25 -17
  25. data/{rails_generators → lib/generators}/dry_crud/templates/test/functional/crud_controller_test_helper.rb +36 -32
  26. data/{rails_generators → lib/generators}/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +17 -4
  27. data/{rails_generators → lib/generators}/dry_crud/templates/test/unit/crud_helper_test.rb +51 -6
  28. data/{rails_generators → lib/generators}/dry_crud/templates/test/unit/render_inheritable_test.rb +31 -39
  29. data/{rails_generators → lib/generators}/dry_crud/templates/test/unit/standard_form_builder_test.rb +0 -0
  30. data/{rails_generators → lib/generators}/dry_crud/templates/test/unit/standard_helper_test.rb +76 -54
  31. data/{rails_generators → lib/generators}/dry_crud/templates/test/unit/standard_table_builder_test.rb +42 -40
  32. data/test/templates/app/views/ajax/ajax.js.rjs +1 -1
  33. data/test/templates/app/views/ajax/index.html.erb +2 -2
  34. data/test/templates/app/views/cities/_form.html.erb +1 -1
  35. data/test/templates/app/views/cities/_list.html.erb +1 -2
  36. data/test/templates/config/routes.rb +14 -5
  37. metadata +51 -37
  38. data/rails_generators/dry_crud/USAGE +0 -1
  39. data/rails_generators/dry_crud/dry_crud_generator.rb +0 -22
  40. data/rails_generators/dry_crud/templates/app/views/crud/_form.html.erb +0 -1
  41. data/rails_generators/dry_crud/templates/app/views/shared/_labeled.html.erb +0 -5
  42. data/rails_generators/dry_crud/templates/lib/crud_callbacks.rb +0 -55
  43. data/rails_generators/dry_crud/templates/lib/render_inheritable.rb +0 -118
data/README.rdoc CHANGED
@@ -1,36 +1,42 @@
1
1
  = DRY CRUD
2
2
 
3
- Generates simple and extendable controller, views and helpers that support you to DRY up the CRUD code in your Rails project. Start with these elements and build a clean base to efficiently develop your application upon. First, you need to install the gem with
3
+ DRY CRUD generates simple and extendable controller, views and helpers that support you to DRY up the CRUD code in your Rails project. Start with these elements and build a clean base to efficiently develop your application upon. First, you need to install the gem with
4
4
 
5
5
  gem install dry_crud
6
6
 
7
- Then simply run the following generator in your Rails app to get the goodies:
7
+ In order to use the generator, you have to register the gem in your Rails application's +Gemfile+. Add the following lines:
8
8
 
9
- script/generate dry_crud
9
+ group :development, :test do
10
+ gem 'dry_crud'
11
+ end
12
+
13
+ Don't worry, it's a simple development dependency. You may even savely remove it after you have run in once. So now, you should run the generator to get the goodies:
14
+
15
+ rails generate dry_crud
16
+
17
+ To integrate DRY CRUD into your code, only a few additions are required:
10
18
 
11
- To integrate dry_crud into your code, only a few additions are required:
19
+ * For uniform CRUD functionality, just subclass your controllers from +CrudController+.
20
+ * To use standard formatting, tables and forms throughout your application, add <tt>helper :standard</tt> to your +ApplicationController+ and benefit everywhere from these little helper methods.
21
+ * Add a <tt>:label</tt> method to your models for a human-friendly representation.
12
22
 
13
- * To use a standard formatting, tables and forms throughout your application, add 'helper :standard' to your ApplicationController.
14
- * To get uniform CRUD functionallity, just subclass your controllers from CrudController.
15
- * Add a :label method to your models for a human-friendly representation.
23
+ Version 1.0.0 is built for Rails 3. If you need a version for Rails 2.3, please get version 0.6.0 of the gem or go to the rails-2.3 branch on Github.
16
24
 
17
25
  == Overview
18
26
 
19
- In most Rails applications, you have some models that require basic CRUD (create, read, update, delete) functionality. There are various possibilities like Rails scaffolding, {Active Scaffold}[http://activescaffold.com/] or {Dry Scalffold}[http://github.com/grimen/dry_scaffold]. Still, various parts in your application remain duplicated. While you might pull up common methods into a common superclass controller, most views still contain very similar code.
27
+ In most Rails applications, you have some models that require basic CRUD (create, read, update, delete) functionality. There are various possibilities like Rails scaffolding, {Active Scaffold}[http://activescaffold.com/] or {Dry Scaffold}[http://github.com/grimen/dry_scaffold]. Still, various parts in your application remain duplicated. While you might pull up common methods into a common superclass controller, most views still contain very similar code.
20
28
 
21
29
  Enter DRY CRUD.
22
30
 
23
31
  <b>
24
- The main idea of DRY CRUD is to concentrate basic functionality of your application, like CRUD actions, uniform formatting, forms and tables into specifically extendable units. DRY CRUD generates various foundation classes that you may freely adapt to your application's needs. For each model, you may transparently customize arbitrary parts or just fallback to the general behaviour. This applies not only for controllers, but also for view templates and helpers.
32
+ The main idea of DRY CRUD is to concentrate basic functionality of your application, like CRUD actions, uniform formatting, forms and tables into specifically extendable units. DRY CRUD generates various foundation classes that you may freely adapt to your application's needs. For each model, you may transparently customize arbitrary parts or just fallback to the general behavior. This applies not only for controllers, but also for view templates and helpers.
25
33
  </b>
26
34
 
27
- A core element of DRY CRUD is the RenderInheritable module. This gives you inheritable views and partials. In the default case, a template is searched in the current controller's view folder. If it is not found there, the template with the same name in the view folder of the superclass controller is used. This lookup path might be customized as well.
35
+ A core element of DRY CRUD is the +RenderInheritable+ module. This gives you inheritable views and partials. In the default case, a template is searched in the current controller's view folder. If it is not found there, the template with the same name in the view folder of the superclass controller is used. This lookup path might be customized as well. RenderInheritable is also available as a stand-alone gem at http://github.com/codez/render_inheritable.
28
36
 
29
37
  DRY CRUD is a Rails generator. All code resides in your application and is open for you to inspect and to extend. You may pick whatever you consider useful or adapt what is not sufficient. Even if you do not require any CRUD functionality, you might find some helpers simplifying your work. There are no runtime dependencies to the dry_crud gem. Having said this, DRY CRUD does not want to provide a maximum of functionality that requires a lot of configuration, but rather a clean and lightweight foundation to build your application's requirements upon. This is why DRY CRUD comes as a generator and not as a Rails plugin.
30
38
 
31
- DRY CRUD does not depend on any other plugins, but easily allows you to integrate them in order to unify the behaviour of your CRUD controllers. You might even use the plugins mentioned above to adapt your generated CrudController base class. All classes come with thorough tests that provide you with a solid foundation for implementing your own adaptions.
32
-
33
- The gem was developped with Rails 2.3.8, we plan to reach a fully compatible version 1.0 when Rails 3 has come out.
39
+ DRY CRUD does not depend on any other plugins, but easily allows you to integrate them in order to unify the behavior of your CRUD controllers. You might even use the plugins mentioned above to adapt your generated +CrudController+ base class. All classes come with thorough tests that provide you with a solid foundation for implementing your own adaptions.
34
40
 
35
41
  See the Examples section for some use cases and the Generated Files section below for details on the single classes and templates.
36
42
 
@@ -38,7 +44,7 @@ See the Examples section for some use cases and the Generated Files section belo
38
44
 
39
45
  === Controller with CRUD functionality
40
46
 
41
- Say you want to manage a Person model. Create the following controller and add a :label method to your model for a human-friendly representation used in page titles.
47
+ Say you want to manage a +Person+ model. Create the following controller and add a <tt>:label</tt> method to your model for a human-friendly representation used in page titles.
42
48
 
43
49
  <tt>app/controllers/people_controller.rb</tt>:
44
50
  class PeopleController < CrudController
@@ -51,21 +57,21 @@ Say you want to manage a Person model. Create the following controller and add a
51
57
  end
52
58
  end
53
59
 
54
- That's it. You have an overview of all people, detail pages and forms to edit and create persons. Oh, and of course, you may delete persons as well. By default, all attributes are displayed and formatted according to their column type whereever they appear. This holds for the input fields as well.
60
+ That's it. You have an overview of all people, detail pages and forms to edit and create persons. Oh, and of course, you may delete persons as well. By default, all attributes are displayed and formatted according to their column type wherever they appear. This holds for the input fields as well.
55
61
 
56
62
 
57
63
  ==== Customize single views
58
64
 
59
- Well, maybe there are certain attributes you do not want to display in the people list, or others that are not editable. No problem, simply create a <tt>list</tt> partial in <tt>app/views/people/_list.html.erb</tt> to customize this:
65
+ Well, maybe there are certain attributes you do not want to display in the people list, or others that are not editable. No problem, simply create a <tt> _list</tt> partial in <tt>app/views/people/_list.html.erb</tt> to customize this:
60
66
 
61
67
  <%= crud_table [:lastname, :firstname, :city, :sex] %>
62
68
 
63
69
  This only displays these three attributes in the table. All other templates, as well as the main index view, fallback to the ones in <tt>app/views/crud</tt>.
64
70
 
65
71
 
66
- ==== Adapt general behaviour
72
+ ==== Adapt general behavior
67
73
 
68
- Next, let's adapt a part of the general behaviour used in all CRUD controllers. As an example, we include pagination with will_paginate[http://wiki.github.com/mislav/will_paginate/] in all our overview tables:
74
+ Next, let's adapt a part of the general behavior used in all CRUD controllers. As an example, we include pagination with will_paginate[http://wiki.github.com/mislav/will_paginate/] in all our overview tables:
69
75
 
70
76
  In <tt>app/controllers/crud_controller.rb</tt>, change the index action to
71
77
 
@@ -77,19 +83,19 @@ In <tt>app/controllers/crud_controller.rb</tt>, change the index action to
77
83
  In <tt>app/views/crud/index.html.erb</tt>, add the following line for the pagination links:
78
84
  <%= will_paginate @entries %>
79
85
 
80
- And we are done again. All our controllers inheriting from CrudController, including above PeopleController, now have paginated index views. Because our customization for the people table is in the seperate <tt>_list</tt> partial, no further modifications are required.
86
+ And we are done again. All our controllers inheriting from +CrudController+, including above +PeopleController+, now have paginated index views. Because our customization for the people table is in the separate <tt> _list</tt> partial, no further modifications are required.
81
87
 
82
88
 
83
89
  ==== Special formatting for selected attributes
84
90
 
85
- Sometimes, the default formatting provided by :format_attr will not be sufficient. We have a boolean column <tt>sex</tt> in our model, but would like to display 'male' or 'female' for it (instead of 'no' or 'yes', which is a bit cryptic). Just define a method in your view helper starting with <tt>format_</tt>, followed by the attribute name:
91
+ Sometimes, the default formatting provided by +:format_attr+ will not be sufficient. We have a boolean column <tt>sex</tt> in our model, but would like to display 'male' or 'female' for it (instead of 'no' or 'yes', which is a bit cryptic). Just define a method in your view helper starting with <tt>format_</tt>, followed by the attribute name:
86
92
 
87
93
  In <tt>app/helpers/people.rb</tt>:
88
94
  def format_sex(person)
89
95
  person.sex ? 'female' : 'male'
90
96
  end
91
97
 
92
- By the way: The method :f in StandardHelper uniformly formats arbitrary values according to their class.
98
+ By the way: The method +:f+ in +StandardHelper+ uniformly formats arbitrary values according to their class.
93
99
 
94
100
 
95
101
  ==== CRUD controller callbacks
@@ -114,11 +120,11 @@ In <tt>app/controllers/people_controller.rb</tt>:
114
120
 
115
121
  === Standard Tables and Forms
116
122
 
117
- DRY CRUD also provides two builder classes for update/create forms and tables for displaying entries of one model. They may be used allover your application to DRY up the form and table code. Normally, they are used with the corresponding methods from StandardHelper.
123
+ DRY CRUD also provides two builder classes for update/create forms and tables for displaying entries of one model. They may be used all over your application to DRY up the form and table code. Normally, they are used with the corresponding methods from +StandardHelper+.
118
124
 
119
125
  ==== Tables
120
126
 
121
- This is the code to define a table with some attribue columns for a list of same-type entries. Columns get a header corresponding to the attribute name:
127
+ This is the code to define a table with some attribute columns for a list of same-type entries. Columns get a header corresponding to the attribute name:
122
128
  <%= table(@people) do |t|
123
129
  t.attrs :lastname, :firstname
124
130
  end %>
@@ -156,14 +162,22 @@ All generated files are supposed to provide a reasonable foundation for the CRUD
156
162
 
157
163
  === Controller:
158
164
 
159
- {controller/crud_controller.rb}[http://codez.ch/dry_crud/?q=CrudController]:: Abstract controller providing basic CRUD actions in a RESTful way. This implementation mainly follows the one of the Rails scaffolding controller. Some enhancements were made to ease extendability. Several protected helper methods are there to be (optionally) overriden by subclasses.
165
+ {controller/crud_controller.rb}[http://codez.ch/dry_crud/?q=CrudController]:: Abstract controller providing basic CRUD actions. This implementation mainly follows the one of the Rails scaffolding controller and responses to HTML and XML requests. Some enhancements were made to ease extendability. Several protected helper methods are there to be (optionally) overriden by subclasses. With the help of additional callbacks, it is possible to hook into the action procedures without overriding the entire method.
166
+
167
+ {controller/render_inheritable.rb}[http://codez.ch/dry_crud/?q=RenderInheritable]:: A controller enhancement that allows one to render inheritable views and partials. If no view file is found for the current controller, the corresponding file is looked up in its superclass hierarchy. Thus, only views or partials that look differently have to be overwritten.
168
+
160
169
 
161
170
  === Helpers:
162
171
 
163
- {helpers/standard_helper.rb}[http://codez.ch/dry_crud/?q=StandardHelper]:: A view helper to standartize often used functions like formatting, tables, forms or action links. This helper is ideally defined in the ApplicationController. It is required to use the StandardTableBuilder and the StandardFormBuilder.
172
+ {helpers/standard_helper.rb}[http://codez.ch/dry_crud/?q=StandardHelper]:: A view helper to standardize often used functions like formatting, tables, forms or action links. This helper is ideally defined in the ApplicationController. It is required to use the StandardTableBuilder and the StandardFormBuilder.
164
173
 
165
174
  {helpers/crud_helper.rb}[http://codez.ch/dry_crud/?q=CrudHelper]:: A small helper for CrudController to render tables and forms with a default set of attributes.
166
175
 
176
+ {helpers/standard_table_builder.rb}[http://codez.ch/dry_crud/?q=StandardTableBuilder]:: A simple helper object to easily define tables listing several rows of the same data type.
177
+
178
+ {helpers/standard_form_builder.rb}[http://codez.ch/dry_crud/?q=StandardFormBuilder]:: A form builder that automatically selects the corresponding input element for ActiveRecord columns. Input elements are rendered with a corresponding label by default.
179
+
180
+
167
181
  === Views:
168
182
 
169
183
  views/crud/index.html.erb:: The index view displaying a table with all entries and an action link to add new ones.
@@ -184,23 +198,14 @@ views/shared/_labeled.html.erb:: Partial to define the layout for an arbitrary c
184
198
 
185
199
  views/layouts/crud.html.erb:: An example layout showing how to use the @title and +flash+. Most probably you want to include this in your application.html.erb or adapt this main crud templates, so you wont need this file.
186
200
 
187
- public/stylesheets/crud.css:: A simple CSS with all the classes and ids used in the crud code.
188
-
189
- === Lib:
190
-
191
- {lib/standard_table_builder.rb}[http://codez.ch/dry_crud/?q=StandardTableBuilder]:: A simple helper to easily define tables listing several rows of the same data type.
192
-
193
- {lib/standard_form_builder.rb}[http://codez.ch/dry_crud/?q=StandardFormBuilder]:: A form builder that automatically selects the corresponding input element for ActiveRecord columns. Input elements are rendered with a corresponding label by default.
194
-
195
- {lib/render_inheritable.rb}[http://codez.ch/dry_crud/?q=RenderInheritable]:: Allows one to render inheritable views and partials. If no view file is found for the current controller, the corresponding file is looked up in its superclass hierarchy. Thus, only views or partials that look differently have to be overwritten.
201
+ public/stylesheets/crud.css:: A simple CSS with all the classes and ids used in the CRUD code.
196
202
 
197
- {lib/crud_callbacks.rb}[http://codez.ch/dry_crud/?q=CrudCallbacks]:: Defines before and after callback hooks for create, update, save and destroy. When to execute the callbacks is in the responsibility of the clients of this module. This module is used in the CrudController to provide callbacks.
198
203
 
199
204
  === Tests:
200
205
 
201
206
  test/crud_test_model.rb:: A dummy model to run CRUD tests against.
202
207
 
203
- {test/functionals/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/?q=CrudControllerTestHelper]:: A module to include into the functional tests for your CrudController subclasses. Contains a handfull of CRUD functionality tests for the provided implementation. So for each new crud controller, you get 20 tests for free.
208
+ {test/functionals/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/?q=CrudControllerTestHelper]:: A module to include into the functional tests for your CrudController subclasses. Contains a handful of CRUD functionality tests for the provided implementation. So for each new CRUD controller, you get 20 tests for free.
204
209
 
205
210
  test/several other tests:: Testing the provided implementation and a great base to test your adaptions of the CRUD code.
206
211
 
data/Rakefile CHANGED
@@ -2,46 +2,50 @@ require 'rubygems'
2
2
  require "rake/testtask"
3
3
  require 'rake/gempackagetask'
4
4
  require 'rake/rdoctask'
5
- sdoc = (require 'sdoc' || true) rescue false
5
+ sdoc = begin
6
+ require 'sdoc'
7
+ true
8
+ rescue Exception
9
+ false
10
+ end
6
11
 
7
- load 'dry_crud.gemspec'
12
+ load 'dry_crud.gemspec'
8
13
 
9
14
  TEST_APP_ROOT = File.join(File.dirname(__FILE__), 'test', 'test_app')
10
- GENERATOR_ROOT = File.join(File.dirname(__FILE__), 'rails_generators', 'dry_crud')
15
+ GENERATOR_ROOT = File.join(File.dirname(__FILE__), 'lib', 'generators', 'dry_crud')
11
16
 
12
17
  task :default => :test
13
18
 
14
19
  desc "Run all tests"
15
20
  task :test => ['test:app:init'] do
16
- Rake::TestTask.new do |test|
17
- test.libs << "test/test_app/test"
18
- test.test_files = Dir[ "test/test_app/test/**/*_test.rb" ]
19
- test.verbose = true
20
- end
21
+ Rake::TestTask.new do |test|
22
+ test.libs << "test/test_app/test"
23
+ test.test_files = Dir[ "test/test_app/test/**/*_test.rb" ]
24
+ test.verbose = true
25
+ end
21
26
  end
22
27
 
23
28
  namespace :test do
24
- namespace :app do
29
+ namespace :app do
25
30
  task :environment do
26
- ::RAILS_ROOT = TEST_APP_ROOT
27
- ::RAILS_ENV = 'test'
31
+ ENV['RAILS_ROOT'] = TEST_APP_ROOT
32
+ ENV['RAILS_ENV'] = 'test'
28
33
 
29
34
  require(File.join(TEST_APP_ROOT, 'config', 'environment'))
30
35
  end
31
36
 
32
- desc "Create a rails test application"
33
- task :create do
34
- unless File.exist?(TEST_APP_ROOT)
35
- sh "rails #{TEST_APP_ROOT}"
36
- end
37
- end
37
+ desc "Create a rails test application"
38
+ task :create do
39
+ unless File.exist?(TEST_APP_ROOT)
40
+ sh "rails new #{TEST_APP_ROOT}"
41
+ end
42
+ end
38
43
 
39
44
  desc "Run the dry_crud generator for the test application"
40
45
  task :generate_crud => [:create, :environment] do
41
- require 'rails_generator'
42
46
  require File.join(GENERATOR_ROOT, 'dry_crud_generator')
43
47
 
44
- Rails::Generator::Spec.new('dry_crud', GENERATOR_ROOT, :RubyGems).klass.new([], :collision => :force).command(:create).invoke!
48
+ DryCrudGenerator.new('', {:force => true}, :destination_root => TEST_APP_ROOT).invoke_all
45
49
  end
46
50
 
47
51
  desc "Initializes the test application with a couple of classes"
@@ -51,51 +55,55 @@ namespace :test do
51
55
  sh "rake db:migrate db:test:prepare"
52
56
  end
53
57
  end
54
- end
58
+ end
55
59
  end
56
60
 
57
61
  desc "Clean up all generated resources"
58
62
  task :clobber do
59
- FileUtils.rm_rf(TEST_APP_ROOT)
63
+ FileUtils.rm_rf(TEST_APP_ROOT)
60
64
  end
61
65
 
62
66
  desc "Install dry_crud as a local gem."
63
67
  task :install => [:package] do
64
- sudo = RUBY_PLATFORM =~ /win32/ ? '' : 'sudo'
65
- gem = RUBY_PLATFORM =~ /java/ ? 'jgem' : 'gem'
66
- sh %{#{sudo} #{gem} install --no-ri pkg/dry_crud-#{File.read('VERSION').strip}}
68
+ sudo = RUBY_PLATFORM =~ /win32/ ? '' : 'sudo'
69
+ gem = RUBY_PLATFORM =~ /java/ ? 'jgem' : 'gem'
70
+ sh %{#{sudo} #{gem} install --no-ri pkg/dry_crud-#{File.read('VERSION').strip}}
67
71
  end
68
72
 
69
73
  desc "Deploy rdoc to website"
70
74
  task :site => :rdoc do
71
- sh "rsync -rzv rdoc/ #{ENV['DEST']}"
75
+ if ENV['DEST']
76
+ sh "rsync -rzv rdoc/ #{ENV['DEST']}"
77
+ else
78
+ puts "Please specify a destination with DEST=user@server:/deploy/dir"
79
+ end
72
80
  end
73
81
 
74
82
  # :package task
75
83
  Rake::GemPackageTask.new(DRY_CRUD_GEMSPEC) do |pkg|
76
- if Rake.application.top_level_tasks.include?('release')
77
- pkg.need_tar_gz = true
78
- pkg.need_tar_bz2 = true
79
- pkg.need_zip = true
80
- end
84
+ if Rake.application.top_level_tasks.include?('release')
85
+ pkg.need_tar_gz = true
86
+ pkg.need_tar_bz2 = true
87
+ pkg.need_zip = true
88
+ end
81
89
  end
82
90
 
83
91
  # :rdoc task
84
92
  Rake::RDocTask.new do |rdoc|
85
- rdoc.title = 'Dry Crud'
86
- rdoc.options << '--line-numbers' << '--inline-source'
93
+ rdoc.title = 'Dry Crud'
94
+ rdoc.options << '--line-numbers' << '--inline-source'
87
95
  if sdoc
88
96
  rdoc.options << '--fmt' << 'shtml'
89
97
  rdoc.template = 'direct'
90
98
  end
91
- rdoc.rdoc_files.include(*FileList.new('*') do |list|
92
- list.exclude(/(^|[^.a-z])[a-z]+/)
93
- list.exclude('TODO')
94
- end.to_a)
95
- rdoc.rdoc_files.include('rails_generators/dry_crud/templates/**/*.rb')
96
- rdoc.rdoc_files.exclude('rails_generators/dry_crud/templates/**/*_test.rb')
97
- rdoc.rdoc_files.exclude('TODO')
98
-
99
- rdoc.rdoc_dir = 'rdoc'
100
- rdoc.main = 'README.rdoc'
101
- end
99
+ rdoc.rdoc_files.include(*FileList.new('*') do |list|
100
+ list.exclude(/(^|[^.a-z])[a-z]+/)
101
+ list.exclude('TODO')
102
+ end.to_a)
103
+ rdoc.rdoc_files.include('generators/dry_crud/templates/**/*.rb')
104
+ rdoc.rdoc_files.exclude('generators/dry_crud/templates/**/*_test.rb')
105
+ rdoc.rdoc_files.exclude('TODO')
106
+
107
+ rdoc.rdoc_dir = 'rdoc'
108
+ rdoc.main = 'README.rdoc'
109
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 1.0.0
@@ -0,0 +1 @@
1
+ rails g dry_crud
@@ -0,0 +1,20 @@
1
+ require 'rails/generators'
2
+
3
+ class DryCrudGenerator < Rails::Generators::Base
4
+
5
+ def self.source_root
6
+ File.join(File.dirname(__FILE__), 'templates')
7
+ end
8
+
9
+ def install_dry_crud
10
+ # copy everything in template subfolders
11
+ Dir.chdir(self.class.source_root) do
12
+ Dir.glob("*").each do |f|
13
+ directory(f) if File.directory?(f)
14
+ end
15
+ end
16
+
17
+ readme "INSTALL"
18
+ end
19
+
20
+ end
@@ -3,10 +3,11 @@ Thank you for using dry_crud. Feel free to adapt all generated classes to
3
3
  your needs. To integrate dry_crud into your code, only a few additions are
4
4
  required:
5
5
 
6
- * To use a standard formatting, tables and forms throught your application,
7
- add 'helper :standard' to your ApplicationController.
8
- * To get uniform CRUD functionallity, just subclass your controllers from
6
+ * For uniform CRUD functionallity, just subclass your controllers from
9
7
  CrudController.
8
+ * To use standard formatting, tables and forms throughout your
9
+ application, add 'helper :standard' to your ApplicationController and
10
+ benefit everywhere from these little helper methods.
10
11
  * Add a :label method to your models for a human-friendly representation.
11
12
 
12
13
  Enjoy dry_crud and stay DRY!
@@ -1,24 +1,40 @@
1
1
  # Abstract controller providing basic CRUD actions.
2
2
  # This implementation mainly follows the one of the Rails scaffolding
3
- # controller. Some enhancements were made to ease extendability.
3
+ # controller and responses to HTML and XML requests. Some enhancements were made to ease extendability.
4
4
  # Several protected helper methods are there to be (optionally) overriden by subclasses.
5
+ # With the help of additional callbacks, it is possible to hook into the action procedures without
6
+ # overriding the entire method.
5
7
  class CrudController < ApplicationController
6
8
 
7
- include CrudCallbacks
8
9
  include RenderInheritable
9
10
 
11
+ extend ActiveModel::Callbacks
12
+
13
+ # Defines before and after callback hooks for create, update, save and destroy.
14
+ define_model_callbacks :create, :update, :save, :destroy
15
+
16
+ # Defines before callbacks for the render actions.
17
+ define_model_callbacks :render_index,
18
+ :render_show,
19
+ :render_new,
20
+ :render_edit,
21
+ :only => :before,
22
+ :terminator => "result == false || performed?"
23
+
10
24
  delegate :model_class, :model_identifier, :models_label, :to => 'self.class'
11
25
 
12
26
  # Verify that required :id param is present and only allow good http methods.
13
- verify :params => :id, :only => :show, :redirect_to => { :action => 'index' }
14
- verify :method => :post, :only => :create, :redirect_to => { :action => 'index' }
15
- verify :method => [:put, :post], :params => :id, :only => :update, :redirect_to => { :action => 'index' }
16
- verify :method => [:delete, :post], :params => :id, :only => :destroy, :redirect_to => { :action => 'index' }
27
+ # Uncomment if you have the Rails verification plugin installed.
28
+ #verify :params => :id, :only => :show, :redirect_to => { :action => 'index' }
29
+ #verify :method => :post, :only => :create, :redirect_to => { :action => 'index' }
30
+ #verify :method => [:put, :post], :params => :id, :only => :update, :redirect_to => { :action => 'index' }
31
+ #verify :method => [:delete, :post], :params => :id, :only => :destroy, :redirect_to => { :action => 'index' }
17
32
 
18
33
  # Set up entry object to use in the various actions.
19
34
  before_filter :build_entry, :only => [:new, :create]
20
35
  before_filter :set_entry, :only => [:show, :edit, :update, :destroy]
21
36
 
37
+ helper :standard
22
38
  helper_method :model_class, :models_label, :full_entry_label
23
39
 
24
40
  hide_action :model_class, :models_label, :model_identifier, :run_callbacks, :inheritable_root_controller
@@ -152,8 +168,8 @@ class CrudController < ApplicationController
152
168
  # Helper method to run before_render callbacks and render the action.
153
169
  # If a callback renders or redirects, the action is not rendered.
154
170
  def render_with_callback(action)
155
- render_callbacks(action)
156
- render_inheritable :action => action unless performed?
171
+ run_callbacks(:"render_#{action}")
172
+ render :action => action unless performed?
157
173
  end
158
174
 
159
175
  # Saves the current entry with callbacks.
@@ -161,6 +177,12 @@ class CrudController < ApplicationController
161
177
  with_callbacks(:save) { @entry.save }
162
178
  end
163
179
 
180
+ # Helper method the run the given block in between the before and after
181
+ # callbacks of the given kind.
182
+ def with_callbacks(kind, &block)
183
+ send(:"_run_#{kind}_callbacks", &block)
184
+ end
185
+
164
186
  class << self
165
187
  # The ActiveRecord class of the model.
166
188
  def model_class
@@ -175,7 +197,7 @@ class CrudController < ApplicationController
175
197
 
176
198
  # A human readable plural name of the model.
177
199
  def models_label
178
- @models_label ||= model_class.human_name.pluralize
200
+ @models_label ||= model_class.model_name.human.pluralize
179
201
  end
180
202
  end
181
203
 
@@ -0,0 +1,152 @@
1
+ # Allows one to render inheritable views and partials.
2
+ # If no view file is found for the current controller, the corresponding file
3
+ # is looked up in its superclass hierarchy. This module must only be
4
+ # included in the root controller of the desired lookup hierarchy.
5
+ #
6
+ # By default, this module only supports direct inheritance over one level. By overriding
7
+ # the method lookup_path, you may define a custom lookup path. By providing an object
8
+ # for the 'with' parameter, this path may even be dynamic.
9
+ module RenderInheritable
10
+
11
+ # Add inheritable_root_path method to including controller.
12
+ def self.included(controller_class)
13
+ controller_class.send(:extend, ClassMethods)
14
+
15
+ controller_class.send(:class_variable_set, :@@inheritable_root_controller, controller_class)
16
+ controller_class.cattr_reader :inheritable_root_controller
17
+ end
18
+
19
+ # Performs a lookup for the given filename and returns the most specific
20
+ # folder that contains the file.
21
+ def find_inheritable_template_folder(name, partial = false)
22
+ self.class.find_inheritable_template_folder(view_context, name, partial, formats, template_lookup_param)
23
+ end
24
+
25
+ # Override this method to specify a dynamic parameter used in the lookup path.
26
+ # For the default inheritance lookup, this parameter is not needed.
27
+ def template_lookup_param
28
+ nil
29
+ end
30
+
31
+ module ClassMethods
32
+ # Performs a lookup for the given filename and returns the most specific
33
+ # folder that contains the file.
34
+ def find_inheritable_template_folder(view_context, name, partial, formats, param = nil)
35
+ find_inheritable_template_folder_cached(view_context, name, partial, formats, param) do
36
+ find_inheritable_artifact(param) do |folder|
37
+ view_context.template_exists?(name, folder, partial)
38
+ end
39
+ end
40
+ end
41
+
42
+ # Performs a lookup for a controller and returns the name of the most specific one found.
43
+ # This method is primarly usefull when given a 'param' argument that is used
44
+ # in a custom #template_lookup_path. In this case, no controller class would need to
45
+ # exist to render templates from corresponding view folders.
46
+ def inheritable_controller(param = nil)
47
+ descendants = inheritable_root_controller.descendants
48
+ c = find_inheritable_artifact(param) do |folder|
49
+ descendants.any? { |s| s.controller_path == folder }
50
+ end
51
+ c || inheritable_root_controller.controller_path
52
+ end
53
+
54
+ # Runs through the lookup path and yields each folder to the passed block.
55
+ # If the block returns true, this folder is returned and no further lookup
56
+ # happens. If no folder is found, the nil is returned.
57
+ def find_inheritable_artifact(param = nil)
58
+ template_lookup_path(param).each { |folder| return folder if yield(folder) }
59
+ nil
60
+ end
61
+
62
+ # An array of controller names / folders, ordered from most specific to most general.
63
+ # May be dynamic dependening on the passed 'param' argument.
64
+ # You may override this method in an own controller to customize the lookup path.
65
+ def template_lookup_path(param = nil)
66
+ inheritance_lookup_path
67
+ end
68
+
69
+ # The inheritance path of controllers that is used as default lookup path.
70
+ def inheritance_lookup_path
71
+ path = [self]
72
+ until path.last == inheritable_root_controller
73
+ path << path.last.superclass
74
+ end
75
+ path.collect(&:controller_path)
76
+ end
77
+
78
+ # Override view context class to includes the render inheritable modules.
79
+ def view_context_class
80
+ @view_context_class ||= begin
81
+ Class.new(super) do
82
+ include RenderInheritable::View
83
+ end
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ # Performs a lookup for a template folder using the cache.
90
+ def find_inheritable_template_folder_cached(view_context, name, partial, formats, param = nil)
91
+ prefix = inheritable_cache_get(formats, name, partial, param)
92
+ return prefix if prefix
93
+
94
+ prefix = yield
95
+
96
+ if prefix
97
+ template = view_context.find_template_without_lookup(name, prefix, partial)
98
+ inheritable_cache_set(template.formats, name, partial, param, prefix)
99
+ end
100
+ prefix
101
+ end
102
+
103
+ # A simple template lookup cache for each controller.
104
+ def inheritable_cache #:nodoc:
105
+ # do not store keys on each access, only return default structure
106
+ @inheritable_cache ||= Hash.new do |h1, k1|
107
+ Hash.new do |h2, k2|
108
+ Hash.new do |h3, k3|
109
+ Hash.new
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ # Gets the prefix from the cache. Returns nil if it's not there yet.
116
+ def inheritable_cache_get(formats, name, partial, param)
117
+ prefixes = formats.collect { |format| inheritable_cache[format.to_sym][partial][name][param] }
118
+ prefixes.compact!
119
+ prefixes.empty? ? nil : prefixes.first
120
+ end
121
+
122
+ # Stores the found prefix in the cache.
123
+ def inheritable_cache_set(formats, name, partial, param, prefix)
124
+ formats.each do |format|
125
+ # assign hash default values to respective key
126
+ inheritable_cache[format.to_sym] = hf = inheritable_cache[format.to_sym]
127
+ hf[partial] = hp = hf[partial]
128
+ hp[name] = hn = hp[name]
129
+ # finally store prefix in the deepest hash
130
+ hn[param] = prefix
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+ # Extend ActionView so templates are looked up on a find_template call.
137
+ module View
138
+ def self.included(base)
139
+ base.send :alias_method_chain, :find_template, :lookup
140
+ end
141
+
142
+ # Perform a template lookup if the prefix corresponds to the current controller's path.
143
+ def find_template_with_lookup(name, prefix = nil, partial = false)
144
+ if prefix == controller_path
145
+ folder = controller.find_inheritable_template_folder(name, partial)
146
+ prefix = folder if folder
147
+ end
148
+ find_template_without_lookup(name, prefix, partial)
149
+ end
150
+ end
151
+
152
+ end
@@ -5,12 +5,12 @@ module CrudHelper
5
5
 
6
6
  # Create a table of the @entries variable with the default or
7
7
  # the passed attributes in its columns.
8
- def crud_table(attrs = nil, &block)
8
+ def crud_table(*attrs, &block)
9
9
  if block_given?
10
- table(@entries, &block)
10
+ table(@entries, *attrs, &block)
11
11
  else
12
- table(@entries) do |t|
13
- t.attrs(*(attrs || default_attrs))
12
+ attributes = attrs.present? ? attrs : default_attrs
13
+ table(@entries, *attributes) do |t|
14
14
  add_list_actions(t)
15
15
  end
16
16
  end