grimen-dry_scaffold 0.1.1

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 (33) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +303 -0
  3. data/Rakefile +47 -0
  4. data/TODO.textile +12 -0
  5. data/generators/USAGE +8 -0
  6. data/generators/dry_scaffold/dry_scaffold_generator.rb +250 -0
  7. data/generators/dry_scaffold/templates/controller_inherited_resources.rb +40 -0
  8. data/generators/dry_scaffold/templates/controller_standard.rb +242 -0
  9. data/generators/dry_scaffold/templates/controller_test_standard.rb +84 -0
  10. data/generators/dry_scaffold/templates/helper_standard.rb +3 -0
  11. data/generators/dry_scaffold/templates/helper_test_standard.rb +5 -0
  12. data/generators/dry_scaffold/templates/prototypes/controller_inherited_resources.rb +23 -0
  13. data/generators/dry_scaffold/templates/prototypes/controller_standard.rb +132 -0
  14. data/generators/dry_scaffold/templates/prototypes/controller_test_standard.rb +64 -0
  15. data/generators/dry_scaffold/templates/prototypes/helper_standard.rb +3 -0
  16. data/generators/dry_scaffold/templates/prototypes/helper_test_standard.rb +5 -0
  17. data/generators/dry_scaffold/templates/prototypes/layout.html.haml +19 -0
  18. data/generators/dry_scaffold/templates/prototypes/view__form.html.haml +3 -0
  19. data/generators/dry_scaffold/templates/prototypes/view__item.html.haml +9 -0
  20. data/generators/dry_scaffold/templates/prototypes/view_edit.html.haml +10 -0
  21. data/generators/dry_scaffold/templates/prototypes/view_index.html.haml +17 -0
  22. data/generators/dry_scaffold/templates/prototypes/view_new.html.haml +10 -0
  23. data/generators/dry_scaffold/templates/prototypes/view_show.html.haml +13 -0
  24. data/generators/dry_scaffold/templates/view__form.html.haml +13 -0
  25. data/generators/dry_scaffold/templates/view__item.html.haml +10 -0
  26. data/generators/dry_scaffold/templates/view_edit.html.haml +18 -0
  27. data/generators/dry_scaffold/templates/view_index.html.haml +20 -0
  28. data/generators/dry_scaffold/templates/view_layout.html.haml +19 -0
  29. data/generators/dry_scaffold/templates/view_new.html.haml +18 -0
  30. data/generators/dry_scaffold/templates/view_show.html.haml +13 -0
  31. data/rails/init.rb +3 -0
  32. data/tasks/dry_scaffold.rake +51 -0
  33. metadata +88 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jonas Grimfelt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,303 @@
1
+ h1. DRY SCAFFOLD
2
+
3
+ A Rails scaffold generator that generates DRYer, cleaner, and more useful code.
4
+
5
+ h2. Description
6
+
7
+ DryScaffold is a replacement for the Rails scaffold generator that generates code that most people end up deleting or rewriting anyway because of the unusable code. The scaffold concept is powerful, but it has more potential than generating messy and almost useless code. The goal with DryScaffold is to generate DRY, beautiful, and standards compliant code based on common patterns without adding a lot of magic.
8
+
9
+ h4. Key concepts:
10
+
11
+ * Controllers that are DRY, RESTful, no code-smells, following conventions, and implementing VERY common patterns
12
+ * Views that are DRY, semantic, standards compliant, valid, and more useful in development
13
+ * Generator that gets smart with additional arguments - but not stupid without them
14
+ * Any Rails developer should be able to switch generator with no effort - follow current conventions, but extend them
15
+
16
+ h2. Dependencies
17
+
18
+ h3. Required:
19
+
20
+ * "*haml*":http://github.com/nex3/haml - ERB sucks like PHP, end of story
21
+
22
+ h3. Optional:
23
+
24
+ * "*will_paginate*":http://github.com/mislav/will_paginate - Pagination
25
+ * "*formtastic*":http://github.com/justinfrench/formtastic - DRY and semantic forms
26
+ * "*inherited_resources*":http://github.com/josevalim/inherited_resources - DRY/Resourceful controllers
27
+
28
+ h2. Features
29
+
30
+ h3. Overview
31
+
32
+ The most characteristic features:
33
+
34
+ * Generates DRY controllers + functional tests.
35
+ * Generates DRY, semantic, and standard compliant views in HAML - not just HAMLized templates.
36
+ * Generates formtastic - very DRY - forms (using "formtastic" by Justin French et. al.) by default. Note: Can be turned off.
37
+ * Generates resourceful - even DRYer - controllers (using the "inherited_resources" by José Valim) by default. Note: Can be turned off.
38
+ * Collection pagination using will_paginate by default. Note: Can be turned off.
39
+ * Optionally specify what actions/views to generate (stubs for specified REST-actions will be generated).
40
+ * Optionally specify what respond_to-formats to generate (stubs for the most common respond_to-formats will be generated).
41
+ * Generates default helpers/models/migrations, and REST-routes.
42
+
43
+ h3. Formtastic Forms
44
+
45
+ Quick and dirty; Formtastic makes your form views cleaner, and your life as a Rails developer easier (for real). Formtastic forms can be turned off, but I would recommend any Rails developer to consider using it - there is really no good reason not to if you not running very old version of Rails.
46
+
47
+ h4. Default HAML (without Formtastic):
48
+
49
+ <pre>- form_for(@<%= singular_name %>) do |f|
50
+ = f.error_messages
51
+ %ul
52
+ %li
53
+ = f.label :title, 'Title'
54
+ = f.text_field :title
55
+ %li
56
+ = f.label :description, 'Description'
57
+ = f.text_field :description
58
+ %p.buttons
59
+ = f.submit 'Create'</pre>
60
+
61
+ h4. Formtastic + HAML:
62
+
63
+ <pre>- semantic_form_for(@resource) do |f|
64
+ - f.inputs do
65
+ = f.input :title
66
+ = f.input :description
67
+ - f.buttons do
68
+ = f.commit_button 'Create'</pre>
69
+
70
+ Find out more about *formtastic*: "http://github.com/justinfrench/formtastic":http://github.com/justinfrench/formtastic
71
+
72
+ h3. Resourceful Controllers
73
+
74
+ Quick and dirty; InheritedResources makes your controllers controllers cleaner, and might make experienced Rails developer's life DRYer code wise. This is possible because of REST as a convention in Rails, and therefore the patterns that arise in controllers can be DRYed up A LOT. Resourceful - InheritedResources-based - controllers can be turned off, but I would recommend any experienced Rails developer to consider using it - there is really no good reason not to unless maybe if you are a Rails beginner, then you should consider get used to the basic Rails building blocks first.
75
+
76
+ h4. Default (without InheritedResources)
77
+
78
+ <pre>def new
79
+ @duck = Duck.new
80
+
81
+ respond_to do |format|
82
+ format.html # new.html.haml
83
+ format.xml { render :xml => @duck }
84
+ format.json { render :json => @duck }
85
+ end
86
+ end</pre>
87
+
88
+ h4. Resourceful (InheritedResources)
89
+
90
+ <pre>actions :new
91
+ respond_to :html, :xml, :json</pre>
92
+
93
+ Find out more about *inherited_resources*: "http://github.com/josevalim/inherited_resources":http://github.com/josevalim/inherited_resources
94
+
95
+ h3. Pagination
96
+
97
+ Pagination is such a common feature that always seems to be implemented anyway, so dry_scaffold will generate a DRY solution for this in each controller that you can tweak - even thought that will not be needed in most cases. See DRY Patterns beneath for more details how it's done.
98
+
99
+ Find out more about *will_paginate*: "http://github.com/mislav/will_paginate":http://github.com/mislav/will_paginate
100
+
101
+ h3. DRY Patterns
102
+
103
+ Either if you choosing default or resourceful controllers, this pattern is used to DRYing up controllers a bit more, and at the same time loading resources in the same place using before_filter while adding automatic pagination for collections.
104
+
105
+ h4. Default (ActionController, without InheritedResources)
106
+
107
+ <pre>before_filter :load_resource, :only => [:show, :edit, :update, :destroy]
108
+ before_filter :load_and_paginate_resources, :only => [:index]
109
+
110
+ protected
111
+
112
+ def collection
113
+ paginate_options ||= {}
114
+ paginate_options[:page] ||= (params[:page] || 1)
115
+ paginate_options[:per_page] ||= (params[:per_page] || 20)
116
+ @collection = @resources ||= Duck.paginate(paginate_options)
117
+ end
118
+ alias :load_and_paginate_resources :collection
119
+
120
+ def resource
121
+ @resource = @resource = ||= Duck.find(params[:id])
122
+ end
123
+ alias :load_resource :resource</pre>
124
+
125
+ h4. Resourceful (InheritedResources)
126
+
127
+ <pre>protected
128
+
129
+ def collection
130
+ paginate_options ||= {}
131
+ paginate_options[:page] ||= (params[:page] || 1)
132
+ paginate_options[:per_page] ||= (params[:per_page] || 20)
133
+ @collection = @resources ||= end_of_association_chain.paginate(paginate_options)
134
+ end
135
+
136
+ def resource
137
+ @resource = @resource ||= end_of_association_chain.find(params[:id])
138
+ end</pre>
139
+
140
+ h3. View Partials
141
+
142
+ A very common pattern is to break up views in partials, wich is also what DryScaffold does:
143
+
144
+ * new/edit => _form
145
+ * index => _item
146
+
147
+ h3. More To Come... (TODO)
148
+
149
+ These are things I have in mind:
150
+
151
+ * Generation of factory stubs instead of fixture stubs that Rails model generator generates
152
+ * Generation of Rails builder stubs (RSS/Atom/...)
153
+ * Break up into multiple generators as dependencies (like Rails generators): dry_controller, dry_views, dry_scaffold, ...
154
+
155
+ h2. Setup
156
+
157
+ Installing DryScaffold is easy as 1-2-3...nah, really:
158
+
159
+ h3. 1. Installation
160
+
161
+ Install DryScaffold...
162
+
163
+ h4. Gem (Recommended)
164
+
165
+ <pre>gem sources -a http://gems.github.com
166
+ sudo gem install grimen-dry_scaffold</pre>
167
+
168
+ h4. Plugin
169
+
170
+ <pre>./script/plugin install git://github.com/grimen/dry_scaffold.git</pre>
171
+
172
+ h3. 2. Configuration (Gem only)
173
+
174
+ In: @config/environments/development.rb@
175
+
176
+ <pre>config.gem 'grimen-dry_scaffold', :lib => 'dry_scaffold'</pre>
177
+
178
+ h3. 3. Install Dependencies (Partly optional)
179
+
180
+ Install dependencies to release the full power of dry_scaffold. Only HAML is really required of these, but how could anyone resist candy? =)
181
+
182
+ h4. Installation, i.e. get the gems
183
+
184
+ <pre>sudo gem install haml</pre>
185
+ <pre>sudo gem install will_paginate</pre>
186
+ <pre>sudo gem install justinfrench-formtastic</pre>
187
+ <pre>sudo gem install josevalim-inherited_resources</pre>
188
+
189
+ h4. Configuration
190
+
191
+ In: @config/environment.rb@
192
+
193
+ <pre>config.gem 'haml'</pre>
194
+ <pre>config.gem 'will_paginate'</pre>
195
+ <pre>config.gem 'justinfrench-formtastic', :lib => 'formtastic, :source => 'http://gems.github.com'</pre>
196
+ <pre>config.gem 'josevalim-inherited_resources', :lib => 'inherited_resources', :source => 'http://gems.github.com'</pre>
197
+
198
+ h2. Usage
199
+
200
+ <pre>./script/generate dry_scaffold ModelName [attribute:type attribute:type] [_actions:new,create,...] [_formats:html,json,...] [--skip-pagination] [--skip-resourceful] [--skip-formtastic] [--skip-views] [--skip-helpers] [--skip-tests] [--include-layout]</pre>
201
+
202
+ h3. Model Name
203
+
204
+ Example: <pre>Hello</pre>
205
+
206
+ Same as in the default scaffold/model generator; the name of a new/existing model.
207
+
208
+ h3. Model Attributes
209
+
210
+ Example: <pre>title:string description:text ...</pre>
211
+
212
+ Same as in the default scaffold/model generator; model attributes and database migration column types.
213
+
214
+ h3. Controller Actions
215
+
216
+ Usage: <pre>_actions:new,create,recent,index,...</pre>
217
+
218
+ You can override what actions that should be generated directly - including custom actions.
219
+
220
+ NOTE: Sorry for the a bit ugly prefix (_), but I had to trick the Rails generator a bit to get this working for now. This is definitely something I want to fix sooner or later, but I skipped that for now with this small hack.
221
+
222
+ h4. Default actions (REST)
223
+
224
+ If no actions are specified, the following REST-actions will be generated by default:
225
+
226
+ * @show@
227
+ * @index@
228
+ * @new@
229
+ * @edit@
230
+ * @create@
231
+ * @update@
232
+ * @destroy@
233
+
234
+ Default controller action stubs, controller action test stubs, and corresponding views (and required partials), are generated for all of these actions.
235
+
236
+ h4. Custom actions
237
+
238
+ The above REST actions are in many RESTful applications the only ones needed. Any other specified actions will generate empty action function stubs for manual implementation. No views will be generated for custom actions.
239
+
240
+ h3. Controller Formats
241
+
242
+ Usage: <pre>_formats:html,xml,txt,...</pre>
243
+
244
+ You can override what respond_to-formats that should be generated directly - only for REST-actions right now because I tried to avoid bad assumptions.
245
+
246
+ NOTE: Sorry for the a bit ugly prefix (_), but I had to trick the Rails generator a bit to get this working for now. This is definitely something I want to fix sooner or later, but I skipped that for now with this small hack.
247
+
248
+ h4. Default formats
249
+
250
+ If no formats are specified, the following formats will be generated by default:
251
+
252
+ * @html@ => Render: resource using view template (HTML/HAML)
253
+ * @js@ => Render: resource using view template (JS/RJS)
254
+ * @xml@ => Render: resource.to_xml
255
+ * @json@ => Render: resource.to_json
256
+
257
+ Default respond block stubs are generated for all of these formats - for each generated REST-action.
258
+
259
+ h4. Additional formats
260
+
261
+ Also, default respond block stubs are generated for any of these formats - for each generated REST-action - if they are specified:
262
+
263
+ * @yaml@ or @yml@ => Render: resource.to_yaml
264
+ * @txt@ or @text@ => Render: resource.to_s
265
+
266
+ h4. Custom formats
267
+
268
+ The above formats are the most commonly used ones, and respond blocks are already implemented using Rails default dependencies. Any other specified formats (such as PDF, CSV, etc.) will generate empty respond block stubs for manual implementation with help of additional dependencies.
269
+
270
+ h3. Options/Flags
271
+
272
+ Example: <pre>--skip-resourceful --include-layout</pre>
273
+
274
+ * @--skip-pagination@ - Don't generate pagination of collections in controller and views, i.e. don't use *will_paginate*.
275
+ * @--skip-resourceful@ - Don't generate resourceful controller, i.e. don't use *inherited_resources*.
276
+ * @--skip-formtastic@ - Don't generate formtastic forms in views, i.e. don't use *formtastic*.
277
+ * @--skip-views@ - Don't generate views.
278
+ * @--skip-helpers@ - Don't generate helpers.
279
+ * @--skip-tests@ - Don't generate tests (functional/unit/...).
280
+ * @--include-layout@ - Generate a neat application layout.
281
+
282
+ As DryScaffold is built upon Rails generator, the default generator options is available as well. For more details; see Rails documentation.
283
+
284
+ h2. Examples
285
+
286
+ No need for more samples here, just create a new Rails project, install dry_scaffold and it's dependencies, and try it out!
287
+
288
+ For your inspiration, you could try the following:
289
+
290
+ <pre>./script/generate dry_scaffold Zebra name:string about:text --skip-resourceful
291
+ ./script/generate dry_scaffold Kangaroo name:string about:text --skip-formtastic
292
+ ./script/generate dry_scaffold Duck name:string about:text _actions:new,create,index,quack
293
+ ./script/generate dry_scaffold Parrot name:string about:text _formats:html,xml,yml</pre>
294
+
295
+ ...or just go crazy!
296
+
297
+ h2. Bugs & Feedback
298
+
299
+ If you experience any issues/bugs or have feature requests, just file a GitHub-issue or send me a message.
300
+ If you think parts of my implementation could be implemented nicer somehow, please let me know...or just fork it and fix it yourself! =)
301
+ At last, positive feedback is always appreciated!
302
+
303
+ Copyright (c) 2009 Jonas Grimfelt
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ NAME = "dry_scaffold"
6
+ SUMMARY = %Q{A DRYer scaffold generator for Rails. Generates dry semantic and standards compliant views, and dry RESTful controllers.}
7
+ HOMEPAGE = "http://github.com/grimen/#{NAME}/tree/master"
8
+ AUTHOR = "Jonas Grimfelt"
9
+ EMAIL = "grimen@gmail.com"
10
+
11
+ begin
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ gem.name = NAME
15
+ gem.summary = SUMMARY
16
+ gem.description = SUMMARY
17
+ gem.homepage = HOMEPAGE
18
+ gem.author = AUTHOR
19
+ gem.email = EMAIL
20
+
21
+ gem.require_paths = %w{lib}
22
+ gem.files = %w(MIT-LICENSE README.textile TODO.textile Rakefile) + Dir.glob(File.join('{generators,rails,tasks}', '**', '*'))
23
+ gem.executables = %w()
24
+ gem.extra_rdoc_files = %w{README.textile}
25
+ end
26
+ rescue LoadError
27
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
28
+ end
29
+
30
+ desc %Q{Run unit tests for "#{NAME}".}
31
+ task :default => :test
32
+
33
+ desc %Q{Run unit tests for "#{NAME}".}
34
+ Rake::TestTask.new(:test) do |test|
35
+ test.libs << 'lib'
36
+ test.pattern = 'test/**/*_test.rb'
37
+ test.verbose = true
38
+ end
39
+
40
+ desc %Q{Generate documentation for "#{NAME}".}
41
+ Rake::RDocTask.new(:rdoc) do |rdoc|
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = NAME
44
+ rdoc.options << '--line-numbers' << '--inline-source' << '--charset=UTF-8'
45
+ rdoc.rdoc_files.include('README.textile')
46
+ rdoc.rdoc_files.include(File.join('lib', '**', '*.rb'))
47
+ end
data/TODO.textile ADDED
@@ -0,0 +1,12 @@
1
+ h1. TODO
2
+
3
+ h2. Next
4
+
5
+ * Something like "model_generator_with_factories" (using machinist, factory_girl, ...). Source: http://github.com/vigetlabs/model_generator_with_factories/tree/master
6
+ * Break up in different generators: dry_controller, dry_views, etc., and use as dependencies in dry_scaffold
7
+ * Optionally generate builders (Atom/RSS/...)
8
+
9
+ h2. Maybe later
10
+
11
+ * Comment the code a bit more =)
12
+ * Check for overridden templates in: RAILS_ROOT/lib/dry_scaffold/templates/
data/generators/USAGE ADDED
@@ -0,0 +1,8 @@
1
+ NAME
2
+ dry_scaffold - A Rails scaffold generator that generates DRYer, cleaner, and more useful code.
3
+
4
+ DESCRIPTION
5
+ A replacement for the Rails scaffold generator that generates code that most people end up deleting or rewriting anyway because of the unusable code. The scaffold concept is powerful, but it has more potential than generating messy and almost useless code. The goal with dry_scaffold is to generate DRY, beautiful, and standards compliant code based on common patterns without adding a lot of magic.
6
+
7
+ EXAMPLE
8
+ ./script/generate dry_scaffold ModelName [attribute:type attribute:type] [_actions:new,create,...] [_formats:html,json,...] [--skip-pagination] [--skip-resourceful] [--skip-formtastic] [--skip-views] [--skip-helpers] [--skip-tests] [--include-layout]
@@ -0,0 +1,250 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'formtastic'
5
+ FORMTASTIC = true
6
+ rescue
7
+ FORMTASTIC = false
8
+ end
9
+ begin
10
+ require 'inherited_resources'
11
+ INHERITED_RESOURCES = true
12
+ rescue
13
+ INHERITED_RESOURCES = false
14
+ end
15
+ begin
16
+ require 'will_paginate'
17
+ WILL_PAGINATE = true
18
+ rescue
19
+ WILL_PAGINATE = false
20
+ end
21
+
22
+ class DryScaffoldGenerator < Rails::Generator::NamedBase
23
+
24
+ DEFAULT_RESPOND_TO_FORMATS = [:html, :xml, :json].freeze
25
+ DEFAULT_MEMBER_ACTIONS = [:show, :new, :edit, :create, :update, :destroy].freeze
26
+ DEFAULT_MEMBER_AUTOLOAD_ACTIONS = (DEFAULT_MEMBER_ACTIONS - [:new, :create])
27
+ DEFAULT_COLLECTION_ACTIONS = [:index].freeze
28
+ DEFAULT_COLLECTION_AUTOLOAD_ACTIONS = DEFAULT_COLLECTION_ACTIONS
29
+ DEFAULT_CONTROLLER_ACTIONS = (DEFAULT_COLLECTION_ACTIONS + DEFAULT_MEMBER_ACTIONS)
30
+
31
+ DEFAULT_VIEW_TEMPLATE_FORMAT = :haml
32
+
33
+ CONTROLLERS_PATH = File.join('app', 'controllers').freeze
34
+ HELPERS_PATH = File.join('app', 'helpers').freeze
35
+ VIEWS_PATH = File.join('app', 'views').freeze
36
+ LAYOUTS_PATH = File.join(VIEWS_PATH, 'layouts').freeze
37
+ MODELS_PATH = File.join('app', 'models').freeze
38
+ FUNCTIONAL_TESTS_PATH = File.join('test', 'functional').freeze
39
+ UNIT_TESTS_PATH = File.join('test', 'unit', 'helpers').freeze
40
+
41
+ RESOURCEFUL_COLLECTION_NAME = 'collection'.freeze
42
+ RESOURCEFUL_SINGULAR_NAME = 'resource'.freeze
43
+
44
+ ARG_KEY_VALUE_DIVIDER = ':'.freeze
45
+ NON_ATTR_ARG_KEY_PREFIX = '_'.freeze
46
+ NON_ATTR_ARG_VALUE_DIVIDER = ','.freeze
47
+
48
+ # :{action} => [:{partial}, ...]
49
+ VIEW_TEMPLATES = {
50
+ :index => [:item],
51
+ :show => [],
52
+ :new => [:form],
53
+ :edit => [:form]
54
+ }.freeze
55
+
56
+ default_options :resourceful => INHERITED_RESOURCES,
57
+ :formtastic => FORMTASTIC,
58
+ :pagination => WILL_PAGINATE,
59
+ :skip_tests => false,
60
+ :skip_helpers => false,
61
+ :skip_views => false,
62
+ :include_layout => false
63
+
64
+ attr_reader :controller_name,
65
+ :controller_class_path,
66
+ :controller_file_path,
67
+ :controller_class_nesting,
68
+ :controller_class_nesting_depth,
69
+ :controller_class_name,
70
+ :controller_underscore_name,
71
+ :controller_singular_name,
72
+ :controller_plural_name,
73
+ :collection_name,
74
+ :model_singular_name,
75
+ :model_plural_name,
76
+ :view_template_format,
77
+ :actions,
78
+ :formats
79
+
80
+ alias_method :controller_file_name, :controller_underscore_name
81
+ alias_method :controller_table_name, :controller_plural_name
82
+
83
+ def initialize(runtime_args, runtime_options = {})
84
+ super
85
+
86
+ @controller_name = @name.pluralize
87
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
88
+ @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name)
89
+ @controller_singular_name = base_name.singularize
90
+
91
+ if @controller_class_nesting.empty?
92
+ @controller_class_name = @controller_class_name_without_nesting
93
+ else
94
+ @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
95
+ end
96
+
97
+ @view_template_format = DEFAULT_VIEW_TEMPLATE_FORMAT
98
+
99
+ @attributes ||= []
100
+ @args_for_model ||= []
101
+
102
+ # Non-attribute args, i.e. "_actions:new,create". Add to options instead
103
+ @args.each do |arg|
104
+ arg_entities = arg.split(ARG_KEY_VALUE_DIVIDER)
105
+ if arg =~ /^#{NON_ATTR_ARG_KEY_PREFIX}actions/
106
+ @actions = arg_entities[1].split(NON_ATTR_ARG_VALUE_DIVIDER).compact.collect { |action| action.dowcase.to_sym }
107
+ elsif arg =~ /^#{NON_ATTR_ARG_KEY_PREFIX}(formats|respond_to)/
108
+ @formats = arg_entities[1].split(NON_ATTR_ARG_VALUE_DIVIDER).compact.collect { |format| format.dowcases.to_sym }
109
+ else
110
+ @attributes << Rails::Generator::GeneratedAttribute.new(*arg_entities)
111
+ @args_for_model << arg
112
+ end
113
+ end
114
+
115
+ @actions ||= DEFAULT_COLLECTION_ACTIONS + DEFAULT_MEMBER_ACTIONS
116
+ @formats ||= DEFAULT_RESPOND_TO_FORMATS
117
+ end
118
+
119
+ def manifest
120
+ record do |m|
121
+ # Check for class naming collisions.
122
+ m.class_collisions "#{controller_class_name}Controller", "#{controller_class_name}ControllerTest"
123
+ m.class_collisions "#{controller_class_name}Helper", "#{controller_class_name}HelperTest"
124
+ m.class_collisions "#{class_path}", "#{class_name}"
125
+
126
+ # Directories.
127
+ m.directory File.join(CONTROLLERS_PATH, controller_class_path)
128
+ m.directory File.join(HELPERS_PATH, controller_class_path) unless options[:skip_helpers]
129
+ m.directory File.join(VIEWS_PATH, controller_class_path, controller_file_name) unless options[:skip_views]
130
+ m.directory File.join(FUNCTIONAL_TESTS_PATH, controller_class_path) unless options[:skip_tests]
131
+ m.directory File.join(UNIT_TESTS_PATH, controller_class_path) unless options[:skip_tests]
132
+
133
+ # Controllers.
134
+ controller_template = options[:resourceful] ? 'inherited_resources' : 'standard'
135
+ m.template "controller_#{controller_template}.rb",
136
+ File.join(CONTROLLERS_PATH, controller_class_path, "#{controller_file_name}_controller.rb")
137
+
138
+ # Controller Tests.
139
+ unless options[:skip_tests]
140
+ m.template 'controller_test_standard.rb',
141
+ File.join(FUNCTIONAL_TESTS_PATH, controller_class_path, "#{controller_file_name}_controller_test.rb")
142
+ end
143
+
144
+ # Helpers.
145
+ unless options[:skip_helpers]
146
+ m.template 'helper_standard.rb',
147
+ File.join(HELPERS_PATH, controller_class_path, "#{controller_file_name}_helper.rb")
148
+ # Helper Tests
149
+ unless options[:skip_tests]
150
+ m.template 'helper_test_standard.rb',
151
+ File.join(UNIT_TESTS_PATH, controller_class_path, "#{controller_file_name}_helper_test.rb")
152
+ end
153
+ end
154
+
155
+ # Views.
156
+ unless options[:skip_views]
157
+ # View template for each action.
158
+ (actions & VIEW_TEMPLATES.keys).each do |action|
159
+ m.template "view_#{action}.html.#{view_template_format}", File.join(VIEWS_PATH, controller_file_name, "#{action}.html.#{view_template_format}")
160
+ # View template for each partial - if not already copied.
161
+ (VIEW_TEMPLATES[action] || []).each do |partial|
162
+ m.template "view__#{partial}.html.#{view_template_format}",
163
+ File.join(VIEWS_PATH, controller_file_name, "_#{partial}.html.#{view_template_format}")
164
+ end
165
+ end
166
+ end
167
+
168
+ # Layout.
169
+ if options[:include_layout]
170
+ m.template "view_layout.html.#{view_template_format}",
171
+ File.join(LAYOUTS_PATH, "#{controller_file_name}.html.#{view_template_format}")
172
+ end
173
+
174
+ # Routes.
175
+ m.route_resources controller_file_name
176
+
177
+ # Models - use Rails default generator.
178
+ m.dependency 'model', [name] + @args_for_model, :collision => :skip
179
+ end
180
+ end
181
+
182
+ protected
183
+
184
+ def symbol_array_to_expression(array)
185
+ ":#{array.compact.join(', :')}" if array.present?
186
+ end
187
+
188
+ def assign_names!(name)
189
+ super
190
+ @model_singular_name = @singular_name
191
+ @model_plural_name = @plural_name
192
+ @collection_name = options[:resourceful] ? RESOURCEFUL_COLLECTION_NAME : @model_plural_name
193
+ @singular_name = options[:resourceful] ? RESOURCEFUL_SINGULAR_NAME : @model_singular_name
194
+ @plural_name = options[:resourceful] ? RESOURCEFUL_SINGULAR_NAME.pluralize : @model_plural_name
195
+ end
196
+
197
+ def add_options!(opt)
198
+ opt.separator ''
199
+ opt.separator 'Options:'
200
+
201
+ opt.on('--skip-pagination',
202
+ "Skip 'will_paginate' for collections in controllers and views, wich requires gem 'mislav-will_paginate'.") do |v|
203
+ options[:pagination] = !v
204
+ end
205
+
206
+ opt.on('--skip-resourceful',
207
+ "Skip 'inherited_resources' style controllers and views, wich requires gem 'josevalim-inherited_resources'.") do |v|
208
+ options[:resourceful] = !v
209
+ end
210
+
211
+ opt.on('--skip-formtastic',
212
+ "Skip 'formtastic' style forms, wich requires gem 'justinfrench-formtastic'.") do |v|
213
+ options[:formtastic] = !v
214
+ end
215
+
216
+ opt.on('--skip-views', "Skip generation of views.") do |v|
217
+ options[:skip_views] = v
218
+ end
219
+
220
+ opt.on('--skip-helper', "Skip generation of helpers.") do |v|
221
+ options[:skip_helpers] = v
222
+ end
223
+
224
+ opt.on('--skip-tests', "Skip generation of tests.") do |v|
225
+ options[:skip_tests] = v
226
+ end
227
+
228
+ opt.on('--include-layout', "Generate layout.") do |v|
229
+ options[:include_layout] = v
230
+ end
231
+ end
232
+
233
+ def model_name
234
+ class_name.demodulize
235
+ end
236
+
237
+ def banner
238
+ "Usage: #{$0} dry_scaffold ModelName [field:type field:type ...]" +
239
+ " [_actions:new,create,...]" +
240
+ " [_formats:html,json,...]" +
241
+ " [--skip-pagination]" +
242
+ " [--skip-resourceful]" +
243
+ " [--skip-formtastic]" +
244
+ " [--skip-views]" +
245
+ " [--skip-helpers]" +
246
+ " [--skip-tests]" +
247
+ " [--include-layout]"
248
+ end
249
+
250
+ end
@@ -0,0 +1,40 @@
1
+ class <%= controller_class_name %>Controller < InheritedResources::Base
2
+
3
+ <% if actions -%>
4
+ actions <%= symbol_array_to_expression(actions) %>
5
+ <% end -%>
6
+ <% if formats -%>
7
+ respond_to <%= symbol_array_to_expression(formats) %>
8
+
9
+ <% end -%>
10
+ <% if actions -%>
11
+ before_filter :load_resource, :only => [<%= symbol_array_to_expression(actions & DryScaffoldGenerator::DEFAULT_MEMBER_AUTOLOAD_ACTIONS) %>]
12
+ <% end -%>
13
+ <% if actions -%>
14
+ before_filter :load_and_paginate_resources, :only => [<%= symbol_array_to_expression(actions & DryScaffoldGenerator::DEFAULT_COLLECTION_AUTOLOAD_ACTIONS) %>]
15
+
16
+ <% end -%>
17
+ <% (actions - DryScaffoldGenerator::DEFAULT_CONTROLLER_ACTIONS).each do |action| -%>
18
+ # GET /<%= plural_name %>/<%= action.to_s %>
19
+ def <%= action.to_s %>
20
+ end
21
+
22
+ <% end -%>
23
+ protected
24
+
25
+ def collection
26
+ <% if options[:pagination] -%>
27
+ paginate_options ||= {}
28
+ paginate_options[:page] ||= (params[:page] || 1)
29
+ paginate_options[:per_page] ||= (params[:per_page] || 20)
30
+ @<%= plural_name %> = @<%= model_plural_name %> ||= end_of_association_chain.paginate(paginate_options)
31
+ <% else -%>
32
+ @<%= plural_name %> = @<%= model_plural_name %> ||= end_of_association_chain.all
33
+ <% end -%>
34
+ end
35
+
36
+ def resource
37
+ @<%= singular_name %> = @<%= model_singular_name %> ||= end_of_association_chain.find(params[:id])
38
+ end
39
+
40
+ end