compony 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0925cbc177ea6e36fd56db15cb41227efcb66b7ea5896a2dd76cc13fc7974a5
4
- data.tar.gz: 517baac0f2d25bb94857c5796d6ae41a94c291628edda7e453736488c2616036
3
+ metadata.gz: 8fa06e0cecacc05de1b6567e29594a44fcbfed063d0268e08de239432c51a7f2
4
+ data.tar.gz: 24ec1426a6259b2cc3b1ddbd0127d8878a46701a0d7b2003bf5668eddf1eb8a0
5
5
  SHA512:
6
- metadata.gz: 2a6ef1cb3327c852d2f544c376f22f34d8bac2eb56ff7c29e13fb887d0b4fcd91aa3de4dcfa3f16393ec386abbbefae593379c87e848518f00978d566250064a
7
- data.tar.gz: d3a985885dc53f7a4556c338038342f17b65991cea8ac0f993ff2ab0b638984d59b9a09b78ec7e9bec08eea4795debe1892a212875262629ff371295d771021c
6
+ metadata.gz: 66fc9fe7beb64285bc2f21a945d1596c24206072b0fd64172a3eea2130754363f11d980b9159b0ebc1702be72526eb2ce8e613d17ece625ac377eeb0698ee876
7
+ data.tar.gz: fce5758f4f812d6ba053cf085c807ffecbce5163ed676d529d00aaa36257478a3887f60d3d6bc1ec0294151144edb6d63dc415f82c8fa6b7727fc4f84be34a97
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ # 0.0.5
2
+
3
+ - Fix row bug for Email field type
4
+ - Auto-focus first non-hidden element in forms
5
+ - Add field type :url
6
+ - Automatically set the correct class when generating known components
7
+ - Add generator `components` that is able to mass-produce the most used components
8
+ - Make fields point to the correct `model_class` in case of STI
9
+ - Support hidden Anchormodel fields
10
+
11
+ # 0.0.4
12
+
13
+ - Unscope the namespace of resourceful components
14
+ - Add field type :email
15
+
16
+ ## Steps to take
17
+
18
+ - When inheriting from components, replace `Components::Resourceful::...` by `Components::...`
19
+
1
20
  # 0.0.3
2
21
 
3
22
  - Tolerate nil anchormodels
data/compony.gemspec CHANGED
@@ -2,31 +2,31 @@
2
2
  # This file is auto-generated via: 'rake gemspec'.
3
3
 
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: compony 0.0.3 ruby lib
5
+ # stub: compony 0.0.5 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "compony".freeze
9
- s.version = "0.0.3".freeze
9
+ s.version = "0.0.5"
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 = "2024-03-25"
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/form.rb".freeze, "lib/compony/components/resourceful/destroy.rb".freeze, "lib/compony/components/resourceful/edit.rb".freeze, "lib/compony/components/resourceful/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/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/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_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]
14
+ s.date = "2023-06-20"
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/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]
16
16
  s.required_ruby_version = Gem::Requirement.new(">= 3.0.0".freeze)
17
- s.rubygems_version = "3.5.6".freeze
17
+ s.rubygems_version = "3.4.13".freeze
18
18
  s.summary = "Needs summary".freeze
19
19
 
20
20
  s.specification_version = 4
21
21
 
22
- s.add_development_dependency(%q<yard>.freeze, [">= 0.9.28".freeze])
23
- s.add_development_dependency(%q<rubocop>.freeze, [">= 1.48".freeze])
24
- s.add_development_dependency(%q<rubocop-rails>.freeze, [">= 2.18.0".freeze])
25
- s.add_runtime_dependency(%q<request_store>.freeze, [">= 1.5".freeze])
26
- s.add_runtime_dependency(%q<dyny>.freeze, [">= 0.0.3".freeze])
27
- s.add_runtime_dependency(%q<schemacop>.freeze, [">= 3.0.17".freeze])
28
- s.add_runtime_dependency(%q<simple_form>.freeze, [">= 5.1.0".freeze])
29
- s.add_runtime_dependency(%q<dslblend>.freeze, [">= 0.0.3".freeze])
30
- s.add_runtime_dependency(%q<anchormodel>.freeze, ["~> 0.1.2".freeze])
31
- s.add_runtime_dependency(%q<cancancan>.freeze, ["~> 3.4.0".freeze])
22
+ s.add_development_dependency(%q<yard>.freeze, [">= 0.9.28"])
23
+ s.add_development_dependency(%q<rubocop>.freeze, [">= 1.48"])
24
+ s.add_development_dependency(%q<rubocop-rails>.freeze, [">= 2.18.0"])
25
+ s.add_runtime_dependency(%q<request_store>.freeze, [">= 1.5"])
26
+ s.add_runtime_dependency(%q<dyny>.freeze, [">= 0.0.3"])
27
+ s.add_runtime_dependency(%q<schemacop>.freeze, [">= 3.0.17"])
28
+ s.add_runtime_dependency(%q<simple_form>.freeze, [">= 5.1.0"])
29
+ s.add_runtime_dependency(%q<dslblend>.freeze, [">= 0.0.3"])
30
+ s.add_runtime_dependency(%q<anchormodel>.freeze, ["~> 0.1.2"])
31
+ s.add_runtime_dependency(%q<cancancan>.freeze, ["~> 3.4.0"])
32
32
  end
@@ -0,0 +1,75 @@
1
+ module Compony
2
+ module Components
3
+ # @api description
4
+ # This component is used for the Rails destroy paradigm. Asks for confirm when queried using GET.
5
+ class Destroy < Compony::Component
6
+ include Compony::ComponentMixins::Resourceful
7
+
8
+ setup do
9
+ standalone path: "#{family_name}/:id/destroy" do
10
+ verb :get do
11
+ authorize { can?(:destroy, @data) }
12
+ end
13
+
14
+ verb :delete do
15
+ authorize { can?(:destroy, @data) }
16
+ store_data # This enables the global store_data block defined below for this path and verb.
17
+ respond do
18
+ evaluate_with_backfire(&@on_destroyed_block)
19
+ end
20
+ end
21
+ end
22
+
23
+ label(:long) { |data| I18n.t('compony.components.destroy.label.long', data_label: data.label) }
24
+ label(:short) { |_| I18n.t('compony.components.destroy.label.short') }
25
+ icon { :trash }
26
+ color { :danger }
27
+
28
+ content do
29
+ div I18n.t('compony.components.destroy.confirm_question', data_label: @data.label)
30
+ div do
31
+ concat compony_button(comp_cst,
32
+ @data,
33
+ label: I18n.t('compony.components.destroy.confirm_button'),
34
+ method: :delete)
35
+ end
36
+ end
37
+
38
+ store_data do
39
+ # Validate params against the form's schema
40
+ local_data = @data # Capture data for usage in the Schemacop call
41
+ schema = Schemacop::Schema3.new :hash, additional_properties: true do
42
+ if local_data.class.primary_key_type_key == :string
43
+ str! :id
44
+ else
45
+ int! :id, cast_str: true
46
+ end
47
+ end
48
+ schema.validate!(controller.request.params)
49
+
50
+ # Perform destroy
51
+ @data.destroy!
52
+ end
53
+
54
+ on_destroyed do
55
+ flash.notice = I18n.t('compony.components.destroy.data_was_destroyed', data_label: @data.label)
56
+ redirect_to evaluate_with_backfire(&@on_destroyed_redirect_path_block), status: :see_other # 303: force GET
57
+ end
58
+
59
+ on_destroyed_redirect_path do
60
+ Compony.path(:index, family_cst)
61
+ end
62
+ end
63
+
64
+ # DSL method
65
+ def on_destroyed(&block)
66
+ @on_destroyed_block = block
67
+ end
68
+
69
+ # DSL method
70
+ def on_destroyed_redirect_path(&block)
71
+ @on_destroyed_redirect_path_block = block
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,94 @@
1
+ module Compony
2
+ module Components
3
+ # @api description
4
+ # This component is used for the Rails edit and update paradigm. Performs update when the form is submitted.
5
+ class Edit < Compony::Components::WithForm
6
+ include Compony::ComponentMixins::Resourceful
7
+ setup do
8
+ submit_verb :patch
9
+ standalone path: "#{family_name}/:id/edit" do
10
+ verb :get do
11
+ authorize { can?(:edit, @data) }
12
+ assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
13
+ end
14
+ verb submit_verb do
15
+ authorize { can?(:update, @data) }
16
+ assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
17
+ store_data # This enables the global store_data block defined below for this path and verb.
18
+ respond do
19
+ if @update_succeeded
20
+ evaluate_with_backfire(&@on_updated_block)
21
+ else
22
+ evaluate_with_backfire(&@on_update_failed_block)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ label(:long) { |data| I18n.t('compony.components.edit.label.long', data_label: data.label) }
29
+ label(:short) { |_| I18n.t('compony.components.edit.label.short') }
30
+ icon { :pencil }
31
+
32
+ content do
33
+ concat form_comp.render(controller, data: @data)
34
+ end
35
+
36
+ assign_attributes do
37
+ # Validate params against the form's schema
38
+ local_form_comp = form_comp # Capture form_comp for usage in the Schemacop call
39
+ local_data = @data # Capture data for usage in the Schemacop call
40
+ schema = Schemacop::Schema3.new :hash, additional_properties: true do
41
+ if local_data.class.primary_key_type_key == :string
42
+ str! :id
43
+ else
44
+ int! :id, cast_str: true
45
+ end
46
+ hsh? local_form_comp.schema_wrapper_key_for(local_data), &local_form_comp.schema_block_for(local_data)
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)]
52
+ @data.assign_attributes(attrs_to_assign) if attrs_to_assign
53
+ end
54
+
55
+ store_data do
56
+ @update_succeeded = @data.save
57
+ end
58
+
59
+ on_updated do
60
+ flash.notice = I18n.t('compony.components.edit.data_was_updated', data_label: data.label)
61
+ redirect_to evaluate_with_backfire(&@on_updated_redirect_path_block)
62
+ end
63
+
64
+ on_updated_redirect_path do
65
+ if Compony.comp_class_for(:show, @data)
66
+ Compony.path(:show, @data)
67
+ else
68
+ Compony.path(:index, @data)
69
+ end
70
+ end
71
+
72
+ on_update_failed do
73
+ Rails.logger.warn(@data&.errors&.full_messages)
74
+ render_standalone(controller, status: :unprocessable_entity)
75
+ end
76
+ end
77
+
78
+ # DSL method
79
+ def on_updated(&block)
80
+ @on_updated_block = block
81
+ end
82
+
83
+ # DSL method
84
+ def on_updated_redirect_path(&block)
85
+ @on_updated_redirect_path_block = block
86
+ end
87
+
88
+ # DSL method
89
+ def on_update_failed(&block)
90
+ @on_update_failed_block = block
91
+ end
92
+ end
93
+ end
94
+ end
@@ -71,6 +71,7 @@ module Compony
71
71
  # @todo Refactor? Could this be greatly simplified by having `form_field to |f|` ?
72
72
  def with_simpleform(simpleform)
73
73
  @simpleform = simpleform
74
+ @focus_given = false
74
75
  yield
75
76
  @simpleform = nil
76
77
  end
@@ -85,8 +86,12 @@ module Compony
85
86
  fail("Field #{name.to_sym.inspect} is not defined on #{@simpleform.object.inspect} but was requested in #{inspect}.") unless model_field
86
87
 
87
88
  if hidden
88
- return @simpleform.input model_field.schema_key, as: :hidden, **input_opts
89
+ return model_field.simpleform_input_hidden(@simpleform, self, **input_opts)
89
90
  else
91
+ unless @focus_given
92
+ input_opts[:autofocus] = true unless input_opts.key? :autofocus
93
+ @focus_given = true
94
+ end
90
95
  return model_field.simpleform_input(@simpleform, self, **input_opts)
91
96
  end
92
97
  end
@@ -0,0 +1,93 @@
1
+ module Compony
2
+ module Components
3
+ # @api description
4
+ # This component is used for the Rails new and create paradigm. Performs update when the form is submitted.
5
+ class New < Compony::Components::WithForm
6
+ include Compony::ComponentMixins::Resourceful
7
+
8
+ setup do
9
+ submit_verb :post
10
+ load_data { @data = data_class.new }
11
+ standalone path: "#{family_name}/new" do
12
+ verb :get do
13
+ authorize { can?(:create, data_class) }
14
+ assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
15
+ end
16
+ verb submit_verb do
17
+ authorize { can?(:create, data_class) }
18
+ assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
19
+ store_data # This enables the global store_data block defined below for this path and verb.
20
+ respond do
21
+ if @create_succeeded
22
+ evaluate_with_backfire(&@on_created_block)
23
+ else
24
+ evaluate_with_backfire(&@on_create_failed_block)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ label(:long) { I18n.t('compony.components.new.label.long', data_class: data_class.model_name.human) }
31
+ label(:short) { I18n.t('compony.components.new.label.short') }
32
+ icon { :plus }
33
+
34
+ add_content do
35
+ h2 component.label
36
+ end
37
+ add_content do
38
+ concat form_comp.render(controller, data: @data)
39
+ end
40
+
41
+ assign_attributes do
42
+ local_form_comp = form_comp # Capture form_comp for usage in the Schemacop call
43
+ local_data = @data # Capture data for usage in the Schemacop call
44
+ schema = Schemacop::Schema3.new :hash, additional_properties: true do
45
+ hsh? local_form_comp.schema_wrapper_key_for(local_data), &local_form_comp.schema_block_for(local_data)
46
+ end
47
+ schema.validate!(controller.request.params)
48
+
49
+ # TODO: Why are we not saving the validated params?
50
+ attrs_to_assign = controller.request.params[form_comp.schema_wrapper_key_for(@data)]
51
+ @data.assign_attributes(attrs_to_assign) if attrs_to_assign
52
+ end
53
+
54
+ store_data do
55
+ @create_succeeded = @data.save
56
+ end
57
+
58
+ on_created do
59
+ flash.notice = I18n.t('compony.components.new.data_was_created', data_label: data.label)
60
+ redirect_to evaluate_with_backfire(&@on_created_redirect_path_block)
61
+ end
62
+
63
+ on_created_redirect_path do
64
+ if Compony.comp_class_for(:show, @data)
65
+ Compony.path(:show, @data)
66
+ else
67
+ Compony.path(:index, @data)
68
+ end
69
+ end
70
+
71
+ on_create_failed do
72
+ Rails.logger.warn(@data&.errors&.full_messages)
73
+ render_standalone(controller, status: :unprocessable_entity)
74
+ end
75
+ end
76
+
77
+ # DSL method
78
+ def on_created(&block)
79
+ @on_created_block = block
80
+ end
81
+
82
+ # DSL method
83
+ def on_created_redirect_path(&block)
84
+ @on_created_redirect_path_block = block
85
+ end
86
+
87
+ # DSL method
88
+ def on_create_failed(&block)
89
+ @on_create_failed_block = block
90
+ end
91
+ end
92
+ end
93
+ end
@@ -23,6 +23,13 @@ module Compony
23
23
  }.merge(input_opts)
24
24
  return form.input @name, **opts
25
25
  end
26
+
27
+ def simpleform_input_hidden(form, _component, **input_opts)
28
+ selected_cst = form.object.send(@name)
29
+ input_opts[:input_html] ||= {}
30
+ input_opts[:input_html][:value] = selected_cst.is_a?(::Anchormodel) ? selected_cst.key : selected_cst
31
+ return form.input @name, as: :hidden, **input_opts
32
+ end
26
33
  end
27
34
  end
28
35
  end
@@ -46,6 +46,12 @@ module Compony
46
46
  return form.input @name, **input_opts
47
47
  end
48
48
 
49
+ # Used in form helper
50
+ # Given a simpleform instance, returns a suitable hidden input for thetype
51
+ def simpleform_input_hidden(form, _component, **input_opts)
52
+ return form.input @name, as: :hidden, **input_opts
53
+ end
54
+
49
55
  protected
50
56
 
51
57
  # If given a scalar, calls the block on the scalar. If given a list, calls the block on every member and joins the result with ",".
@@ -0,0 +1,13 @@
1
+ module Compony
2
+ module ModelFields
3
+ class Email < Base
4
+ def value_for(data, controller: nil, **_)
5
+ return transform_and_join(data.send(@name), controller:) do |el|
6
+ fail('Must pass controller to generate the link to the email.') unless controller
7
+ return nil unless el
8
+ return controller.helpers.mail_to(el)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Compony
2
+ module ModelFields
3
+ class Url < Base
4
+ def value_for(data, controller: nil, **_)
5
+ return transform_and_join(data.send(@name), controller:) do |el|
6
+ fail('Must pass controller to generate the link to the link.') unless controller
7
+ return nil unless el
8
+ return controller.helpers.link_to(el, el, target: '_blank', rel: 'noopener')
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -11,6 +11,13 @@ module Compony
11
11
  end
12
12
 
13
13
  class_methods do
14
+ # This hook updates all fields from a subclass, making sure that fields point to correct model classes even in STI
15
+ # e.g. in Parent: field :foo, ... omitted in child -> child.fields[:foo] should point to Child and not Parent.
16
+ def inherited(subclass)
17
+ super
18
+ subclass.fields = subclass.fields.transform_values { |f| f.class.new(f.name, subclass, **f.extra_attrs) }
19
+ end
20
+
14
21
  # DSL method, defines a new field which will be translated and can be added to field groups
15
22
  # For virtual attributes, you must pass a type explicitely, otherwise it's auto-infered.
16
23
  def field(name, type, **extra_attrs)
@@ -2,7 +2,7 @@ module Compony
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- PATCH = 3
5
+ PATCH = 5
6
6
 
7
7
  EDGE = false
8
8
 
data/lib/compony.rb CHANGED
@@ -247,6 +247,7 @@ require 'compony/model_fields/currency'
247
247
  require 'compony/model_fields/date'
248
248
  require 'compony/model_fields/datetime'
249
249
  require 'compony/model_fields/decimal'
250
+ require 'compony/model_fields/email'
250
251
  require 'compony/model_fields/float'
251
252
  require 'compony/model_fields/integer'
252
253
  require 'compony/model_fields/phone'
@@ -254,6 +255,7 @@ require 'compony/model_fields/rich_text'
254
255
  require 'compony/model_fields/string'
255
256
  require 'compony/model_fields/text'
256
257
  require 'compony/model_fields/time'
258
+ require 'compony/model_fields/url'
257
259
  require 'compony/component_mixins/default/standalone'
258
260
  require 'compony/component_mixins/default/standalone/standalone_dsl'
259
261
  require 'compony/component_mixins/default/standalone/verb_dsl'
@@ -264,9 +266,9 @@ require 'compony/component'
264
266
  require 'compony/components/button'
265
267
  require 'compony/components/form'
266
268
  require 'compony/components/with_form'
267
- require 'compony/components/resourceful/new'
268
- require 'compony/components/resourceful/edit'
269
- require 'compony/components/resourceful/destroy'
269
+ require 'compony/components/new'
270
+ require 'compony/components/edit'
271
+ require 'compony/components/destroy'
270
272
  require 'compony/method_accessible_hash'
271
273
  require 'compony/model_mixin'
272
274
  require 'compony/request_context'
@@ -3,12 +3,23 @@ class ComponentGenerator < Rails::Generators::NamedBase
3
3
 
4
4
  def add_component
5
5
  segments = name.underscore.split('/')
6
- fail('NAME must be of the form Family::ComponentName or family/component_name') if segments.size != 2
6
+ fail("NAME must be of the form Family::ComponentName or family/component_name but got #{name.inspect}") if segments.size != 2
7
7
  @family, @comp = segments
8
8
  @family = @family.pluralize # Force plural
9
9
  @family_cst = @family.camelize.pluralize # Force plural
10
10
  @comp_cst = @comp.camelize # Tolerate singular and plural
11
11
 
12
- template 'component.rb.erb', "app/components/#{@family}/#{@comp}.rb"
12
+ case @comp_cst
13
+ when 'Destroy'
14
+ template 'destroy.rb.erb', "app/components/#{@family}/#{@comp}.rb"
15
+ when 'Edit'
16
+ template 'edit.rb.erb', "app/components/#{@family}/#{@comp}.rb"
17
+ when 'Form'
18
+ template 'form.rb.erb', "app/components/#{@family}/#{@comp}.rb"
19
+ when 'New'
20
+ template 'new.rb.erb', "app/components/#{@family}/#{@comp}.rb"
21
+ else
22
+ template 'component.rb.erb', "app/components/#{@family}/#{@comp}.rb"
23
+ end
13
24
  end
14
25
  end
@@ -1,4 +1,4 @@
1
1
  class Components::<%= @family_cst %>::<%= @comp_cst %> < Compony::Component
2
2
  setup do
3
3
  end
4
- end
4
+ end
@@ -0,0 +1,2 @@
1
+ class Components::<%= @family_cst %>::<%= @comp_cst %> < Compony::Components::Destroy
2
+ end
@@ -0,0 +1,2 @@
1
+ class Components::<%= @family_cst %>::<%= @comp_cst %> < Compony::Components::Edit
2
+ end
@@ -0,0 +1,8 @@
1
+ class Components::<%= @family_cst %>::<%= @comp_cst %> < Compony::Components::Form
2
+ setup do
3
+ form_fields do
4
+ end
5
+
6
+ schema_fields
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ class Components::<%= @family_cst %>::<%= @comp_cst %> < Compony::Components::New
2
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generate the most used components for a family
3
+
4
+ Example:
5
+ bin/rails generate components Users
6
+
7
+ This will create and fill with the usual components:
8
+ app/components/users/
@@ -0,0 +1,12 @@
1
+ class ComponentsGenerator < Rails::Generators::NamedBase
2
+ source_root File.expand_path('templates', __dir__)
3
+
4
+ def add_component
5
+ @family = name.underscore.pluralize # Force plural
6
+ @family_cst = @family.camelize.pluralize # Force plural
7
+
8
+ %w[Destroy Edit Form New].each do |comp_cst|
9
+ generate "component #{name}::#{comp_cst}"
10
+ end
11
+ end
12
+ 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.0.3
4
+ version: 0.0.5
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-03-25 00:00:00.000000000 Z
12
+ date: 2023-06-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yard
@@ -182,10 +182,10 @@ files:
182
182
  - lib/compony/component_mixins/default/standalone/verb_dsl.rb
183
183
  - lib/compony/component_mixins/resourceful.rb
184
184
  - lib/compony/components/button.rb
185
+ - lib/compony/components/destroy.rb
186
+ - lib/compony/components/edit.rb
185
187
  - lib/compony/components/form.rb
186
- - lib/compony/components/resourceful/destroy.rb
187
- - lib/compony/components/resourceful/edit.rb
188
- - lib/compony/components/resourceful/new.rb
188
+ - lib/compony/components/new.rb
189
189
  - lib/compony/components/with_form.rb
190
190
  - lib/compony/controller_mixin.rb
191
191
  - lib/compony/engine.rb
@@ -199,6 +199,7 @@ files:
199
199
  - lib/compony/model_fields/date.rb
200
200
  - lib/compony/model_fields/datetime.rb
201
201
  - lib/compony/model_fields/decimal.rb
202
+ - lib/compony/model_fields/email.rb
202
203
  - lib/compony/model_fields/float.rb
203
204
  - lib/compony/model_fields/integer.rb
204
205
  - lib/compony/model_fields/phone.rb
@@ -206,6 +207,7 @@ files:
206
207
  - lib/compony/model_fields/string.rb
207
208
  - lib/compony/model_fields/text.rb
208
209
  - lib/compony/model_fields/time.rb
210
+ - lib/compony/model_fields/url.rb
209
211
  - lib/compony/model_mixin.rb
210
212
  - lib/compony/request_context.rb
211
213
  - lib/compony/version.rb
@@ -213,6 +215,12 @@ files:
213
215
  - lib/generators/component/USAGE
214
216
  - lib/generators/component/component_generator.rb
215
217
  - lib/generators/component/templates/component.rb.erb
218
+ - lib/generators/component/templates/destroy.rb.erb
219
+ - lib/generators/component/templates/edit.rb.erb
220
+ - lib/generators/component/templates/form.rb.erb
221
+ - lib/generators/component/templates/new.rb.erb
222
+ - lib/generators/components/USAGE
223
+ - lib/generators/components/components_generator.rb
216
224
  homepage:
217
225
  licenses: []
218
226
  metadata: {}
@@ -1,77 +0,0 @@
1
- module Compony
2
- module Components
3
- module Resourceful
4
- # @api description
5
- # This component is used for the Rails destroy paradigm. Asks for confirm when queried using GET.
6
- class Destroy < Compony::Component
7
- include Compony::ComponentMixins::Resourceful
8
-
9
- setup do
10
- standalone path: "#{family_name}/:id/destroy" do
11
- verb :get do
12
- authorize { can?(:destroy, @data) }
13
- end
14
-
15
- verb :delete do
16
- authorize { can?(:destroy, @data) }
17
- store_data # This enables the global store_data block defined below for this path and verb.
18
- respond do
19
- evaluate_with_backfire(&@on_destroyed_block)
20
- end
21
- end
22
- end
23
-
24
- label(:long) { |data| I18n.t('compony.components.destroy.label.long', data_label: data.label) }
25
- label(:short) { |_| I18n.t('compony.components.destroy.label.short') }
26
- icon { :trash }
27
- color { :danger }
28
-
29
- content do
30
- div I18n.t('compony.components.destroy.confirm_question', data_label: @data.label)
31
- div do
32
- concat compony_button(comp_cst,
33
- @data,
34
- label: I18n.t('compony.components.destroy.confirm_button'),
35
- method: :delete)
36
- end
37
- end
38
-
39
- store_data do
40
- # Validate params against the form's schema
41
- local_data = @data # Capture data for usage in the Schemacop call
42
- schema = Schemacop::Schema3.new :hash, additional_properties: true do
43
- if local_data.class.primary_key_type_key == :string
44
- str! :id
45
- else
46
- int! :id, cast_str: true
47
- end
48
- end
49
- schema.validate!(controller.request.params)
50
-
51
- # Perform destroy
52
- @data.destroy!
53
- end
54
-
55
- on_destroyed do
56
- flash.notice = I18n.t('compony.components.destroy.data_was_destroyed', data_label: @data.label)
57
- redirect_to evaluate_with_backfire(&@on_destroyed_redirect_path_block), status: :see_other # 303: force GET
58
- end
59
-
60
- on_destroyed_redirect_path do
61
- Compony.path(:index, family_cst)
62
- end
63
- end
64
-
65
- # DSL method
66
- def on_destroyed(&block)
67
- @on_destroyed_block = block
68
- end
69
-
70
- # DSL method
71
- def on_destroyed_redirect_path(&block)
72
- @on_destroyed_redirect_path_block = block
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1,96 +0,0 @@
1
- module Compony
2
- module Components
3
- module Resourceful
4
- # @api description
5
- # This component is used for the Rails edit and update paradigm. Performs update when the form is submitted.
6
- class Edit < Compony::Components::WithForm
7
- include Compony::ComponentMixins::Resourceful
8
- setup do
9
- submit_verb :patch
10
- standalone path: "#{family_name}/:id/edit" do
11
- verb :get do
12
- authorize { can?(:edit, @data) }
13
- assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
14
- end
15
- verb submit_verb do
16
- authorize { can?(:update, @data) }
17
- assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
18
- store_data # This enables the global store_data block defined below for this path and verb.
19
- respond do
20
- if @update_succeeded
21
- evaluate_with_backfire(&@on_updated_block)
22
- else
23
- evaluate_with_backfire(&@on_update_failed_block)
24
- end
25
- end
26
- end
27
- end
28
-
29
- label(:long) { |data| I18n.t('compony.components.edit.label.long', data_label: data.label) }
30
- label(:short) { |_| I18n.t('compony.components.edit.label.short') }
31
- icon { :pencil }
32
-
33
- content do
34
- concat form_comp.render(controller, data: @data)
35
- end
36
-
37
- assign_attributes do
38
- # Validate params against the form's schema
39
- local_form_comp = form_comp # Capture form_comp for usage in the Schemacop call
40
- local_data = @data # Capture data for usage in the Schemacop call
41
- schema = Schemacop::Schema3.new :hash, additional_properties: true do
42
- if local_data.class.primary_key_type_key == :string
43
- str! :id
44
- else
45
- int! :id, cast_str: true
46
- end
47
- hsh? local_form_comp.schema_wrapper_key_for(local_data), &local_form_comp.schema_block_for(local_data)
48
- end
49
- schema.validate!(controller.request.params)
50
-
51
- # TODO: Why are we not saving the validated params?
52
- attrs_to_assign = controller.request.params[form_comp.schema_wrapper_key_for(@data)]
53
- @data.assign_attributes(attrs_to_assign) if attrs_to_assign
54
- end
55
-
56
- store_data do
57
- @update_succeeded = @data.save
58
- end
59
-
60
- on_updated do
61
- flash.notice = I18n.t('compony.components.edit.data_was_updated', data_label: data.label)
62
- redirect_to evaluate_with_backfire(&@on_updated_redirect_path_block)
63
- end
64
-
65
- on_updated_redirect_path do
66
- if Compony.comp_class_for(:show, @data)
67
- Compony.path(:show, @data)
68
- else
69
- Compony.path(:index, @data)
70
- end
71
- end
72
-
73
- on_update_failed do
74
- Rails.logger.warn(@data&.errors&.full_messages)
75
- render_standalone(controller, status: :unprocessable_entity)
76
- end
77
- end
78
-
79
- # DSL method
80
- def on_updated(&block)
81
- @on_updated_block = block
82
- end
83
-
84
- # DSL method
85
- def on_updated_redirect_path(&block)
86
- @on_updated_redirect_path_block = block
87
- end
88
-
89
- # DSL method
90
- def on_update_failed(&block)
91
- @on_update_failed_block = block
92
- end
93
- end
94
- end
95
- end
96
- end
@@ -1,95 +0,0 @@
1
- module Compony
2
- module Components
3
- module Resourceful
4
- # @api description
5
- # This component is used for the Rails new and create paradigm. Performs update when the form is submitted.
6
- class New < Compony::Components::WithForm
7
- include Compony::ComponentMixins::Resourceful
8
-
9
- setup do
10
- submit_verb :post
11
- load_data { @data = data_class.new }
12
- standalone path: "#{family_name}/new" do
13
- verb :get do
14
- authorize { can?(:create, data_class) }
15
- assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
16
- end
17
- verb submit_verb do
18
- authorize { can?(:create, data_class) }
19
- assign_attributes # This enables the global assign_attributes block defined below for this path and verb.
20
- store_data # This enables the global store_data block defined below for this path and verb.
21
- respond do
22
- if @create_succeeded
23
- evaluate_with_backfire(&@on_created_block)
24
- else
25
- evaluate_with_backfire(&@on_create_failed_block)
26
- end
27
- end
28
- end
29
- end
30
-
31
- label(:long) { I18n.t('compony.components.new.label.long', data_class: data_class.model_name.human) }
32
- label(:short) { I18n.t('compony.components.new.label.short') }
33
- icon { :plus }
34
-
35
- add_content do
36
- h2 component.label
37
- end
38
- add_content do
39
- concat form_comp.render(controller, data: @data)
40
- end
41
-
42
- assign_attributes do
43
- local_form_comp = form_comp # Capture form_comp for usage in the Schemacop call
44
- local_data = @data # Capture data for usage in the Schemacop call
45
- schema = Schemacop::Schema3.new :hash, additional_properties: true do
46
- hsh? local_form_comp.schema_wrapper_key_for(local_data), &local_form_comp.schema_block_for(local_data)
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)]
52
- @data.assign_attributes(attrs_to_assign) if attrs_to_assign
53
- end
54
-
55
- store_data do
56
- @create_succeeded = @data.save
57
- end
58
-
59
- on_created do
60
- flash.notice = I18n.t('compony.components.new.data_was_created', data_label: data.label)
61
- redirect_to evaluate_with_backfire(&@on_created_redirect_path_block)
62
- end
63
-
64
- on_created_redirect_path do
65
- if Compony.comp_class_for(:show, @data)
66
- Compony.path(:show, @data)
67
- else
68
- Compony.path(:index, @data)
69
- end
70
- end
71
-
72
- on_create_failed do
73
- Rails.logger.warn(@data&.errors&.full_messages)
74
- render_standalone(controller, status: :unprocessable_entity)
75
- end
76
- end
77
-
78
- # DSL method
79
- def on_created(&block)
80
- @on_created_block = block
81
- end
82
-
83
- # DSL method
84
- def on_created_redirect_path(&block)
85
- @on_created_redirect_path_block = block
86
- end
87
-
88
- # DSL method
89
- def on_create_failed(&block)
90
- @on_create_failed_block = block
91
- end
92
- end
93
- end
94
- end
95
- end