forked from ryanb/nifty-generators
/
nifty_scaffold_generator.rb
224 lines (186 loc) · 6.62 KB
/
nifty_scaffold_generator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
class NiftyScaffoldGenerator < Rails::Generator::Base
attr_accessor :name, :attributes, :controller_actions
def initialize(runtime_args, runtime_options = {})
super
usage if @args.empty?
@name = @args.first
@controller_actions = []
@attributes = []
@args[1..-1].each do |arg|
if arg == '!'
options[:invert] = true
elsif arg.include? ':'
@attributes << Rails::Generator::GeneratedAttribute.new(*arg.split(":"))
else
@controller_actions << arg
@controller_actions << 'create' if arg == 'new'
@controller_actions << 'update' if arg == 'edit'
end
end
@controller_actions.uniq!
@attributes.uniq!
if options[:invert] || @controller_actions.empty?
@controller_actions = all_actions - @controller_actions
end
if @attributes.empty?
options[:skip_model] = true # default to skipping model if no attributes passed
if model_exists?
model_columns_for_attributes.each do |column|
@attributes << Rails::Generator::GeneratedAttribute.new(column.name.to_s, column.type.to_s)
end
else
@attributes << Rails::Generator::GeneratedAttribute.new('name', 'string')
end
end
end
def manifest
record do |m|
unless options[:skip_model]
m.directory "app/models"
m.template "model.rb", "app/models/#{singular_name}.rb"
unless options[:skip_migration]
m.migration_template "migration.rb", "db/migrate", :migration_file_name => "create_#{plural_name}"
end
if rspec?
m.directory "spec/models"
m.template "tests/#{test_framework}/model.rb", "spec/models/#{singular_name}_spec.rb"
m.directory "spec/fixtures"
m.template "fixtures.yml", "spec/fixtures/#{plural_name}.yml"
else
m.directory "test/unit"
m.template "tests/#{test_framework}/model.rb", "test/unit/#{singular_name}_test.rb"
m.directory "test/fixtures"
m.template "fixtures.yml", "test/fixtures/#{plural_name}.yml"
end
end
unless options[:skip_controller]
m.directory "app/controllers"
m.template "controller.rb", "app/controllers/#{plural_name}_controller.rb"
m.directory "app/helpers"
m.template "helper.rb", "app/helpers/#{plural_name}_helper.rb"
m.directory "app/views/#{plural_name}"
controller_actions.each do |action|
if File.exist? source_path("views/#{view_language}/#{action}.html.#{view_language}")
m.template "views/#{view_language}/#{action}.html.#{view_language}", "app/views/#{plural_name}/#{action}.html.#{view_language}"
end
end
if form_partial?
m.template "views/#{view_language}/_form.html.#{view_language}", "app/views/#{plural_name}/_form.html.#{view_language}"
end
m.route_resources plural_name
if rspec?
m.directory "spec/controllers"
m.template "tests/#{test_framework}/controller.rb", "spec/controllers/#{plural_name}_controller_spec.rb"
else
m.directory "test/functional"
m.template "tests/#{test_framework}/controller.rb", "test/functional/#{plural_name}_controller_test.rb"
end
end
end
end
def form_partial?
actions? :new, :edit
end
def all_actions
%w[index show new create edit update destroy]
end
def action?(name)
controller_actions.include? name.to_s
end
def actions?(*names)
names.all? { |n| action? n.to_s }
end
def singular_name
name.underscore
end
def plural_name
name.underscore.pluralize
end
def class_name
name.camelize
end
def plural_class_name
plural_name.camelize
end
def controller_methods(dir_name)
controller_actions.map do |action|
read_template("#{dir_name}/#{action}.rb")
end.join(" \n").strip
end
def render_form
if form_partial?
if options[:haml]
"= render :partial => 'form'"
else
"<%= render :partial => 'form' %>"
end
else
read_template("views/#{view_language}/_form.html.#{view_language}")
end
end
def item_path(suffix = 'path')
if action? :show
"@#{singular_name}"
else
"#{plural_name}_#{suffix}"
end
end
def item_path_for_spec(suffix = 'path')
if action? :show
"#{singular_name}_#{suffix}(assigns[:#{singular_name}])"
else
"#{plural_name}_#{suffix}"
end
end
def item_path_for_test(suffix = 'path')
if action? :show
"#{singular_name}_#{suffix}(assigns(:#{singular_name}))"
else
"#{plural_name}_#{suffix}"
end
end
def model_columns_for_attributes
class_name.constantize.columns.reject do |column|
column.name.to_s =~ /^(id|created_at|updated_at)$/
end
end
def rspec?
test_framework == :rspec
end
protected
def view_language
options[:haml] ? 'haml' : 'erb'
end
def test_framework
options[:test_framework] ||= default_test_framework
end
def default_test_framework
File.exist?(destination_path("spec")) ? :rspec : :testunit
end
def add_options!(opt)
opt.separator ''
opt.separator 'Options:'
opt.on("--skip-model", "Don't generate a model or migration file.") { |v| options[:skip_model] = v }
opt.on("--skip-migration", "Don't generate migration file for model.") { |v| options[:skip_migration] = v }
opt.on("--skip-timestamps", "Don't add timestamps to migration file.") { |v| options[:skip_timestamps] = v }
opt.on("--skip-controller", "Don't generate controller, helper, or views.") { |v| options[:skip_controller] = v }
opt.on("--invert", "Generate all controller actions except these mentioned.") { |v| options[:invert] = v }
opt.on("--haml", "Generate HAML views instead of ERB.") { |v| options[:haml] = v }
opt.on("--testunit", "Use test/unit for test files.") { options[:test_framework] = :testunit }
opt.on("--rspec", "Use RSpec for test files.") { options[:test_framework] = :rspec }
opt.on("--shoulda", "Use Shoulda for test files.") { options[:test_framework] = :shoulda }
end
# is there a better way to do this? Perhaps with const_defined?
def model_exists?
File.exist? destination_path("app/models/#{singular_name}.rb")
end
def read_template(relative_path)
ERB.new(File.read(source_path(relative_path)), nil, '-').result(binding)
end
def banner
<<-EOS
Creates a controller and optional model given the name, actions, and attributes.
USAGE: #{$0} #{spec.name} ModelName [controller_actions and model:attributes] [options]
EOS
end
end