compony 0.5.2 → 0.5.4

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +15 -0
  4. data/Gemfile.lock +6 -6
  5. data/README.md +38 -0
  6. data/VERSION +1 -1
  7. data/app/controllers/compony_controller.rb +4 -0
  8. data/compony.gemspec +4 -4
  9. data/doc/ComponentGenerator.html +1 -1
  10. data/doc/Components.html +1 -1
  11. data/doc/ComponentsGenerator.html +1 -1
  12. data/doc/Compony/Component.html +1 -1
  13. data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
  14. data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
  15. data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +96 -27
  16. data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +1 -1
  17. data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
  18. data/doc/Compony/ComponentMixins/Default.html +1 -1
  19. data/doc/Compony/ComponentMixins/Resourceful.html +1 -1
  20. data/doc/Compony/ComponentMixins.html +1 -1
  21. data/doc/Compony/Components/Button.html +9 -5
  22. data/doc/Compony/Components/Destroy.html +1 -1
  23. data/doc/Compony/Components/Edit.html +1 -1
  24. data/doc/Compony/Components/Form.html +289 -135
  25. data/doc/Compony/Components/New.html +1 -1
  26. data/doc/Compony/Components/WithForm.html +1 -1
  27. data/doc/Compony/Components.html +1 -1
  28. data/doc/Compony/ControllerMixin.html +1 -1
  29. data/doc/Compony/Engine.html +1 -1
  30. data/doc/Compony/MethodAccessibleHash.html +1 -1
  31. data/doc/Compony/ModelFields/Anchormodel.html +1 -1
  32. data/doc/Compony/ModelFields/Association.html +1 -1
  33. data/doc/Compony/ModelFields/Attachment.html +1 -1
  34. data/doc/Compony/ModelFields/Base.html +1 -1
  35. data/doc/Compony/ModelFields/Boolean.html +1 -1
  36. data/doc/Compony/ModelFields/Color.html +1 -1
  37. data/doc/Compony/ModelFields/Currency.html +1 -1
  38. data/doc/Compony/ModelFields/Date.html +1 -1
  39. data/doc/Compony/ModelFields/Datetime.html +1 -1
  40. data/doc/Compony/ModelFields/Decimal.html +1 -1
  41. data/doc/Compony/ModelFields/Email.html +1 -1
  42. data/doc/Compony/ModelFields/Float.html +1 -1
  43. data/doc/Compony/ModelFields/Integer.html +1 -1
  44. data/doc/Compony/ModelFields/Percentage.html +1 -1
  45. data/doc/Compony/ModelFields/Phone.html +1 -1
  46. data/doc/Compony/ModelFields/RichText.html +1 -1
  47. data/doc/Compony/ModelFields/String.html +1 -1
  48. data/doc/Compony/ModelFields/Text.html +1 -1
  49. data/doc/Compony/ModelFields/Time.html +1 -1
  50. data/doc/Compony/ModelFields/Url.html +1 -1
  51. data/doc/Compony/ModelFields.html +1 -1
  52. data/doc/Compony/ModelMixin.html +25 -25
  53. data/doc/Compony/NaturalOrdering.html +1 -1
  54. data/doc/Compony/RequestContext.html +1 -1
  55. data/doc/Compony/Version.html +1 -1
  56. data/doc/Compony/ViewHelpers.html +30 -12
  57. data/doc/Compony.html +4 -4
  58. data/doc/ComponyController.html +1 -1
  59. data/doc/_index.html +1 -1
  60. data/doc/file.README.html +39 -1
  61. data/doc/index.html +39 -1
  62. data/doc/method_list.html +65 -41
  63. data/doc/top-level-namespace.html +1 -1
  64. data/lib/compony/component_mixins/default/standalone/standalone_dsl.rb +18 -10
  65. data/lib/compony/components/button.rb +5 -3
  66. data/lib/compony/components/form.rb +57 -32
  67. data/lib/compony/model_mixin.rb +19 -13
  68. data/lib/compony/view_helpers.rb +12 -4
  69. data/lib/compony.rb +3 -3
  70. metadata +3 -9
@@ -7,7 +7,7 @@ module Compony
7
7
 
8
8
  # path: If given a block, it will be evaluated in the helpers context when rendering
9
9
  # enabled: If given a block, it will be evaluated in the helpers context when rendering
10
- def initialize(*, label: nil, path: nil, method: nil, type: nil, enabled: nil, visible: nil, title: nil, **, &)
10
+ def initialize(*, label: nil, path: nil, method: nil, type: nil, enabled: nil, visible: nil, title: nil, button_params: nil, value: nil, **, &)
11
11
  @label = label || Compony.button_defaults[:label]
12
12
  @type = type&.to_sym || Compony.button_defaults[:type] || :button
13
13
  @path = path || Compony.button_defaults[:path] || 'javascript:void(0)'
@@ -23,6 +23,8 @@ module Compony
23
23
  @visible = Compony.button_defaults[:visible] if @visible.nil?
24
24
  @visible = true if @visible.nil?
25
25
  @title = title || Compony.button_defaults[:title]
26
+ @button_params = button_params
27
+ @value = value
26
28
 
27
29
  fail "Unsupported button type #{@type}, use on of: #{SUPPORTED_TYPES.inspect}" unless SUPPORTED_TYPES.include?(@type)
28
30
 
@@ -47,9 +49,9 @@ module Compony
47
49
  if @visible
48
50
  case @type
49
51
  when :button
50
- concat button_to(@label, @path, method: @method, disabled: !@enabled, title: @title)
52
+ concat button_to(@label, @path, method: @method, disabled: !@enabled, title: @title, params: @button_params)
51
53
  when :submit
52
- concat button_tag(@label, type: :submit, disabled: !@enabled, title: @title)
54
+ concat button_tag(@label, type: :submit, disabled: !@enabled, title: @title, value: @value)
53
55
  end
54
56
  end
55
57
  end
@@ -3,9 +3,10 @@ module Compony
3
3
  # @api description
4
4
  # This component is used for the _form partial in the Rails paradigm.
5
5
  class Form < Component
6
- def initialize(*args, cancancan_action: :missing, **kwargs)
6
+ def initialize(*args, cancancan_action: :missing, disabled: false, **kwargs)
7
7
  @schema_lines_for_data = [] # Array of procs taking data returning a Schemacop proc
8
8
  @cancancan_action = cancancan_action
9
+ @form_disabled = disabled
9
10
  super
10
11
  end
11
12
 
@@ -35,7 +36,8 @@ module Compony
35
36
  end
36
37
 
37
38
  content do
38
- form_html = simple_form_for(data, method: @comp_opts[:submit_verb], url: @submit_path) do |f|
39
+ form_params = { method: @comp_opts[:submit_verb], url: @submit_path }.merge(@form_params || {})
40
+ form_html = simple_form_for(data, **form_params) do |f|
39
41
  component.with_simpleform(f, controller) do
40
42
  instance_exec(&form_fields)
41
43
  div class: 'compony-form-buttons' do
@@ -94,30 +96,38 @@ module Compony
94
96
 
95
97
  # Called inside the form_fields block. This makes the method `field` available in the block.
96
98
  # See also notes for `with_simpleform`.
97
- def field(name, **input_opts)
99
+ # If multilang is true, a suffixed field is generated for every available locale (useful with gem "mobility"). Render the array as you wish.
100
+ def field(name, multilang: false, **input_opts)
98
101
  fail("The `field` method may only be called inside `form_fields` for #{inspect}.") unless @simpleform
99
- name = name.to_sym
100
102
 
101
- # Check per-field authorization
102
- if @cancancan_action.present? && @controller.current_ability.permitted_attributes(@cancancan_action, @simpleform.object).exclude?(name)
103
- Rails.logger.debug do
104
- "Skipping form field #{name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{@simpleform.object}."
103
+ if multilang
104
+ I18n.available_locales.map { |locale| field("#{name}_#{locale}", **input_opts) }
105
+ else
106
+ name = name.to_sym
107
+
108
+ input_opts.merge!(disabled: true) if @form_disabled
109
+
110
+ # Check per-field authorization
111
+ if @cancancan_action.present? && @controller.current_ability.permitted_attributes(@cancancan_action, @simpleform.object).exclude?(name)
112
+ Rails.logger.debug do
113
+ "Skipping form field #{name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{@simpleform.object}."
114
+ end
115
+ return
105
116
  end
106
- return
107
- end
108
117
 
109
- hidden = input_opts.delete(:hidden)
110
- model_field = @simpleform.object.fields[name]
111
- fail("Field #{name.inspect} is not defined on #{@simpleform.object.inspect} but was requested in #{inspect}.") unless model_field
118
+ hidden = input_opts.delete(:hidden)
119
+ model_field = @simpleform.object.fields[name]
120
+ fail("Field #{name.inspect} is not defined on #{@simpleform.object.inspect} but was requested in #{inspect}.") unless model_field
112
121
 
113
- if hidden
114
- return model_field.simpleform_input_hidden(@simpleform, self, **input_opts)
115
- else
116
- unless @focus_given || @skip_autofocus
117
- input_opts[:autofocus] = true unless input_opts.key? :autofocus
118
- @focus_given = true
122
+ if hidden
123
+ return model_field.simpleform_input_hidden(@simpleform, self, **input_opts)
124
+ else
125
+ unless @focus_given || @skip_autofocus
126
+ input_opts[:autofocus] = true unless input_opts.key? :autofocus
127
+ @focus_given = true
128
+ end
129
+ return model_field.simpleform_input(@simpleform, self, **input_opts)
119
130
  end
120
- return model_field.simpleform_input(@simpleform, self, **input_opts)
121
131
  end
122
132
  end
123
133
 
@@ -155,6 +165,16 @@ module Compony
155
165
  Compony::ModelFields::Anchormodel.collect(...)
156
166
  end
157
167
 
168
+ # DSL method, disables all inputs
169
+ def disable!
170
+ @form_disabled = true
171
+ end
172
+
173
+ # DSL method, allows to customize parameters given to simple_form_for
174
+ def form_params(**new_form_params)
175
+ @form_params = new_form_params
176
+ end
177
+
158
178
  protected
159
179
 
160
180
  # DSL method, adds a new line to the schema whitelisting a single param inside the schema's wrapper
@@ -165,19 +185,24 @@ module Compony
165
185
 
166
186
  # DSL method, adds a new field to the schema whitelisting a single field of data_class
167
187
  # This auto-generates the correct schema line for the field.
168
- def schema_field(field_name)
169
- # This runs upon component setup.
170
- @schema_lines_for_data << proc do |data, controller|
171
- # This runs within a request context.
172
- field = data.class.fields[field_name.to_sym] || fail("No field #{field_name.to_sym.inspect} found for #{data.inspect} in #{inspect}.")
173
- # Check per-field authorization
174
- if @cancancan_action.present? && controller.current_ability.permitted_attributes(@cancancan_action.to_sym, data).exclude?(field.name.to_sym)
175
- Rails.logger.debug do
176
- "Skipping form schema_field #{field_name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{data}."
188
+ # If multilang is true, a suffixed field is generated for every available locale (useful with gem "mobility")
189
+ def schema_field(field_name, multilang: false)
190
+ if multilang
191
+ I18n.available_locales.each { |locale| schema_field("#{field_name}_#{locale}") }
192
+ else
193
+ # This runs upon component setup.
194
+ @schema_lines_for_data << proc do |data, controller|
195
+ # This runs within a request context.
196
+ field = data.class.fields[field_name.to_sym] || fail("No field #{field_name.to_sym.inspect} found for #{data.inspect} in #{inspect}.")
197
+ # Check per-field authorization
198
+ if @cancancan_action.present? && controller.current_ability.permitted_attributes(@cancancan_action.to_sym, data).exclude?(field.name.to_sym)
199
+ Rails.logger.debug do
200
+ "Skipping form schema_field #{field_name.inspect} because the current user is not allowed to perform #{@cancancan_action.inspect} on #{data}."
201
+ end
202
+ next nil
177
203
  end
178
- next nil
204
+ next field.schema_line
179
205
  end
180
- next field.schema_line
181
206
  end
182
207
  end
183
208
 
@@ -190,7 +215,7 @@ module Compony
190
215
  # Check per-field authorization
191
216
  unless @cancancan_action.nil? || controller.current_ability.can?(:set_password, data)
192
217
  Rails.logger.debug do
193
- "Skipping form schema_pw_field #{name.inspect} because the current user is not allowed to perform :set_password on #{data}."
218
+ "Skipping form schema_pw_field #{field_name.inspect} because the current user is not allowed to perform :set_password on #{data}."
194
219
  end
195
220
  next nil
196
221
  end
@@ -19,21 +19,27 @@ module Compony
19
19
  end
20
20
 
21
21
  # DSL method, defines a new field which will be translated and can be added to field groups
22
- def field(name, type, **extra_attrs)
23
- name = name.to_sym
24
- self.fields = fields.dup
25
- field = Compony.model_field_class_for(type.to_s.camelize).new(name, self, **extra_attrs)
26
- # Handle the case where ActiveType would interfere with attribute registration
27
- if defined?(ActiveType) && self <= ActiveType::Object && !include?(ActiveModel::Attributes)
28
- fail "Please add `include ActiveModel::Attributes` at the top of the class #{self}, as attributes cannot be registered otherwise with ActiveType."
29
- end
30
- # Register the field as an attribute
31
- if defined?(ActiveType) && self <= ActiveType::Object
32
- ar_attribute(name)
22
+ # If multilang is true, a suffixed field is generated for every available locale, along with a non-suffixed virtual field (useful with gem "mobility")
23
+ def field(name, type, multilang: false, **extra_attrs)
24
+ if multilang
25
+ field(name, type, virtual: true, **extra_attrs)
26
+ I18n.available_locales.each { |locale| field("#{name}_#{locale}", type, **extra_attrs) }
33
27
  else
34
- attribute(name)
28
+ name = name.to_sym
29
+ self.fields = fields.dup
30
+ field = Compony.model_field_class_for(type.to_s.camelize).new(name, self, **extra_attrs)
31
+ # Handle the case where ActiveType would interfere with attribute registration
32
+ if defined?(ActiveType) && self <= ActiveType::Object && !include?(ActiveModel::Attributes)
33
+ fail "Please add `include ActiveModel::Attributes` at the top of the class #{self}, as attributes cannot be registered otherwise with ActiveType."
34
+ end
35
+ # Register the field as an attribute
36
+ if defined?(ActiveType) && self <= ActiveType::Object
37
+ ar_attribute(name)
38
+ else
39
+ attribute(name)
40
+ end
41
+ fields[name] = field
35
42
  end
36
- fields[name] = field
37
43
  end
38
44
 
39
45
  # DSL method, sets the containing model.
@@ -19,11 +19,19 @@ module Compony
19
19
  # @param link_args [Array] Positional arguments that will be passed to the Rails `link_to` helper
20
20
  # @param label_opts [Hash] Options hash that will be passed to the label method (see {Compony::ComponentMixins::Default::Labelling#label})
21
21
  # @param link_kwargs [Hash] Named arguments that will be passed to the Rails `link_to` helper
22
- def compony_link(comp_name_or_cst, model_or_family_name_or_cst, *link_args, label_opts: {}, **link_kwargs)
22
+ def compony_link(comp_name_or_cst_or_class, model_or_family_name_or_cst = nil, *link_args, label_opts: {}, params: {}, standalone_name: nil, **link_kwargs)
23
23
  model = model_or_family_name_or_cst.respond_to?(:model_name) ? model_or_family_name_or_cst : nil
24
- comp = Compony.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst).new(data: model)
25
- return unless comp.standalone_access_permitted_for?(self)
26
- return helpers.link_to(comp.label(model, **label_opts), Compony.path(comp.comp_name, comp.family_name, model), *link_args, **link_kwargs)
24
+ if comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component)
25
+ target_comp_instance = comp_name_or_cst_or_class.new(data: model)
26
+ else
27
+ target_comp_instance = Compony.comp_class_for!(comp_name_or_cst_or_class, model_or_family_name_or_cst).new(data: model)
28
+ end
29
+ return unless target_comp_instance.standalone_access_permitted_for?(self, standalone_name:)
30
+ return helpers.link_to(
31
+ target_comp_instance.label(model, **label_opts),
32
+ Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, standalone_name:, **params),
33
+ *link_args, **link_kwargs
34
+ )
27
35
  end
28
36
 
29
37
  # Given a component and a family/model, this instanciates and renders a button component.
data/lib/compony.rb CHANGED
@@ -79,13 +79,13 @@ module Compony
79
79
  end
80
80
 
81
81
  # Getter for content_before_root_comp_block
82
- # @see Compony#content_before_root_comp
82
+ # @see Compony#content_before_root_comp=
83
83
  def self.content_before_root_comp_block
84
84
  @content_before_root_comp_block
85
85
  end
86
86
 
87
87
  # Getter for content_after_root_comp_block
88
- # @see Compony#content_after_root_comp
88
+ # @see Compony#content_after_root_comp=
89
89
  def self.content_after_root_comp_block
90
90
  @content_after_root_comp_block
91
91
  end
@@ -198,7 +198,7 @@ module Compony
198
198
  color: target_comp_instance.color,
199
199
  path: Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, standalone_name:, **params),
200
200
  method:,
201
- visible: ->(controller) { target_comp_instance.standalone_access_permitted_for?(controller, verb: method) }
201
+ visible: ->(controller) { target_comp_instance.standalone_access_permitted_for?(controller, standalone_name:, verb: method) }
202
202
  }
203
203
  if feasibility_target
204
204
  options.merge!({
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: compony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Kalbermatter
8
8
  - contributors
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-11-20 00:00:00.000000000 Z
11
+ date: 2025-02-14 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: yard
@@ -165,8 +164,6 @@ dependencies:
165
164
  - - "~>"
166
165
  - !ruby/object:Gem::Version
167
166
  version: 3.6.1
168
- description:
169
- email:
170
167
  executables: []
171
168
  extensions: []
172
169
  extra_rdoc_files: []
@@ -312,10 +309,8 @@ files:
312
309
  - lib/generators/components/USAGE
313
310
  - lib/generators/components/components_generator.rb
314
311
  - logo.svg
315
- homepage:
316
312
  licenses: []
317
313
  metadata: {}
318
- post_install_message:
319
314
  rdoc_options: []
320
315
  require_paths:
321
316
  - lib
@@ -330,8 +325,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
330
325
  - !ruby/object:Gem::Version
331
326
  version: '0'
332
327
  requirements: []
333
- rubygems_version: 3.5.22
334
- signing_key:
328
+ rubygems_version: 3.6.3
335
329
  specification_version: 4
336
330
  summary: Compony is a Gem that allows you to write your Rails application in component-style
337
331
  fashion. It combines a controller action and route along \ with its view into a