resource_policy 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +20 -0
  3. data/.gitignore +15 -0
  4. data/.hound.yml +3 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +43 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +7 -0
  9. data/CHANGELOG.md +19 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/Gemfile +11 -0
  12. data/Gemfile.lock +232 -0
  13. data/LICENSE.txt +21 -0
  14. data/Rakefile +6 -0
  15. data/bin/console +14 -0
  16. data/bin/setup +8 -0
  17. data/docs/.nojekyll +0 -0
  18. data/docs/README.md +163 -0
  19. data/docs/_sidebar.md +6 -0
  20. data/docs/components/action_validator.md +34 -0
  21. data/docs/components/actions_policy.md +68 -0
  22. data/docs/components/attributes_policy.md +68 -0
  23. data/docs/components/policy.md +202 -0
  24. data/docs/index.html +70 -0
  25. data/lib/resource_policy/policy/action_policy_configuration.rb +37 -0
  26. data/lib/resource_policy/policy/actions_policy/action_policy.rb +32 -0
  27. data/lib/resource_policy/policy/actions_policy/actions_policy_model.rb +39 -0
  28. data/lib/resource_policy/policy/actions_policy.rb +35 -0
  29. data/lib/resource_policy/policy/attributes_policy/attribute_configuration.rb +72 -0
  30. data/lib/resource_policy/policy/attributes_policy/attribute_policy.rb +49 -0
  31. data/lib/resource_policy/policy/attributes_policy/attributes_policy_model.rb +52 -0
  32. data/lib/resource_policy/policy/attributes_policy.rb +58 -0
  33. data/lib/resource_policy/policy/merge_policies.rb +44 -0
  34. data/lib/resource_policy/policy/policy_configuration.rb +87 -0
  35. data/lib/resource_policy/policy.rb +31 -0
  36. data/lib/resource_policy/protected_resource.rb +43 -0
  37. data/lib/resource_policy/rails.rb +5 -0
  38. data/lib/resource_policy/validators/action_policy_validator.rb +54 -0
  39. data/lib/resource_policy/version.rb +5 -0
  40. data/lib/resource_policy.rb +11 -0
  41. data/resource_policy.gemspec +47 -0
  42. metadata +212 -0
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ module Policy
5
+ module AttributesPolicy
6
+ # Class which isolates methods defined via attributes_policy config
7
+ class AttributesPolicyModel
8
+ require 'resource_policy/policy/attributes_policy/attribute_policy'
9
+
10
+ def initialize(policy)
11
+ @policy = policy
12
+ @policy_item_by_name ||= {}
13
+ end
14
+
15
+ def all
16
+ @all ||= config.attributes.keys.map do |attribute_name|
17
+ policy_item(attribute_name)
18
+ end
19
+ end
20
+
21
+ def all_allowed_to(status)
22
+ all.select { |attribute| attribute.allowed_to?(status) }
23
+ end
24
+
25
+ def method_missing(method_name)
26
+ return super unless config.attributes.key?(method_name.to_sym)
27
+
28
+ policy_item(method_name.to_sym)
29
+ end
30
+
31
+ def respond_to_missing?(method_name, *args)
32
+ config.attributes.key?(method_name.to_sym) || super
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :policy
38
+
39
+ def config
40
+ policy.class.policy
41
+ end
42
+
43
+ def policy_item(name)
44
+ @policy_item_by_name[name] ||= begin
45
+ attribute = config.attributes.fetch(name)
46
+ AttributePolicy.new(attribute, policy: policy)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ module Policy
5
+ # Allows to define fields policy using configuration block.
6
+ #
7
+ # Usage example:
8
+ #
9
+ # class SomeModelPolicy
10
+ # include ResourcePolicy::AttributesPolicy
11
+ #
12
+ # policy do |c|
13
+ # c.attribute(:some_name)
14
+ # .allowed(:read, if: :readable?)
15
+ # .allowed(:write, if: :writable?)
16
+ #
17
+ # c.group(:current_user_is_admin?) do |g|
18
+ # g.attribute(:password).allowed(:write)
19
+ # end
20
+ # end
21
+ #
22
+ # def current_user_is_admin?
23
+ # current_user.admin?
24
+ # end
25
+ # ...
26
+ # end
27
+ #
28
+ module AttributesPolicy
29
+ require 'resource_policy/policy/attributes_policy/attributes_policy_model'
30
+
31
+ def protected_resource
32
+ @protected_resource ||= ProtectedResource.new(self)
33
+ end
34
+
35
+ def action(name)
36
+ actions_policy.public_send(name) if actions_policy.respond_to?(name)
37
+ end
38
+
39
+ def attribute(name)
40
+ attributes_policy.public_send(name) if attributes_policy.respond_to?(name)
41
+ end
42
+
43
+ def policy_target
44
+ send(self.class.policy.policy_target)
45
+ end
46
+
47
+ def attributes_policy
48
+ @attributes_policy ||= AttributesPolicyModel.new(self)
49
+ end
50
+
51
+ private
52
+
53
+ def resource_policy_initialize(*args)
54
+ @policy_target = args.first
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ module Policy
5
+ # Service object using for merging two policy configurations
6
+ class MergePolicies
7
+ class OverlappingActionError < ResourcePolicy::Error; end
8
+
9
+ def self.call(*args)
10
+ new(*args).call
11
+ end
12
+
13
+ def initialize(policy, other_policy)
14
+ @policy = policy
15
+ @other_policy = other_policy
16
+ end
17
+
18
+ def call
19
+ merge_actions
20
+ merge_attributes
21
+ policy
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :policy, :other_policy
27
+
28
+ def merge_actions
29
+ other_policy.actions.values.each do |action|
30
+ policy.action(action.name).allowed(if: action.conditions)
31
+ end
32
+ end
33
+
34
+ def merge_attributes
35
+ other_policy.attributes.values.each do |attribute|
36
+ attribute.defined_actions.each do |action_name|
37
+ conditions = attribute.conditions_for(action_name)
38
+ policy.attribute(attribute.name).allowed(action_name, if: conditions)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ module Policy
5
+ # Stores all configuration about policy
6
+ class PolicyConfiguration
7
+ require 'resource_policy/policy/action_policy_configuration'
8
+
9
+ require 'resource_policy/policy/attributes_policy/attribute_configuration'
10
+ require 'resource_policy/policy/merge_policies'
11
+
12
+ EmptyConfiguration = Class.new do
13
+ def group_conditions
14
+ []
15
+ end
16
+ end
17
+
18
+ EMPTY_CONFIGURATION = EmptyConfiguration.new
19
+
20
+ def initialize(parent_configuration: EMPTY_CONFIGURATION, extra_group_conditions: [])
21
+ @actions = {}
22
+ @attributes = {}
23
+ @parent_configuration = parent_configuration
24
+ @extra_group_conditions = extra_group_conditions
25
+ end
26
+
27
+ def initialize_copy(_other)
28
+ @actions = @actions.dup.each.with_object({}) { |(key, value), result| result[key] = value.dup }
29
+ @attributes = @attributes.dup.each.with_object({}) { |(key, value), result| result[key] = value.dup }
30
+ end
31
+
32
+ def policy_target(policy_target_name = nil)
33
+ @policy_target = policy_target_name if policy_target_name
34
+ @policy_target
35
+ end
36
+
37
+ def attribute(attribute_name)
38
+ symbolized_name = attribute_name.to_sym
39
+
40
+ @attributes[symbolized_name] ||= AttributesPolicy::AttributeConfiguration.new(
41
+ symbolized_name, policy_configuration: self
42
+ )
43
+ end
44
+
45
+ def attributes
46
+ @attributes.select { |_name, action| action.configured? }
47
+ end
48
+
49
+ def actions
50
+ @actions.select { |_name, action| action.configured? }
51
+ end
52
+
53
+ def action(attribute_name)
54
+ symbolized_name = attribute_name.to_sym
55
+
56
+ @actions[symbolized_name] ||= ActionPolicyConfiguration.new(
57
+ symbolized_name, policy_configuration: self
58
+ )
59
+ end
60
+
61
+ def group(*new_conditions)
62
+ return @group if new_conditions.empty?
63
+
64
+ unique_new_conditions = new_conditions.map(&:to_sym).uniq
65
+ group_config = self.class.new(
66
+ parent_configuration: self,
67
+ extra_group_conditions: unique_new_conditions
68
+ )
69
+
70
+ yield(group_config)
71
+ tap { |config| config.merge(group_config) }
72
+ end
73
+
74
+ def group_conditions
75
+ (parent_configuration.group_conditions + extra_group_conditions).uniq
76
+ end
77
+
78
+ def merge(other)
79
+ MergePolicies.call(self, other)
80
+ end
81
+
82
+ protected
83
+
84
+ attr_reader :extra_group_conditions, :parent_configuration
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ # Gives policy configuration methods for any policy class
5
+ module Policy
6
+ require 'resource_policy/protected_resource'
7
+ require 'resource_policy/policy/policy_configuration'
8
+ require 'resource_policy/policy/attributes_policy'
9
+ require 'resource_policy/policy/actions_policy'
10
+
11
+ # Class methods.
12
+ module ClassMethods
13
+ def policy
14
+ @policy ||= Policy::PolicyConfiguration.new
15
+ yield(@policy) if block_given?
16
+ @policy
17
+ end
18
+
19
+ def inherited(subclass)
20
+ super
21
+ subclass.instance_variable_set(:@policy, policy.dup)
22
+ end
23
+ end
24
+
25
+ def self.included(receiver)
26
+ receiver.send(:extend, ClassMethods)
27
+ receiver.send(:include, ::ResourcePolicy::Policy::ActionsPolicy)
28
+ receiver.send(:include, ::ResourcePolicy::Policy::AttributesPolicy)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ # Generates resource which has same attributes as policy target,
5
+ # but returns `nil` when attribute in not readable according to policy
6
+ class ProtectedResource
7
+ def initialize(policy)
8
+ @policy = policy
9
+ end
10
+
11
+ def method_missing(method_name, *args)
12
+ return super unless target_respond_to?(method_name, *args)
13
+ return nil unless policy.attribute(method_name).readable?
14
+
15
+ policy_target.public_send(method_name, *args)
16
+ end
17
+
18
+ def respond_to_missing?(*args)
19
+ target_respond_to?(*args) || super
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :policy
25
+
26
+ def target_respond_to?(method_name, *args)
27
+ accessible_attributes.include?(method_name.to_sym) &&
28
+ policy_target.respond_to?(method_name, *args)
29
+ end
30
+
31
+ def accessible_attributes
32
+ attributes = policy.class.policy.attributes.values.select do |attribute|
33
+ attribute.defined_action?(:read)
34
+ end
35
+
36
+ attributes.map(&:name)
37
+ end
38
+
39
+ def policy_target
40
+ policy.policy_target
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Incudes resource policy and rails specific helpers
4
+ require 'resource_policy'
5
+ require 'resource_policy/validators/action_policy_validator'
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Available options:
4
+ #
5
+ # * `:allowed_to` (required) - action type which we need to check.
6
+ # * `:as` (optional) - key which will be used to display errors.
7
+ #
8
+ # Usage example:
9
+ #
10
+ # class SomeClass
11
+ # validates :some_policy, 'resource_policy/action': { allowed_to: :create, as: :some_item }
12
+ #
13
+ # def some_policy
14
+ # SomePolicy.new
15
+ # end
16
+ # end
17
+ #
18
+ module ResourcePolicy
19
+ class ActionValidator < ActiveModel::EachValidator
20
+ def validate_each(record, default_attribute, policy)
21
+ attribute = options.fetch(:as, default_attribute)
22
+ action_policy = policy.action(action_name)
23
+ validate_action_policy(action_policy, record:, attribute:)
24
+ end
25
+
26
+ private
27
+
28
+ def validate_action_policy(policy, record:, attribute:)
29
+ if policy.nil?
30
+ add_missing_policy_error_for(record, attribute:)
31
+ elsif !policy.allowed?
32
+ add_not_permitted_error_for(record, attribute:)
33
+ end
34
+ end
35
+
36
+ def action_name
37
+ @action_name ||= options.fetch(:allowed_to)
38
+ end
39
+
40
+ def add_missing_policy_error_for(record, attribute:)
41
+ record.errors.add(
42
+ attribute,
43
+ "does not have #{action_name.to_s.inspect} action policy defined"
44
+ )
45
+ end
46
+
47
+ def add_not_permitted_error_for(record, attribute:)
48
+ record.errors.add(
49
+ attribute,
50
+ "action #{action_name.to_s.inspect} is not allowed"
51
+ )
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ResourcePolicy
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resource_policy/version'
4
+
5
+ # Root namespace
6
+ module ResourcePolicy
7
+ class Error < StandardError; end
8
+
9
+ require 'resource_policy/policy'
10
+ # Your code goes here...
11
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'resource_policy/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'resource_policy'
9
+ spec.version = ResourcePolicy::VERSION
10
+ spec.authors = ['Povilas Jurcys']
11
+ spec.email = ['po.jurcys@gmail.com']
12
+
13
+ spec.summary = "Access control for single resource and it's methods"
14
+ spec.homepage = 'https://github.com/samesystem/resource_policy'
15
+ spec.license = 'MIT'
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['homepage_uri'] = spec.homepage
21
+ spec.metadata['source_code_uri'] = 'https://github.com/samesystem/resource_policy'
22
+ spec.metadata['changelog_uri'] = \
23
+ "https://github.com/samesystem/resource_policy/blob/v#{ResourcePolicy::VERSION}/CHANGELOG.md"
24
+ else
25
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
26
+ 'public gem pushes.'
27
+ end
28
+
29
+ # Specify which files should be added to the gem when it is released.
30
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
32
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ end
34
+ spec.bindir = 'exe'
35
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ['lib']
37
+
38
+ spec.add_development_dependency 'bundler', '~> 2.0'
39
+ spec.add_development_dependency 'pry-byebug'
40
+ spec.add_development_dependency 'rake', '~> 13.0'
41
+ spec.add_development_dependency 'rspec', '~> 3.0'
42
+ spec.add_development_dependency 'rubocop'
43
+ spec.add_development_dependency 'rubocop-performance'
44
+ spec.add_development_dependency 'rubocop-rails'
45
+ spec.add_development_dependency 'rubocop-rspec'
46
+ spec.add_development_dependency 'rails', '~> 7.0.0'
47
+ end
metadata ADDED
@@ -0,0 +1,212 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resource_policy
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Povilas Jurcys
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry-byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-performance
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 7.0.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 7.0.0
139
+ description:
140
+ email:
141
+ - po.jurcys@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".github/workflows/ruby.yml"
147
+ - ".gitignore"
148
+ - ".hound.yml"
149
+ - ".rspec"
150
+ - ".rubocop.yml"
151
+ - ".ruby-version"
152
+ - ".travis.yml"
153
+ - CHANGELOG.md
154
+ - CODE_OF_CONDUCT.md
155
+ - Gemfile
156
+ - Gemfile.lock
157
+ - LICENSE.txt
158
+ - Rakefile
159
+ - bin/console
160
+ - bin/setup
161
+ - docs/.nojekyll
162
+ - docs/README.md
163
+ - docs/_sidebar.md
164
+ - docs/components/action_validator.md
165
+ - docs/components/actions_policy.md
166
+ - docs/components/attributes_policy.md
167
+ - docs/components/policy.md
168
+ - docs/index.html
169
+ - lib/resource_policy.rb
170
+ - lib/resource_policy/policy.rb
171
+ - lib/resource_policy/policy/action_policy_configuration.rb
172
+ - lib/resource_policy/policy/actions_policy.rb
173
+ - lib/resource_policy/policy/actions_policy/action_policy.rb
174
+ - lib/resource_policy/policy/actions_policy/actions_policy_model.rb
175
+ - lib/resource_policy/policy/attributes_policy.rb
176
+ - lib/resource_policy/policy/attributes_policy/attribute_configuration.rb
177
+ - lib/resource_policy/policy/attributes_policy/attribute_policy.rb
178
+ - lib/resource_policy/policy/attributes_policy/attributes_policy_model.rb
179
+ - lib/resource_policy/policy/merge_policies.rb
180
+ - lib/resource_policy/policy/policy_configuration.rb
181
+ - lib/resource_policy/protected_resource.rb
182
+ - lib/resource_policy/rails.rb
183
+ - lib/resource_policy/validators/action_policy_validator.rb
184
+ - lib/resource_policy/version.rb
185
+ - resource_policy.gemspec
186
+ homepage: https://github.com/samesystem/resource_policy
187
+ licenses:
188
+ - MIT
189
+ metadata:
190
+ homepage_uri: https://github.com/samesystem/resource_policy
191
+ source_code_uri: https://github.com/samesystem/resource_policy
192
+ changelog_uri: https://github.com/samesystem/resource_policy/blob/v1.0.0/CHANGELOG.md
193
+ post_install_message:
194
+ rdoc_options: []
195
+ require_paths:
196
+ - lib
197
+ required_ruby_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ required_rubygems_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ requirements: []
208
+ rubygems_version: 3.3.7
209
+ signing_key:
210
+ specification_version: 4
211
+ summary: Access control for single resource and it's methods
212
+ test_files: []