grimen-dry_scaffold 0.2.0 → 0.2.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.
data/README.textile CHANGED
@@ -6,7 +6,7 @@ h2. Description
6
6
 
7
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
8
 
9
- h3. Key concepts:
9
+ h3. Key Concepts:
10
10
 
11
11
  * Controllers that are DRY, RESTful, no code-smells, following conventions, and implementing VERY common patterns.
12
12
  * Views that are DRY, semantic, standards compliant, valid, and more useful in development.
@@ -160,7 +160,7 @@ h3. More To Come... (TODO)
160
160
  These are things I have in mind:
161
161
 
162
162
  * Generation of Rails builder stubs automatically for formats atom/rss.
163
- * Read default scaffold options for current Rails porject from a config (say "config/scaffold.yml")
163
+ * Make routing smarter; if route is already declared in _config/routes.rb_, then don't generate it (no duplication).
164
164
  * Break up into multiple generators as dependencies (like Rails generators): dry_controller, dry_views, dry_scaffold, ...
165
165
 
166
166
  h2. Setup
@@ -218,11 +218,15 @@ In: @config/environment.rb@
218
218
 
219
219
  h2. Usage
220
220
 
221
- <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>
221
+ <pre>./script/generate dry_scaffold ModelName [attribute:type attribute:type] [_actions:new,create,...] [_formats:html,json,...] [_indexes:attribute,...] [--skip-pagination] [--skip-resourceful] [--skip-formtastic] [--skip-views] [--skip-helpers] [--skip-tests] [--include-layout] [--fixtures] [--fgirl] [--machinist] [--odaddy] [--skip-migration] [--skip-timestamps]</pre>
222
222
 
223
- ...or use the alias (instead of @dry_scaffold@):
223
+ ...or use the alias @dscaffold@ instead of @dry_scaffold@.
224
224
 
225
- <pre>./script/generate dscaffold ...</pre>
225
+ For generating just a *model*, then use:
226
+
227
+ <pre>./script/generate dry_model ModelName [attribute:type attribute:type] [_indexes:attribute,...] [--fixtures] [--fgirl] [--machinist] [--odaddy] [--skip-migration] [--skip-timestamps] [--skip-tests]</pre>
228
+
229
+ ...or use the alias @dmodel@ instead of @dry_model@.
226
230
 
227
231
  h3. Model Name
228
232
 
@@ -242,7 +246,7 @@ Same as in the default scaffold/model generator; model attributes and database m
242
246
 
243
247
  h3. Controller Actions
244
248
 
245
- Usage:
249
+ Example:
246
250
 
247
251
  <pre>_actions:new,create,quack,index,...</pre>
248
252
 
@@ -250,7 +254,7 @@ You can override what actions that should be generated directly - including cust
250
254
 
251
255
  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.
252
256
 
253
- h4. Default actions (REST)
257
+ h4. Default Actions (REST)
254
258
 
255
259
  If no actions are specified, the following REST-actions will be generated by default:
256
260
 
@@ -269,13 +273,13 @@ These default actions can also be included using the alias symbol @*@, which mak
269
273
  <pre>_actions:quack # => quack</pre>
270
274
  <pre>_actions:*,quack # => show,index,new,edit,create,update,destroy,quack</pre>
271
275
 
272
- h4. Custom actions
276
+ h4. Custom Actions
273
277
 
274
278
  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.
275
279
 
276
280
  h3. Controller Formats
277
281
 
278
- Usage:
282
+ Example:
279
283
 
280
284
  <pre>_formats:html,xml,txt,... # <=> _respond_to:html,xml,txt,...</pre>
281
285
 
@@ -283,7 +287,7 @@ You can override what respond_to-formats that should be generated directly - onl
283
287
 
284
288
  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.
285
289
 
286
- h4. Default formats
290
+ h4. Default Formats
287
291
 
288
292
  If no formats are specified, the following formats will be generated by default:
289
293
 
@@ -299,7 +303,7 @@ Like for actions, these default respond_to-formats can also be included using th
299
303
  <pre>_formats:iphone # => _formats:iphone</pre>
300
304
  <pre>_formats:*,iphone # => _formats:html,js,xml,json,iphone</pre>
301
305
 
302
- h4. Additional formats
306
+ h4. Additional Formats
303
307
 
304
308
  Also, default respond block stubs are generated for any of these formats - for each generated REST-action - if they are specified:
305
309
 
@@ -308,10 +312,28 @@ Also, default respond block stubs are generated for any of these formats - for e
308
312
 
309
313
  NOTE: Only for Non-InheritedResources controllers for now.
310
314
 
311
- h4. Custom formats
315
+ h4. Custom Formats
312
316
 
313
317
  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.
314
318
 
319
+ h3. Model Indexes
320
+
321
+ Example:
322
+
323
+ If model attributes are specified as:
324
+
325
+ <pre>name:string owner:reference</pre>
326
+
327
+ ...then we could do this (for polymorphic association):
328
+
329
+ <pre>_indexes:owner_id # => (In migration:) add_index :duck, :owner_id</pre>
330
+
331
+ ...or in account for a polymorphic association:
332
+
333
+ <pre>_indexes:owner_id+owner_type # => (In migration:) add_index :duck, [:owner_id, :owner_type]</pre>
334
+
335
+ NOTE: Of course...you need to specify indexes based on attributes that exists for this model, otherwise your migration will not be valid - DryScaffold is leaving this responsible to you.
336
+
315
337
  h3. Options/Flags
316
338
 
317
339
  Example:
@@ -339,6 +361,12 @@ h4. Model-specific
339
361
 
340
362
  As DryScaffold is built upon Rails generator, the default generator options is available as well. For more details; see Rails documentation.
341
363
 
364
+ h3. Setting Defaults
365
+
366
+ You can set defaults for the generator args/options in @config/scaffold.yml@. To generate this file, simply do:
367
+
368
+ <pre>rake dry_scaffold:config:generate</pre>
369
+
342
370
  h2. Examples
343
371
 
344
372
  No need for more samples here, just create a new Rails project, install DryScaffold and it's dependencies, and try it out!
@@ -349,8 +377,8 @@ For your inspiration, you could try the following:
349
377
  ./script/generate dry_scaffold Kangaroo name:string about:text --skip-formtastic
350
378
  ./script/generate dry_scaffold Duck name:string about:text _actions:new,create,index,quack
351
379
  ./script/generate dry_scaffold Parrot name:string about:text _formats:html,xml,yml
352
- ./script/generate dry_scaffold Parrot name:string about:text _indexes:name --fgirl
353
- ./script/generate dry_scaffold Parrot name:string about:text _indexes:name,name+about --fixtures</pre>
380
+ ./script/generate dry_scaffold GoldFish name:string about:text _indexes:name --fgirl
381
+ ./script/generate dry_scaffold Frog name:string about:text _indexes:name,name+about --fixtures</pre>
354
382
 
355
383
  ...or just go crazy!
356
384
 
data/TODO.textile CHANGED
@@ -3,10 +3,10 @@ h1. TODO
3
3
  h2. Next
4
4
 
5
5
  * Feature: Generate Atom/RSS builder stubs for formats - if specified - atom/rss for index action. (Reference: http://gatezero.org/~tim/2008/04/22/generating-valid-atom-feeds-from-rails-202/)
6
- * Feature: Read default scaffold options from a config in: "RAILS_ROOT/config/scaffold.yml"
6
+ * Feature: If route is already declared in config/routes.rb, then don't generate it.
7
7
 
8
8
  h2. Maybe later
9
9
 
10
10
  * Clean-up: Comment the code a bit more =)
11
- * Feature: Check for overridden templates in: RAILS_ROOT/lib/dry_scaffold/templates/
12
- * Refactor: Break up in different generators: dry_controller, dry_views, etc., and use as dependencies in dry_scaffold
11
+ * Refactor: Break up in different generators: dry_controller, dry_views, etc., and use as dependencies in dry_scaffold?
12
+ * Feature: Check for overridden templates in: RAILS_ROOT/lib/dry_scaffold/templates/
@@ -1,25 +1,35 @@
1
1
  require 'rubygems'
2
- begin
3
- require 'factory_girl'
4
- FACTORY_GIRL = true
5
- rescue MissingSourceFile
6
- FACTORY_GIRL = false
7
- end
8
- begin
9
- require 'machinist'
10
- MACHINIST = true
11
- rescue MissingSourceFile
12
- MACHINIST = false
13
- end
14
- begin
15
- require 'object_daddy'
16
- OBJECT_DADDY = true
17
- rescue MissingSourceFile
18
- OBJECT_DADDY = false
2
+ %w(factory_girl machinist object_daddy).each do |lib|
3
+ begin
4
+ require lib
5
+ rescue MissingSourceFile
6
+ eval("#{lib.upcase} = #{false}")
7
+ else
8
+ eval("#{lib.upcase} = #{false}")
9
+ end
19
10
  end
20
11
 
21
12
  class DryModelGenerator < Rails::Generator::NamedBase
22
13
 
14
+ # Load defaults from config file - default or custom.
15
+ begin
16
+ default_config_file = File.join(File.dirname(__FILE__), '..', '..', 'config', 'scaffold.yml')
17
+ custom_config_file = File.join(Rails.root, 'config', 'scaffold.yml')
18
+ config_file = File.join(File.exist?(custom_config_file) ? custom_config_file : default_config_file)
19
+ config = YAML::load(File.open(config_file))
20
+ CONFIG_OPTIONS = config['dry_model']['options'] rescue nil
21
+ end
22
+
23
+ DEFAULT_OPTIONS = {
24
+ :fixtures => CONFIG_OPTIONS['fixtures'] || false,
25
+ :factory_girl => CONFIG_OPTIONS['factory_girl'] || false,
26
+ :machinist => CONFIG_OPTIONS['machinist'] || false,
27
+ :object_daddy => !CONFIG_OPTIONS['object_daddy'] || false,
28
+ :skip_timestamps => !CONFIG_OPTIONS['skip_timestamps'] || false,
29
+ :skip_migration => !CONFIG_OPTIONS['skip_migration'] || false,
30
+ :skip_tests => CONFIG_OPTIONS['skip_tests'] || false
31
+ }
32
+
23
33
  MODELS_PATH = File.join('app', 'models').freeze
24
34
  MIGRATIONS_PATH = File.join('db', 'migrate').freeze
25
35
  TESTS_PATH = File.join('test').freeze
@@ -29,15 +39,6 @@ class DryModelGenerator < Rails::Generator::NamedBase
29
39
  MACHINIST_FACTORIES_PATH = File.join(TESTS_PATH, 'blueprints').freeze
30
40
 
31
41
  NON_ATTR_ARG_KEY_PREFIX = '_'.freeze
32
-
33
- default_options :fixtures => false,
34
- :factory_girl => false,
35
- :machinist => false,
36
- :object_daddy => false,
37
- :faker => false,
38
- :skip_timestamps => false,
39
- :skip_migration => false,
40
- :skip_tests => false
41
42
 
42
43
  attr_reader :indexes,
43
44
  :references
@@ -66,8 +67,10 @@ class DryModelGenerator < Rails::Generator::NamedBase
66
67
  args_for_model << arg
67
68
  end
68
69
  end
70
+
69
71
  @args = args_for_model
70
72
  @references = attributes.select(&:reference?)
73
+ @options = DEFAULT_OPTIONS.merge(runtime_options)
71
74
  end
72
75
 
73
76
  def manifest
@@ -1,25 +1,40 @@
1
1
  require 'rubygems'
2
- begin
3
- require 'formtastic'
4
- FORMTASTIC = true
5
- rescue
6
- FORMTASTIC = false
7
- end
8
- begin
9
- require 'inherited_resources'
10
- INHERITED_RESOURCES = true
11
- rescue
12
- INHERITED_RESOURCES = false
13
- end
14
- begin
15
- require 'will_paginate'
16
- WILL_PAGINATE = true
17
- rescue
18
- WILL_PAGINATE = false
2
+ %w(will_paginate formtastic inherited_resources).each do |lib|
3
+ begin
4
+ require lib
5
+ rescue MissingSourceFile
6
+ eval("#{lib.upcase} = #{false}")
7
+ else
8
+ eval("#{lib.upcase} = #{false}")
9
+ end
19
10
  end
20
11
 
21
12
  class DryScaffoldGenerator < Rails::Generator::NamedBase
22
13
 
14
+ # Load defaults from config file - default or custom.
15
+ begin
16
+ default_config_file = File.join(File.dirname(__FILE__), '..', '..', 'config', 'scaffold.yml')
17
+ custom_config_file = File.join(Rails.root, 'config', 'scaffold.yml')
18
+ config_file = File.join(File.exist?(custom_config_file) ? custom_config_file : default_config_file)
19
+ config = YAML::load(File.open(config_file))
20
+ CONFIG_ARGS = config['dry_scaffold']['args'] rescue nil
21
+ CONFIG_OPTIONS = config['dry_scaffold']['options'] rescue nil
22
+ end
23
+
24
+ DEFAULT_ARGS = {
25
+ :actions => (CONFIG_ARGS['actions'].split(',').compact.uniq.collect { |v| v.downcase.to_sym } rescue nil),
26
+ :formats => (CONFIG_ARGS['formats'].split(',').compact.uniq.collect { |v| v.downcase.to_sym } rescue nil)
27
+ }
28
+ DEFAULT_OPTIONS = {
29
+ :resourceful => CONFIG_OPTIONS['resourceful'] || INHERITED_RESOURCES,
30
+ :formtastic => CONFIG_OPTIONS['formtastic'] || FORMTASTIC,
31
+ :pagination => CONFIG_OPTIONS['pagination'] || WILL_PAGINATE,
32
+ :skip_tests => !CONFIG_OPTIONS['tests'] || false,
33
+ :skip_helpers => !CONFIG_OPTIONS['helpers'] || false,
34
+ :skip_views => !CONFIG_OPTIONS['views'] || false,
35
+ :generate_layout => CONFIG_OPTIONS['layout'] || false
36
+ }
37
+
23
38
  DEFAULT_RESPOND_TO_FORMATS = [:html, :xml, :json].freeze
24
39
  DEFAULT_MEMBER_ACTIONS = [:show, :new, :edit, :create, :update, :destroy].freeze
25
40
  DEFAULT_MEMBER_AUTOLOAD_ACTIONS = (DEFAULT_MEMBER_ACTIONS - [:new, :create])
@@ -50,14 +65,6 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
50
65
  :edit => [:form]
51
66
  }.freeze
52
67
 
53
- default_options :resourceful => INHERITED_RESOURCES,
54
- :formtastic => FORMTASTIC,
55
- :pagination => WILL_PAGINATE,
56
- :skip_tests => false,
57
- :skip_helpers => false,
58
- :skip_views => false,
59
- :include_layout => false
60
-
61
68
  attr_reader :controller_name,
62
69
  :controller_class_path,
63
70
  :controller_file_path,
@@ -72,7 +79,8 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
72
79
  :model_plural_name,
73
80
  :view_template_format,
74
81
  :actions,
75
- :formats
82
+ :formats,
83
+ :config
76
84
 
77
85
  alias_method :controller_file_name, :controller_underscore_name
78
86
  alias_method :controller_table_name, :controller_plural_name
@@ -109,7 +117,9 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
109
117
  # Replace a '*' with default respond_to-formats
110
118
  arg_entities[1].gsub!(/\*/, DEFAULT_RESPOND_TO_FORMATS.join(','))
111
119
  arg_formats = arg_entities[1].split(',').compact.uniq
112
- @formats = arg_formats.collect { |format| format.downcases.to_sym }
120
+ @formats = arg_formats.collect { |format| format.downcase.to_sym }
121
+ elsif arg =~ /^#{NON_ATTR_ARG_KEY_PREFIX}index/
122
+ @args_for_model << arg
113
123
  end
114
124
  else
115
125
  @attributes << Rails::Generator::GeneratedAttribute.new(*arg_entities)
@@ -117,8 +127,9 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
117
127
  end
118
128
  end
119
129
 
120
- @actions ||= DEFAULT_CONTROLLER_ACTIONS
121
- @formats ||= DEFAULT_RESPOND_TO_FORMATS
130
+ @actions ||= DEFAULT_ARGS[:actions] || DEFAULT_CONTROLLER_ACTIONS
131
+ @formats ||= DEFAULT_ARGS[:formats] || DEFAULT_RESPOND_TO_FORMATS
132
+ @options = DEFAULT_OPTIONS.merge(runtime_options)
122
133
  end
123
134
 
124
135
  def manifest
@@ -171,7 +182,7 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
171
182
  end
172
183
 
173
184
  # Layout.
174
- if options[:include_layout]
185
+ if options[:generate_layout]
175
186
  m.template "view_layout.html.#{view_template_format}",
176
187
  File.join(LAYOUTS_PATH, "#{controller_file_name}.html.#{view_template_format}")
177
188
  end
@@ -180,17 +191,7 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
180
191
  m.route_resources controller_file_name
181
192
 
182
193
  # Models - use Rails default generator.
183
- m.dependency 'dry_model',
184
- [name] + @args_for_model +
185
- options.slice(:skip_tests,
186
- :fixtures,
187
- :factory_girl,
188
- :machinist,
189
- :object_daddy,
190
- :skip_timestamps,
191
- :skip_migration
192
- ),
193
- :collision => :skip
194
+ m.dependency 'dry_model', [name] + @args_for_model, :collision => :skip
194
195
  end
195
196
  end
196
197
 
@@ -213,6 +214,8 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
213
214
  opt.separator ''
214
215
  opt.separator 'Options:'
215
216
 
217
+ ### CONTROLLERS + VIEWS
218
+
216
219
  opt.on('--skip-pagination',
217
220
  "Skip 'will_paginate' for collections in controllers and views, wich requires gem 'mislav-will_paginate'.") do |v|
218
221
  options[:pagination] = !v
@@ -229,7 +232,7 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
229
232
  end
230
233
 
231
234
  opt.on('--layout', "Generate layout.") do |v|
232
- options[:include_layout] = v
235
+ options[:generate_layout] = v
233
236
  end
234
237
 
235
238
  opt.on('--skip-views', "Skip generation of views.") do |v|
@@ -240,10 +243,14 @@ class DryScaffoldGenerator < Rails::Generator::NamedBase
240
243
  options[:skip_helpers] = v
241
244
  end
242
245
 
246
+ ### CONTROLLERS + MODELS
247
+
243
248
  opt.on('--skip-tests', "Skip generation of tests.") do |v|
244
249
  options[:skip_tests] = v
245
250
  end
246
251
 
252
+ ### MODELS ONLY
253
+
247
254
  opt.on('--fixtures', "Model: Generate fixtures.") do |v|
248
255
  options[:fixtures] = v
249
256
  end
@@ -1,25 +1,47 @@
1
1
  namespace :dry_scaffold do
2
2
 
3
+ GEM_ROOT = File.join(File.dirname(__FILE__), '..').freeze
4
+
3
5
  desc "Setup for this plugin/gem."
4
6
  task :setup => :environment do
5
7
  Rake::Task['dry_scaffold:dependencies:install'].invoke
8
+ Rake::Task['dry_scaffold:config:generate'].invoke
9
+ end
10
+
11
+ namespace :config do
12
+
13
+ desc "Generate a dry_scaffold config file as 'RAILS_ROOT/config/scaffold.yml'"
14
+ task :generate do
15
+ template = File.join(GEM_ROOT, 'config', 'scaffold.yml')
16
+ to_file = File.join(Rails.root, 'config', 'scaffold.yml')
17
+
18
+ `cp #{template} #{to_file}`
19
+
20
+ if File.exists?(to_file)
21
+ puts "Generated config file: '#{to_file}'"
22
+ else
23
+ puts "Could not create the config file. Hint: Try with sudo."
24
+ end
25
+ end
26
+
6
27
  end
7
28
 
8
29
  namespace :dependencies do
9
30
 
10
- require File.join(File.dirname(__FILE__), '..', 'lib', 'setup_helper')
31
+ require File.join(GEM_ROOT, 'lib', 'setup_helper')
11
32
  include SetupHelper
12
33
 
13
34
  GEMS = [:haml, :will_paginate, :'josevalim-inherited_resources', :'justinfrench-formtastic'].freeze
14
35
  PLUGINS = [].freeze
15
36
 
16
- puts "---------------------------------------"
17
- puts " Dependencies"
18
- puts "---------------------------------------"
19
-
20
37
  desc "Install dependencies for fully advantage of this generator."
21
- puts "Installing gems..."
22
38
  task :install => :environment do
39
+
40
+ puts "---------------------------------------"
41
+ puts " Dependencies"
42
+ puts "---------------------------------------"
43
+ puts "Installing gems..."
44
+
23
45
  # Install gems
24
46
  unless GEMS.empty?
25
47
  puts "GEMS: #{GEMS.to_sentence}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grimen-dry_scaffold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Grimfelt
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-01 00:00:00 -07:00
12
+ date: 2009-05-03 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15