jrhicks-static-scaffolds 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,90 @@
1
+ body {
2
+ font-family: "lucida grande", verdana, lucida, sans-serif;
3
+ font-size: 8pt;
4
+ }
5
+
6
+
7
+
8
+ pre {
9
+ background-color: #eee;
10
+ padding: 10px;
11
+ font-size: 11px;
12
+ }
13
+
14
+ a { color: #000; }
15
+ a:visited { color: #666; }
16
+ a:hover { color: #fff; background-color:#000; }
17
+
18
+ .fieldWithErrors {
19
+ padding: 2px;
20
+ background-color: red;
21
+ display: table;
22
+ }
23
+
24
+ #errorExplanation {
25
+ width: 400px;
26
+ border: 2px solid red;
27
+ padding: 7px;
28
+ padding-bottom: 12px;
29
+ margin-bottom: 20px;
30
+ background-color: #f0f0f0;
31
+ }
32
+
33
+ #errorExplanation h2 {
34
+ text-align: left;
35
+ font-weight: bold;
36
+ padding: 5px 5px 5px 15px;
37
+ font-size: 12px;
38
+ margin: -7px;
39
+ background-color: #c00;
40
+ color: #fff;
41
+ }
42
+
43
+ #errorExplanation p {
44
+ color: #333;
45
+ margin-bottom: 0;
46
+ padding: 5px;
47
+ }
48
+
49
+ #errorExplanation ul li {
50
+ font-size: 12px;
51
+ list-style: square;
52
+ }
53
+
54
+
55
+ .sortable {
56
+ border: 1px solid #D9D9D9;
57
+ #border-collapse:separate;
58
+ border-spacing:0;
59
+ }
60
+
61
+ .sortable th {
62
+ border: 1px solid #FFF;
63
+ border-right-color: #CCC;
64
+ border-bottom-color: #CCC;
65
+ padding: 0 6px;
66
+ float: none !important; /*For Opera*/
67
+ float: left; /*For IE*/
68
+ background: #EEE;
69
+ color: #666;
70
+ font: bold 10px/22px Verdana, Arial, Helvetica, sans-serif;
71
+ text-decoration: none;
72
+ height: auto !important;
73
+ height: 1%; /*For IE*/
74
+ }
75
+
76
+ .sortable tbody tr td {
77
+ font-family: "lucida grande", verdana, sans-serif;
78
+ font-size: 8pt;
79
+ padding: 3px 8px;
80
+ border-left: 1px solid #D9D9D9;
81
+ }
82
+
83
+ .sortable tbody tr.selected td {
84
+ background-color: #3d80df;
85
+ color: #ffffff;
86
+ font-weight: bold;
87
+ border-left: 1px solid #346DBE;
88
+ border-bottom: 1px solid #7DAAEA;
89
+ }
90
+
@@ -0,0 +1,343 @@
1
+ class StaticGenSpecsGenerator < Rails::Generator::NamedBase
2
+ default_options :skip_timestamps => false, :skip_migration => false, :force_plural => false
3
+
4
+ attr_reader :controller_name,
5
+ :controller_class_path,
6
+ :controller_file_path,
7
+ :controller_class_nesting,
8
+ :controller_class_nesting_depth,
9
+ :controller_class_name,
10
+ :controller_underscore_name,
11
+ :controller_singular_name,
12
+ :controller_plural_name
13
+ alias_method :controller_file_name, :controller_underscore_name
14
+ alias_method :controller_table_name, :controller_plural_name
15
+
16
+
17
+ def initialize(runtime_args, runtime_options = {})
18
+ super
19
+
20
+ if @name == @name.pluralize && !options[:force_plural]
21
+ logger.warning "Plural version of the model detected, using singularized version. Override with --force-plural."
22
+ @name = @name.singularize
23
+ end
24
+
25
+ @controller_name = @name.pluralize
26
+
27
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
28
+ @controller_class_name_without_nesting, @controller_underscore_name, @controller_plural_name = inflect_names(base_name)
29
+ @controller_singular_name=base_name.singularize
30
+ if @controller_class_nesting.empty?
31
+ @controller_class_name = @controller_class_name_without_nesting
32
+ else
33
+ @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
34
+ end
35
+ end
36
+
37
+ def manifest
38
+ record do |m|
39
+ # Check for class naming collisions.
40
+ m.class_collisions("#{controller_class_name}Controller", "#{controller_class_name}Helper")
41
+ m.class_collisions(class_name)
42
+
43
+ # Controller, helper, views, test and stylesheets directories.
44
+ m.directory("static_scaffold")
45
+
46
+ # Model
47
+ m.template(
48
+ "generator_specs.rb",
49
+ File.join('static_scaffold',"generator_specs.rb"))
50
+ m.template(
51
+ "model_gen_specs.rb",
52
+ File.join('static_scaffold',"#{@controller_singular_name.underscore.downcase}_gen_specs.rb"))
53
+
54
+ end
55
+ end
56
+
57
+ protected
58
+ # Override with your own usage banner.
59
+ def banner
60
+ "Usage: #{$0} static_gen_specs ModelName [table_name]"
61
+ end
62
+
63
+ def add_options!(opt)
64
+ opt.separator ''
65
+ opt.separator 'Options:'
66
+ opt.on("--skip-timestamps",
67
+ "Don't add timestamps to the migration file for this model") { |v| options[:skip_timestamps] = v }
68
+ opt.on("--skip-migration",
69
+ "Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
70
+ opt.on("--force-plural",
71
+ "Forces the generation of a plural ModelName") { |v| options[:force_plural] = v }
72
+ end
73
+
74
+ def scaffold_views
75
+ %w[ index show new edit ]
76
+ end
77
+
78
+ def model_name
79
+ class_name.demodulize
80
+ end
81
+
82
+ def columns
83
+ ActiveRecord::Base.connection.columns(table_name)
84
+ end
85
+
86
+ def table_name
87
+ if @args and @args.length>=1
88
+ return @args.first
89
+ else
90
+ return @controller_plural_name
91
+ end
92
+ end
93
+
94
+ def belongs_to_columns
95
+ # return columns indending in '_id'
96
+ columns.select {|c| c.name.slice(-3,3)=="_id"}
97
+ end
98
+
99
+ def has_many_columns
100
+ # search other tables for foreign keys, match based on naming convention
101
+ # for example: friend_user_id would be assumed to be a foreign key to a User
102
+ results = []
103
+ tables = ActiveRecord::Base.connection.tables
104
+ ref_id = "#{model_name.underscore.singularize.downcase}_id"
105
+ for t in tables
106
+ for c in ActiveRecord::Base.connection.columns(t)
107
+ if c.name.slice(0-ref_id.length,ref_id.length)==ref_id
108
+ results << {:table=>t, :column=>c.name}
109
+ end
110
+ end
111
+ end
112
+ return results
113
+ end
114
+
115
+ # a helper method
116
+
117
+ def max_length(objects, method)
118
+ (objects.map {|item| item.send(method.to_s).inspect.length} << method.to_s.length).max
119
+ end
120
+
121
+ def column(col_name)
122
+ columns.select {|c| c.name==col_name }.first
123
+ end
124
+
125
+ def column_names
126
+ cnames = columns.map {|c| c.name}
127
+ end
128
+
129
+ def estimate_cols(cname)
130
+ c=column(cname)
131
+ case c.type
132
+ when :text then 30
133
+ when :integer then
134
+ if belongs_to_columns.map {|bt| bt.name}.select {|name| name==cname}.first
135
+ 30
136
+ else
137
+ 5
138
+ end
139
+ when :datetime then 18
140
+ when :float then 8
141
+ when :string then estimate_string(cname)
142
+ else 30
143
+ end
144
+ end
145
+
146
+ def estimate_rows(cname)
147
+ c=column(cname)
148
+ case c.type
149
+ when :text then 3
150
+ else 1
151
+ end
152
+ end
153
+
154
+ def estimate_string(cname)
155
+ # Look for commonly named fields and guess length otherwise make an educated guess based on db limits
156
+ c=column(cname)
157
+ common_lengths = { "phone"=>15,"fax"=>15, "zip"=>12, "first_name"=> 15, "last_name"=>15 }
158
+ key=common_lengths.keys.select {|key| cname[key]}.first
159
+ if key
160
+ common_lengths[key]
161
+ else
162
+ case c.limit
163
+ when 0..15
164
+ c.limit
165
+ when 15..30
166
+ 20
167
+ else
168
+ 30
169
+ end
170
+ end
171
+ end
172
+
173
+ def guess_type(cname)
174
+ if belongs_to_columns.map {|bt| bt.name}.select {|name| name==cname}.first
175
+ return :foreign_key
176
+ end
177
+ if cname=="id"
178
+ return :primary_key
179
+ end
180
+ if is_file_column?(cname)
181
+ return :file
182
+ end
183
+ if is_photo_column?(cname)
184
+ return :photo
185
+ end
186
+ return column(cname).type
187
+ end
188
+
189
+ def guess_alignment(cname)
190
+ c=column(cname)
191
+ case guess_type(cname)
192
+ when :integer
193
+ "right"
194
+ when :float
195
+ "right"
196
+ when :decimal
197
+ "right"
198
+ else
199
+ "left"
200
+ end
201
+ end
202
+
203
+ def guess_decimals(cname)
204
+ c=column(cname)
205
+ case guess_type(cname)
206
+ when :integer
207
+ 0
208
+ when :float
209
+ 3
210
+ when :decimal
211
+ 3
212
+ else
213
+ nil
214
+ end
215
+ end
216
+
217
+ def find_column_names_matching(name_list)
218
+ results = []
219
+ for item in name_list
220
+ results = results+column_names.select {|cname| cname.match(item)}
221
+ end
222
+ return results
223
+ end
224
+
225
+ def is_photo_column?(cname)
226
+ find_column_names_matching("photo thumbnail".split).include?(cname)
227
+ end
228
+
229
+ def is_file_column?(cname)
230
+ find_column_names_matching("file fname attachment document fpath".split).include?(cname)
231
+ end
232
+
233
+ def guess_short_name
234
+ guess = find_column_names_matching("name")
235
+ if guess.length==0
236
+ ["id"]
237
+ else
238
+ guess
239
+ end
240
+ end
241
+
242
+ def guess_ordered_columns
243
+ # return names and dates otherwise id
244
+ names = columns.map {|c| c.name}.select {|name| name.match("name")}
245
+ dates = columns.select {|c| c.type==:datetime}.map {|c| c.name }
246
+ combined = names+dates
247
+ if combined
248
+ return combined
249
+ else
250
+ return "#{table_name}.id"
251
+ end
252
+ end
253
+
254
+ def guess_list_columns
255
+ text_fields = columns.select {|c|c.type==:text}.map{|c|c.name}
256
+ meta_fields = ["id","created_at", "updated_at", "version", "guid"]
257
+ return column_names - text_fields - meta_fields
258
+ end
259
+
260
+ # the idea here is to guess at whate columns should be included in the list/table view
261
+ # the anticipation is that some columns will be hidden by default
262
+
263
+ def guess_in_list(cname)
264
+ c=column(cname)
265
+ if c.type==:text
266
+ return false
267
+ end
268
+ hidden_fields = "password guid".split
269
+ for h in hidden_fields
270
+ if cname.match(h)
271
+ return false
272
+ end
273
+ end
274
+
275
+ return true
276
+ end
277
+
278
+ # units helpers - the idea is to encourage folks to append their units to the end of their db column names
279
+
280
+ def units_hash
281
+ {
282
+ "_hrs" => "hours",
283
+ "_hours"=>"hours",
284
+ "_min"=>"minutes",
285
+ "_minutes"=>"minutes",
286
+ "_ppm"=>"ppm",
287
+ "_ppb"=>"ppb",
288
+ "_mgm3"=>"mg/m3",
289
+ "_f"=>"&deg;f",
290
+ "_c"=>"&deg;c",
291
+ "_rh"=>"% rh",
292
+ "_utf"=>""
293
+ }
294
+ end
295
+
296
+ def units(cname)
297
+ u=units_hash[units_key(cname)]
298
+ if u
299
+ u
300
+ else
301
+ nil
302
+ end
303
+ end
304
+
305
+ def label(cname)
306
+ ukey = units_key(cname)
307
+ if ukey
308
+ cname.slice(0,cname.length-ukey.length).titleize
309
+ else
310
+ cname.titleize
311
+ end
312
+ end
313
+
314
+ def units_key(cname)
315
+ units_hash.keys.select {|k| cname.slice((0-k.length),k.length)==k }.first
316
+ end
317
+
318
+
319
+
320
+ end
321
+
322
+ class CodeJustifier
323
+ # This class is designed to generate readable code, but is a hypocrate
324
+
325
+ attr_accessor :objects, :parameters
326
+
327
+ def initialize(objects)
328
+ self.objects = objects
329
+ self.parameters = []
330
+ end
331
+
332
+ def add_parameter(&p)
333
+ self.parameters << p
334
+ end
335
+
336
+ def render(object)
337
+ self.parameters.map {|p| p.call(object).ljust(max_length(p))}.join("")
338
+ end
339
+
340
+ def max_length(parameter)
341
+ self.objects.map {|o| parameter.call(o).to_s.length }.max
342
+ end
343
+ end
@@ -0,0 +1,60 @@
1
+ # Load all generator specs
2
+ #spec_files = Dir.glob(File.join(RAILS_ROOT,"static_scaffold","*.rb"))
3
+ #for f in spec_files
4
+ # require f
5
+ #end
6
+
7
+ class GenSpecFactory
8
+
9
+ def GenSpecFactory.constantize(mname)
10
+ if mname.type==Array
11
+ return mname.map {|m|m.constantize_gen_spec}
12
+ else
13
+ # Instantiate the GenSpec based on model name
14
+ mname = model_name if not mname
15
+ gen_specs_mname = "#{mname}GenSpecs"
16
+ Object::const_get(gen_specs_mname).new()
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+ class GeneratorSpecs < GenSpecFactory
23
+
24
+
25
+ def table_name
26
+ raise Exception("table_name method not implimented.")
27
+ end
28
+
29
+ def schema
30
+ ActiveRecord::Base.connection.columns(table_name)
31
+ end
32
+
33
+ def small_icon
34
+ "small_icon_#{table_name}.gif"
35
+ end
36
+
37
+ def model_file_name
38
+ # <%=model_name.underscore.inspect%>
39
+ model_name.underscore
40
+ end
41
+
42
+ def controller_class_name
43
+ # <%="#{model_name.pluralize}Controller".inspect%>
44
+ "#{model_name.pluralize}Controller"
45
+ end
46
+
47
+ def controller_file_name
48
+ # "<%="#{model_name.pluralize}Controller".underscore.inspect%>"
49
+ "#{model_name.pluralize}Controller".underscore
50
+ end
51
+
52
+ def view_folder_name
53
+ # <%=model_name.underscore.inspect%>
54
+ model_name.pluralize.underscore
55
+ end
56
+
57
+
58
+ end
59
+
60
+