compony 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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