compony 0.2.3 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +80 -13
- data/VERSION +1 -1
- data/compony.gemspec +4 -4
- data/doc/ComponentGenerator.html +1 -1
- data/doc/Components.html +1 -1
- data/doc/ComponentsGenerator.html +1 -1
- data/doc/Compony/Component.html +308 -341
- data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
- data/doc/Compony/ComponentMixins/Default.html +1 -1
- data/doc/Compony/ComponentMixins/Resourceful.html +1 -1
- data/doc/Compony/ComponentMixins.html +1 -1
- data/doc/Compony/Components/Button.html +3 -3
- data/doc/Compony/Components/Destroy.html +3 -3
- data/doc/Compony/Components/Edit.html +19 -19
- data/doc/Compony/Components/Form.html +3 -3
- data/doc/Compony/Components/New.html +19 -19
- data/doc/Compony/Components/WithForm.html +4 -4
- data/doc/Compony/Components.html +1 -1
- data/doc/Compony/ControllerMixin.html +1 -1
- data/doc/Compony/Engine.html +1 -1
- data/doc/Compony/MethodAccessibleHash.html +1 -1
- data/doc/Compony/ModelFields/Anchormodel.html +1 -1
- data/doc/Compony/ModelFields/Association.html +1 -1
- data/doc/Compony/ModelFields/Attachment.html +1 -1
- data/doc/Compony/ModelFields/Base.html +1 -1
- data/doc/Compony/ModelFields/Boolean.html +1 -1
- data/doc/Compony/ModelFields/Color.html +1 -1
- data/doc/Compony/ModelFields/Currency.html +1 -1
- data/doc/Compony/ModelFields/Date.html +1 -1
- data/doc/Compony/ModelFields/Datetime.html +1 -1
- data/doc/Compony/ModelFields/Decimal.html +1 -1
- data/doc/Compony/ModelFields/Email.html +1 -1
- data/doc/Compony/ModelFields/Float.html +1 -1
- data/doc/Compony/ModelFields/Integer.html +1 -1
- data/doc/Compony/ModelFields/Percentage.html +1 -1
- data/doc/Compony/ModelFields/Phone.html +1 -1
- data/doc/Compony/ModelFields/RichText.html +1 -1
- data/doc/Compony/ModelFields/String.html +1 -1
- data/doc/Compony/ModelFields/Text.html +1 -1
- data/doc/Compony/ModelFields/Time.html +1 -1
- data/doc/Compony/ModelFields/Url.html +1 -1
- data/doc/Compony/ModelFields.html +1 -1
- data/doc/Compony/ModelMixin.html +1 -1
- data/doc/Compony/NaturalOrdering.html +292 -0
- data/doc/Compony/RequestContext.html +72 -1
- data/doc/Compony/Version.html +1 -1
- data/doc/Compony/ViewHelpers.html +1 -1
- data/doc/Compony.html +3 -3
- data/doc/ComponyController.html +1 -1
- data/doc/_index.html +8 -1
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +73 -16
- data/doc/index.html +73 -16
- data/doc/method_list.html +100 -100
- data/doc/top-level-namespace.html +1 -1
- data/lib/compony/component.rb +30 -54
- data/lib/compony/components/edit.rb +2 -4
- data/lib/compony/components/new.rb +4 -6
- data/lib/compony/components/with_form.rb +1 -1
- data/lib/compony/natural_ordering.rb +56 -0
- data/lib/compony/request_context.rb +8 -0
- data/lib/compony.rb +1 -0
- metadata +4 -2
@@ -102,7 +102,7 @@
|
|
102
102
|
</div>
|
103
103
|
|
104
104
|
<div id="footer">
|
105
|
-
Generated on
|
105
|
+
Generated on Wed May 29 15:53:00 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>
|
data/lib/compony/component.rb
CHANGED
@@ -7,6 +7,7 @@ module Compony
|
|
7
7
|
|
8
8
|
attr_reader :parent_comp
|
9
9
|
attr_reader :comp_opts
|
10
|
+
attr_reader :content_blocks # needed in RequestContext for nesting
|
10
11
|
|
11
12
|
# root comp: component that is registered to be root of the application.
|
12
13
|
# parent comp: component that is registered to be the parent of this comp. If there is none, this is the root comp.
|
@@ -24,9 +25,9 @@ module Compony
|
|
24
25
|
@sub_comps = []
|
25
26
|
@index = index
|
26
27
|
@comp_opts = comp_opts
|
27
|
-
@
|
28
|
-
@content_blocks =
|
29
|
-
@actions =
|
28
|
+
@before_render_blocks = NaturalOrdering.new
|
29
|
+
@content_blocks = NaturalOrdering.new
|
30
|
+
@actions = NaturalOrdering.new
|
30
31
|
@skipped_actions = Set.new
|
31
32
|
|
32
33
|
init_standalone
|
@@ -111,46 +112,39 @@ module Compony
|
|
111
112
|
comp_cst.to_s.underscore
|
112
113
|
end
|
113
114
|
|
114
|
-
# @todo deprecate (check for usages beforehand)
|
115
|
-
def comp_class_for(...)
|
116
|
-
Compony.comp_class_for(...)
|
117
|
-
end
|
118
|
-
|
119
|
-
# @todo deprecate (check for usages beforehand)
|
120
|
-
def comp_class_for!(...)
|
121
|
-
Compony.comp_class_for!(...)
|
122
|
-
end
|
123
|
-
|
124
115
|
# DSL method
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
#
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
fail("`content` expects a block in #{inspect}.") unless block_given?
|
134
|
-
@content_blocks = [block]
|
116
|
+
# Adds or overrides a before_render block.
|
117
|
+
# You can use controller.redirect_to to redirect away and halt the before_render/content chain
|
118
|
+
# @param [Symbol,String] name The name of the before_render block, defaults to `:main`
|
119
|
+
# @param [nil,Symbol,String] before If nil, the block will be added to the bottom of the before_render chain. Otherwise, pass the name of another block.
|
120
|
+
# @param [Proc] block The block that should be run as part of the before_render pipeline. Will run in the component's context.
|
121
|
+
def before_render(name = :main, before: nil, **kwargs, &block)
|
122
|
+
fail("`before_render` expects a block in #{inspect}.") unless block_given?
|
123
|
+
@before_render_blocks.natural_push(name, block, before:, **kwargs)
|
135
124
|
end
|
136
125
|
|
137
126
|
# DSL method
|
138
|
-
# Adds a content block
|
139
|
-
#
|
140
|
-
#
|
141
|
-
|
127
|
+
# Adds or overrides a content block.
|
128
|
+
# @param [Symbol,String] name The name of the content block, defaults to `:main`
|
129
|
+
# @param [nil,Symbol,String] before If nil, the block will be added to the bottom of the content chain. Otherwise, pass the name of another block.
|
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
|
+
# @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
|
+
def content(name = :main, before: nil, **kwargs, &block)
|
142
133
|
fail("`content` expects a block in #{inspect}.") unless block_given?
|
143
|
-
@content_blocks
|
144
|
-
@content_blocks.insert(index, block)
|
134
|
+
@content_blocks.natural_push(name, block, before:, **kwargs)
|
145
135
|
end
|
146
136
|
|
147
137
|
# Renders the component using the controller passsed to it and returns it as a string.
|
148
138
|
# @param [Boolean] standalone pass true iff `render` is called from `render_standalone`
|
149
139
|
# Do not overwrite.
|
150
140
|
def render(controller, standalone: false, **locals)
|
151
|
-
# Call before_render
|
152
|
-
|
153
|
-
|
141
|
+
# Call before_render hooks (if any) and backfire instance variables back to the component
|
142
|
+
@before_render_blocks.each do |element|
|
143
|
+
RequestContext.new(self, controller, locals:).evaluate_with_backfire(&element.payload)
|
144
|
+
# Stop if a `before_render` block issued a body (e.g. through redirecting)
|
145
|
+
break unless controller.response_body.nil?
|
146
|
+
end
|
147
|
+
|
154
148
|
# Render, unless before_render has already issued a body (e.g. through redirecting).
|
155
149
|
if controller.response_body.nil?
|
156
150
|
fail "#{self.class.inspect} must define `content` or set a response body in `before_render`" if @content_blocks.none?
|
@@ -161,9 +155,9 @@ module Compony
|
|
161
155
|
if Compony.content_before_root_comp_block && standalone
|
162
156
|
Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&Compony.content_before_root_comp_block)
|
163
157
|
end
|
164
|
-
content_blocks.each do |
|
158
|
+
content_blocks.reject{ |el| el.hidden }.each do |element|
|
165
159
|
# Instanciate and evaluate a fresh RequestContext in order to use the buffer allocated by the ActionView (needed for `concat` calls)
|
166
|
-
Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&
|
160
|
+
Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&element.payload)
|
167
161
|
end
|
168
162
|
if Compony.content_after_root_comp_block && standalone
|
169
163
|
Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&Compony.content_after_root_comp_block)
|
@@ -179,25 +173,7 @@ module Compony
|
|
179
173
|
# Adds or replaces an action (for action buttons)
|
180
174
|
# If before: is specified, will insert the action before the named action. When replacing, an element keeps its position unless before: is specified.
|
181
175
|
def action(action_name, before: nil, &block)
|
182
|
-
action_name
|
183
|
-
before_name = before&.to_sym
|
184
|
-
action = MethodAccessibleHash.new(name: action_name, block:)
|
185
|
-
|
186
|
-
existing_index = @actions.find_index { |el| el.name == action_name }
|
187
|
-
if existing_index.present? && before_name.present?
|
188
|
-
@actions.delete_at(existing_index) # Replacing an existing element with a before: directive - must delete before calculating indices
|
189
|
-
end
|
190
|
-
if before_name.present?
|
191
|
-
before_index = @actions.find_index { |el| el.name == before_name } || fail("Action #{before_name} for :before not found in #{inspect}.")
|
192
|
-
end
|
193
|
-
|
194
|
-
if before_index.present?
|
195
|
-
@actions.insert(before_index, action)
|
196
|
-
elsif existing_index.present?
|
197
|
-
@actions[existing_index] = action
|
198
|
-
else
|
199
|
-
@actions << action
|
200
|
-
end
|
176
|
+
@actions.natural_push(action_name, block, before:)
|
201
177
|
end
|
202
178
|
|
203
179
|
# DSL method
|
@@ -213,7 +189,7 @@ module Compony
|
|
213
189
|
button_htmls = @actions.map do |action|
|
214
190
|
next if @skipped_actions.include?(action.name)
|
215
191
|
Compony.with_button_defaults(feasibility_action: action.name.to_sym) do
|
216
|
-
action_button = action.
|
192
|
+
action_button = action.payload.call(controller)
|
217
193
|
next unless action_button
|
218
194
|
button_html = action_button.render(controller)
|
219
195
|
next if button_html.blank?
|
@@ -50,10 +50,8 @@ module Compony
|
|
50
50
|
end
|
51
51
|
hsh? local_form_comp.schema_wrapper_key_for(local_data), &local_form_comp.schema_block_for(local_data)
|
52
52
|
end
|
53
|
-
schema.validate!(controller.request.params)
|
54
|
-
|
55
|
-
# TODO: Why are we not saving the validated params?
|
56
|
-
attrs_to_assign = controller.request.params[form_comp.schema_wrapper_key_for(@data)]
|
53
|
+
validated_params = schema.validate!(controller.request.params)
|
54
|
+
attrs_to_assign = validated_params[form_comp.schema_wrapper_key_for(@data)]
|
57
55
|
@data.assign_attributes(attrs_to_assign) if attrs_to_assign
|
58
56
|
end
|
59
57
|
|
@@ -32,10 +32,10 @@ module Compony
|
|
32
32
|
label(:short) { I18n.t('compony.components.new.label.short') }
|
33
33
|
icon { :plus }
|
34
34
|
|
35
|
-
|
35
|
+
content :label do
|
36
36
|
h2 component.label
|
37
37
|
end
|
38
|
-
|
38
|
+
content do
|
39
39
|
concat form_comp.render(controller, data: @data)
|
40
40
|
end
|
41
41
|
|
@@ -45,10 +45,8 @@ module Compony
|
|
45
45
|
schema = Schemacop::Schema3.new :hash, additional_properties: true do
|
46
46
|
hsh? local_form_comp.schema_wrapper_key_for(local_data), &local_form_comp.schema_block_for(local_data)
|
47
47
|
end
|
48
|
-
schema.validate!(controller.request.params)
|
49
|
-
|
50
|
-
# TODO: Why are we not saving the validated params?
|
51
|
-
attrs_to_assign = controller.request.params[form_comp.schema_wrapper_key_for(@data)]
|
48
|
+
validated_params = schema.validate!(controller.request.params)
|
49
|
+
attrs_to_assign = validated_params[form_comp.schema_wrapper_key_for(@data)]
|
52
50
|
@data.assign_attributes(attrs_to_assign) if attrs_to_assign
|
53
51
|
end
|
54
52
|
|
@@ -13,7 +13,7 @@ module Compony
|
|
13
13
|
# Returns an instance of the form component responsible for rendering the form.
|
14
14
|
# Feel free to override this in subclasses.
|
15
15
|
def form_comp
|
16
|
-
@form_comp ||= (form_comp_class || comp_class_for!(:form, family_cst)).new(
|
16
|
+
@form_comp ||= (form_comp_class || Compony.comp_class_for!(:form, family_cst)).new(
|
17
17
|
self,
|
18
18
|
submit_verb:,
|
19
19
|
# If applicable, Rails adds the route keys automatically, thus, e.g. :id does not need to be passed here, as it comes from the request.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Compony
|
2
|
+
# @api description
|
3
|
+
# This class provides an array-based data structure where elements have symbol names. New elements can be appended or placed at a location using `before:`.
|
4
|
+
# Important: do not mutate this class with any other method call than the natural_-prefixed methods defined below.
|
5
|
+
# Example:<br>
|
6
|
+
# ```ruby
|
7
|
+
# collection = Compony::NaturalOrdering.new
|
8
|
+
# collection.natural_push(:a, a_payload)
|
9
|
+
# collection.natural_push(:c, c_payload)
|
10
|
+
# collection.natural_push(:b, b_payload, before: :c)
|
11
|
+
# collection.natural_push(:d, d_payload, hidden: true)
|
12
|
+
# collection.natural_push(:a, a_new_payload) # overwrites :a
|
13
|
+
#
|
14
|
+
# collection.reject{|el| el.hidden}.map(&:name) # --> :a, :b, :c
|
15
|
+
# collection.map(&:payload) # --> a_new_payload, b_payload, c_payload, d_payload
|
16
|
+
# ```
|
17
|
+
class NaturalOrdering < Array
|
18
|
+
def natural_push(name, payload, before: nil, **kwargs)
|
19
|
+
name = name.to_sym
|
20
|
+
before_name = before&.to_sym
|
21
|
+
old_kwargs = {}
|
22
|
+
|
23
|
+
# Fetch existing element if any
|
24
|
+
existing_index = find_index { |el| el.name == name }
|
25
|
+
if existing_index.present?
|
26
|
+
# Copy all non-mentionned kwargs from the element we are about to overwrite
|
27
|
+
old_kwargs = self[existing_index].except(:name, :payload)
|
28
|
+
|
29
|
+
# Replacing an existing element with a before: directive - must delete before calculating indices
|
30
|
+
if before_name.present?
|
31
|
+
delete_at(existing_index)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Fetch before element
|
36
|
+
if before_name.present?
|
37
|
+
before_index = find_index { |el| el.name == before_name } || fail("Element #{before_name.inspect} for :before not found in #{inspect}.")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Create the element to insert
|
41
|
+
element = MethodAccessibleHash.new(name:, payload:, **old_kwargs.merge(kwargs))
|
42
|
+
|
43
|
+
# Insert new element
|
44
|
+
if before_index.present?
|
45
|
+
# Insert before another element
|
46
|
+
insert(before_index, element)
|
47
|
+
elsif existing_index.present?
|
48
|
+
# Override another element
|
49
|
+
self[existing_index] = element
|
50
|
+
else
|
51
|
+
# Append at the end
|
52
|
+
self << element
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -41,5 +41,13 @@ module Compony
|
|
41
41
|
return true if @local_assigns.key?(method)
|
42
42
|
return super
|
43
43
|
end
|
44
|
+
|
45
|
+
# Renders a content block from the current component.
|
46
|
+
def content(name)
|
47
|
+
name = name.to_sym
|
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)
|
51
|
+
end
|
44
52
|
end
|
45
53
|
end
|
data/lib/compony.rb
CHANGED
@@ -300,6 +300,7 @@ require 'compony/components/new'
|
|
300
300
|
require 'compony/components/edit'
|
301
301
|
require 'compony/components/destroy'
|
302
302
|
require 'compony/method_accessible_hash'
|
303
|
+
require 'compony/natural_ordering'
|
303
304
|
require 'compony/model_mixin'
|
304
305
|
require 'compony/request_context'
|
305
306
|
require 'compony/version'
|
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.
|
4
|
+
version: 0.3.0
|
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-
|
12
|
+
date: 2024-05-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: yard
|
@@ -233,6 +233,7 @@ files:
|
|
233
233
|
- doc/Compony/ModelFields/Time.html
|
234
234
|
- doc/Compony/ModelFields/Url.html
|
235
235
|
- doc/Compony/ModelMixin.html
|
236
|
+
- doc/Compony/NaturalOrdering.html
|
236
237
|
- doc/Compony/RequestContext.html
|
237
238
|
- doc/Compony/Version.html
|
238
239
|
- doc/Compony/ViewHelpers.html
|
@@ -297,6 +298,7 @@ files:
|
|
297
298
|
- lib/compony/model_fields/time.rb
|
298
299
|
- lib/compony/model_fields/url.rb
|
299
300
|
- lib/compony/model_mixin.rb
|
301
|
+
- lib/compony/natural_ordering.rb
|
300
302
|
- lib/compony/request_context.rb
|
301
303
|
- lib/compony/version.rb
|
302
304
|
- lib/compony/view_helpers.rb
|