compony 0.3.0 → 0.3.2

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +10 -0
  4. data/VERSION +1 -1
  5. data/compony.gemspec +3 -3
  6. data/doc/ComponentGenerator.html +1 -1
  7. data/doc/Components.html +1 -1
  8. data/doc/ComponentsGenerator.html +1 -1
  9. data/doc/Compony/Component.html +244 -56
  10. data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
  11. data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
  12. data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +1 -1
  13. data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +1 -1
  14. data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
  15. data/doc/Compony/ComponentMixins/Default.html +1 -1
  16. data/doc/Compony/ComponentMixins/Resourceful.html +1 -1
  17. data/doc/Compony/ComponentMixins.html +1 -1
  18. data/doc/Compony/Components/Button.html +2 -2
  19. data/doc/Compony/Components/Destroy.html +14 -14
  20. data/doc/Compony/Components/Edit.html +18 -18
  21. data/doc/Compony/Components/Form.html +86 -86
  22. data/doc/Compony/Components/New.html +14 -14
  23. data/doc/Compony/Components/WithForm.html +2 -2
  24. data/doc/Compony/Components.html +1 -1
  25. data/doc/Compony/ControllerMixin.html +1 -1
  26. data/doc/Compony/Engine.html +1 -1
  27. data/doc/Compony/MethodAccessibleHash.html +1 -1
  28. data/doc/Compony/ModelFields/Anchormodel.html +1 -1
  29. data/doc/Compony/ModelFields/Association.html +1 -1
  30. data/doc/Compony/ModelFields/Attachment.html +1 -1
  31. data/doc/Compony/ModelFields/Base.html +1 -1
  32. data/doc/Compony/ModelFields/Boolean.html +1 -1
  33. data/doc/Compony/ModelFields/Color.html +1 -1
  34. data/doc/Compony/ModelFields/Currency.html +1 -1
  35. data/doc/Compony/ModelFields/Date.html +1 -1
  36. data/doc/Compony/ModelFields/Datetime.html +1 -1
  37. data/doc/Compony/ModelFields/Decimal.html +1 -1
  38. data/doc/Compony/ModelFields/Email.html +1 -1
  39. data/doc/Compony/ModelFields/Float.html +1 -1
  40. data/doc/Compony/ModelFields/Integer.html +1 -1
  41. data/doc/Compony/ModelFields/Percentage.html +1 -1
  42. data/doc/Compony/ModelFields/Phone.html +1 -1
  43. data/doc/Compony/ModelFields/RichText.html +1 -1
  44. data/doc/Compony/ModelFields/String.html +1 -1
  45. data/doc/Compony/ModelFields/Text.html +1 -1
  46. data/doc/Compony/ModelFields/Time.html +1 -1
  47. data/doc/Compony/ModelFields/Url.html +1 -1
  48. data/doc/Compony/ModelFields.html +1 -1
  49. data/doc/Compony/ModelMixin.html +1 -1
  50. data/doc/Compony/NaturalOrdering.html +14 -6
  51. data/doc/Compony/RequestContext.html +16 -4
  52. data/doc/Compony/Version.html +1 -1
  53. data/doc/Compony/ViewHelpers.html +1 -1
  54. data/doc/Compony.html +1 -1
  55. data/doc/ComponyController.html +1 -1
  56. data/doc/_index.html +1 -1
  57. data/doc/file.README.html +10 -1
  58. data/doc/index.html +10 -1
  59. data/doc/method_list.html +16 -0
  60. data/doc/top-level-namespace.html +1 -1
  61. data/lib/compony/component.rb +25 -2
  62. data/lib/compony/components/destroy.rb +9 -1
  63. data/lib/compony/components/edit.rb +4 -0
  64. data/lib/compony/components/form.rb +16 -5
  65. data/lib/compony/components/new.rb +1 -0
  66. data/lib/compony/natural_ordering.rb +6 -2
  67. data/lib/compony/request_context.rb +8 -2
  68. metadata +2 -2
data/doc/file.README.html CHANGED
@@ -555,6 +555,15 @@
555
555
  <pre class="code ruby"><code class="ruby">&lt;div class=&quot;card card-body&quot;&gt;&lt;h1&gt;Hello&lt;/h1&gt;&lt;p&gt;Welcome to my site.&lt;/p&gt;&lt;/div&gt;
556
556
  </code></pre>
557
557
 
558
+ <h5 id="label-Removing+content+blocks">Removing content blocks</h5>
559
+
560
+ <p>If a component’s parent class defines a content block that is undesired in a subclass component, the content block can be removed as follows:</p>
561
+
562
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
563
+ <span class='id identifier rubyid_remove_content'>remove_content</span> <span class='symbol'>:some_content_defined_in_parent</span> <span class='comment'># This component will now behave as if this content block was never declared in its parent.
564
+ </span><span class='kw'>end</span>
565
+ </code></pre>
566
+
558
567
  <h4 id="label-Redirecting+away+-2F+Intercepting+rendering">Redirecting away / Intercepting rendering</h4>
559
568
 
560
569
  <p>Immediately before the <code>content</code> block(s) are evaluated, another chain of blocks is evaluated if present: <code>before_render</code>. If on of these blocks creates a reponse body in the Rails controller, the subsequent <code>before_render</code> blocks and all <code>content</code> blocks are skipped.</p>
@@ -1612,7 +1621,7 @@ my_button = Compony.button(:index, :users, enabled: -&gt; { |controller| control
1612
1621
  </div></div>
1613
1622
 
1614
1623
  <div id="footer">
1615
- Generated on Wed May 29 15:53:00 2024 by
1624
+ Generated on Sat Jun 1 14:22:42 2024 by
1616
1625
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
1617
1626
  0.9.34 (ruby-3.2.2).
1618
1627
  </div>
data/doc/index.html CHANGED
@@ -555,6 +555,15 @@
555
555
  <pre class="code ruby"><code class="ruby">&lt;div class=&quot;card card-body&quot;&gt;&lt;h1&gt;Hello&lt;/h1&gt;&lt;p&gt;Welcome to my site.&lt;/p&gt;&lt;/div&gt;
556
556
  </code></pre>
557
557
 
558
+ <h5 id="label-Removing+content+blocks">Removing content blocks</h5>
559
+
560
+ <p>If a component’s parent class defines a content block that is undesired in a subclass component, the content block can be removed as follows:</p>
561
+
562
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
563
+ <span class='id identifier rubyid_remove_content'>remove_content</span> <span class='symbol'>:some_content_defined_in_parent</span> <span class='comment'># This component will now behave as if this content block was never declared in its parent.
564
+ </span><span class='kw'>end</span>
565
+ </code></pre>
566
+
558
567
  <h4 id="label-Redirecting+away+-2F+Intercepting+rendering">Redirecting away / Intercepting rendering</h4>
559
568
 
560
569
  <p>Immediately before the <code>content</code> block(s) are evaluated, another chain of blocks is evaluated if present: <code>before_render</code>. If on of these blocks creates a reponse body in the Rails controller, the subsequent <code>before_render</code> blocks and all <code>content</code> blocks are skipped.</p>
@@ -1612,7 +1621,7 @@ my_button = Compony.button(:index, :users, enabled: -&gt; { |controller| control
1612
1621
  </div></div>
1613
1622
 
1614
1623
  <div id="footer">
1615
- Generated on Wed May 29 15:52:59 2024 by
1624
+ Generated on Sat Jun 1 14:22:41 2024 by
1616
1625
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
1617
1626
  0.9.34 (ruby-3.2.2).
1618
1627
  </div>
data/doc/method_list.html CHANGED
@@ -932,6 +932,22 @@
932
932
  </li>
933
933
 
934
934
 
935
+ <li class="even ">
936
+ <div class="item">
937
+ <span class='object_link'><a href="Compony/Component.html#remove_content-instance_method" title="Compony::Component#remove_content (method)">#remove_content</a></span>
938
+ <small>Compony::Component</small>
939
+ </div>
940
+ </li>
941
+
942
+
943
+ <li class="odd ">
944
+ <div class="item">
945
+ <span class='object_link'><a href="Compony/Component.html#remove_content!-instance_method" title="Compony::Component#remove_content! (method)">#remove_content!</a></span>
946
+ <small>Compony::Component</small>
947
+ </div>
948
+ </li>
949
+
950
+
935
951
  <li class="even ">
936
952
  <div class="item">
937
953
  <span class='object_link'><a href="Compony/Component.html#render-instance_method" title="Compony::Component#render (method)">#render</a></span>
@@ -102,7 +102,7 @@
102
102
  </div>
103
103
 
104
104
  <div id="footer">
105
- Generated on Wed May 29 15:53:00 2024 by
105
+ Generated on Sat Jun 1 14:22:42 2024 by
106
106
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
107
107
  0.9.34 (ruby-3.2.2).
108
108
  </div>
@@ -130,8 +130,31 @@ module Compony
130
130
  # @param [Hash] kwargs If hidden is true, the content will not be rendered by default, allowing you to nest it in another content block.
131
131
  # @param [Proc] block The block that should be run as part of the content pipeline. Will run in the component's context. You can use Dyny here.
132
132
  def content(name = :main, before: nil, **kwargs, &block)
133
- fail("`content` expects a block in #{inspect}.") unless block_given?
134
- @content_blocks.natural_push(name, block, before:, **kwargs)
133
+ # A block is required here, but if this is an override (e.g. to hide another content block), we can tolerate the missing block.
134
+ if !block_given? && @content_blocks.find { |b| b.name == name }.nil?
135
+ fail("`content` expects a block in #{inspect}.")
136
+ end
137
+ @content_blocks.natural_push(name, block || :missing, before:, **kwargs)
138
+ end
139
+
140
+ # DSL method
141
+ # Removes a content block. Use this in subclasses if a content block defined in the parent should be removed from the child.
142
+ # @param [Symbol,String] name Name of the content block that should be removed
143
+ def remove_content(name)
144
+ existing_index = @content_blocks.find_index { |el| el.name == name.to_sym }
145
+ if existing_index.nil?
146
+ return false
147
+ else
148
+ @content_blocks.delete_at(existing_index)
149
+ return true
150
+ end
151
+ end
152
+
153
+ # DSL method
154
+ # Removes a content block and fails if the content block was not found.
155
+ # @param [Symbol,String] name Name of the content block that should be removed
156
+ def remove_content!(name)
157
+ remove_content(name) || fail("Content block #{name.inspect} not found for removal in #{inspect}.")
135
158
  end
136
159
 
137
160
  # Renders the component using the controller passsed to it and returns it as a string.
@@ -26,8 +26,11 @@ module Compony
26
26
  icon { :trash }
27
27
  color { :danger }
28
28
 
29
- content do
29
+ content :confirm_question, hidden: true do
30
30
  div I18n.t('compony.components.destroy.confirm_question', data_label: @data.label)
31
+ end
32
+
33
+ content :confirm_button, hidden: true do
31
34
  div do
32
35
  concat compony_button(comp_cst,
33
36
  @data,
@@ -36,6 +39,11 @@ module Compony
36
39
  end
37
40
  end
38
41
 
42
+ content do
43
+ content :confirm_question
44
+ content :confirm_button
45
+ end
46
+
39
47
  action :back_to_owner do
40
48
  next if data_class.owner_model_attr.blank?
41
49
  Compony.button(:show, @data.send(data_class.owner_model_attr), icon: :xmark, color: :secondary, label: I18n.t('compony.cancel'))
@@ -35,6 +35,10 @@ module Compony
35
35
  Compony.button(:show, @data.send(data_class.owner_model_attr), icon: :xmark, color: :secondary, label: I18n.t('compony.cancel'))
36
36
  end
37
37
 
38
+ content :label do
39
+ h2 component.label
40
+ end
41
+
38
42
  content do
39
43
  concat form_comp.render(controller, data: @data)
40
44
  end
@@ -13,19 +13,30 @@ module Compony
13
13
  # Make sure the error message is going to be nice if form_fields were not implemented
14
14
  fail "#{component.inspect} requires config.form_fields do ..." if @form_fields.nil?
15
15
 
16
- # Must render the buttons now as the rendering within simple form breaks the form
17
- @submit_button = Compony.button_component_class.new(
18
- label: @submit_label || I18n.t('compony.components.form.submit'), icon: 'arrow-right', type: :submit
19
- ).render(controller)
16
+ # Calculate paths
20
17
  @submit_path = @comp_opts[:submit_path]
21
18
  @submit_path = @submit_path.call(controller) if @submit_path.respond_to?(:call)
22
19
  end
23
20
 
21
+ # Override this to provide a custom submit button
22
+ content :submit_button, hidden: true do
23
+ concat Compony.button_component_class.new(
24
+ label: @submit_label || I18n.t('compony.components.form.submit'), icon: 'arrow-right', type: :submit
25
+ ).render(controller)
26
+ end
27
+
28
+ # Override this to provide additional submit buttons.
29
+ content :buttons, hidden: true do
30
+ content(:submit_button)
31
+ end
32
+
24
33
  content do
25
34
  form_html = simple_form_for(data, method: @comp_opts[:submit_verb], url: @submit_path) do |f|
26
35
  component.with_simpleform(f) do
27
36
  instance_exec(&form_fields)
28
- div @submit_button, class: 'compony-form-buttons'
37
+ div class: 'compony-form-buttons' do
38
+ content(:buttons)
39
+ end
29
40
  end
30
41
  end
31
42
  concat form_html
@@ -35,6 +35,7 @@ module Compony
35
35
  content :label do
36
36
  h2 component.label
37
37
  end
38
+
38
39
  content do
39
40
  concat form_comp.render(controller, data: @data)
40
41
  end
@@ -15,21 +15,25 @@ module Compony
15
15
  # collection.map(&:payload) # --> a_new_payload, b_payload, c_payload, d_payload
16
16
  # ```
17
17
  class NaturalOrdering < Array
18
- def natural_push(name, payload, before: nil, **kwargs)
18
+ def natural_push(name, payload = :missing, before: nil, **kwargs)
19
19
  name = name.to_sym
20
20
  before_name = before&.to_sym
21
21
  old_kwargs = {}
22
+ old_payload = nil
22
23
 
23
24
  # Fetch existing element if any
24
25
  existing_index = find_index { |el| el.name == name }
25
26
  if existing_index.present?
26
27
  # Copy all non-mentionned kwargs from the element we are about to overwrite
27
28
  old_kwargs = self[existing_index].except(:name, :payload)
29
+ old_payload = self[existing_index].payload
28
30
 
29
31
  # Replacing an existing element with a before: directive - must delete before calculating indices
30
32
  if before_name.present?
31
33
  delete_at(existing_index)
32
34
  end
35
+ elsif payload == :missing
36
+ fail("Cannot insert new element #{name} without a payload (payload can only omitted if overriding another element) in #{inspect}.")
33
37
  end
34
38
 
35
39
  # Fetch before element
@@ -38,7 +42,7 @@ module Compony
38
42
  end
39
43
 
40
44
  # Create the element to insert
41
- element = MethodAccessibleHash.new(name:, payload:, **old_kwargs.merge(kwargs))
45
+ element = MethodAccessibleHash.new(name:, payload: payload == :missing ? old_payload : payload, **old_kwargs.merge(kwargs))
42
46
 
43
47
  # Insert new element
44
48
  if before_index.present?
@@ -46,8 +46,14 @@ module Compony
46
46
  def content(name)
47
47
  name = name.to_sym
48
48
  content_block = component.content_blocks.find { |el| el.name == name } || fail("Content block #{name.inspect} not found in #{component.inspect}.")
49
- # A fresh RequestContext is needed due to Rails' buffer
50
- concat Compony::RequestContext.new(component, controller, helpers:, locals: local_assigns).evaluate(&content_block.payload)
49
+ # We have to clear Rails' output_buffer to prevent double rendering of blocks. To achieve this, a fresh render context is instanciated.
50
+ concat controller.render_to_string(
51
+ type: :dyny,
52
+ locals: { render_component: component, render_controller: controller, render_locals: local_assigns, render_block: content_block },
53
+ inline: <<~RUBY
54
+ Compony::RequestContext.new(render_component, render_controller, helpers: self, locals: local_assigns).evaluate_with_backfire(&render_block.payload)
55
+ RUBY
56
+ )
51
57
  end
52
58
  end
53
59
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Kalbermatter
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-05-29 00:00:00.000000000 Z
12
+ date: 2024-06-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yard