consent 1.0.0 → 1.0.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: 66e7e1705d61760713253718eabda896ffa49f25ea6e1a9a6c4fc1a188730cfb
4
- data.tar.gz: 4dc120c6f1e89a3cb612a62cf9fdbac565e51b9fabe9d04a68c64c3d9a8fd193
3
+ metadata.gz: 925e2e71db7ce7b4c7104784bbd54cfeb8273b2502f0f73f599e64754d5a010a
4
+ data.tar.gz: 256326fbd83020d39881b53eadc1b3b7cb9c5169bedee5aac5491661a0e3023b
5
5
  SHA512:
6
- metadata.gz: 9ca74d2788b689711966b38e11ce4b857009064d1fce59c2b5335adc437c1b20a9298acb61a0e71cf3aac2eef1f13f6b8b06570014938ef757374b6a4f98b9c4
7
- data.tar.gz: 9d4e6cf5d18d0671c9aade10a33933cc93b0cb704c623d6705332de55a1a02b3952b01fdee9d357a1c0ba9f37d570910ac1fe54614087cd88c94d3d890b5761d
6
+ metadata.gz: 84ee14b357d0edd8c7be190cc4f79e67d6a0a7f8e0f869d1bf15b0d1ebe87e6f076939aa9db684c172eec8f489bb83f8794c3ca0946a4edc569c07f04a6a9889
7
+ data.tar.gz: 490da917b1363a0b5d2f209df9363978764874fbe74d500c548b91a95f16f3ca35fab2a80a1ab7ac4de7364e7892101efc4e4a022d25683d0dc82896c7b39da9
data/consent.gemspec CHANGED
@@ -20,9 +20,12 @@ Gem::Specification.new do |spec|
20
20
  end
21
21
  spec.require_paths = ['lib']
22
22
 
23
+ spec.add_development_dependency 'activerecord', '>= 5'
23
24
  spec.add_development_dependency 'bundler', '>= 1.17.3'
24
25
  spec.add_development_dependency 'cancancan', '~> 1.15.0'
26
+ spec.add_development_dependency 'pry', '~> 0.14.1'
25
27
  spec.add_development_dependency 'rake', '>= 12.3.3'
26
28
  spec.add_development_dependency 'rspec', '~> 3.0'
27
29
  spec.add_development_dependency 'rubocop', '~> 0.65.0'
30
+ spec.add_development_dependency 'sqlite3', '~> 1.4.2'
28
31
  end
data/lib/consent.rb CHANGED
@@ -5,7 +5,6 @@ require 'consent/subject'
5
5
  require 'consent/view'
6
6
  require 'consent/action'
7
7
  require 'consent/dsl'
8
- require 'consent/permission'
9
8
  require 'consent/ability' if defined?(CanCan)
10
9
  require 'consent/railtie' if defined?(Rails)
11
10
 
@@ -13,6 +12,8 @@ require 'consent/railtie' if defined?(Rails)
13
12
  # concise DSL for authorization so that all abilities do not have
14
13
  # to be in your `Ability` class.
15
14
  module Consent
15
+ ViewNotFound = Class.new(StandardError)
16
+
16
17
  # Default views available to every permission
17
18
  #
18
19
  # i.e.:
@@ -35,7 +36,7 @@ module Consent
35
36
  #
36
37
  # @return [Array<Consent::Subject>]
37
38
  def self.find_subjects(subject_key)
38
- @subjects.find_all do |subject|
39
+ subjects.find_all do |subject|
39
40
  subject.key.eql?(subject_key)
40
41
  end
41
42
  end
@@ -44,21 +45,20 @@ module Consent
44
45
  #
45
46
  # @return [Consent::Action,nil]
46
47
  def self.find_action(subject_key, action_key)
47
- Consent.find_subjects(subject_key)
48
- .map(&:actions).flatten
49
- .find do |action|
50
- action.key.eql?(action_key)
51
- end
48
+ find_subjects(subject_key)
49
+ .flat_map(&:actions)
50
+ .find do |action|
51
+ action.key.eql?(action_key)
52
+ end
52
53
  end
53
54
 
54
55
  # Finds a view within a subject context
55
56
  #
56
57
  # @return [Consent::View,nil]
57
- def self.find_view(subject_key, view_key)
58
- views = Consent.find_subjects(subject_key)
59
- .map(&:views)
60
- .reduce({}, &:merge)
61
- views[view_key]
58
+ def self.find_view(subject_key, action_key, view_key)
59
+ find_action(subject_key, action_key)&.yield_self do |action|
60
+ action.views[view_key] || raise(Consent::ViewNotFound)
61
+ end
62
62
  end
63
63
 
64
64
  # Loads all permission (ruby) files from the given directory
@@ -87,11 +87,4 @@ module Consent
87
87
  DSL.build(subject, defaults, &block)
88
88
  end
89
89
  end
90
-
91
- # Maps a permissions hash to a Consent::Permissions
92
- #
93
- # @return [Consent::Permissions]
94
- def self.permissions(permissions)
95
- Permissions.new(permissions)
96
- end
97
90
  end
@@ -10,17 +10,26 @@ module Consent
10
10
  apply_defaults! if apply_defaults
11
11
  end
12
12
 
13
- def consent(permission: nil, subject: nil, action: nil, view: nil)
14
- permission ||= Permission.new(subject, action, view)
15
- return unless permission.valid?
13
+ def consent!(subject: nil, action: nil, view: nil)
14
+ view = case view
15
+ when Consent::View
16
+ view
17
+ when Symbol
18
+ Consent.find_view(subject, action, view)
19
+ end
16
20
 
17
21
  can(
18
- permission.action_key, permission.subject_key,
19
- permission.conditions(*@context),
20
- &permission.object_conditions(*@context)
22
+ action, subject,
23
+ view&.conditions(*@context), &view&.object_conditions(*@context)
21
24
  )
22
25
  end
23
26
 
27
+ def consent(**kwargs)
28
+ consent!(**kwargs)
29
+ rescue Consent::ViewNotFound
30
+ nil
31
+ end
32
+
24
33
  private
25
34
 
26
35
  def apply_defaults!
@@ -2,20 +2,23 @@
2
2
 
3
3
  module Consent
4
4
  class Action # :nodoc:
5
- attr_reader :key, :label, :options
5
+ attr_reader :subject, :key, :label, :options
6
6
 
7
- def initialize(key, label, options = {})
7
+ def initialize(subject, key, label, options = {})
8
+ @subject = subject
8
9
  @key = key
9
10
  @label = label
10
11
  @options = options
11
12
  end
12
13
 
13
- def view_keys
14
- @options.fetch(:views, [])
14
+ def views
15
+ @views ||= @subject.views.slice(*@options.fetch(:views, []))
15
16
  end
16
17
 
17
18
  def default_view
18
- @options[:default_view]
19
+ return unless @options.key?(:default_view)
20
+
21
+ @default_view ||= @subject.views[@options[:default_view]]
19
22
  end
20
23
  end
21
24
  end
data/lib/consent/dsl.rb CHANGED
@@ -27,7 +27,8 @@ module Consent
27
27
  end
28
28
 
29
29
  def action(key, label, options = {})
30
- @subject.actions << Action.new(key, label, @defaults.merge(options))
30
+ @subject.actions << Action.new(@subject, key, label,
31
+ @defaults.merge(options))
31
32
  end
32
33
 
33
34
  def self.build(subject, defaults = {}, &block)
data/lib/consent/rspec.rb CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'consent'
4
4
 
5
+ require_relative 'rspec/consent_action'
6
+ require_relative 'rspec/consent_view'
7
+
5
8
  module Consent
6
9
  # RSpec helpers for consent. Given permissions are loaded,
7
10
  # gives you the ability of defining permission specs like
@@ -20,7 +23,11 @@ module Consent
20
23
  # let(:user) { double(department_id: 15) }
21
24
  #
22
25
  # it do
23
- # is_expected.to consent_view(:department, department_id: 15).to(user)
26
+ # is_expected.to(
27
+ # consent_view(:department)
28
+ # .with_conditions(department_id: 15)
29
+ # .to(user)
30
+ # )
24
31
  # end
25
32
  # it { is_expected.to consent_action(:read) }
26
33
  # it { is_expected.to consent_action(:update).with_views(:department) }
@@ -29,79 +36,12 @@ module Consent
29
36
  # Find more examples at:
30
37
  # https://github.com/powerhome/consent
31
38
  module Rspec
32
- extend RSpec::Matchers::DSL
33
-
34
- matcher :consent_action do |action_key|
35
- chain :with_views do |*views|
36
- @views = views
37
- end
38
-
39
- match do |subject_key|
40
- action = Consent.find_action(subject_key, action_key)
41
- if action && @views
42
- values_match?(action.view_keys.sort, @views.sort)
43
- else
44
- !action.nil?
45
- end
46
- end
47
-
48
- failure_message do |subject_key|
49
- action = Consent.find_action(subject_key, action_key)
50
- message = format(
51
- 'expected %<skey>s (%<sclass>s) to provide action %<action>s',
52
- skey: subject_key.to_s, sclass: subject.class, action: action_key
53
- )
54
-
55
- if action && @views
56
- format(
57
- '%<message>s with views %<views>s, but actual views are %<keys>p',
58
- message: message, views: @views, keys: action.view_keys
59
- )
60
- else
61
- message
62
- end
63
- end
39
+ def consent_view(view_key, conditions = nil)
40
+ ConsentView.new(view_key, conditions)
64
41
  end
65
42
 
66
- matcher :consent_view do |view_key, conditions|
67
- chain :to do |*context|
68
- @context = context
69
- end
70
-
71
- match do |subject_key|
72
- view = Consent.find_view(subject_key, view_key)
73
- if conditions
74
- view&.conditions(*@context).eql?(conditions)
75
- else
76
- !view.nil?
77
- end
78
- end
79
-
80
- failure_message do |subject_key|
81
- view = Consent.find_view(subject_key, view_key)
82
- message = format(
83
- 'expected %<skey>s (%<sclass>s) to provide view %<view>s with` \
84
- `%<conditions>p, but',
85
- skey: subject_key.to_s, sclass: subject.class,
86
- view: view_key, conditions: conditions
87
- )
88
-
89
- if view && conditions
90
- actual_conditions = view.conditions(*@context)
91
- format(
92
- '%<message>s conditions are %<conditions>p',
93
- message: message, conditions: actual_conditions
94
- )
95
- else
96
- actual_views = Consent.find_subjects(subject_key)
97
- .map(&:views)
98
- .map(&:keys).flatten
99
- format(
100
- '%<message>s available views are %<views>p',
101
- message: message, views: actual_views
102
- )
103
- end
104
- end
43
+ def consent_action(action_key)
44
+ ConsentAction.new(action_key)
105
45
  end
106
46
  end
107
47
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'consent'
4
+ RSpec::Support.require_rspec_support 'fuzzy_matcher'
5
+
6
+ module Consent
7
+ module Rspec
8
+ # @private
9
+ class ConsentAction
10
+ def initialize(action_key)
11
+ @action_key = action_key
12
+ end
13
+
14
+ def with_views(*views)
15
+ @views = views
16
+ self
17
+ end
18
+
19
+ def description
20
+ message = "consents action #{@action_key}"
21
+ "#{message} with views #{@views}" if @views
22
+ end
23
+
24
+ def matches?(subject_key)
25
+ @subject_key = subject_key
26
+ @action = Consent.find_action(@subject_key, @action_key)
27
+ if @action && @views
28
+ RSpec::Support::FuzzyMatcher.values_match?(
29
+ @action.views.keys.sort,
30
+ @views.sort
31
+ )
32
+ else
33
+ !@action.nil?
34
+ end
35
+ end
36
+
37
+ def failure_message
38
+ failure_message_base 'to'
39
+ end
40
+
41
+ def failure_message_when_negated
42
+ failure_message_base 'to not'
43
+ end
44
+
45
+ private
46
+
47
+ def failure_message_base(failure) # rubocop:disable Metrics/MethodLength
48
+ message = format(
49
+ 'expected %<skey>s (%<sclass>s) %<failure> provide action %<action>s',
50
+ skey: @subject_key.to_s, sclass: @subject_key.class,
51
+ action: @action_key, failure: failure
52
+ )
53
+
54
+ if @action && @views
55
+ format(
56
+ '%<message>s with views %<views>s, but actual views are %<keys>p',
57
+ message: message, views: @views, keys: @action.views.keys
58
+ )
59
+ else
60
+ message
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Consent
4
+ module Rspec
5
+ # @private
6
+ class ConsentView
7
+ def initialize(view_key, conditions)
8
+ @conditions = comparable_conditions(conditions) if conditions
9
+ @view_key = view_key
10
+ end
11
+
12
+ def to(*context)
13
+ @context = context
14
+ self
15
+ end
16
+
17
+ def description
18
+ message = "consents view #{@view_key}"
19
+ "#{message} with conditions #{@conditions}" if @conditions
20
+ end
21
+
22
+ def with_conditions(conditions)
23
+ @conditions = comparable_conditions(conditions)
24
+ self
25
+ end
26
+
27
+ def matches?(subject_key)
28
+ @subject_key = subject_key
29
+ @target = Consent.find_subjects(subject_key)
30
+ .map do |subject|
31
+ subject.views[@view_key]&.conditions(*@context)
32
+ end
33
+ .compact
34
+ .map(&method(:comparable_conditions))
35
+ @target.include?(@conditions)
36
+ end
37
+
38
+ def failure_message
39
+ failure_message_base 'to'
40
+ end
41
+
42
+ def failure_message_when_negated
43
+ failure_message_base 'to not'
44
+ end
45
+
46
+ private
47
+
48
+ def comparable_conditions(conditions)
49
+ return conditions.to_sql if conditions.respond_to?(:to_sql)
50
+
51
+ conditions
52
+ end
53
+
54
+ def failure_message_base(failure) # rubocop:disable Metrics/MethodLength
55
+ message = format(
56
+ 'expected %<skey>s (%<sclass>s) %<fail>s provide view %<view>s with`\
57
+ `%<conditions>p, but',
58
+ skey: @subject_key.to_s, sclass: @subject_key.class,
59
+ view: @view_key, conditions: @conditions, fail: failure
60
+ )
61
+
62
+ if @target.any?
63
+ format(
64
+ '%<message>s conditions are %<conditions>p',
65
+ message: message, conditions: @target
66
+ )
67
+ else
68
+ actual_views = Consent.find_subjects(subject_key)
69
+ .map(&:views)
70
+ .map(&:keys).flatten
71
+ format(
72
+ '%<message>s available views are %<views>p',
73
+ message: message, views: actual_views
74
+ )
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Consent
4
- VERSION = '1.0.0'
4
+ VERSION = '1.0.1'
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: consent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Palhares
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-22 00:00:00.000000000 Z
11
+ date: 2021-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: 1.15.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.14.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.14.1
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rake
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +108,20 @@ dependencies:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
110
  version: 0.65.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: sqlite3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.4.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.4.2
83
125
  description: Consent
84
126
  email:
85
127
  - chjunior@gmail.com
@@ -105,10 +147,11 @@ files:
105
147
  - lib/consent/ability.rb
106
148
  - lib/consent/action.rb
107
149
  - lib/consent/dsl.rb
108
- - lib/consent/permission.rb
109
150
  - lib/consent/railtie.rb
110
151
  - lib/consent/reloader.rb
111
152
  - lib/consent/rspec.rb
153
+ - lib/consent/rspec/consent_action.rb
154
+ - lib/consent/rspec/consent_view.rb
112
155
  - lib/consent/subject.rb
113
156
  - lib/consent/version.rb
114
157
  - lib/consent/view.rb
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Consent
4
- class Permission # :nodoc:
5
- attr_reader :subject_key, :action_key, :view_key, :view
6
-
7
- def initialize(subject_key, action_key, view_key = nil)
8
- @subject_key = subject_key
9
- @action_key = action_key
10
- @view_key = view_key
11
- @view = Consent.find_view(subject_key, view_key) if view_key
12
- end
13
-
14
- def action
15
- @action ||= Consent.find_action(subject_key, action_key)
16
- end
17
-
18
- def valid?
19
- action && (@view_key.nil? == @view.nil?)
20
- end
21
-
22
- def conditions(*args)
23
- @view.nil? ? nil : @view.conditions(*args)
24
- end
25
-
26
- def object_conditions(*args)
27
- @view.nil? ? nil : @view.object_conditions(*args)
28
- end
29
- end
30
- end