compony 0.0.8 → 0.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 328b6b6671f93fa0575bf4224a5da90fecde74a0c00430346d36ca45a675cf24
4
- data.tar.gz: a92107d9f9cf7b270d57059ad10bdec614d269615fd2eabfe58caeb0e44300bc
3
+ metadata.gz: 8157d970b7bb216a92e5ff27931775e1744063efcb91bd8c2c094d998bc0d74d
4
+ data.tar.gz: 1a10cfd007f6c94f2bd71076bd90688bd6761a597962414f56f31570cb4b6c31
5
5
  SHA512:
6
- metadata.gz: 1ae81390416e9f14dcfb1a1d2723fbd3714e4f271afe9dc9e2a3ee2f27012a1ee82cb846fb8b80be14b6fac73451477b9b8e00a960b8f88777670a10e4dcec13
7
- data.tar.gz: d318c0bdc852f4ff1fcf1aef638eac97356a03621f70bb4bac7957bece7050ba5e152a4114d165c79200d3e2eefe6d61af69ac4fec10371da354f908164ab929
6
+ metadata.gz: 37fdaa0c7e0c6e905fbf5239d79dc9df15bb27e3cf805953fc9daf75e421f04dc14b087165e2049c5e4ff87a13464d197a837cea24517467d591ff115c7f2cd3
7
+ data.tar.gz: 3f59823928a888c4bb5f501f4e1440ff4e3a1f83f627d23117af9c5b5e7afba65db48168a70685010c9c251f4b7331a232843a6209634ad004c3a15a0ee6653a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 0.0.9
2
+
3
+ - Support forms with references to tables with uuid type primary key
4
+ - Support for `owned_by` in model:
5
+ - Smart redirect
6
+ - Auto-generate a back / cancel button
7
+ - Add `clear_standalone!` to components
8
+ - Allow passing an array to `prevent` to prevent multiple actions at once
9
+ - Add features `Compony.content_before_root_comp` and `Compony.content_after_root_comp`
10
+ - Add new field kind percentage
11
+
1
12
  # 0.0.8
2
13
 
3
14
  - Support selecting anchormodel inputs via radio buttons
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- compony (0.0.1)
4
+ compony (0.0.9.edge)
5
5
  anchormodel (~> 0.1.2)
6
6
  cancancan (~> 3.4.0)
7
7
  dslblend (>= 0.0.3)
@@ -203,4 +203,4 @@ DEPENDENCIES
203
203
  yard (>= 0.9.28)
204
204
 
205
205
  BUNDLED WITH
206
- 2.4.13
206
+ 2.4.19
data/compony.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
  # This file is auto-generated via: 'rake gemspec'.
3
3
 
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: compony 0.0.8 ruby lib
5
+ # stub: compony 0.0.9 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "compony".freeze
9
- s.version = "0.0.8"
9
+ s.version = "0.0.9"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Sandro Kalbermatter".freeze, "contributors".freeze]
14
- s.date = "2023-10-03"
15
- s.files = [".gitignore".freeze, ".ruby-version".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "Gemfile.lock".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "app/controllers/compony_controller.rb".freeze, "compony.gemspec".freeze, "config/locales/de.yml".freeze, "config/locales/en.yml".freeze, "config/routes.rb".freeze, "doc/resourceful_lifecycle.graphml".freeze, "doc/resourceful_lifecycle.pdf".freeze, "lib/compony.rb".freeze, "lib/compony/component.rb".freeze, "lib/compony/component_mixins/default/labelling.rb".freeze, "lib/compony/component_mixins/default/standalone.rb".freeze, "lib/compony/component_mixins/default/standalone/resourceful_verb_dsl.rb".freeze, "lib/compony/component_mixins/default/standalone/standalone_dsl.rb".freeze, "lib/compony/component_mixins/default/standalone/verb_dsl.rb".freeze, "lib/compony/component_mixins/resourceful.rb".freeze, "lib/compony/components/button.rb".freeze, "lib/compony/components/destroy.rb".freeze, "lib/compony/components/edit.rb".freeze, "lib/compony/components/form.rb".freeze, "lib/compony/components/new.rb".freeze, "lib/compony/components/with_form.rb".freeze, "lib/compony/controller_mixin.rb".freeze, "lib/compony/engine.rb".freeze, "lib/compony/method_accessible_hash.rb".freeze, "lib/compony/model_fields/anchormodel.rb".freeze, "lib/compony/model_fields/association.rb".freeze, "lib/compony/model_fields/attachment.rb".freeze, "lib/compony/model_fields/base.rb".freeze, "lib/compony/model_fields/boolean.rb".freeze, "lib/compony/model_fields/color.rb".freeze, "lib/compony/model_fields/currency.rb".freeze, "lib/compony/model_fields/date.rb".freeze, "lib/compony/model_fields/datetime.rb".freeze, "lib/compony/model_fields/decimal.rb".freeze, "lib/compony/model_fields/email.rb".freeze, "lib/compony/model_fields/float.rb".freeze, "lib/compony/model_fields/integer.rb".freeze, "lib/compony/model_fields/phone.rb".freeze, "lib/compony/model_fields/rich_text.rb".freeze, "lib/compony/model_fields/string.rb".freeze, "lib/compony/model_fields/text.rb".freeze, "lib/compony/model_fields/time.rb".freeze, "lib/compony/model_fields/url.rb".freeze, "lib/compony/model_mixin.rb".freeze, "lib/compony/request_context.rb".freeze, "lib/compony/version.rb".freeze, "lib/compony/view_helpers.rb".freeze, "lib/generators/component/USAGE".freeze, "lib/generators/component/component_generator.rb".freeze, "lib/generators/component/templates/component.rb.erb".freeze, "lib/generators/component/templates/destroy.rb.erb".freeze, "lib/generators/component/templates/edit.rb.erb".freeze, "lib/generators/component/templates/form.rb.erb".freeze, "lib/generators/component/templates/new.rb.erb".freeze, "lib/generators/components/USAGE".freeze, "lib/generators/components/components_generator.rb".freeze]
14
+ s.date = "2023-11-03"
15
+ s.files = [".gitignore".freeze, ".ruby-version".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "Gemfile.lock".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "app/controllers/compony_controller.rb".freeze, "compony.gemspec".freeze, "config/locales/de.yml".freeze, "config/locales/en.yml".freeze, "config/routes.rb".freeze, "doc/resourceful_lifecycle.graphml".freeze, "doc/resourceful_lifecycle.pdf".freeze, "lib/compony.rb".freeze, "lib/compony/component.rb".freeze, "lib/compony/component_mixins/default/labelling.rb".freeze, "lib/compony/component_mixins/default/standalone.rb".freeze, "lib/compony/component_mixins/default/standalone/resourceful_verb_dsl.rb".freeze, "lib/compony/component_mixins/default/standalone/standalone_dsl.rb".freeze, "lib/compony/component_mixins/default/standalone/verb_dsl.rb".freeze, "lib/compony/component_mixins/resourceful.rb".freeze, "lib/compony/components/button.rb".freeze, "lib/compony/components/destroy.rb".freeze, "lib/compony/components/edit.rb".freeze, "lib/compony/components/form.rb".freeze, "lib/compony/components/new.rb".freeze, "lib/compony/components/with_form.rb".freeze, "lib/compony/controller_mixin.rb".freeze, "lib/compony/engine.rb".freeze, "lib/compony/method_accessible_hash.rb".freeze, "lib/compony/model_fields/anchormodel.rb".freeze, "lib/compony/model_fields/association.rb".freeze, "lib/compony/model_fields/attachment.rb".freeze, "lib/compony/model_fields/base.rb".freeze, "lib/compony/model_fields/boolean.rb".freeze, "lib/compony/model_fields/color.rb".freeze, "lib/compony/model_fields/currency.rb".freeze, "lib/compony/model_fields/date.rb".freeze, "lib/compony/model_fields/datetime.rb".freeze, "lib/compony/model_fields/decimal.rb".freeze, "lib/compony/model_fields/email.rb".freeze, "lib/compony/model_fields/float.rb".freeze, "lib/compony/model_fields/integer.rb".freeze, "lib/compony/model_fields/percentage.rb".freeze, "lib/compony/model_fields/phone.rb".freeze, "lib/compony/model_fields/rich_text.rb".freeze, "lib/compony/model_fields/string.rb".freeze, "lib/compony/model_fields/text.rb".freeze, "lib/compony/model_fields/time.rb".freeze, "lib/compony/model_fields/url.rb".freeze, "lib/compony/model_mixin.rb".freeze, "lib/compony/request_context.rb".freeze, "lib/compony/version.rb".freeze, "lib/compony/view_helpers.rb".freeze, "lib/generators/component/USAGE".freeze, "lib/generators/component/component_generator.rb".freeze, "lib/generators/component/templates/component.rb.erb".freeze, "lib/generators/component/templates/destroy.rb.erb".freeze, "lib/generators/component/templates/edit.rb.erb".freeze, "lib/generators/component/templates/form.rb.erb".freeze, "lib/generators/component/templates/new.rb.erb".freeze, "lib/generators/components/USAGE".freeze, "lib/generators/components/components_generator.rb".freeze]
16
16
  s.required_ruby_version = Gem::Requirement.new(">= 3.0.0".freeze)
17
17
  s.rubygems_version = "3.4.19".freeze
18
18
  s.summary = "Needs summary".freeze
@@ -1,5 +1,6 @@
1
1
  de:
2
2
  compony:
3
+ cancel: 'Abbrechen'
3
4
  filtered: '[Filtered]' # Not translated as this appears in log
4
5
  boolean:
5
6
  true: 'Ja'
@@ -1,5 +1,6 @@
1
1
  en:
2
2
  compony:
3
+ cancel: 'Cancel'
3
4
  filtered: '[Filtered]'
4
5
  boolean:
5
6
  yes: 'Yes'
@@ -146,8 +146,9 @@ module Compony
146
146
  end
147
147
 
148
148
  # Renders the component using the controller passsed to it and returns it as a string.
149
+ # @param standalone: pass true iff `render` is called from `render_standalone`
149
150
  # Do not overwrite.
150
- def render(controller, **locals)
151
+ def render(controller, standalone: false, **locals)
151
152
  # Call before_render hook if any and backfire instance variables back to the component
152
153
  RequestContext.new(self, controller, locals:).request_context.evaluate_with_backfire(&@before_render_block) if @before_render_block
153
154
  # Render, unless before_render has already issued a body (e.g. through redirecting).
@@ -155,12 +156,18 @@ module Compony
155
156
  fail "#{self.class.inspect} must define `content` or set a response body in `before_render`" if @content_blocks.none?
156
157
  return controller.render_to_string(
157
158
  type: :dyny,
158
- locals: { content_blocks: @content_blocks, component: self, render_locals: locals },
159
+ locals: { content_blocks: @content_blocks, standalone:, component: self, render_locals: locals },
159
160
  inline: <<~RUBY
161
+ if Compony.content_before_root_comp_block && standalone
162
+ Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&Compony.content_before_root_comp_block)
163
+ end
160
164
  content_blocks.each do |block|
161
165
  # Instanciate and evaluate a fresh RequestContext in order to use the buffer allocated by the ActionView (needed for `concat` calls)
162
166
  Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&block)
163
167
  end
168
+ if Compony.content_after_root_comp_block && standalone
169
+ Compony::RequestContext.new(component, controller, helpers: self, locals: render_locals).evaluate(&Compony.content_after_root_comp_block)
170
+ end
164
171
  RUBY
165
172
  )
166
173
  else
@@ -88,7 +88,7 @@ module Compony
88
88
  # Do not overwrite
89
89
  def render_standalone(controller, status: nil, standalone_name: nil)
90
90
  # Start the render process. This produces a nil value if before_render has already produced a response, e.g. a redirect.
91
- rendered_html = render(controller)
91
+ rendered_html = render(controller, standalone: true)
92
92
  if rendered_html.present? # If nil, a response body was already produced in the controller and we take no action here (would have DoubleRenderError)
93
93
  opts = { html: rendered_html, layout: @standalone_configs[standalone_name].layout }
94
94
  opts[:status] = status if status.present?
@@ -111,6 +111,11 @@ module Compony
111
111
  @standalone_configs[name].deep_merge! StandaloneDsl.new(self, name, *args, **nargs).to_conf(&block)
112
112
  end
113
113
 
114
+ # Undoes previous standalone calls
115
+ def clear_standalone!
116
+ @standalone_configs = {}
117
+ end
118
+
114
119
  private
115
120
 
116
121
  def init_standalone
@@ -36,6 +36,11 @@ module Compony
36
36
  end
37
37
  end
38
38
 
39
+ action :back_to_owner do
40
+ next if data_class.owner_model_attr.blank?
41
+ Compony.button(:show, @data.send(data_class.owner_model_attr), icon: :xmark, color: :secondary, label: I18n.t('compony.cancel'))
42
+ end
43
+
39
44
  store_data do
40
45
  # Validate params against the form's schema
41
46
  local_data = @data # Capture data for usage in the Schemacop call
@@ -58,7 +63,11 @@ module Compony
58
63
  end
59
64
 
60
65
  on_destroyed_redirect_path do
61
- Compony.path(:index, family_cst)
66
+ if data_class.owner_model_attr.present?
67
+ Compony.path(:show, @data.send(data_class.owner_model_attr))
68
+ else
69
+ Compony.path(:index, family_cst)
70
+ end
62
71
  end
63
72
  end
64
73
 
@@ -30,6 +30,11 @@ module Compony
30
30
  label(:short) { |_| I18n.t('compony.components.edit.label.short') }
31
31
  icon { :pencil }
32
32
 
33
+ action :back_to_owner do
34
+ next if data_class.owner_model_attr.blank?
35
+ Compony.button(:show, @data.send(data_class.owner_model_attr), icon: :xmark, color: :secondary, label: I18n.t('compony.cancel'))
36
+ end
37
+
33
38
  content do
34
39
  concat form_comp.render(controller, data: @data)
35
40
  end
@@ -65,6 +70,8 @@ module Compony
65
70
  on_updated_redirect_path do
66
71
  if Compony.comp_class_for(:show, @data)
67
72
  Compony.path(:show, @data)
73
+ elsif data_class.owner_model_attr.present?
74
+ Compony.path(:show, @data.send(data_class.owner_model_attr))
68
75
  else
69
76
  Compony.path(:index, @data)
70
77
  end
@@ -64,6 +64,8 @@ module Compony
64
64
  on_created_redirect_path do
65
65
  if Compony.comp_class_for(:show, @data)
66
66
  Compony.path(:show, @data)
67
+ elsif data_class.owner_model_attr.present?
68
+ Compony.path(:show, @data.send(data_class.owner_model_attr))
67
69
  else
68
70
  Compony.path(:index, @data)
69
71
  end
@@ -24,15 +24,28 @@ module Compony
24
24
 
25
25
  def schema_line
26
26
  local_schema_key = @schema_key # Capture schema_key as it will not be available within the lambda
27
+ target_primary_key_type = @target_class.primary_key_type_key
27
28
  if multi?
28
29
  return proc do
29
30
  ary? local_schema_key do
30
- list :integer, cast_str: true
31
+ if target_primary_key_type == :integer
32
+ list :integer, cast_str: true
33
+ elsif target_primary_key_type == :string
34
+ list :string
35
+ else
36
+ fail("Unsupported target primary_key_type_key #{target_primary_key_type}")
37
+ end
31
38
  end
32
39
  end
33
40
  else
34
41
  return proc do
35
- int? local_schema_key, cast_str: true
42
+ if target_primary_key_type == :integer
43
+ int? local_schema_key, cast_str: true
44
+ elsif target_primary_key_type == :string
45
+ str? local_schema_key
46
+ else
47
+ fail("Unsupported target primary_key_type_key #{target_primary_key_type}")
48
+ end
36
49
  end
37
50
  end
38
51
  end
@@ -53,6 +66,7 @@ module Compony
53
66
  @association = true
54
67
  association_info = @model_class.reflect_on_association(@name) || fail("Association #{@name.inspect} does not exist for #{@model_class.inspect}.")
55
68
  @multi = association_info.macro == :has_many
69
+ @target_class = association_info.klass
56
70
  id_name = "#{@name.to_s.singularize}_id"
57
71
  @schema_key = @multi ? id_name.pluralize.to_sym : id_name.to_sym
58
72
  rescue ActiveRecord::NoDatabaseError
@@ -0,0 +1,9 @@
1
+ module Compony
2
+ module ModelFields
3
+ class Percentage < Base
4
+ def value_for(data, controller: nil, **_)
5
+ return transform_and_join(data.send(@name), controller:) { |el| controller.helpers.sanitize "#{(el * 100.0).round(2)}%" }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -6,6 +6,7 @@ module Compony
6
6
  class_attribute :fields, default: {}
7
7
  class_attribute :feasibility_preventions, default: {}
8
8
  class_attribute :primary_key_type_key, default: :integer
9
+ class_attribute :owner_model_attr
9
10
 
10
11
  class_attribute :autodetect_feasibilities_completed, default: false
11
12
  end
@@ -34,12 +35,23 @@ module Compony
34
35
  self.primary_key_type_key = new_type.to_sym
35
36
  end
36
37
 
38
+ # DSL method, sets the containing model.
39
+ # Use this when a model only makes sense within the context of another model and typically has no own index page.
40
+ # For instance, a model LineItem that belongs_to :invoice would typically be owned_by :invoice.
41
+ # Compony will automatically adjust Redirects and top actions.
42
+ def owned_by(attribute_name)
43
+ self.owner_model_attr = attribute_name.to_sym
44
+ end
45
+
37
46
  # DSL method, part of the Feasibility feature
38
47
  # Block must return `false` if the action should be prevented.
39
- def prevent(action_name, message, &block)
40
- self.feasibility_preventions = feasibility_preventions.dup # Prevent cross-class contamination
41
- feasibility_preventions[action_name.to_sym] ||= []
42
- feasibility_preventions[action_name.to_sym] << MethodAccessibleHash.new(action_name:, message:, block:)
48
+ def prevent(action_names, message, &block)
49
+ action_names = [action_names] unless action_names.is_a? Enumerable
50
+ action_names.each do |action_name|
51
+ self.feasibility_preventions = feasibility_preventions.dup # Prevent cross-class contamination
52
+ feasibility_preventions[action_name.to_sym] ||= []
53
+ feasibility_preventions[action_name.to_sym] << MethodAccessibleHash.new(action_name:, message:, block:)
54
+ end
43
55
  end
44
56
 
45
57
  # DSL method, part of the Feasibility feature
@@ -2,7 +2,7 @@ module Compony
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- PATCH = 8
5
+ PATCH = 9
6
6
 
7
7
  EDGE = false
8
8
 
data/lib/compony.rb CHANGED
@@ -40,6 +40,20 @@ module Compony
40
40
  @authentication_before_action = authentication_before_action.to_sym
41
41
  end
42
42
 
43
+ # Setter for a content block that runs before the root component gets rendered (standalone only). Usage is the same as `content`.
44
+ # The block runs between `before_render` and `render`, i.e. before the first `content` block.
45
+ def self.content_before_root_comp(&block)
46
+ fail('`Compony.content_before` requires a block.') unless block_given?
47
+ @content_before_root_comp_block = block
48
+ end
49
+
50
+ # Setter for a content block that runs after the root component gets rendered (standalone only). Usage is the same as `content`.
51
+ # The block runs after `render`, i.e. after the last `content` block.
52
+ def self.content_after_root_comp(&block)
53
+ fail('`Compony.content_after` requires a block.') unless block_given?
54
+ @content_after_root_comp_block = block
55
+ end
56
+
43
57
  ##########=====-------
44
58
  # Configuration readers
45
59
  ##########=====-------
@@ -64,6 +78,18 @@ module Compony
64
78
  @authentication_before_action
65
79
  end
66
80
 
81
+ # Getter for content_before_root_comp_block
82
+ # @see Compony#content_before_root_comp
83
+ def self.content_before_root_comp_block
84
+ @content_before_root_comp_block
85
+ end
86
+
87
+ # Getter for content_after_root_comp_block
88
+ # @see Compony#content_after_root_comp
89
+ def self.content_after_root_comp_block
90
+ @content_after_root_comp_block
91
+ end
92
+
67
93
  ##########=====-------
68
94
  # Application-wide available pure helpers
69
95
  ##########=====-------
@@ -253,6 +279,7 @@ require 'compony/model_fields/decimal'
253
279
  require 'compony/model_fields/email'
254
280
  require 'compony/model_fields/float'
255
281
  require 'compony/model_fields/integer'
282
+ require 'compony/model_fields/percentage'
256
283
  require 'compony/model_fields/phone'
257
284
  require 'compony/model_fields/rich_text'
258
285
  require 'compony/model_fields/string'
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.0.8
4
+ version: 0.0.9
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: 2023-10-03 00:00:00.000000000 Z
12
+ date: 2023-11-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yard
@@ -203,6 +203,7 @@ files:
203
203
  - lib/compony/model_fields/email.rb
204
204
  - lib/compony/model_fields/float.rb
205
205
  - lib/compony/model_fields/integer.rb
206
+ - lib/compony/model_fields/percentage.rb
206
207
  - lib/compony/model_fields/phone.rb
207
208
  - lib/compony/model_fields/rich_text.rb
208
209
  - lib/compony/model_fields/string.rb