hot-glue 0.4.0 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,8 @@ require_relative './markup_templates/erb'
6
6
  require_relative './markup_templates/haml'
7
7
  require_relative './markup_templates/slim'
8
8
 
9
+ require_relative './layout/builder'
10
+
9
11
  module HotGlue
10
12
  class Error < StandardError
11
13
  end
@@ -56,26 +58,27 @@ module HotGlue
56
58
  class_option :no_paginate, type: :boolean, default: false
57
59
  class_option :big_edit, type: :boolean, default: false
58
60
  class_option :show_only, type: :string, default: ""
59
- class_option :stimulus_syntax, type: :boolean, default: nil
61
+
62
+ class_option :stimulus_syntax, type: :boolean, default: nil # TODO: rename to ujs_syntax and default to false
63
+
60
64
  class_option :downnest, type: :string, default: nil
61
- class_option :nestable, type: :boolean, default: false
62
65
  class_option :magic_buttons, type: :string, default: nil
63
66
  class_option :display_list_after_update, type: :boolean, default: false
64
-
67
+ class_option :smart_layout, type: :boolean, default: false
65
68
  class_option :markup, type: :string, default: nil # deprecated -- use in app config instead
66
- class_option :layout, type: :string, default: nil # deprecated -- use in app config instead
69
+ class_option :layout, type: :string, default: nil # if used here it will override what is in the config
67
70
 
68
71
 
69
72
  def initialize(*meta_args)
70
73
  super
71
74
 
75
+
72
76
  begin
73
77
  @the_object = eval(class_name)
74
78
  rescue StandardError => e
75
79
  message = "*** Oops: It looks like there is no object for #{class_name}. Please define the object + database table first."
76
80
  puts message
77
- exit
78
- # raise(HotGlue::Error, message)
81
+ raise(HotGlue::Error, message)
79
82
  end
80
83
 
81
84
  if !options['spec_only'].nil? && !options['no_spec'].nil?
@@ -83,10 +86,13 @@ module HotGlue
83
86
  end
84
87
 
85
88
  if !options['exclude'].empty? && !options['include'].empty?
86
- puts "*** Oops: You seem to have specified both --include and --exclude. Please use one or the other. Aborting."
87
- exit
89
+ exit_message = "*** Oops: You seem to have specified both --include and --exclude. Please use one or the other. Aborting."
90
+ puts exit_message
91
+
92
+ raise(HotGlue::Error, exit_message)
88
93
  end
89
94
 
95
+
90
96
  if @stimulus_syntax.nil?
91
97
  if Rails.version.split(".")[0].to_i >= 7
92
98
  @stimulus_syntax = true
@@ -96,13 +102,14 @@ module HotGlue
96
102
  end
97
103
 
98
104
  if !options['markup'].nil?
99
- puts "Using --markup flag in the generator is deprecated; instead, use a file at config/hot_glue.yml with a key markup set to `erb` or `haml`"
100
- exit
105
+ message = "Using --markup flag in the generator is deprecated; instead, use a file at config/hot_glue.yml with a key markup set to `erb` or `haml`"
106
+ raise(HotGlue::Error, message)
107
+
101
108
  end
102
109
 
103
110
  if !options['markup'].nil?
104
- puts "Using --layout flag in the generator is deprecated; instead, use a file at config/hot_glue.yml with a key markup set to `erb` or `haml`"
105
- exit
111
+ message = "Using --layout flag in the generator is deprecated; instead, use a file at config/hot_glue.yml with a key markup set to `erb` or `haml`"
112
+ raise(HotGlue::Error, message)
106
113
  end
107
114
 
108
115
  yaml_from_config = YAML.load(File.read("config/hot_glue.yml"))
@@ -111,8 +118,8 @@ module HotGlue
111
118
  if @markup == "erb"
112
119
  @template_builder = HotGlue::ErbTemplate.new
113
120
  elsif @markup == "slim"
114
- puts "SLIM IS NOT IMPLEMENTED; please see https://github.com/jasonfb/hot-glue/issues/3"
115
- abort
121
+ message = "SLIM IS NOT IMPLEMENTED; please see https://github.com/jasonfb/hot-glue/issues/3"
122
+ raise(HotGlue::Error, message)
116
123
  @template_builder = HotGlue::SlimTemplate.new
117
124
 
118
125
  elsif @markup == "haml"
@@ -120,13 +127,16 @@ module HotGlue
120
127
  end
121
128
 
122
129
 
123
- @layout = yaml_from_config[:layout]
130
+ if !options['layout']
131
+ @layout = yaml_from_config[:layout]
124
132
 
125
- if !['hotglue', 'bootstrap'].include? @layout
126
- raise "Invalid option #{@layout} in Hot glue config (config/hot_glue.yml). You must pass either hotglue (default) or bootstrap to config"
133
+ if !['hotglue', 'bootstrap'].include? @layout
134
+ raise "Invalid option #{@layout} in Hot glue config (config/hot_glue.yml). You must either use --layout= when generating or have a file config/hotglue.yml; specify layout as either 'hotglue' or 'bootstrap'"
135
+ end
136
+ else
137
+ @layout = options['layout']
127
138
  end
128
139
 
129
-
130
140
  args = meta_args[0]
131
141
  @singular = args.first.tableize.singularize # should be in form hello_world
132
142
  @plural = options['plural'] || @singular + "s" # supply to override; leave blank to use default
@@ -144,7 +154,8 @@ module HotGlue
144
154
 
145
155
  if !options['include'].empty?
146
156
  @include_fields = []
147
- @include_fields += options['include'].split(",").collect(&:to_sym)
157
+ # semicolon to denote layout columns; commas separate fields
158
+ @include_fields += options['include'].gsub(":","").split(",").collect(&:to_sym)
148
159
  end
149
160
 
150
161
 
@@ -168,10 +179,9 @@ module HotGlue
168
179
  @no_list = options['no_list'] || false
169
180
 
170
181
  @display_list_after_update = options['display_list_after_update'] || false
182
+ @smart_layout = options['smart_layout']
171
183
 
172
184
 
173
-
174
- @col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col"
175
185
  @container_name = @layout == "hotglue" ? "scaffold-container" : "container-fluid"
176
186
 
177
187
  @downnest = options['downnest'] || false
@@ -211,7 +221,6 @@ module HotGlue
211
221
  @build_update_action = !@no_edit || !@magic_buttons.empty?
212
222
  # if the magic buttons are present, build the update action anyway
213
223
 
214
- # @nestable = options['nestable'] || false
215
224
 
216
225
  if @auth && ! @self_auth && @nested_args.none?
217
226
  @object_owner_sym = @auth.gsub("current_", "").to_sym
@@ -227,12 +236,22 @@ module HotGlue
227
236
  end
228
237
  end
229
238
 
230
-
231
-
232
239
  @reference_name = HotGlue.derrive_reference_name(singular_class)
233
240
 
234
241
  identify_object_owner
235
242
  setup_fields
243
+
244
+ builder = HotGlue::Layout::Builder.new({
245
+ include_setting: options['include'],
246
+ downnest_children: @downnest_children,
247
+ no_edit: @no_edit,
248
+ no_delete: @no_delete,
249
+ columns: @columns,
250
+ smart_layout: @smart_layout
251
+ })
252
+ @layout_object = builder.construct
253
+
254
+ @menu_file_exists = true if @nested_args.none? && File.exists?("#{Rails.root}/app/views/#{namespace_with_trailing_dash}_menu.#{@markup}")
236
255
  end
237
256
 
238
257
  def identify_object_owner
@@ -251,17 +270,15 @@ module HotGlue
251
270
  if @god
252
271
  exit_message= "*** Oops: Gd mode could not find the association(#{@object_owner_sym}). Something is wrong."
253
272
  else
254
- @auth_check = "current_user"
273
+ @auth_check = eval(@auth_identifier.titleize)
255
274
  @nested_args.each do |arg|
256
-
257
- if !@auth_check.method("#{arg}s")
275
+ if ! @auth_check.reflect_on_association("#{arg}s".to_sym)
258
276
  exit_message = "*** Oops: your nesting chain does not have a association for #{arg}s on #{@auth_check} something is wrong."
259
277
  end
260
278
  end
261
279
  end
262
280
  puts exit_message
263
- exit
264
-
281
+ raise(HotGlue::Error, exit_message)
265
282
  end
266
283
  end
267
284
  end
@@ -302,26 +319,20 @@ module HotGlue
302
319
  begin
303
320
  eval(assoc.class_name)
304
321
  rescue NameError => e
305
- 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."
322
+ exit_message = "*** Oops: The model #{singular_class} is missing an association for :#{assoc_name} or the model #{assoc_name.titlecase} doesn't exist. TODO: Please implement a model for #{assoc_name.titlecase}; your model #{singular_class.titlecase} should belong_to :#{assoc_name}. To make a controller that can read all records, specify with --god."
306
323
  puts exit_message
307
- exit
308
- # raise(HotGlue::Error, exit_message)
309
-
324
+ raise(HotGlue::Error, exit_message)
310
325
  end
311
326
 
312
327
 
313
328
  if assoc.nil?
314
329
  exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
315
330
  puts exit_message
316
- exit
317
- # raise(HotGlue::Error,exit_message)
331
+ raise(HotGlue::Error,exit_message)
318
332
  end
319
333
 
320
334
  assoc_class = eval(assoc.class_name)
321
-
322
335
  name_list = [:name, :to_label, :full_name, :display_name, :email]
323
-
324
-
325
336
  if name_list.collect{ |field|
326
337
  assoc_class.column_names.include?(field.to_s) || assoc_class.instance_methods.include?(field)
327
338
  }.any?
@@ -335,7 +346,6 @@ module HotGlue
335
346
  end
336
347
  end
337
348
 
338
- #
339
349
  def formats
340
350
  [format]
341
351
  end
@@ -359,7 +369,25 @@ module HotGlue
359
369
  end
360
370
 
361
371
  unless @no_specs
362
- template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
372
+ dest_file = File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
373
+
374
+ if File.exists?(dest_file)
375
+ existing_file = File.open(dest_file)
376
+ existing_content = existing_file.read
377
+ if existing_content =~ /\#HOTGLUE-SAVESTART/
378
+ if existing_content !~ /\#HOTGLUE-END/
379
+ raise "Your file at #{dest_file} contains a #HOTGLUE-SAVESTART marker without #HOTGLUE-END"
380
+ end
381
+ @existing_content = existing_content[(existing_content =~ /\#HOTGLUE-SAVESTART/) .. (existing_content =~ /\#HOTGLUE-END/)-1]
382
+ @existing_content << "#HOTGLUE-END"
383
+
384
+ end
385
+ existing_file.rewind
386
+ else
387
+ @existing_content = " #HOTGLUE-SAVESTART\n #HOTGLUE-END"
388
+ end
389
+
390
+ template "system_spec.rb.erb", dest_file
363
391
  end
364
392
 
365
393
  template "#{@markup}/_errors.#{@markup}", File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", "_errors.#{@markup}")
@@ -368,24 +396,26 @@ module HotGlue
368
396
  def list_column_headings
369
397
  if @nested_args.any?
370
398
  column_width = each_col * @columns.count
371
-
372
- "<div class='#{@col_identifier}' style='flex-basis: #{column_width}%'>"
373
399
  else
374
- @template_builder.list_column_headings(
375
- column_width: each_col,
376
- columns: @columns,
377
- col_identifier: @col_identifier
378
- )
400
+ column_width = 0
379
401
  end
380
402
 
403
+ if !@smart_layout
404
+ col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col-md-1"
405
+ else
406
+ col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col-md-2"
407
+ end
381
408
 
409
+ @template_builder.list_column_headings(
410
+ columns: @layout_object[:columns][:container],
411
+ col_identifier: col_identifier,
412
+ layout: @layout,
413
+ column_width: column_width
414
+ )
382
415
  end
383
416
 
384
417
  def columns_spec_with_sample_data
385
418
  @columns.map { |c|
386
- if eval("#{singular_class}.columns_hash['#{c}']").nil?
387
- byebug
388
- end
389
419
  type = eval("#{singular_class}.columns_hash['#{c}']").type
390
420
  random_data = case type
391
421
  when :integer
@@ -590,21 +620,6 @@ module HotGlue
590
620
  magic_buttons: @magic_buttons
591
621
  )
592
622
  end
593
- # def erb_replace_ampersands!(filename = nil)
594
- #
595
- # return if filename.nil?
596
- # file = File.open(filename, "r")
597
- # contents = file.read
598
- # file.close
599
- #
600
- # file = File.open(filename, "w")
601
- # file.write( contents.gsub('\%', '%'))
602
- # file.close
603
- # end
604
-
605
-
606
-
607
-
608
623
 
609
624
  def copy_view_files
610
625
  return if @specs_only
@@ -656,20 +671,35 @@ module HotGlue
656
671
  end
657
672
 
658
673
  def all_views
659
- res = %w(index edit _form _line _list _show _errors)
674
+ res = %w(index _line _list _show _errors)
660
675
 
661
676
  unless @no_create
662
677
  res += %w(new _new_form _new_button)
663
678
  end
664
679
 
680
+ unless @no_edit
681
+ res << 'edit'
682
+ res << '_form'
683
+ end
684
+
665
685
  res
666
686
  end
667
687
 
668
688
  def turbo_stream_views
669
- res = %w(create edit update)
689
+ res = []
670
690
  unless @no_delete
671
691
  res << 'destroy'
672
692
  end
693
+
694
+ unless @no_create
695
+ res << 'create'
696
+ end
697
+
698
+ unless @no_edit
699
+ res << 'edit'
700
+ res << 'update'
701
+ end
702
+
673
703
  res
674
704
  end
675
705
 
@@ -687,13 +717,19 @@ module HotGlue
687
717
  end
688
718
 
689
719
  def all_form_fields
720
+ # TODO: DRY THIS
721
+ if !@smart_layout
722
+ col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col-md-1"
723
+ else
724
+ col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col-md-2"
725
+ end
690
726
 
691
727
  @template_builder.all_form_fields(
692
- columns: @columns,
728
+ columns: @layout_object[:columns][:container],
693
729
  show_only: @show_only,
694
730
  singular_class: singular_class,
695
731
  singular: singular,
696
- col_identifier: @col_identifier
732
+ col_identifier: col_identifier
697
733
  )
698
734
  end
699
735
 
@@ -702,7 +738,8 @@ module HotGlue
702
738
  end
703
739
 
704
740
  def each_col
705
- (col_width/@columns.count).to_i
741
+ return col_width if @columns.count == 0
742
+ (col_width/(@columns.count)).to_i
706
743
  end
707
744
 
708
745
  def col_width
@@ -724,7 +761,7 @@ module HotGlue
724
761
 
725
762
  @template_builder.all_line_fields(
726
763
  perc_width: column_width,
727
- columns: @columns,
764
+ columns: @layout_object[:columns][:container],
728
765
  show_only: @show_only,
729
766
  singular_class: singular_class,
730
767
  singular: singular,
@@ -1,7 +1,7 @@
1
- def login_as(account)
2
- visit '/accounts/sign_in'
1
+ def login_as(user)
2
+ visit '/users/sign_in'
3
3
  within("#new_account") do
4
- fill_in 'Email', with: account.email
4
+ fill_in 'Email', with: user.email
5
5
  fill_in 'Password', with: 'password'
6
6
  end
7
7
  click_button 'Log in'
@@ -1,7 +1,7 @@
1
1
  <div class="row">
2
2
  <%= all_form_fields %>
3
3
 
4
- <div class="<% @layout == "hotglue" ? 'scaffold-cell' : 'col' %>">
4
+ <div class="<%= @layout == "hotglue" ? 'scaffold-cell' : 'col-md-2' %>">
5
5
  <\%= link_to "Cancel", <%= path_helper_plural %>, {class: "btn btn-secondary"} %>
6
6
  <\%= f.submit "Save", class: "btn btn-primary pull-right" %>
7
7
  </div>
@@ -2,31 +2,30 @@
2
2
  <div class="<%= @container_name %> scaffold-list">
3
3
  <% unless @no_list || @nested_args.any? %><h4><%= plural.gsub("_", " ").upcase %></h4><% end %>
4
4
 
5
- <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + plural + '/new_button", locals: {' + nested_assignments + '}' + '%\>'.gsub('\\',"") %><% end %>
5
+ <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + plural + '/new_button", locals: {' + nested_assignments + '}' + '%\>'.gsub('\\',"") %><br /><% end %>
6
6
 
7
7
  <% unless @no_list %>
8
- <div class="row scaffold-row">
8
+ <div class="row scaffold-heading-row">
9
9
  <%= list_column_headings %>
10
10
  <% if @downnest_children.any? %>
11
11
  <% each_downnest_width = @downnest_children.count == 1 ? 40 : (60/@downnest_children.count).floor %>
12
- <% downnest_column_style = @layout == "hotglue" ? 'style="flex-basis: ' + each_downnest_width + '%;' : "" %>
12
+ <% downnest_column_style = @layout == "hotglue" ? 'style="flex-basis: ' + each_downnest_width.to_s + '%;' : "" %>
13
13
 
14
- <% @downnest_children.each do |downnest| %>
15
- <div class="<%= @col_identifer %> scaffold-col-heading<%= ' col-md-3' if @layout=="bootstrap" %>" <%= downnest_column_style %>>
16
- <h4>
14
+ <% @downnest_children.each_with_index do |downnest,i| %>
15
+ <div class=" scaffold-col-heading<%= " col-sm-#{ @layout_object[:portals][downnest][:size] }" if @layout=="bootstrap" %>" <%= downnest_column_style %>>
16
+ <strong>
17
17
  <%= downnest.titleize %>
18
- </h4>
18
+ </strong>
19
19
  </div>
20
20
  <% end %>
21
21
  <% end %>
22
22
 
23
23
  <% button_column_style = @layout == "hotglue" ? 'style="flex-basis: 150px' : "" %>
24
24
 
25
- <div class='<%= @col_identifer %> scaffold-col-heading scaffold-col-heading-buttons<%= ' col-md-2' if @layout=="bootstrap" %>' <%= button_column_style %>>
25
+ <div class=' scaffold-col-heading scaffold-col-heading-buttons<%= ' col-md-2' if @layout=="bootstrap" %>' <%= button_column_style %>>
26
26
 
27
27
  </div>
28
28
  </div>
29
-
30
29
  <\% if <%= plural %>.empty? %>
31
30
  <div>
32
31
  None
@@ -36,8 +35,6 @@
36
35
  <\%= render partial: '<%= line_path_partial %>', locals: {<%= singular %>: <%= singular %><%= nested_assignments_with_leading_comma if @nestable %><%= ", nested_for: nested_for" if @nestable %> } %>
37
36
  <\% end %>
38
37
  <%= @no_paginate ? "" : paginate %>
39
-
40
- </div>
41
- <% end %>
38
+ <% end %>
42
39
  </div>
43
40
  <\% end %>
@@ -3,29 +3,31 @@
3
3
  <% if @downnest_children.any? %>
4
4
  <% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
5
5
 
6
- <% @downnest_children.each do |downnest| %>
6
+ <% @downnest_children.each_with_index do |downnest,i| %>
7
7
 
8
- <% downnest_style = @layout == "hotglue" ? 'style="flex-basis: ' + each_downnest_width + '%"' : "" %>
9
- <div class="<%= @col_identifier %><%= ' col-md-3' if @layout == "bootstrap" %> scaffold-downnest" <%= downnest_style %> >
10
- <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest %>/list", locals: {
8
+ <% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest})") %>
9
+ <% downnest_class = downnest_object.class_name %>
10
+ <% downnest_object_name = eval("#{downnest_class}.table_name") %>
11
+ <% downnest_style = @layout == "hotglue" ? 'style="flex-basis: ' + each_downnest_width.to_s + '%"' : "" %>
12
+ <div class="<%= " col-md-#{@layout_object[:portals][downnest][:size]}" if @layout == "bootstrap" %> scaffold-downnest" <%= downnest_style %> >
13
+ <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {
11
14
  nested_for: "<% if @nested_args.any? %>#{nested_for + "__" if nested_for}<% end %><%= @singular %>-#{<%= @singular %>.id}",
12
15
  <%= @singular %>: <%= @singular %><%= nest_assignments_operator(false, true) %>,
13
- <%= downnest %>: <%= @singular %>.<%= downnest %>} %>
16
+ <%= downnest_object_name %>: <%= @singular %>.<%= downnest %>} %>
14
17
  </div>
15
18
  <% end %>
16
19
  <% end %>
17
20
 
18
21
  <% button_style = @layout == "hotglue" ? 'style="flex-basis: ' + (100 - (column_width * @columns.count)).floor.to_s + '%;"' : "" %>
19
22
  <div class="<%= @col_identifier %> scaffold-line-buttons <%= ' col-md-2' if @layout == "bootstrap" %>" <%= button_style %>>
23
+ <%= magic_button_output %>
24
+
20
25
  <% if destroy_action %>
21
26
  <\%= form_with url: <%= path_helper_singular %>(<%= path_helper_args %>), html: {style: "display: inline-block;"}, method: :delete do |f| %>
22
27
  <\%= f.submit "Delete".html_safe, data: <%= delete_confirmation_syntax %>, class: "delete-<%= singular %>-button btn btn-primary btn-sm" %>
23
28
  <\% end %>
24
29
  <% end %>
25
30
 
26
-
27
- <%= magic_button_output %>
28
-
29
31
  <% unless @no_edit %>
30
32
  <\%= link_to "Edit <i class='fa fa-1x fa-list-alt'></i>".html_safe, edit_<%= path_helper_singular %>(<%= path_helper_args %>), <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary btn-sm" %>
31
33
  <% end %>
@@ -1,3 +1,5 @@
1
+ <% if @menu_file_exists %><\%= render partial: "<%= namespace_with_trailing_dash %>menu", locals: {active: '<%= plural %>'} %><% end %>
2
+
1
3
  <div class="<%= @container_name %>">
2
4
  <% if @layout == "bootstrap" %><div class="row"> <div class="col-md-12">
3
5
  <% else %>