jrhicks-static-generators 0.1.6

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 (34) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +21 -0
  3. data/Manifest +32 -0
  4. data/README.md +27 -0
  5. data/Rakefile +15 -0
  6. data/TODO +4 -0
  7. data/USAGE +17 -0
  8. data/lib/static_generators.rb +3 -0
  9. data/rails_generators/static_app/USAGE +0 -0
  10. data/rails_generators/static_app/static_app_generator.rb +26 -0
  11. data/rails_generators/static_app/templates/application_helper.rb +11 -0
  12. data/rails_generators/static_app/templates/layout.html.erb +0 -0
  13. data/rails_generators/static_app/templates/layout_helper.rb +9 -0
  14. data/rails_generators/static_app/templates/sorttable.js +568 -0
  15. data/rails_generators/static_app/templates/static_style.css +90 -0
  16. data/rails_generators/static_gen_specs/USAGE +0 -0
  17. data/rails_generators/static_gen_specs/static_gen_specs_generator.rb +343 -0
  18. data/rails_generators/static_gen_specs/templates/generator_specs.rb +60 -0
  19. data/rails_generators/static_gen_specs/templates/model_gen_specs.rb +145 -0
  20. data/rails_generators/static_scaffold/USAGE +29 -0
  21. data/rails_generators/static_scaffold/static_scaffold_generator.rb +150 -0
  22. data/rails_generators/static_scaffold/templates/controller.rb +85 -0
  23. data/rails_generators/static_scaffold/templates/functional_test.rb +45 -0
  24. data/rails_generators/static_scaffold/templates/helper.rb +2 -0
  25. data/rails_generators/static_scaffold/templates/helper_test.rb +4 -0
  26. data/rails_generators/static_scaffold/templates/layout.html.erb +18 -0
  27. data/rails_generators/static_scaffold/templates/model.rb +109 -0
  28. data/rails_generators/static_scaffold/templates/view_edit.html.erb +19 -0
  29. data/rails_generators/static_scaffold/templates/view_index.html.erb +26 -0
  30. data/rails_generators/static_scaffold/templates/view_new.html.erb +18 -0
  31. data/rails_generators/static_scaffold/templates/view_show.html.erb +13 -0
  32. data/static-generators.gemspec +31 -0
  33. data/tasks/deployment.rake +9 -0
  34. metadata +95 -0
@@ -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
+