hot-glue 0.0.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -1
  3. data/Gemfile.lock +21 -18
  4. data/README.md +84 -50
  5. data/app/helpers/hot_glue/controller_helper.rb +1 -1
  6. data/db/migrate/20210306223305_create_ghis.rb +9 -0
  7. data/db/schema.rb +1 -1
  8. data/lib/generators/hot_glue/install_generator.rb +0 -2
  9. data/lib/generators/hot_glue/markup_templates/base.rb +7 -0
  10. data/lib/generators/hot_glue/markup_templates/erb.rb +228 -0
  11. data/lib/generators/hot_glue/markup_templates/haml.rb +223 -0
  12. data/lib/generators/hot_glue/markup_templates/slim.rb +9 -0
  13. data/lib/generators/hot_glue/scaffold_generator.rb +172 -280
  14. data/lib/generators/hot_glue/templates/controller.rb.erb +12 -10
  15. data/lib/generators/hot_glue/templates/erb/_errors.erb +11 -0
  16. data/lib/generators/hot_glue/templates/erb/_flash_notices.erb +12 -0
  17. data/lib/generators/hot_glue/templates/erb/_form.erb +8 -0
  18. data/lib/generators/hot_glue/templates/erb/_line.erb +10 -0
  19. data/lib/generators/hot_glue/templates/erb/_list.erb +19 -0
  20. data/lib/generators/hot_glue/templates/erb/_new_button.erb +3 -0
  21. data/lib/generators/hot_glue/templates/erb/_new_form.erb +8 -0
  22. data/lib/generators/hot_glue/templates/erb/_show.erb +8 -0
  23. data/lib/generators/hot_glue/templates/erb/create.turbo_stream.erb +18 -0
  24. data/lib/generators/hot_glue/templates/erb/destroy.turbo_stream.erb +3 -0
  25. data/lib/generators/hot_glue/templates/erb/edit.erb +30 -0
  26. data/lib/generators/hot_glue/templates/erb/edit.turbo_stream.erb +3 -0
  27. data/lib/generators/hot_glue/templates/erb/index.erb +10 -0
  28. data/lib/generators/hot_glue/templates/erb/new.erb +1 -0
  29. data/lib/generators/hot_glue/templates/erb/update.turbo_stream.erb +10 -0
  30. data/lib/generators/hot_glue/templates/{_errors.haml → haml/_errors.haml} +0 -0
  31. data/lib/generators/hot_glue/templates/{_flash_notices.haml → haml/_flash_notices.haml} +0 -0
  32. data/lib/generators/hot_glue/templates/{_form.haml → haml/_form.haml} +1 -0
  33. data/lib/generators/hot_glue/templates/{_line.haml → haml/_line.haml} +0 -0
  34. data/lib/generators/hot_glue/templates/{_list.haml → haml/_list.haml} +0 -0
  35. data/lib/generators/hot_glue/templates/{_new_button.haml → haml/_new_button.haml} +0 -0
  36. data/lib/generators/hot_glue/templates/{_new_form.haml → haml/_new_form.haml} +0 -3
  37. data/lib/generators/hot_glue/templates/haml/_show.haml +7 -0
  38. data/lib/generators/hot_glue/templates/{create.turbo_stream.haml → haml/create.turbo_stream.haml} +0 -0
  39. data/lib/generators/hot_glue/templates/{destroy.turbo_stream.haml → haml/destroy.turbo_stream.haml} +0 -0
  40. data/lib/generators/hot_glue/templates/{edit.haml → haml/edit.haml} +0 -0
  41. data/lib/generators/hot_glue/templates/{edit.turbo_stream.haml → haml/edit.turbo_stream.haml} +0 -0
  42. data/lib/generators/hot_glue/templates/{index.haml → haml/index.haml} +0 -0
  43. data/lib/generators/hot_glue/templates/{new.haml → haml/new.haml} +0 -0
  44. data/lib/generators/hot_glue/templates/haml/update.turbo_stream.haml +9 -0
  45. data/lib/generators/hot_glue/templates/system_spec.rb.erb +115 -76
  46. data/lib/hot-glue.rb +6 -20
  47. data/lib/hotglue/version.rb +1 -1
  48. metadata +45 -27
  49. data/db/migrate/20210306223305_create_hgis.rb +0 -9
  50. data/lib/generators/hot_glue/templates/_show.haml +0 -7
  51. data/lib/generators/hot_glue/templates/request_spec.rb.erb +0 -110
  52. data/lib/generators/hot_glue/templates/update.turbo_stream.haml +0 -5
@@ -0,0 +1,223 @@
1
+ module HotGlue
2
+ class HamlTemplate < TemplateBase
3
+
4
+ attr_accessor :singular
5
+
6
+ def field_output(col, type = nil, width, col_identifier )
7
+
8
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if @#{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
9
+ = f.text_field :#{col.to_s}, value: @#{@singular}.#{col.to_s}, size: #{width}, class: 'form-control', type: '#{type}'
10
+ %label.form-text
11
+ #{col.to_s.humanize}\n"
12
+ end
13
+
14
+
15
+ def all_form_fields(*args)
16
+
17
+ columns = args[0][:columns]
18
+ show_only = args[0][:show_only]
19
+ singular_class = args[0][:singular_class]
20
+
21
+ # TODO: CLEAN ME
22
+ @singular = args[0][:singular]
23
+ singular = @singular
24
+
25
+
26
+ col_identifier = " .col"
27
+ col_spaces_prepend = " "
28
+
29
+ res = columns.map { |col|
30
+
31
+ if show_only.include?(col)
32
+
33
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
34
+ = @#{singular}.#{col.to_s}
35
+ %label.form-text
36
+ #{col.to_s.humanize}\n"
37
+ else
38
+
39
+
40
+ type = eval("#{singular_class}.columns_hash['#{col}']").type
41
+ limit = eval("#{singular_class}.columns_hash['#{col}']").limit
42
+ sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
43
+
44
+ case type
45
+ when :integer
46
+ # look for a belongs_to on this object
47
+ if col.to_s.ends_with?("_id")
48
+ assoc_name = col.to_s.gsub("_id","")
49
+ assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
50
+ if assoc.nil?
51
+ exit_message= "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
52
+ exit
53
+ end
54
+ display_column = derrive_reference_name(assoc.class_name)
55
+
56
+
57
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{assoc_name.to_s})}\"}
58
+ #{col_spaces_prepend}= f.collection_select(:#{col.to_s}, #{assoc.class_name}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col.to_s} }, class: 'form-control')
59
+ #{col_spaces_prepend}%label.small.form-text.text-muted
60
+ #{col_spaces_prepend} #{col.to_s.humanize}"
61
+
62
+ else
63
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if @#{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
64
+ #{col_spaces_prepend}= f.text_field :#{col.to_s}, value: #{singular}.#{col.to_s}, class: 'form-control', size: 4, type: 'number'
65
+ #{col_spaces_prepend}%label.form-text
66
+ #{col_spaces_prepend} #{col.to_s.humanize}\n"
67
+ end
68
+ when :string
69
+ limit ||= 256
70
+ if limit <= 256
71
+ field_output(col, nil, limit, col_identifier)
72
+ else
73
+ text_area_output(col, limit, col_identifier)
74
+ end
75
+
76
+ when :text
77
+ limit ||= 256
78
+ if limit <= 256
79
+ field_output(col, nil, limit, col_identifier)
80
+ else
81
+ text_area_output(col, limit, col_identifier)
82
+ end
83
+ when :float
84
+ limit ||= 256
85
+ field_output(col, nil, limit, col_identifier)
86
+
87
+
88
+ when :datetime
89
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
90
+ #{col_spaces_prepend}= datetime_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
91
+ when :date
92
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
93
+ #{col_spaces_prepend}= date_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
94
+ when :time
95
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
96
+ #{col_spaces_prepend}= time_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
97
+ when :boolean
98
+ "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
99
+ #{col_spaces_prepend}%span
100
+ #{col_spaces_prepend} #{col.to_s.humanize}
101
+ #{col_spaces_prepend}= f.radio_button(:#{col.to_s}, '0', checked: #{singular}.#{col.to_s} ? '' : 'checked')
102
+ #{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'No', for: '#{singular}_#{col.to_s}_0')
103
+
104
+ #{col_spaces_prepend}= f.radio_button(:#{col.to_s}, '1', checked: #{singular}.#{col.to_s} ? 'checked' : '')
105
+ #{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'Yes', for: '#{singular}_#{col.to_s}_1')
106
+ "
107
+ end
108
+ end
109
+ }.join("\n")
110
+ return res
111
+ end
112
+
113
+
114
+
115
+ def paginate(*args)
116
+ plural = args[0][:plural]
117
+
118
+ "- if #{plural}.respond_to?(:total_pages)
119
+ = paginate #{plural}"
120
+ end
121
+
122
+ def all_line_fields(*args)
123
+ columns = args[0][:columns]
124
+ show_only = args[0][:show_only]
125
+ singular_class = args[0][:singular_class]
126
+ singular = args[0][:singular]
127
+
128
+ columns_count = columns.count + 1
129
+ perc_width = (100/columns_count).floor
130
+
131
+ col_identifer = ".col"
132
+ columns.map { |col|
133
+ type = eval("#{singular_class}.columns_hash['#{col}']").type
134
+ limit = eval("#{singular_class}.columns_hash['#{col}']").limit
135
+ sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
136
+
137
+ case type
138
+ when :integer
139
+ # look for a belongs_to on this object
140
+ if col.to_s.ends_with?("_id")
141
+
142
+ assoc_name = col.to_s.gsub("_id","")
143
+
144
+
145
+ assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
146
+
147
+ if assoc.nil?
148
+ exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
149
+ raise(HotGlue::Error,exit_message)
150
+ end
151
+
152
+ display_column = derrive_reference_name(assoc.class_name)
153
+
154
+
155
+ "#{col_identifer}
156
+ = #{singular}.#{assoc.name.to_s}.try(:#{display_column}) || '<span class=\"content alert-danger\">MISSING</span>'.html_safe"
157
+
158
+ else
159
+ "#{col_identifer}
160
+ = #{singular}.#{col}"
161
+ end
162
+ when :float
163
+ width = (limit && limit < 40) ? limit : (40)
164
+ "#{col_identifer}
165
+ = #{singular}.#{col}"
166
+
167
+ when :string
168
+ width = (limit && limit < 40) ? limit : (40)
169
+ "#{col_identifer}
170
+ = #{singular}.#{col}"
171
+ when :text
172
+ "#{col_identifer}
173
+ = #{singular}.#{col}"
174
+ when :datetime
175
+ "#{col_identifer}
176
+ - unless #{singular}.#{col}.nil?
177
+ = #{singular}.#{col}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone)
178
+ - else
179
+ %span.alert-danger
180
+ MISSING
181
+ "
182
+ when :date
183
+ "#{col_identifer}
184
+ - unless #{singular}.#{col}.nil?
185
+ = #{singular}.#{col}
186
+ - else
187
+ %span.alert-danger
188
+ MISSING
189
+ "
190
+ when :time
191
+ "#{col_identifer}
192
+ - unless #{singular}.#{col}.nil?
193
+ = #{singular}.#{col}.in_time_zone(current_timezone).strftime('%l:%M %p ') + timezonize(current_timezone)
194
+ - else
195
+ %span.alert-danger
196
+ MISSING
197
+ "
198
+ when :boolean
199
+ "#{col_identifer}
200
+ - if #{singular}.#{col}.nil?
201
+ %span.alert-danger
202
+ MISSING
203
+ - elsif #{singular}.#{col}
204
+ YES
205
+ - else
206
+ NO
207
+ "
208
+ end #end of switch
209
+ }.join("\n")
210
+ end
211
+
212
+ def list_column_headings(*args)
213
+ columns = args[0][:columns]
214
+
215
+ columns.map(&:to_s).map{|col_name| ' .col ' + col_name.humanize}.join("\n")
216
+ end
217
+
218
+ end
219
+
220
+
221
+
222
+
223
+ end
@@ -0,0 +1,9 @@
1
+
2
+
3
+ module HotGlue
4
+ class Slim < TemplateBase
5
+
6
+
7
+
8
+ end
9
+ end
@@ -1,15 +1,37 @@
1
1
  require 'rails/generators/erb/scaffold/scaffold_generator'
2
2
  require 'ffaker'
3
3
 
4
+ require_relative './markup_templates/base'
5
+ require_relative './markup_templates/erb'
6
+ require_relative './markup_templates/haml'
7
+ require_relative './markup_templates/slim'
4
8
 
5
9
  module HotGlue
6
-
7
-
8
10
  class Error < StandardError
9
11
  end
10
12
 
11
-
12
13
  module GeneratorHelper
14
+ def derrive_reference_name thing_as_string
15
+ assoc_class = eval(thing_as_string)
16
+
17
+ if assoc_class.respond_to?("name")
18
+ display_column = "name"
19
+ elsif assoc_class.respond_to?("to_label")
20
+ display_column = "to_label"
21
+ elsif assoc_class.respond_to?("full_name")
22
+ display_column = "full_name"
23
+ elsif assoc_class.respond_to?("display_name")
24
+ display_column = "display_name"
25
+ elsif assoc_class.respond_to?("email")
26
+ display_column = "email"
27
+ else
28
+ raise("this should have been caught by the checker in the initializer")
29
+ # puts "*** Oops: Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
30
+ end
31
+ display_column
32
+ end
33
+
34
+
13
35
  def text_area_output(col, field_length, col_identifier )
14
36
  lines = field_length % 40
15
37
  if lines > 5
@@ -24,13 +46,7 @@ module HotGlue
24
46
 
25
47
 
26
48
 
27
- def field_output(col, type = nil, width, col_identifier )
28
49
 
29
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
30
- = f.text_field :#{col.to_s}, value: @#{singular}.#{col.to_s}, size: #{width}, class: 'form-control', type: '#{type}'
31
- %label.form-text
32
- #{col.to_s.humanize}\n"
33
- end
34
50
  end
35
51
 
36
52
 
@@ -55,19 +71,30 @@ module HotGlue
55
71
  class_option :include, type: :string, default: ""
56
72
  class_option :god, type: :boolean, default: false
57
73
  class_option :gd, type: :boolean, default: false # alias for god
58
- class_option :spacs_only, type: :boolean, default: false
74
+ class_option :specs_only, type: :boolean, default: false
59
75
  class_option :no_specs, type: :boolean, default: false
60
76
  class_option :no_delete, type: :boolean, default: false
61
77
  class_option :no_create, type: :boolean, default: false
62
78
  class_option :no_paginate, type: :boolean, default: false
63
79
  class_option :big_edit, type: :boolean, default: false
64
80
  class_option :show_only, type: :string, default: ""
81
+ class_option :markup, type: :string, default: "erb"
82
+
83
+
84
+
85
+ # def erb_replace_ampersands
86
+ # if @template_builder.is_a?(HotGlue::ErbTemplate)
87
+ # @output_buffer.gsub!('\%', '%')
88
+ # end
89
+ # end
90
+
65
91
 
66
- def initialize(*meta_args) #:nodoc:
92
+
93
+ def initialize(*meta_args)
67
94
  super
68
95
 
69
96
  begin
70
- object = eval(class_name)
97
+ @the_object = eval(class_name)
71
98
  rescue StandardError => e
72
99
  message = "*** Oops: It looks like there is no object for #{class_name}. Please define the object + database table first."
73
100
  raise(HotGlue::Error, message)
@@ -77,14 +104,29 @@ module HotGlue
77
104
  raise(HotGlue::Error, "*** Oops: You seem to have specified both the --specs-only flag and --no-specs flags. this doesn't make any sense, so I am aborting. sorry.")
78
105
  end
79
106
 
107
+ if options['markup'] == "erb"
108
+ @template_builder = HotGlue::ErbTemplate.new
109
+ elsif options['markup'] == "slim"
110
+ puts "SLIM IS NOT IMPLEMENTED; please see https://github.com/jasonfb/hot-glue/issues/3"
111
+ abort
112
+ @template_builder = HotGlue::SlimTemplate.new
113
+
114
+ elsif options['markup'] == "haml"
115
+ @template_builder = HotGlue::HamlTemplate.new
116
+ end
117
+ @markup = options['markup']
118
+
80
119
 
81
120
  args = meta_args[0]
82
121
  @singular = args.first.tableize.singularize # should be in form hello_world
83
122
  @plural = options['plural'] || @singular + "s" # supply to override; leave blank to use default
84
123
  @auth = options['auth'] || "current_user"
85
- @auth_identifier = options['auth'] || (!@auth.nil? && @auth.gsub("current_", "")) || nil
86
- @nest = options['auth'] || nil
124
+ @auth_identifier = options['auth_identifier'] || (!@auth.nil? && @auth.gsub("current_", "")) || nil
125
+
126
+
127
+ @nest = (!options['nest'].empty? && options['nest']) || nil
87
128
  @namespace = options['namespace'] || nil
129
+
88
130
  @singular_class = @singular.titleize.gsub(" ", "")
89
131
  @exclude_fields = []
90
132
  @exclude_fields += options['exclude'].split(",").collect(&:to_sym)
@@ -100,10 +142,10 @@ module HotGlue
100
142
  @show_only += options['show_only'].split(",").collect(&:to_sym)
101
143
  end
102
144
 
103
- auth_assoc = @auth.gsub("current_","")
104
145
 
105
146
  @god = options['god'] || options['gd'] || false
106
147
  @specs_only = options['specs_only'] || false
148
+
107
149
  @no_specs = options['no_specs'] || false
108
150
  @no_delete = options['no_delete'] || false
109
151
 
@@ -146,22 +188,46 @@ module HotGlue
146
188
  end
147
189
  end
148
190
 
191
+ identify_object_owner
192
+ setup_fields
193
+ end
194
+
195
+ def identify_object_owner
196
+ auth_assoc = @auth && @auth.gsub("current_","")
149
197
 
150
198
  if !@object_owner_sym.empty?
151
199
  auth_assoc_field = auth_assoc + "_id"
152
200
  assoc = eval("#{singular_class}.reflect_on_association(:#{@object_owner_sym})")
153
201
 
154
202
  if assoc
155
- ownership_field = assoc.name.to_s + "_id"
203
+ @ownership_field = assoc.name.to_s + "_id"
204
+ elsif !@nest
205
+ exit_message = "*** Oops: It looks like is no association from current_#{@object_owner_sym} to a class called #{@singular_class}. If your user is called something else, pass with flag auth=current_X where X is the model for your users as lowercase. Also, be sure to implement current_X as a method on your controller. (If you really don't want to implement a current_X on your controller and want me to check some other method for your current user, see the section in the docs for auth_identifier.) To make a controller that can read all records, specify with --god."
206
+
156
207
  else
157
- # if @auth
158
- exit_message= "*** Oops: It looks like is no association from current_#{@object_owner_sym} to a class called #{singular_class}. If your user is called something else, pass with flag auth=current_X where X is the model for your users as lowercase. Also, be sure to implement current_X as a method on your controller. (If you really don't want to implement a current_X on your controller and want me to check some other method for your current user, see the section in the docs for auth_identifier.) To make a controller that can read all records, specify with --god."
159
- # else
160
- # exit_message= "*** Oops: god mode could not find the association(?). something is wrong."
161
- # end
208
+ if @god
209
+
210
+ exit_message= "*** Oops: god mode could not find the association(?). something is wrong."
211
+ else
212
+ @auth_check = "current_user"
213
+ @nested_args.each do |arg|
214
+
215
+ if !@auth_check.method("#{arg}s")
216
+ exit_message= "*** Oops: your nesting chain does not have a assocation for #{arg}s on #{@auth_check} something is wrong."
217
+ end
218
+ byebug
219
+ puts ""
220
+ end
221
+ end
222
+
162
223
  raise(HotGlue::Error, exit_message)
163
224
  end
164
225
  end
226
+ end
227
+
228
+
229
+ def setup_fields
230
+ auth_assoc = @auth && @auth.gsub("current_","")
165
231
 
166
232
  if !@include_fields
167
233
  @exclude_fields.push :id, :created_at, :updated_at, :encrypted_password,
@@ -170,15 +236,14 @@ module HotGlue
170
236
  :confirmation_token, :confirmed_at,
171
237
  :confirmation_sent_at, :unconfirmed_email
172
238
 
173
- @exclude_fields.push(auth_assoc_field.to_sym) if !auth_assoc_field.nil?
174
- @exclude_fields.push(ownership_field.to_sym) if !ownership_field.nil?
239
+ @exclude_fields.push( (auth_assoc + "_id").to_sym) if ! auth_assoc.nil?
240
+ @exclude_fields.push( @ownership_field.to_sym ) if ! @ownership_field.nil?
175
241
 
176
242
 
177
- @columns = object.columns.map(&:name).map(&:to_sym).reject{|field| @exclude_fields.include?(field) }
243
+ @columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| @exclude_fields.include?(field) }
178
244
 
179
245
  else
180
- @columns = object.columns.map(&:name).map(&:to_sym).reject{|field| !@include_fields.include?(field) }
181
-
246
+ @columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| !@include_fields.include?(field) }
182
247
  end
183
248
 
184
249
  @columns.each do |col|
@@ -186,7 +251,7 @@ module HotGlue
186
251
  @show_only << col
187
252
  end
188
253
 
189
- if object.columns_hash[col.to_s].type == :integer
254
+ if @the_object.columns_hash[col.to_s].type == :integer
190
255
  if col.to_s.ends_with?("_id")
191
256
  # guess the association name label
192
257
  assoc_name = col.to_s.gsub("_id","")
@@ -196,7 +261,7 @@ module HotGlue
196
261
  begin
197
262
  eval(assoc.class_name)
198
263
  rescue NameError => e
199
- exit_message = "*** Oops: The table #{singular_class} has an association for '#{assoc.name.to_s}', but I can't find an assoicated model for that association. TODO: Please implement a model for #{assoc.name.to_s} that belongs to #{singular_class} "
264
+ exit_message = "*** Oops: The model #{singular_class} is missing an association for #{assoc_name} or the model doesn't exist. TODO: Please implement a model for #{assoc_name.titlecase}; your model #{singular_class.titlecase} should have_many :#{assoc_name}s. To make a controller that can read all records, specify with --god."
200
265
  raise(HotGlue::Error, exit_message)
201
266
 
202
267
  end
@@ -208,18 +273,16 @@ module HotGlue
208
273
  end
209
274
 
210
275
  assoc_class = eval(assoc.class_name)
211
- if assoc_class.respond_to?(:name)
212
- # display_column = "name"
213
- elsif assoc_class.respond_to?(:to_label)
214
- # display_column = "to_label"
215
- elsif assoc_class.respond_to?(:full_name)
216
- # display_column = "full_name"
217
- elsif assoc_class.respond_to?(:display_name)
218
- # display_column = "display_name"
219
- elsif assoc_class.respond_to?(:email)
220
- # display_column = "email"
276
+
277
+ name_list = [:name, :to_label, :full_name, :display_name, :email]
278
+
279
+
280
+ if name_list.collect{ |field|
281
+ assoc_class.column_names.include?(field.to_s) || assoc_class.instance_methods.include?(field)
282
+ }.any?
283
+ # do nothing here
221
284
  else
222
- exit_message= "*** Oops: Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
285
+ exit_message= "*** Oops: Missing a label for #{assoc.class_name.upcase}. Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name.upcase} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
223
286
  raise(HotGlue::Error,exit_message)
224
287
  end
225
288
  end
@@ -227,8 +290,6 @@ module HotGlue
227
290
  end
228
291
  end
229
292
 
230
-
231
-
232
293
  #
233
294
  def formats
234
295
  [format]
@@ -243,22 +304,26 @@ module HotGlue
243
304
 
244
305
  unless @specs_only
245
306
  template "controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "#{plural}_controller.rb")
246
- if @namespace && defined?(controller_descends_from) == nil
247
- template "base_controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "base_controller.rb")
307
+ if @namespace
308
+ begin
309
+ eval(controller_descends_from)
310
+ puts " skipping base controller #{controller_descends_from}"
311
+ rescue NameError => e
312
+ template "base_controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "base_controller.rb")
313
+ end
248
314
  end
249
315
  end
250
316
 
251
317
  unless @no_specs
252
- template "request_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/request#{namespace_with_dash}", "#{plural}_spec.rb")
253
- template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_spec.rb")
254
-
318
+ template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
255
319
  end
256
320
 
257
- template "_errors.haml", File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", "_errors.haml")
321
+ template "#{@markup}/_errors.#{@markup}", File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", "_errors.#{@markup}")
258
322
  end
259
323
 
260
324
  def list_column_headings
261
- @columns.map(&:to_s).map{|col_name| ' .col ' + col_name.humanize}.join("\n")
325
+ @template_builder.list_column_headings(columns: @columns)
326
+
262
327
  end
263
328
 
264
329
  def columns_spec_with_sample_data
@@ -329,11 +394,6 @@ module HotGlue
329
394
  @auth_identifier
330
395
  end
331
396
 
332
-
333
- def path_helper_full
334
- "#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{singular}_path"
335
- end
336
-
337
397
  def path_helper_args
338
398
  if @nested_args.any?
339
399
  [(@nested_args).collect{|a| "@#{a}"} , singular].join(",")
@@ -426,37 +486,60 @@ module HotGlue
426
486
  end
427
487
 
428
488
  def all_objects_variable
429
-
430
- # needs the authenticated root user
431
- # "#{@auth}.#{ @nested_args.map{|a| "#{@nested_args_plural[a]}.find(@#{a})"}.join('.') + "." if @nested_args.any?}#{plural}"
432
-
433
489
  all_objects_root + ".page(params[:page])"
434
-
435
490
  end
436
491
 
437
492
  def auth_object
438
493
  @auth
439
494
  end
440
495
 
441
-
442
496
  def no_devise_installed
443
497
  !Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }['devise']
444
498
  end
445
499
 
500
+ # def erb_replace_ampersands!(filename = nil)
501
+ #
502
+ # return if filename.nil?
503
+ # file = File.open(filename, "r")
504
+ # contents = file.read
505
+ # file.close
506
+ #
507
+ # file = File.open(filename, "w")
508
+ # file.write( contents.gsub('\%', '%'))
509
+ # file.close
510
+ # end
511
+
512
+
513
+
514
+
446
515
 
447
516
  def copy_view_files
448
517
  return if @specs_only
449
- haml_views.each do |view|
518
+ all_views.each do |view|
450
519
  formats.each do |format|
451
- filename = cc_filename_with_extensions(view, "haml")
452
- template filename, File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", controller_file_path, filename)
520
+ source_filename = cc_filename_with_extensions("#{@markup}/#{view}", "#{@markup}")
521
+ dest_filename = cc_filename_with_extensions("#{view}", "#{@markup}")
522
+ dest_filepath = File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}",
523
+ controller_file_path, dest_filename)
524
+
525
+
526
+ template source_filename, dest_filepath
527
+ gsub_file dest_filepath, '\%', '%'
528
+
453
529
  end
454
530
  end
455
531
 
456
532
  turbo_stream_views.each do |view|
457
533
  formats.each do |format|
458
- filename = cc_filename_with_extensions(view, 'turbo_stream.haml')
459
- template filename, File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", controller_file_path, filename)
534
+ source_filename = cc_filename_with_extensions( "#{@markup}/#{view}.turbo_stream.#{@markup}")
535
+ dest_filename = cc_filename_with_extensions("#{view}", "turbo_stream.#{@markup}")
536
+ dest_filepath = File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}",
537
+ controller_file_path, dest_filename)
538
+
539
+
540
+ template source_filename, dest_filepath
541
+ gsub_file dest_filepath, '\%', '%'
542
+
460
543
  end
461
544
  end
462
545
  end
@@ -477,7 +560,7 @@ module HotGlue
477
560
  end
478
561
  end
479
562
 
480
- def haml_views
563
+ def all_views
481
564
  res = %w(index edit _form _line _list _show _errors)
482
565
 
483
566
  unless @no_create
@@ -509,212 +592,23 @@ module HotGlue
509
592
  end
510
593
 
511
594
  def all_form_fields
512
- col_identifier = " .col"
513
- col_spaces_prepend = " "
514
-
515
- res = @columns.map { |col|
516
-
517
- if @show_only.include?(col)
518
-
519
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
520
- = @#{singular}.#{col.to_s}
521
- %label.form-text
522
- #{col.to_s.humanize}\n"
523
- else
524
-
525
-
526
- type = eval("#{singular_class}.columns_hash['#{col}']").type
527
- limit = eval("#{singular_class}.columns_hash['#{col}']").limit
528
- sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
529
-
530
- case type
531
- when :integer
532
- # look for a belongs_to on this object
533
- if col.to_s.ends_with?("_id")
534
- assoc_name = col.to_s.gsub("_id","")
535
- assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
536
- if assoc.nil?
537
- exit_message= "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
538
- exit
539
- end
540
-
541
-
542
- assoc_class = eval(assoc.class_name)
543
-
544
- if assoc_class.respond_to?("name")
545
- display_column = "name"
546
- elsif assoc_class.respond_to?("to_label")
547
- display_column = "to_label"
548
- elsif assoc_class.respond_to?("full_name")
549
- display_column = "full_name"
550
- elsif assoc_class.respond_to?("display_name")
551
- display_column = "display_name"
552
- elsif assoc_class.respond_to?("email")
553
- display_column = "email"
554
- else
555
- raise("this should have been caught by the checker in the initializer")
556
- # puts "*** Oops: Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
557
- end
558
-
559
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{assoc_name.to_s})}\"}
560
- #{col_spaces_prepend}= f.collection_select(:#{col.to_s}, #{assoc_class}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col.to_s} }, class: 'form-control')
561
- #{col_spaces_prepend}%label.small.form-text.text-muted
562
- #{col_spaces_prepend} #{col.to_s.humanize}"
563
-
564
- else
565
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if @#{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
566
- #{col_spaces_prepend}= f.text_field :#{col.to_s}, value: #{singular}.#{col.to_s}, class: 'form-control', size: 4, type: 'number'
567
- #{col_spaces_prepend}%label.form-text
568
- #{col_spaces_prepend} #{col.to_s.humanize}\n"
569
- end
570
- when :string
571
- limit ||= 256
572
- if limit <= 256
573
- field_output(col, nil, limit, col_identifier)
574
- else
575
- text_area_output(col, limit, col_identifier)
576
- end
577
-
578
- when :text
579
- limit ||= 256
580
- if limit <= 256
581
- field_output(col, nil, limit, col_identifier)
582
- else
583
- text_area_output(col, limit, col_identifier)
584
- end
585
- when :float
586
- limit ||= 256
587
- field_output(col, nil, limit, col_identifier)
588
-
589
-
590
- when :datetime
591
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
592
- #{col_spaces_prepend}= datetime_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
593
- when :date
594
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
595
- #{col_spaces_prepend}= date_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
596
- when :time
597
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
598
- #{col_spaces_prepend}= time_field_localized(f, :#{col.to_s}, #{singular}.#{col.to_s}, '#{col.to_s.humanize}', #{@auth ? @auth+'.timezone' : 'nil'})"
599
- when :boolean
600
- "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
601
- #{col_spaces_prepend}%span
602
- #{col_spaces_prepend} #{col.to_s.humanize}
603
- #{col_spaces_prepend}= f.radio_button(:#{col.to_s}, '0', checked: #{singular}.#{col.to_s} ? '' : 'checked')
604
- #{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'No', for: '#{singular}_#{col.to_s}_0')
605
-
606
- #{col_spaces_prepend}= f.radio_button(:#{col.to_s}, '1', checked: #{singular}.#{col.to_s} ? 'checked' : '')
607
- #{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'Yes', for: '#{singular}_#{col.to_s}_1')
608
- "
609
- end
610
- end
611
- }.join("\n")
612
- return res
595
+ @template_builder.all_form_fields(
596
+ columns: @columns,
597
+ show_only: @show_only,
598
+ singular_class: singular_class,
599
+ singular: singular
600
+ )
613
601
  end
614
602
 
615
-
616
603
  def all_line_fields
617
- columns = @columns.count + 1
618
- perc_width = (100/columns).floor
619
-
620
- col_identifer = ".col"
621
- @columns.map { |col|
622
- type = eval("#{singular_class}.columns_hash['#{col}']").type
623
- limit = eval("#{singular_class}.columns_hash['#{col}']").limit
624
- sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
625
-
626
- case type
627
- when :integer
628
- # look for a belongs_to on this object
629
- if col.to_s.ends_with?("_id")
630
-
631
- assoc_name = col.to_s.gsub("_id","")
632
-
633
-
634
- assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
635
-
636
- if assoc.nil?
637
- exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
638
- raise(HotGlue::Error,exit_message)
639
- end
640
-
641
- assoc_class = eval(assoc.class_name)
642
-
643
- if assoc_class.respond_to?("name")
644
- display_column = "name"
645
- elsif assoc_class.respond_to?("to_label")
646
- display_column = "to_label"
647
- elsif assoc_class.respond_to?("full_name")
648
- display_column = "full_name"
649
- elsif assoc_class.respond_to?("display_name")
650
- display_column = "display_name"
651
- elsif assoc_class.respond_to?("email")
652
- display_column = "email"
653
- elsif assoc_class.respond_to?("number")
654
- display_column = "number"
655
-
656
- else
657
- puts "*** Oops: Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, 5) email, or 6) number directly on your #{assoc.class_name} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
658
- end
659
-
660
- "#{col_identifer}
661
- = #{singular}.#{assoc.name.to_s}.try(:#{display_column}) || '<span class=\"content alert-danger\">MISSING</span>'.html_safe"
662
-
663
- else
664
- "#{col_identifer}
665
- = #{singular}.#{col}"
666
- end
667
- when :float
668
- width = (limit && limit < 40) ? limit : (40)
669
- "#{col_identifer}
670
- = #{singular}.#{col}"
671
-
672
- when :string
673
- width = (limit && limit < 40) ? limit : (40)
674
- "#{col_identifer}
675
- = #{singular}.#{col}"
676
- when :text
677
- "#{col_identifer}
678
- = #{singular}.#{col}"
679
- when :datetime
680
- "#{col_identifer}
681
- - unless #{singular}.#{col}.nil?
682
- = #{singular}.#{col}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone)
683
- - else
684
- %span.alert-danger
685
- MISSING
686
- "
687
- when :date
688
- ".cell
689
- - unless #{singular}.#{col}.nil?
690
- = #{singular}.#{col}
691
- - else
692
- %span.alert-danger
693
- MISSING
694
- "
695
- when :time
696
- "#{col_identifer}
697
- - unless #{singular}.#{col}.nil?
698
- = #{singular}.#{col}.in_time_zone(current_timezone).strftime('%l:%M %p ') + timezonize(current_timezone)
699
- - else
700
- %span.alert-danger
701
- MISSING
702
- "
703
- when :boolean
704
- "#{col_identifer}
705
- - if #{singular}.#{col}.nil?
706
- %span.alert-danger
707
- MISSING
708
- - elsif #{singular}.#{col}
709
- YES
710
- - else
711
- NO
712
- "
713
- end
714
- }.join("\n")
604
+ @template_builder.all_line_fields(
605
+ columns: @columns,
606
+ show_only: @show_only,
607
+ singular_class: singular_class,
608
+ singular: singular
609
+ )
715
610
  end
716
611
 
717
-
718
612
  def controller_descends_from
719
613
  if defined?(@namespace.titlecase + "::BaseController")
720
614
  @namespace.titlecase + "::BaseController"
@@ -729,19 +623,20 @@ module HotGlue
729
623
  me = eval(singular_class)
730
624
 
731
625
  @display_class ||=
732
- if me.respond_to?("name")
626
+ if me.column_names.include?("name") || me.instance_methods(false).include?(:name)
627
+ # note that all class object respond_to?(:name) with the name of their own class
628
+ # this one is unique
733
629
  "name"
734
- elsif me.respond_to?("to_label")
630
+ elsif me.column_names.include?("to_label") || me.instance_methods(false).include?(:to_label)
735
631
  "to_label"
736
- elsif me.respond_to?("full_name")
632
+ elsif me.column_names.include?("full_name") || me.instance_methods(false).include?(:full_name)
737
633
  "full_name"
738
- elsif me.respond_to?("display_name")
634
+ elsif me.column_names.include?("display_name") || me.instance_methods(false).include?(:display_name)
739
635
  "display_name"
740
- elsif me.respond_to?("email")
636
+ elsif me.column_names.include?("email") || me.instance_methods(false).include?(:email)
741
637
  "email"
742
- elsif me.respond_to?("number")
743
- display_column = "number"
744
-
638
+ elsif me.column_names.include?("number") || me.instance_methods(false).include?(:number)
639
+ "number"
745
640
  else
746
641
  exit_message = "*** Oops: Can't find any column to use as the display label on #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, 5) email, or 6) number directly on your #{singular_class} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
747
642
  raise(HotGlue::Error, exit_message)
@@ -766,12 +661,9 @@ module HotGlue
766
661
  end
767
662
  end
768
663
 
769
-
770
-
771
- def paginate
772
- "= paginate #{plural}"
773
- end
774
-
664
+ def paginate
665
+ @template_builder.paginate(plural: plural)
666
+ end
775
667
  private # thor does something fancy like sending the class all of its own methods during some strange run sequence
776
668
  # does not like public methods
777
669