action_link 0.1.1

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 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: []