templet_rails 0.1.0

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 (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +1059 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/lib/generators/templet/controller/USAGE +13 -0
  11. data/lib/generators/templet/controller/controller_generator.rb +106 -0
  12. data/lib/generators/templet/core/USAGE +23 -0
  13. data/lib/generators/templet/core/core_generator.rb +128 -0
  14. data/lib/generators/templet/core_rspec/USAGE +16 -0
  15. data/lib/generators/templet/core_rspec/core_rspec_generator.rb +65 -0
  16. data/lib/generators/templet/destroy/USAGE +19 -0
  17. data/lib/generators/templet/destroy/destroy_generator.rb +126 -0
  18. data/lib/generators/templet/routes/USAGE +14 -0
  19. data/lib/generators/templet/routes/routes_generator.rb +64 -0
  20. data/lib/generators/templet/rspec/USAGE +10 -0
  21. data/lib/generators/templet/rspec/rspec_generator.rb +124 -0
  22. data/lib/generators/templet/scaffold/USAGE +22 -0
  23. data/lib/generators/templet/scaffold/scaffold_generator.rb +75 -0
  24. data/lib/generators/templet/shared/actions_option.rb +24 -0
  25. data/lib/generators/templet/shared/add_routes_option.rb +19 -0
  26. data/lib/generators/templet/shared/child_option.rb +23 -0
  27. data/lib/generators/templet/shared/comment_tests_option.rb +19 -0
  28. data/lib/generators/templet/shared/core_helpers.rb +48 -0
  29. data/lib/generators/templet/shared/grand_parent_option.rb +20 -0
  30. data/lib/generators/templet/shared/model_fields.rb +55 -0
  31. data/lib/generators/templet/shared/model_option.rb +25 -0
  32. data/lib/generators/templet/shared/parent_option.rb +20 -0
  33. data/lib/generators/templet/templates/controller.rb.erb +108 -0
  34. data/lib/generators/templet/templates/core/app/base_viewer.rb +7 -0
  35. data/lib/generators/templet/templates/core/app/link_sets/navbar.rb +12 -0
  36. data/lib/generators/templet/templates/core/app/panel/flash_messages.rb +33 -0
  37. data/lib/generators/templet/templates/core/app/panel/layout_base.rb +40 -0
  38. data/lib/generators/templet/templates/core/app/panel/layout_header.rb +22 -0
  39. data/lib/generators/templet/templates/core/app/panel/layout_header_sidebar.rb +18 -0
  40. data/lib/generators/templet/templates/core/app/panel/nav.rb +55 -0
  41. data/lib/generators/templet/templates/core/app/panel/nav_args_option.rb +30 -0
  42. data/lib/generators/templet/templates/core/app/panel/options_config.rb +19 -0
  43. data/lib/generators/templet/templates/core/app/panel/show_parents_option.rb +22 -0
  44. data/lib/generators/templet/templates/core/app/panel/sidebar_links_option.rb +24 -0
  45. data/lib/generators/templet/templates/core/controllers/.keep +0 -0
  46. data/lib/generators/templet/templates/core/controllers/json_rendering_helpers.rb +12 -0
  47. data/lib/generators/templet/templates/core/controllers/rendering_helpers.rb +53 -0
  48. data/lib/generators/templet/templates/core/controllers/viewer_call_string.rb +144 -0
  49. data/lib/generators/templet/templates/core/controllers/viewer_call_string_class.rb +65 -0
  50. data/lib/generators/templet/templates/core/controllers/viewer_responders.rb +121 -0
  51. data/lib/generators/templet/templates/core/helpers/app.rb +4 -0
  52. data/lib/generators/templet/templates/core/helpers/templet_helper.rb +10 -0
  53. data/lib/generators/templet/templates/core/spec/support/apis/api_helper.rb +13 -0
  54. data/lib/generators/templet/templates/core/spec/support/apis/shared_examples_a_json_controller.rb +196 -0
  55. data/lib/generators/templet/templates/core/spec/support/core/model_parent_helpers.rb +36 -0
  56. data/lib/generators/templet/templates/core/spec/support/core/rest_link_procs_assignments.rb +43 -0
  57. data/lib/generators/templet/templates/core/spec/support/core/rest_link_procs_helpers.rb +15 -0
  58. data/lib/generators/templet/templates/core/spec/support/viewer/partial_test_helpers.rb +32 -0
  59. data/lib/generators/templet/templates/core/spec/support/viewer/shared_examples_a_viewer.rb +105 -0
  60. data/lib/generators/templet/templates/core/spec/templet/forms/bs_form_errors_spec.rb +18 -0
  61. data/lib/generators/templet/templates/core/spec/templet/forms/bs_form_spec.rb +58 -0
  62. data/lib/generators/templet/templates/core/spec/templet/layout/html_rails_spec.rb +64 -0
  63. data/lib/generators/templet/templates/core/spec/templet/links/bs_link_set_collection_spec.rb +79 -0
  64. data/lib/generators/templet/templates/core/spec/templet/links/rest_link_procs_params_spec.rb +68 -0
  65. data/lib/generators/templet/templates/core/spec/templet/links/rest_link_procs_parents_spec.rb +78 -0
  66. data/lib/generators/templet/templates/core/spec/templet/links/rest_link_procs_spec.rb +140 -0
  67. data/lib/generators/templet/templates/core/templet/constants.rb +54 -0
  68. data/lib/generators/templet/templates/core/templet/forms/bs_form.rb +73 -0
  69. data/lib/generators/templet/templates/core/templet/forms/bs_form_errors.rb +38 -0
  70. data/lib/generators/templet/templates/core/templet/forms/bs_form_field.rb +114 -0
  71. data/lib/generators/templet/templates/core/templet/forms/bs_form_group.rb +115 -0
  72. data/lib/generators/templet/templates/core/templet/layouts/html_rails.rb +36 -0
  73. data/lib/generators/templet/templates/core/templet/links.rb +28 -0
  74. data/lib/generators/templet/templates/core/templet/links/bs_btn_class.rb +61 -0
  75. data/lib/generators/templet/templates/core/templet/links/bs_link_set_base.rb +168 -0
  76. data/lib/generators/templet/templates/core/templet/links/bs_link_set_collection.rb +21 -0
  77. data/lib/generators/templet/templates/core/templet/links/bs_link_set_navigation.rb +62 -0
  78. data/lib/generators/templet/templates/core/templet/links/rest_link_procs.rb +163 -0
  79. data/lib/generators/templet/templates/core/templet/links/rest_link_procs_parent.rb +39 -0
  80. data/lib/generators/templet/templates/core/templet/links/rest_link_procs_sets.rb +30 -0
  81. data/lib/generators/templet/templates/core/templet/links/rest_link_text.rb +102 -0
  82. data/lib/generators/templet/templates/core/templet/links/rest_path.rb +90 -0
  83. data/lib/generators/templet/templates/core/templet/mixins.rb +9 -0
  84. data/lib/generators/templet/templates/core/templet/mixins/bs.rb +11 -0
  85. data/lib/generators/templet/templates/core/templet/mixins/bs/grid.rb +53 -0
  86. data/lib/generators/templet/templates/core/templet/mixins/bs/lists.rb +77 -0
  87. data/lib/generators/templet/templates/core/templet/mixins/field_procs.rb +140 -0
  88. data/lib/generators/templet/templates/core/templet/mixins/html_presenters.rb +82 -0
  89. data/lib/generators/templet/templates/core/templet/require_all.rb +45 -0
  90. data/lib/generators/templet/templates/core/templet/utils/html_search_form.rb +53 -0
  91. data/lib/generators/templet/templates/core/templet/utils/link_set_factory.rb +46 -0
  92. data/lib/generators/templet/templates/core/templet/utils/link_set_factory_wrapper.rb +53 -0
  93. data/lib/generators/templet/templates/core/templet/utils/list_model_parents.rb +27 -0
  94. data/lib/generators/templet/templates/core/templet/utils/navbar_form.rb +26 -0
  95. data/lib/generators/templet/templates/core/templet/utils/selected_wrapper.rb +40 -0
  96. data/lib/generators/templet/templates/core/templet/viewer.rb +11 -0
  97. data/lib/generators/templet/templates/core/templet/viewer/meta_model.rb +66 -0
  98. data/lib/generators/templet/templates/core/templet/viewer/meta_model_defaults.rb +56 -0
  99. data/lib/generators/templet/templates/core/templet/viewer/presenters.rb +44 -0
  100. data/lib/generators/templet/templates/core/templet/viewer/rest_actions.rb +24 -0
  101. data/lib/generators/templet/templates/core/templet/viewer_base.rb +111 -0
  102. data/lib/generators/templet/templates/core/templet/viewer_rest.rb +144 -0
  103. data/lib/generators/templet/viewer/USAGE +10 -0
  104. data/lib/generators/templet/viewer/viewer_generator.rb +86 -0
  105. data/lib/templet_rails.rb +5 -0
  106. data/lib/templet_rails/version.rb +3 -0
  107. data/templet_rails.gemspec +36 -0
  108. metadata +178 -0
@@ -0,0 +1,20 @@
1
+
2
+ module Shared
3
+ module GrandParentOption
4
+ def self.included(base)
5
+ desc = "The parent's dependent - the record type the parent belongs to"
6
+
7
+ base.class_eval do
8
+ class_option 'grand-parent', type: :string, aliases: "-g",
9
+ banner: 'singular name',
10
+ default: '', desc: desc
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def grand_parent
17
+ options['grand-parent'].present? ? options['grand-parent'] : nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,55 @@
1
+
2
+ module Shared
3
+ module ModelFields
4
+ private
5
+
6
+ def model_fields(model_name)
7
+ if klass = model_class(model_name)
8
+ klass.column_names.reject do |name|
9
+ %w(id created_at updated_at).include? name
10
+ end
11
+ else
12
+ []
13
+ end
14
+ end
15
+
16
+ def textual_field_with_tag(model_name)
17
+ name, type = field_with_type(model_name, %i(string text))
18
+
19
+ return name, (type == :text ? 'textarea' : 'input')
20
+ end
21
+
22
+ #
23
+
24
+ def field_with_type(model_name, types)
25
+ names_to_types = model_types(model_fields model_name)
26
+
27
+ types.each do |wanted_type|
28
+ names_to_types.each do |(name, type)|
29
+ return name, type if type == wanted_type
30
+ end
31
+ end
32
+ nil
33
+ end
34
+
35
+ def model_types(model_fields)
36
+ model_fields.map do |name|
37
+ type = model_field_type(model_name, name)
38
+
39
+ [ name.to_sym, type.to_sym ]
40
+ end
41
+ end
42
+
43
+ def model_field_type(model_name, field_name)
44
+ if klass = model_class(model_name)
45
+ column = klass.columns.detect {|column| column.name == field_name.to_s }
46
+
47
+ column&.type
48
+ end
49
+ end
50
+
51
+ def model_class(name)
52
+ name.classify.constantize rescue nil
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Shared
3
+ # Passed as model, but becomes model_name
4
+ module ModelOption
5
+ def self.included(base)
6
+ desc = "The model to use inside the controller (instance variable and class)"
7
+
8
+ base.class_eval do
9
+ class_option :model, type: :string, aliases: "-m",
10
+ banner: 'singular name',
11
+ default: '', desc: desc
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def model_name
18
+ model_name? ? options['model'] : singular_name
19
+ end
20
+
21
+ def model_name?
22
+ options['model'].present?
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module Shared
3
+ module ParentOption
4
+ def self.included(base)
5
+ desc = "The model's dependent - the record type the model belongs_to"
6
+
7
+ base.class_eval do
8
+ class_option :parent, type: :string, aliases: "-p",
9
+ banner: 'singular name',
10
+ default: '', desc: desc
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def parent
17
+ options['parent'].present? ? options['parent'] : nil
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,108 @@
1
+
2
+ class <%= class_name.pluralize %>Controller < ApplicationController
3
+ include Templet::ViewerResponders
4
+ <%= before_action parent -%>
5
+ <%= before_action model_name, set_model_actions if set_model? -%>
6
+
7
+ <% if include_action? :index -%>
8
+ # GET /<%= path_controller %>
9
+ # GET /<%= path_controller %>.json
10
+ def index
11
+ @<%= model_plural %> = <%= receiver %>.all
12
+
13
+ respond_to_index
14
+ end
15
+
16
+ <% end -%>
17
+ <% if include_action? :show -%>
18
+ # GET /<%= path_controller '1' %>
19
+ # GET /<%= path_controller '1' %>.json
20
+ def show
21
+ respond_to_show
22
+ end
23
+
24
+ <% end -%>
25
+ <% if include_action? :new -%>
26
+ # GET /<%= path_controller 'new' %>
27
+ def new
28
+ @<%= model_name %> = <%= receiver %>.new
29
+
30
+ respond_to_new
31
+ end
32
+
33
+ <% end -%>
34
+ <% if include_action? :edit -%>
35
+ # GET /<%= path_controller %w(1 edit) %>
36
+ def edit
37
+ respond_to_edit
38
+ end
39
+
40
+ <% end -%>
41
+ <% if include_action? :create -%>
42
+ # POST /<%= path_controller '1' %>
43
+ # POST /<%= path_controller '1' %>.json
44
+ def create
45
+ @<%= model_name %> = <%= receiver %>.new(<%= model_name %>_params)
46
+
47
+ if @<%= model_name %>.save
48
+ respond_to_save_success(@<%= model_name %>, <%= redirect_path %>)
49
+ else
50
+ respond_to_save_failure(:new, @<%= model_name %>)
51
+ end
52
+ end
53
+
54
+ <% end -%>
55
+ <% if include_action? :update -%>
56
+ # PATCH/PUT /<%= path_controller '1' %>
57
+ # PATCH/PUT /<%= path_controller '1' %>.json
58
+ def update
59
+ if @<%= model_name %>.update(<%= model_name %>_params)
60
+ respond_to_save_success(@<%= model_name %>, <%= redirect_path %>)
61
+ else
62
+ respond_to_save_failure(:edit, @<%= model_name %>)
63
+ end
64
+ end
65
+
66
+ <% end -%>
67
+ <% if include_action?(:delete) or include_action?(:destroy) -%>
68
+ # DELETE /<%= path_controller '1' %>
69
+ # DELETE /<%= path_controller '1' %>.json
70
+ def destroy
71
+ @<%= model_name %>.destroy
72
+
73
+ respond_to_destroy(@<%= model_name %>, <%= redirect_path(false) %>)
74
+ end
75
+
76
+ <% end -%>
77
+ private
78
+ <% if parent -%>
79
+
80
+ def set_<%= parent %>
81
+ @<%= parent %> = <%= parent.classify %>.find(params[:<%= parent %>_id])
82
+ end
83
+ <% end -%>
84
+ <% if set_model? -%>
85
+
86
+ def set_<%= model_name %>
87
+ @<%= model_name %> = <%= receiver %>.find(params[:id])
88
+ end
89
+
90
+ def <%= model_name %>_params
91
+ params.require(:<%= model_name %>).permit(*<%= model_name %>_fields)
92
+ end
93
+
94
+ def <%= model_name %>_fields
95
+ %i(<%= model_fields(model_name).join ' ' %>)
96
+ end
97
+ <% end -%>
98
+ <% if model_name? -%>
99
+
100
+ def model_name
101
+ :<%= model_name %>
102
+ end
103
+ <% end -%>
104
+
105
+ def viewer_options
106
+ super.merge({ <%= to_option :parent, parent %><%= to_option :grand_parent, grand_parent, ', ' %> })
107
+ end
108
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module App
3
+ class BaseViewer < Templet::ViewerRest
4
+ include Panel::OptionsConfig
5
+ end
6
+ end
7
+
@@ -0,0 +1,12 @@
1
+
2
+ module App
3
+ module LinkSets
4
+ class Navbar < Templet::Links::BsLinkSetCollection
5
+ def call(action=nil)
6
+ super.tap do |links|
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,33 @@
1
+
2
+ module App
3
+ module Panel
4
+ # Shows flash messages in a Bootstrap alert - inside a Bootstrap grid
5
+ class FlashMessages < Templet::Component::Partial
6
+ include Templet::Mixins::Bs::Grid
7
+
8
+ BUTTON_ATTS = { class: "close",
9
+ data_dismiss: "alert",
10
+ aria_hidden: "true" }
11
+
12
+ def call(**column_opts)
13
+ super() do
14
+ if flash.any?
15
+ in_rows renderer, **column_opts do
16
+ flash.map do |name, message|
17
+ if message.is_a?(String)
18
+ alert_name = name.to_s == 'notice' ? 'success' : 'danger'
19
+
20
+ div "alert alert-dismissible alert-#{alert_name}" do
21
+ [ button('&times;', BUTTON_ATTS),
22
+ div(message, id: "flash_#{name}") ]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,40 @@
1
+
2
+ module App
3
+ module Panel
4
+ # Renders a navbar, flash messages and yielded content in Bootstrap grid
5
+ class LayoutBase < Templet::Component::Partial
6
+ include Templet::Mixins::Bs::Grid
7
+
8
+ def call(action, **options)
9
+ super() do
10
+ js_target_div :outer,
11
+ navbar(*options[:nav_args]),
12
+ messages,
13
+ in_rows(renderer, yield(renderer), **bs_column_opts)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ # Adds a surrounding div tag, whose content is replaced in JS requests
20
+ def js_target_div(suffix, *content)
21
+ renderer.call do
22
+ div(id: "panel-#{suffix}") { content }
23
+ end
24
+ end
25
+
26
+ def bs_column_opts
27
+ { cols: 10, offset: 1 }
28
+ end
29
+
30
+ def messages
31
+ FlashMessages.new(renderer).(**bs_column_opts)
32
+ end
33
+
34
+ def navbar(*args)
35
+ Nav.new(renderer).(*args)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,22 @@
1
+
2
+ module App
3
+ module Panel
4
+ # Renders a heading with a title, subtitle and perhaps something on right
5
+ class LayoutHeader < LayoutBase
6
+ def call(action, **options)
7
+ args = options.values_at :title, :subtitle, :header_right
8
+
9
+ super { [ header(*args), yield(renderer) ] }
10
+ end
11
+
12
+ def header(title, subtitle, on_right)
13
+ renderer.call do
14
+ div :page_header do
15
+ [ div(on_right, :pull_right), h1([title, small(subtitle)]) ]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,18 @@
1
+
2
+ module App
3
+ module Panel
4
+ # Renders a given sidebar
5
+ class LayoutHeaderSidebar < LayoutHeader
6
+ def call(action, **options)
7
+ side_cols = options[:sidebar_cols] || 2
8
+ main_cols = 12 - side_cols
9
+
10
+ super do
11
+ in_cols renderer, side_cols => options[:sidebar_content],
12
+ main_cols => js_target_div(:inner, *yield(renderer))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,55 @@
1
+
2
+ module App
3
+ module Panel
4
+ # Renders a Bootstrap navbar, with a title and some links on right
5
+ class Nav < Templet::Component::Partial
6
+ NAVBAR_CLASS = "navbar navbar-default"
7
+ BUTTON_ID = "bs-navbar-collapse-1"
8
+
9
+ def call(title, links, before: nil, after: nil)
10
+ super() do
11
+ nav role: "navigation", class: NAVBAR_CLASS do
12
+ div "container-fluid" do
13
+ [ nav_header(title),
14
+ before,
15
+ nav_collapse(links),
16
+ after ]
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def nav_header(title)
25
+ brand_atts = { class: 'navbar-brand', style: 'font-size: large' }
26
+
27
+ renderer.call do
28
+ div "navbar-header page-scroll" do
29
+ [ button(button_spans, button_atts),
30
+ link_to(title, root_path, brand_atts) ]
31
+ end
32
+ end
33
+ end
34
+ def button_spans
35
+ "<span class='sr-only'>Toggle navigation</span>\n" +
36
+ "<span class='icon-bar'></span>\n" * 3
37
+ end
38
+ def button_atts
39
+ { type: 'button', class: "navbar-toggle",
40
+ data_toggle: "collapse", data_target: "##{BUTTON_ID}" }
41
+ end
42
+
43
+ def nav_collapse(links)
44
+ if links
45
+ renderer.call do
46
+ div "collapse navbar-collapse", id: BUTTON_ID do
47
+ ul links, "nav navbar-nav navbar-right"
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,30 @@
1
+
2
+ module App
3
+ module Panel
4
+ module NavArgsOption
5
+ private
6
+
7
+ def panel_options(renderer=nil, **options)
8
+ super renderer, options.merge(nav_args: nav_args(renderer))
9
+ end
10
+
11
+ def nav_args(renderer)
12
+ return page_title, navbar_links(renderer)
13
+ end
14
+
15
+ def navbar_links(renderer)
16
+ Templet::Utils::LinkSetFactory
17
+ .new(renderer, action, navbar_links_class, navbar_links_options)
18
+ end
19
+
20
+ def navbar_links_class
21
+ App::LinkSets::Navbar
22
+ end
23
+
24
+ def navbar_links_options
25
+ { html_class: '', remote: nil, wrapper: :li }
26
+ end
27
+ end
28
+ end
29
+ end
30
+