action_link 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1fb82eefce04018119e077392dd55980535cb21407adcb14988605f199bd3e42
4
+ data.tar.gz: ea83ec0bf21af581e71ec2a79783adb97a3e65f8fe91ef43d1ef241f1ad56232
5
+ SHA512:
6
+ metadata.gz: b1f640474051d8720d8de893567ded1129277abde85b36f07d2c2d16932dd2d7a1c7b349dd9a9c23f274f67d4892f5b68ac14427f20c930887b996546a29e214
7
+ data.tar.gz: b142f701ff7b43541fb9a5d99c98ec297e1480701b0dfeab848b243662c5c05c5abcc2c42ced17333e615380064f5a8c10e34a88d219f1436b0188aeb21c93ec
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-08-24
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 halo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # ActionLink
2
+
3
+ Intuitive ViewComponents for CRUD resource link actions in Rails.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ # In Rails view
9
+ = render ActionLink::Show.new(url: [:admin, @post], current_user:)
10
+ ```
11
+
12
+ ## Installation
13
+
14
+ Install the gem and add to the application's Gemfile by executing:
15
+
16
+ $ bundle add action_link
17
+
18
+ If bundler is not being used to manage dependencies, install the gem by executing:
19
+
20
+ $ gem install action_link
21
+
22
+ ## Development
23
+
24
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
25
+
26
+ ## Contributing
27
+
28
+ Bug reports and pull requests are welcome on GitHub at https://github.com/halo/action_link.
29
+
30
+ ## License
31
+
32
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
33
+
34
+ The icons are taken from the incredible [iconmonstr](https://iconmonstr.com/license/).
@@ -0,0 +1,9 @@
1
+ .o-acticon
2
+ font-family: 'acticons'
3
+ speak: none
4
+ font-style: normal
5
+ font-weight: normal
6
+ font-variant: normal
7
+ text-transform: none
8
+ -webkit-font-smoothing: antialiased
9
+ -moz-osx-font-smoothing: grayscale
@@ -0,0 +1,4 @@
1
+ @import ./variables
2
+ @import ./style
3
+ @import ./fonts
4
+ @import ./acticons
@@ -0,0 +1,5 @@
1
+ @font-face
2
+ font-family: 'acticons'
3
+ font-weight: normal
4
+ font-style: normal
5
+ src: url('action_link/acticons.woff') format('woff')
@@ -0,0 +1,42 @@
1
+ // This file is autogenerated by `rake acticons:update`
2
+
3
+ .o-acticon--info-circle {
4
+ &:before {
5
+ content: $o-acticon--info-circle;
6
+ }
7
+ }
8
+ .o-acticon--questionmark {
9
+ &:before {
10
+ content: $o-acticon--questionmark;
11
+ }
12
+ }
13
+ .o-acticon--arrow-down-circle {
14
+ &:before {
15
+ content: $o-acticon--arrow-down-circle;
16
+ }
17
+ }
18
+ .o-acticon--pencil-circle {
19
+ &:before {
20
+ content: $o-acticon--pencil-circle;
21
+ }
22
+ }
23
+ .o-acticon--check-circle {
24
+ &:before {
25
+ content: $o-acticon--check-circle;
26
+ }
27
+ }
28
+ .o-acticon--chevron-circle-right {
29
+ &:before {
30
+ content: $o-acticon--chevron-circle-right;
31
+ }
32
+ }
33
+ .o-acticon--plus-circle {
34
+ &:before {
35
+ content: $o-acticon--plus-circle;
36
+ }
37
+ }
38
+ .o-acticon--times-circle {
39
+ &:before {
40
+ content: $o-acticon--times-circle;
41
+ }
42
+ }
@@ -0,0 +1,10 @@
1
+ // This file is autogenerated by `rake acticons:update`
2
+
3
+ $o-acticon--info-circle: "\e907";
4
+ $o-acticon--questionmark: "\2753";
5
+ $o-acticon--arrow-down-circle: "\e9af";
6
+ $o-acticon--pencil-circle: "\e9ae";
7
+ $o-acticon--check-circle: "\e93b";
8
+ $o-acticon--chevron-circle-right: "\e928";
9
+ $o-acticon--plus-circle: "\e919";
10
+ $o-acticon--times-circle: "\e91a";
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # A component that every other component inherits from in this gem.
5
+ # It adds convenience methods for initialization of a component.
6
+ class ApplicationComponent < ViewComponent::Base
7
+ extend Dry::Initializer
8
+
9
+ # By default, Dry::Initializer doesn't complain about invalid arguments.
10
+ # We want it to raise an error.
11
+ def initialize(...)
12
+ __check_for_unknown_options(...)
13
+ super
14
+ end
15
+
16
+ private
17
+
18
+ def __check_for_unknown_options(*args, **kwargs)
19
+ return if __defined_options.empty?
20
+
21
+ # Checking params
22
+ opts = args.drop(__defined_params.length).first || kwargs
23
+ raise ArgumentError, "Unexpected argument #{opts}" unless opts.is_a? Hash
24
+
25
+ # Checking options
26
+ unknown_options = opts.keys - __defined_options
27
+ message = "Key(s) #{unknown_options} not found in #{__defined_options}"
28
+ raise KeyError, message if unknown_options.any?
29
+ end
30
+
31
+ def __defined_options
32
+ self.class.dry_initializer.options.map(&:source)
33
+ end
34
+
35
+ def __defined_params
36
+ self.class.dry_initializer.params.map(&:source)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # A component that every action link inherits from.
5
+ # It adds the API that all action links have in common.
6
+ class Base < ApplicationComponent
7
+ # The following options are common for all subclasses.
8
+
9
+ # Authorization
10
+ option :current_user # User passed to the policy
11
+ option :policy_library, as: :manual_policy_library, default: -> {}
12
+ option :policy_subject, as: :manual_policy_subject, default: -> {} # Record passed to the policy
13
+
14
+ # Visualization
15
+ option :icon, default: -> {}
16
+
17
+ # The following options may vary for different subclasses.
18
+ # Here, in the superclass, they're all defined as optional.
19
+ option :class, as: :css_class, default: -> {}
20
+ option :data, default: -> {}
21
+ option :model, as: :manual_model, default: -> {}
22
+ option :i18n_model, as: :manual_i18n_model, default: -> {}
23
+ option :title, as: :manual_title, default: -> {}
24
+ option :url, default: -> {}
25
+
26
+ def permission?
27
+ _policy.public_send(:"#{_action}?")
28
+ end
29
+
30
+ # Allows you to turn off the icon.
31
+ def icon?
32
+ icon != false
33
+ end
34
+
35
+ def icon_tag(name)
36
+ helpers.content_tag :i, nil,
37
+ class: "o-acticon o-acticon--#{name}"
38
+ end
39
+
40
+ def options
41
+ {
42
+ title: _title,
43
+ class: _class,
44
+ data: _data,
45
+ target: _target,
46
+ method: http_method
47
+ }
48
+ end
49
+
50
+ private
51
+
52
+ # May be accessed and/or overriden in subclasses
53
+
54
+ def i18n_title_key
55
+ "action_link_component.titles.#{_action}"
56
+ end
57
+
58
+ def http_method; end
59
+ def confirmation; end
60
+
61
+ def default_confirmation_subject
62
+ _title_subject_name
63
+ end
64
+
65
+ # Below this point, strictly internal to this superclass.
66
+ # If you find yourself overwriting any of these methods, question the concept.
67
+ # Don't call these methods from the view, either.
68
+
69
+ # Options for `link_to`
70
+
71
+ def _title
72
+ t(i18n_title_key, subject: strip_tags(_title_subject_name))
73
+ end
74
+
75
+ def _data
76
+ (data || {}).merge(confirm: confirmation)
77
+ end
78
+
79
+ def _class
80
+ ['c-action-link', css_class].join(' ').squish
81
+ end
82
+
83
+ def _target
84
+ :_blank if url.to_s.start_with?('http:') || url.to_s.start_with?('https:')
85
+ end
86
+
87
+ def _additional_data
88
+ { confirm: confirmation }
89
+ end
90
+
91
+ # Helpers
92
+
93
+ def _model
94
+ @_model ||= ::ActionLink::Model.call(manual_model:, url:)
95
+ end
96
+
97
+ # Converts a class like `::ActionLink::New` to the symbol `:new`.
98
+ def _action
99
+ @_action ||= self.class.name[12..].underscore.to_sym
100
+ end
101
+
102
+ def _title_subject_name
103
+ @_title_subject_name ||= ::ActionLink::TitleSubjectName.call(
104
+ manual_title:,
105
+ manual_i18n_model:,
106
+ model: _model
107
+ )
108
+ end
109
+
110
+ def _policy_subject
111
+ manual_policy_subject ||
112
+ _model ||
113
+ raise("Expected a policy subject #{self}")
114
+ end
115
+
116
+ def _policy_library
117
+ manual_policy_library || :auto
118
+ end
119
+
120
+ def _policy
121
+ if (_policy_library == :auto && defined?(::ActionPolicy)) || _policy_library == :action_policy
122
+ _policy_from_action_policy
123
+ elsif (_policy_library == :auto && defined?(::Pundit)) || _policy_library == :pundit
124
+ _policy_from_pundit
125
+ else
126
+ raise 'Implement me in a sane way, once it is actually needed'
127
+ end
128
+ end
129
+
130
+ def _policy_from_action_policy
131
+ ::ActionPolicy.lookup(_policy_subject).new(_policy_subject, user: current_user)
132
+ end
133
+
134
+ def _policy_from_pundit
135
+ ::Pundit.policy!(current_user, _policy_subject)
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # An action link that indicates deleting a new record.
5
+ class Destroy < Base
6
+ ICON = 'times-circle'
7
+
8
+ erb_template <<~ERB.gsub("\n", '')
9
+ <% if permission? %>
10
+ <%= link_to(url, **options) do %>
11
+ <%= content %>
12
+ <% if icon? %><%= ' ' %><%= icon_tag ::ActionLink::Destroy::ICON %><% end %>
13
+ <% end %>
14
+ <% else %>
15
+ <%= content %>
16
+ <% end %>
17
+ ERB
18
+
19
+ option :url
20
+ option :confirmation, as: :manual_confirmation, default: -> {}
21
+ option :confirmation_subject, default: -> {}
22
+ option :associative, default: -> { false }
23
+
24
+ def i18n_title_key
25
+ return 'action_link_component.titles.unassign' if associative
26
+
27
+ super
28
+ end
29
+
30
+ def confirmation
31
+ return manual_confirmation if manual_confirmation
32
+
33
+ I18n.t(i18n_confirmation_key,
34
+ subject: strip_tags(confirmation_subject || default_confirmation_subject))
35
+ end
36
+
37
+ def http_method
38
+ :delete
39
+ end
40
+
41
+ private
42
+
43
+ def i18n_confirmation_key
44
+ if associative
45
+ 'action_link_component.confirmations.unassign'
46
+ else
47
+ 'action_link_component.confirmations.destroy'
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # An action link that indicates editing an existing record.
5
+ class Edit < Base
6
+ ICON = 'pencil-circle'
7
+
8
+ erb_template <<~ERB.gsub("\n", '')
9
+ <% if permission? %>
10
+ <%= link_to(url, **options) do %>
11
+ <%= content %>
12
+ <% if icon? %><%= ' ' %><%= icon_tag ::ActionLink::Edit::ICON %><% end %>
13
+ <% end %>
14
+ <% else %>
15
+ <%= content %>
16
+ <% end %>
17
+ ERB
18
+
19
+ option :url
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # An action link that indicates adding a new record.
5
+ class New < Base
6
+ ICON = 'plus-circle'
7
+
8
+ erb_template <<~ERB.gsub("\n", '')
9
+ <% if permission? %>
10
+ <%= link_to(url, **options) do %>
11
+ <%= content %>
12
+ <% if icon? %><%= ' ' %><%= icon_tag ::ActionLink::New::ICON %><% end %>
13
+ <% end %>
14
+ <% else %>
15
+ <%= content %>
16
+ <% end %>
17
+ ERB
18
+
19
+ # `model:` is mandatory because `[:new, :admin, Klass]` would
20
+ # translate to the route `[:new, :admin, :klasses]` and that's incorrect (plural vs singular).
21
+ option :model, as: :manual_model
22
+ option :url
23
+ option :associative, default: -> { false }
24
+
25
+ def i18n_title_key
26
+ return 'action_link_component.titles.assign' if associative
27
+
28
+ super
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # An action link that indicates showing an existing record.
5
+ class Show < Base
6
+ ICON = 'chevron-circle-right'
7
+
8
+ erb_template <<~ERB.gsub("\n", '')
9
+ <% if permission? %>
10
+ <%= link_to(url, **options) do %>
11
+ <%= content %>
12
+ <% if icon? %><%= ' ' %><%= icon_tag ::ActionLink::Show::ICON %><% end %>
13
+ <% end %>
14
+ <% else %>
15
+ <%= content %>
16
+ <% end %>
17
+ ERB
18
+
19
+ option :url
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ de:
2
+ action_link_component:
3
+ confirmations:
4
+ destroy: "Möchtest du %{subject} löschen?"
5
+ unassign: "Möchtest du %{subject} entkoppeln? Bei dieser Aktion wird nichts gelöscht."
6
+ titles:
7
+ assign: "%{subject} zuweisen"
8
+ destroy: "%{subject} löschen"
9
+ edit: "%{subject} bearbeiten"
10
+ new: "%{subject} anlegen"
11
+ show: "%{subject} anzeigen"
12
+ unassign: "%{subject} entkoppeln"
@@ -0,0 +1,12 @@
1
+ en:
2
+ action_link_component:
3
+ confirmations:
4
+ destroy: "Would you like to delete %{subject}?"
5
+ unassign: "Would you like to unassign %{subject}? This action does not delete."
6
+ titles:
7
+ assign: "Assign %{subject}"
8
+ destroy: "Delete %{subject}"
9
+ edit: "Edit %{subject}"
10
+ new: Add %{subject}
11
+ show: "Show %{subject}"
12
+ unassign: "Unassign %{subject}"
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/engine'
4
+ require 'dry-initializer'
5
+
6
+ module ActionLink
7
+ # :nodoc:
8
+ class Engine < ::Rails::Engine
9
+ isolate_namespace ActionLink
10
+
11
+ config.to_prepare do
12
+ # Our ActionLink components are subclasses of `ViewComponent::Base`.
13
+ # When `ViewComponent::Base` is subclassed, two things happen:
14
+ #
15
+ # 1. Rails routes are included into the component
16
+ # 2. The ViewComponent configuration is accessed
17
+ #
18
+ # So we can only require our components, once Rails has booted
19
+ # AND the view_component gem has been fully initialized (configured).
20
+ #
21
+ # That's right here and now.
22
+ require_relative '../../app/components/action_link/application_component'
23
+ require_relative '../../app/components/action_link/base'
24
+ require_relative '../../app/components/action_link/destroy'
25
+ require_relative '../../app/components/action_link/edit'
26
+ require_relative '../../app/components/action_link/new'
27
+ require_relative '../../app/components/action_link/show'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # Extracts a model from the provided model options.
5
+ class Model
6
+ include Calls
7
+
8
+ option :manual_model
9
+ option :url
10
+
11
+ def call
12
+ model.respond_to?(:model_name) ||
13
+ raise(MissingModelError, "Model `#{model.inspect}` must respond to #model_name")
14
+
15
+ model
16
+ end
17
+
18
+ private
19
+
20
+ def model
21
+ return manual_model if manual_model
22
+
23
+ url.last if url.is_a?(Array)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ # Extracts a model from the provided i18n options.
5
+ class TitleSubjectName
6
+ include Calls
7
+
8
+ option :manual_title
9
+ option :manual_i18n_model
10
+ option :model
11
+
12
+ def call
13
+ manual_title || compliant_model.model_name.human
14
+ end
15
+
16
+ private
17
+
18
+ def compliant_model
19
+ compliant_manual_model || model
20
+ end
21
+
22
+ def compliant_manual_model
23
+ return unless manual_i18n_model
24
+ return manual_i18n_model if manual_i18n_model.respond_to?(:model_name)
25
+
26
+ raise ArgumentError,
27
+ "Expected `i18n_model:` `#{manual_i18n_model.inspect}` to respond to `#model_name`"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionLink
4
+ VERSION = '0.1.1'
5
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/initializer'
4
+ require 'calls'
5
+
6
+ require 'action_link/version'
7
+ require 'action_link/model'
8
+ require 'action_link/title_subject_name'
9
+
10
+ require 'action_link/engine' if defined?(Rails::Engine)
11
+
12
+ module ActionLink
13
+ class Error < ::StandardError; end
14
+ class MissingModelError < Error; end
15
+ class SubclassNameError < Error; end
16
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_link
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - halo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-06-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionview
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: calls
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-initializer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: view_component
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Every action has an icon, such as a "plus-sign" for the "new" action
70
+ email:
71
+ - github@posteo.org
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - CHANGELOG.md
77
+ - LICENSE.txt
78
+ - README.md
79
+ - app/assets/fonts/action_link/acticons.woff
80
+ - app/assets/stylesheets/action_link/acticons.sass
81
+ - app/assets/stylesheets/action_link/all.sass
82
+ - app/assets/stylesheets/action_link/fonts.sass
83
+ - app/assets/stylesheets/action_link/style.scss
84
+ - app/assets/stylesheets/action_link/variables.scss
85
+ - app/components/action_link/application_component.rb
86
+ - app/components/action_link/base.rb
87
+ - app/components/action_link/destroy.rb
88
+ - app/components/action_link/edit.rb
89
+ - app/components/action_link/new.rb
90
+ - app/components/action_link/show.rb
91
+ - config/locales/action_link_component.de.yml
92
+ - config/locales/action_link_component.en.yml
93
+ - lib/action_link.rb
94
+ - lib/action_link/engine.rb
95
+ - lib/action_link/model.rb
96
+ - lib/action_link/title_subject_name.rb
97
+ - lib/action_link/version.rb
98
+ homepage: https://github.com/halo/action_link
99
+ licenses:
100
+ - MIT
101
+ metadata:
102
+ homepage_uri: https://github.com/halo/action_link
103
+ source_code_uri: https://github.com/halo/action_link
104
+ changelog_uri: https://github.com/halo/halo/blob/main/CHANGELOG.md
105
+ rubygems_mfa_required: 'true'
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 3.2.0
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubygems_version: 3.5.6
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: A set of ViewComponents for common links (show, edit, delete, etc.)
125
+ test_files: []