cancancan 3.0.0 → 3.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77676f7b21c8e3000fc960cf841b10bc2e41b46d0131928683411b1aa44f8d3a
4
- data.tar.gz: b14fb24388906a0e6309fbc3f5f729aa222f9b9bac4bc8fc7388c62d642047f8
3
+ metadata.gz: d109d94a089119e1183b6ed77e78316e212b3d78506b8ed10aabb1e8e0e090ce
4
+ data.tar.gz: '09d6acb72b55c2892be6d7c614bbf9a55b4f60ca3eee1e6aa898e1213e0e807d'
5
5
  SHA512:
6
- metadata.gz: 7a35baf8436bac8174101d920996e1680249e9dfb8040035ec5a3a770938d1257c12047cdcc3c3d408900e32f1bf5e366f8c4d4d524fe9b8a4c31823369b9269
7
- data.tar.gz: bd6472ac5d5adb531146f7af7c374f0e7c996d01797a4d39e8b8da94a597bc4e66586f810382186a58cb95fd1412ba6d0a04007b1706162b22167b66407f1666
6
+ metadata.gz: c708dbbefc7a0d120cf9dbacb3d478e2a6155dbb72800563be83b2fced563118b79454a6d9f6eb372bad88f7c4835ebefa636058d055f161b395a6076d154781
7
+ data.tar.gz: 269ff0d42f16aff0db8882473364fee508504c5f8dd5e4e8d271810d7420e76bebf3c64a16b58a81ed2754e9b1c7fdb9f576c5bc3804c6d26d5b19386e3e9f8e
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cancan/version'
4
+ require 'cancan/config'
4
5
  require 'cancan/parameter_validators'
5
6
  require 'cancan/ability'
6
7
  require 'cancan/rule'
@@ -16,6 +17,7 @@ require 'cancan/rules_compressor'
16
17
  if defined? ActiveRecord
17
18
  require 'cancan/model_adapters/conditions_extractor'
18
19
  require 'cancan/model_adapters/conditions_normalizer'
20
+ require 'cancan/model_adapters/sti_normalizer'
19
21
  require 'cancan/model_adapters/active_record_adapter'
20
22
  require 'cancan/model_adapters/active_record_4_adapter'
21
23
  require 'cancan/model_adapters/active_record_5_adapter'
@@ -302,7 +302,11 @@ module CanCan
302
302
 
303
303
  def alternative_subjects(subject)
304
304
  subject = subject.class unless subject.is_a?(Module)
305
- [:all, *subject.ancestors, subject.class.to_s]
305
+ if subject.respond_to?(:subclasses) && defined?(ActiveRecord::Base) && subject < ActiveRecord::Base
306
+ [:all, *(subject.ancestors + subject.subclasses), subject.class.to_s]
307
+ else
308
+ [:all, *subject.ancestors, subject.class.to_s]
309
+ end
306
310
  end
307
311
  end
308
312
  end
@@ -0,0 +1,26 @@
1
+ # This class is responsible for matching classes and their subclasses as well as
2
+ # upmatching classes to their ancestors.
3
+ # This is used to generate sti connections
4
+ class SubjectClassMatcher
5
+ def self.matches_subject_class?(subjects, subject)
6
+ subjects.any? do |sub|
7
+ has_subclasses = subject.respond_to?(:subclasses)
8
+ matching_class_check(subject, sub, has_subclasses)
9
+ end
10
+ end
11
+
12
+ def self.matching_class_check(subject, sub, has_subclasses)
13
+ matches = matches_class_or_is_related(subject, sub)
14
+ if has_subclasses
15
+ matches || subject.subclasses.include?(sub)
16
+ else
17
+ matches
18
+ end
19
+ end
20
+
21
+ def self.matches_class_or_is_related(subject, sub)
22
+ sub.is_a?(Module) && (subject.is_a?(sub) ||
23
+ subject.class.to_s == sub.to_s ||
24
+ (subject.is_a?(Module) && subject.ancestors.include?(sub)))
25
+ end
26
+ end
@@ -21,7 +21,7 @@ module CanCan
21
21
  def matches_block_conditions(subject, *extra_args)
22
22
  return @base_behavior if subject_class?(subject)
23
23
 
24
- @block.call(subject, *extra_args)
24
+ @block.call(subject, *extra_args.compact)
25
25
  end
26
26
 
27
27
  def matches_non_block_conditions(subject)
@@ -78,7 +78,7 @@ module CanCan
78
78
 
79
79
  def hash_condition_match?(attribute, value)
80
80
  if attribute.is_a?(Array) || (defined?(ActiveRecord) && attribute.is_a?(ActiveRecord::Relation))
81
- attribute.any? { |element| matches_conditions_hash?(element, value) }
81
+ attribute.to_a.any? { |element| matches_conditions_hash?(element, value) }
82
82
  else
83
83
  attribute && matches_conditions_hash?(attribute, value)
84
84
  end
@@ -97,7 +97,10 @@ module CanCan
97
97
  end
98
98
 
99
99
  def conditions_empty?
100
- @conditions == {} || @conditions.nil?
100
+ # @conditions might be an ActiveRecord::Associations::CollectionProxy
101
+ # which it's `==` implementation will fetch all records for comparison
102
+
103
+ (@conditions.is_a?(Hash) && @conditions == {}) || @conditions.nil?
101
104
  end
102
105
  end
103
106
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ def self.valid_accessible_by_strategies
5
+ strategies = [:left_join]
6
+ strategies << :subquery unless does_not_support_subquery_strategy?
7
+ strategies
8
+ end
9
+
10
+ # Determines how CanCan should build queries when calling accessible_by,
11
+ # if the query will contain a join. The default strategy is `:subquery`.
12
+ #
13
+ # # config/initializers/cancan.rb
14
+ # CanCan.accessible_by_strategy = :subquery
15
+ #
16
+ # Valid strategies are:
17
+ # - :subquery - Creates a nested query with all joins, wrapped by a
18
+ # WHERE IN query.
19
+ # - :left_join - Calls the joins directly using `left_joins`, and
20
+ # ensures records are unique using `distinct`. Note that
21
+ # `distinct` is not reliable in some cases. See
22
+ # https://github.com/CanCanCommunity/cancancan/pull/605
23
+ def self.accessible_by_strategy
24
+ @accessible_by_strategy || default_accessible_by_strategy
25
+ end
26
+
27
+ def self.default_accessible_by_strategy
28
+ if does_not_support_subquery_strategy?
29
+ # see https://github.com/CanCanCommunity/cancancan/pull/655 for where this was added
30
+ # the `subquery` strategy (from https://github.com/CanCanCommunity/cancancan/pull/619
31
+ # only works in Rails 5 and higher
32
+ :left_join
33
+ else
34
+ :subquery
35
+ end
36
+ end
37
+
38
+ def self.accessible_by_strategy=(value)
39
+ unless valid_accessible_by_strategies.include?(value)
40
+ raise ArgumentError, "accessible_by_strategy must be one of #{valid_accessible_by_strategies.join(', ')}"
41
+ end
42
+
43
+ if value == :subquery && does_not_support_subquery_strategy?
44
+ raise ArgumentError, 'accessible_by_strategy = :subquery requires ActiveRecord 5 or newer'
45
+ end
46
+
47
+ @accessible_by_strategy = value
48
+ end
49
+
50
+ def self.does_not_support_subquery_strategy?
51
+ !defined?(CanCan::ModelAdapters::ActiveRecordAdapter) ||
52
+ CanCan::ModelAdapters::ActiveRecordAdapter.version_lower?('5.0.0')
53
+ end
54
+ end
@@ -58,5 +58,13 @@ module CanCan
58
58
  def to_s
59
59
  @message || @default_message
60
60
  end
61
+
62
+ def inspect
63
+ details = %i[action subject conditions message].map do |attribute|
64
+ value = instance_variable_get "@#{attribute}"
65
+ "#{attribute}: #{value.inspect}" if value.present?
66
+ end.compact.join(', ')
67
+ "#<#{self.class.name} #{details}>"
68
+ end
61
69
  end
62
70
  end
@@ -5,7 +5,7 @@ module CanCan
5
5
  class AbstractAdapter
6
6
  def self.inherited(subclass)
7
7
  @subclasses ||= []
8
- @subclasses << subclass
8
+ @subclasses.insert(0, subclass)
9
9
  end
10
10
 
11
11
  def self.adapter_class(model_class)
@@ -34,10 +34,8 @@ module CanCan
34
34
  # look inside the where clause to decide to outer join tables
35
35
  # you're using in the where. Instead, `references()` is required
36
36
  # in addition to `includes()` to force the outer join.
37
- def build_relation(*where_conditions)
38
- relation = @model_class.where(*where_conditions)
39
- relation = relation.includes(joins).references(joins) if joins.present?
40
- relation
37
+ def build_joins_relation(relation, *_where_conditions)
38
+ relation.includes(joins).references(joins)
41
39
  end
42
40
 
43
41
  # Rails 4.2 deprecates `sanitize_sql_hash_for_conditions`
@@ -21,13 +21,19 @@ module CanCan
21
21
 
22
22
  private
23
23
 
24
- def build_relation(*where_conditions)
25
- relation = @model_class.where(*where_conditions)
26
- relation = relation.left_joins(joins).distinct if joins.present?
27
- relation
24
+ def build_joins_relation(relation, *where_conditions)
25
+ case CanCan.accessible_by_strategy
26
+ when :subquery
27
+ inner = @model_class.unscoped do
28
+ @model_class.left_joins(joins).where(*where_conditions)
29
+ end
30
+ @model_class.where(@model_class.primary_key => inner)
31
+
32
+ when :left_join
33
+ relation.left_joins(joins).distinct
34
+ end
28
35
  end
29
36
 
30
- # Rails 4.2 deprecates `sanitize_sql_hash_for_conditions`
31
37
  def sanitize_sql(conditions)
32
38
  if conditions.is_a?(Hash)
33
39
  sanitize_sql_activerecord5(conditions)
@@ -41,11 +47,7 @@ module CanCan
41
47
  table_metadata = ActiveRecord::TableMetadata.new(@model_class, table)
42
48
  predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata)
43
49
 
44
- conditions = predicate_builder.resolve_column_aliases(conditions)
45
-
46
- conditions.stringify_keys!
47
-
48
- predicate_builder.build_from_hash(conditions).map { |b| visit_nodes(b) }.join(' AND ')
50
+ predicate_builder.build_from_hash(conditions.stringify_keys).map { |b| visit_nodes(b) }.join(' AND ')
49
51
  end
50
52
 
51
53
  def visit_nodes(node)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'conditions_extractor.rb'
4
- require 'cancan/rules_compressor'
5
3
  module CanCan
6
4
  module ModelAdapters
7
5
  class ActiveRecordAdapter < AbstractAdapter
@@ -16,6 +14,7 @@ module CanCan
16
14
  def initialize(model_class, rules)
17
15
  super
18
16
  @compressed_rules = RulesCompressor.new(@rules.reverse).rules_collapsed.reverse
17
+ StiNormalizer.normalize(@compressed_rules)
19
18
  ConditionsNormalizer.normalize(model_class, @compressed_rules)
20
19
  end
21
20
 
@@ -60,6 +59,14 @@ module CanCan
60
59
  end
61
60
  end
62
61
 
62
+ def build_relation(*where_conditions)
63
+ relation = @model_class.where(*where_conditions)
64
+ return relation unless joins.present?
65
+
66
+ # subclasses must implement `build_joins_relation`
67
+ build_joins_relation(relation, *where_conditions)
68
+ end
69
+
63
70
  # Returns the associations used in conditions for the :joins option of a search.
64
71
  # See ModelAdditions#accessible_by
65
72
  def joins
@@ -31,7 +31,7 @@ module CanCan
31
31
  raise WrongAssociationName, "Association '#{key}' not defined in model '#{model_class.name}'"
32
32
  end
33
33
 
34
- if reflection.options[:through].present?
34
+ if normalizable_association? reflection
35
35
  key = reflection.options[:through]
36
36
  value = { reflection.source_reflection_name => value }
37
37
  reflection = model_class.reflect_on_association(key)
@@ -39,6 +39,10 @@ module CanCan
39
39
 
40
40
  { key => normalize_conditions(reflection.klass.name.constantize, value) }
41
41
  end
42
+
43
+ def normalizable_association?(reflection)
44
+ reflection.options[:through].present? && !reflection.options[:source_type].present?
45
+ end
42
46
  end
43
47
  end
44
48
  end
@@ -0,0 +1,39 @@
1
+ # this class is responsible for detecting sti classes and creating new rules for the
2
+ # relevant subclasses, using the inheritance_column as a merger
3
+ module CanCan
4
+ module ModelAdapters
5
+ class StiNormalizer
6
+ class << self
7
+ def normalize(rules)
8
+ rules_cache = []
9
+ return unless defined?(ActiveRecord::Base)
10
+
11
+ rules.delete_if do |rule|
12
+ subjects = rule.subjects.select do |subject|
13
+ update_rule(subject, rule, rules_cache)
14
+ end
15
+ subjects.length == rule.subjects.length
16
+ end
17
+ rules_cache.each { |rule| rules.push(rule) }
18
+ end
19
+
20
+ private
21
+
22
+ def update_rule(subject, rule, rules_cache)
23
+ return false unless subject.respond_to?(:descends_from_active_record?)
24
+ return false if subject == :all || subject.descends_from_active_record?
25
+ return false unless subject < ActiveRecord::Base
26
+
27
+ rules_cache.push(build_rule_for_subclass(rule, subject))
28
+ true
29
+ end
30
+
31
+ # create a new rule for the subclasses that links on the inheritance_column
32
+ def build_rule_for_subclass(rule, subject)
33
+ CanCan::Rule.new(rule.base_behavior, rule.actions, subject.superclass,
34
+ rule.conditions.merge(subject.inheritance_column => subject.name), rule.block)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module Relevant
5
+ # Matches both the action, subject, and attribute, not necessarily the conditions
6
+ def relevant?(action, subject)
7
+ subject = subject.values.first if subject.class == Hash
8
+ @match_all || (matches_action?(action) && matches_subject?(subject))
9
+ end
10
+
11
+ private
12
+
13
+ def matches_action?(action)
14
+ @expanded_actions.include?(:manage) || @expanded_actions.include?(action)
15
+ end
16
+
17
+ def matches_subject?(subject)
18
+ @subjects.include?(:all) || @subjects.include?(subject) || matches_subject_class?(subject)
19
+ end
20
+
21
+ def matches_subject_class?(subject)
22
+ @subjects.any? do |sub|
23
+ sub.is_a?(Module) && (subject.is_a?(sub) ||
24
+ subject.class.to_s == sub.to_s ||
25
+ (subject.is_a?(Module) && subject.ancestors.include?(sub)))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'conditions_matcher.rb'
4
+ require_relative 'class_matcher.rb'
5
+ require_relative 'relevant.rb'
6
+
4
7
  module CanCan
5
8
  # This class is used internally and should only be called through Ability.
6
9
  # it holds the information about a "can" call made on Ability and provides
7
10
  # helpful methods to determine permission checking and conditions hash generation.
8
11
  class Rule # :nodoc:
9
12
  include ConditionsMatcher
13
+ include Relevant
10
14
  include ParameterValidators
11
- attr_reader :base_behavior, :subjects, :actions, :conditions, :attributes
15
+ attr_reader :base_behavior, :subjects, :actions, :conditions, :attributes, :block
12
16
  attr_writer :expanded_actions, :conditions
13
17
 
14
18
  # The first argument when initializing is the base_behavior which is a true/false
@@ -24,9 +28,9 @@ module CanCan
24
28
  raise Error, "Subject is required for #{action}" if action && subject.nil?
25
29
 
26
30
  @base_behavior = base_behavior
27
- @actions = Array(action)
28
- @subjects = Array(subject)
29
- @attributes = Array(attributes)
31
+ @actions = wrap(action)
32
+ @subjects = wrap(subject)
33
+ @attributes = wrap(attributes)
30
34
  @conditions = extra_args || {}
31
35
  @block = block
32
36
  end
@@ -34,11 +38,13 @@ module CanCan
34
38
  def inspect
35
39
  repr = "#<#{self.class.name}"
36
40
  repr += "#{@base_behavior ? 'can' : 'cannot'} #{@actions.inspect}, #{@subjects.inspect}, #{@attributes.inspect}"
37
- repr += if with_scope?
38
- ", #{@conditions.where_values_hash}"
39
- elsif [Hash, String].include?(@conditions.class)
40
- ", #{@conditions.inspect}"
41
- end
41
+
42
+ if with_scope?
43
+ repr += ", #{@conditions.where_values_hash}"
44
+ elsif [Hash, String].include?(@conditions.class)
45
+ repr += ", #{@conditions.inspect}"
46
+ end
47
+
42
48
  repr + '>'
43
49
  end
44
50
 
@@ -55,12 +61,6 @@ module CanCan
55
61
  (!with_scope? && [nil, false, [], {}, '', ' '].include?(@conditions))
56
62
  end
57
63
 
58
- # Matches both the action, subject, and attribute, not necessarily the conditions
59
- def relevant?(action, subject)
60
- subject = subject.values.first if subject.class == Hash
61
- @match_all || (matches_action?(action) && matches_subject?(subject))
62
- end
63
-
64
64
  def only_block?
65
65
  conditions_empty? && @block
66
66
  end
@@ -111,11 +111,7 @@ module CanCan
111
111
  end
112
112
 
113
113
  def matches_subject_class?(subject)
114
- @subjects.any? do |sub|
115
- sub.is_a?(Module) && (subject.is_a?(sub) ||
116
- subject.class.to_s == sub.to_s ||
117
- (subject.is_a?(Module) && subject.ancestors.include?(sub)))
118
- end
114
+ SubjectClassMatcher.matches_subject_class?(@subjects, subject)
119
115
  end
120
116
 
121
117
  def parse_attributes_from_extra_args(args)
@@ -130,5 +126,15 @@ module CanCan
130
126
  raise BlockAndConditionsError, 'A hash of conditions is mutually exclusive with a block. '\
131
127
  "Check \":#{action} #{subject}\" ability."
132
128
  end
129
+
130
+ def wrap(object)
131
+ if object.nil?
132
+ []
133
+ elsif object.respond_to?(:to_ary)
134
+ object.to_ary || [object]
135
+ else
136
+ [object]
137
+ end
138
+ end
133
139
  end
134
140
  end
@@ -3,10 +3,12 @@
3
3
  module CanCan
4
4
  module UnauthorizedMessageResolver
5
5
  def unauthorized_message(action, subject)
6
+ subject = subject.values.last if subject.is_a?(Hash)
6
7
  keys = unauthorized_message_keys(action, subject)
7
- variables = { action: action.to_s }
8
+ variables = {}
9
+ variables[:action] = I18n.translate("actions.#{action}", default: action.to_s)
8
10
  variables[:subject] = translate_subject(subject)
9
- message = I18n.translate(keys.shift, variables.merge(scope: :unauthorized, default: keys + ['']))
11
+ message = I18n.translate(keys.shift, **variables.merge(scope: :unauthorized, default: keys + ['']))
10
12
  message.blank? ? nil : message
11
13
  end
12
14
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CanCan
4
- VERSION = '3.0.0'.freeze
4
+ VERSION = '3.2.1'.freeze
5
5
  end
metadata CHANGED
@@ -1,38 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cancancan
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi (Renuo AG)
8
8
  - Bryan Rite
9
9
  - Ryan Bates
10
10
  - Richard Wilson
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-04-03 00:00:00.000000000 Z
14
+ date: 2020-12-29 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: appraisal
18
18
  requirement: !ruby/object:Gem::Requirement
19
19
  requirements:
20
- - - "~>"
21
- - !ruby/object:Gem::Version
22
- version: '2.0'
23
20
  - - ">="
24
21
  - !ruby/object:Gem::Version
25
22
  version: 2.0.0
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
26
  type: :development
27
27
  prerelease: false
28
28
  version_requirements: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: '2.0'
33
30
  - - ">="
34
31
  - !ruby/object:Gem::Version
35
32
  version: 2.0.0
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '2.0'
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
38
  requirement: !ruby/object:Gem::Requirement
@@ -71,22 +71,22 @@ dependencies:
71
71
  name: rspec
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - "~>"
75
- - !ruby/object:Gem::Version
76
- version: '3.2'
77
74
  - - ">="
78
75
  - !ruby/object:Gem::Version
79
76
  version: 3.2.0
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.2'
80
80
  type: :development
81
81
  prerelease: false
82
82
  version_requirements: !ruby/object:Gem::Requirement
83
83
  requirements:
84
- - - "~>"
85
- - !ruby/object:Gem::Version
86
- version: '3.2'
87
84
  - - ">="
88
85
  - !ruby/object:Gem::Version
89
86
  version: 3.2.0
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.2'
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: rubocop
92
92
  requirement: !ruby/object:Gem::Requirement
@@ -115,7 +115,9 @@ files:
115
115
  - lib/cancan/ability/actions.rb
116
116
  - lib/cancan/ability/rules.rb
117
117
  - lib/cancan/ability/strong_parameter_support.rb
118
+ - lib/cancan/class_matcher.rb
118
119
  - lib/cancan/conditions_matcher.rb
120
+ - lib/cancan/config.rb
119
121
  - lib/cancan/controller_additions.rb
120
122
  - lib/cancan/controller_resource.rb
121
123
  - lib/cancan/controller_resource_builder.rb
@@ -132,8 +134,10 @@ files:
132
134
  - lib/cancan/model_adapters/conditions_extractor.rb
133
135
  - lib/cancan/model_adapters/conditions_normalizer.rb
134
136
  - lib/cancan/model_adapters/default_adapter.rb
137
+ - lib/cancan/model_adapters/sti_normalizer.rb
135
138
  - lib/cancan/model_additions.rb
136
139
  - lib/cancan/parameter_validators.rb
140
+ - lib/cancan/relevant.rb
137
141
  - lib/cancan/rule.rb
138
142
  - lib/cancan/rules_compressor.rb
139
143
  - lib/cancan/unauthorized_message_resolver.rb
@@ -146,7 +150,7 @@ homepage: https://github.com/CanCanCommunity/cancancan
146
150
  licenses:
147
151
  - MIT
148
152
  metadata: {}
149
- post_install_message:
153
+ post_install_message:
150
154
  rdoc_options: []
151
155
  require_paths:
152
156
  - lib
@@ -161,9 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
165
  - !ruby/object:Gem::Version
162
166
  version: '0'
163
167
  requirements: []
164
- rubyforge_project:
165
- rubygems_version: 2.7.6
166
- signing_key:
168
+ rubygems_version: 3.0.6
169
+ signing_key:
167
170
  specification_version: 4
168
171
  summary: Simple authorization solution for Rails.
169
172
  test_files: []