grabli 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 22817abd7cf1fcd173e9c6d804fd9ce27df4c6b5ef3df83678e65c4d1a43c911
4
+ data.tar.gz: f59006fd5d79f420043a94bbf98fe9103802ac42f39bcc10543ac2310fff2af6
5
+ SHA512:
6
+ metadata.gz: dc895810cd249c7646d188e73da2c2715356077bbe43eb5051a9bd12caef9b5b5a3fc458ee2f29d761dc5f82ba2d1854281d9e17582b3feb63cf208ed16af5db
7
+ data.tar.gz: ca971071066b83c562e2721c6eadc294f94fda1ae429842b6ce1e2fe4246753cae63fd9986023f32b80ec600e80e8118a245c3b0075a5d59eeb7afe6769d785c
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.ruby-version
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.16.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in grabli.gemspec
6
+ gemspec
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ grabli (0.1.0)
5
+ pundit (> 0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (5.1.5)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (~> 0.7)
13
+ minitest (~> 5.1)
14
+ tzinfo (~> 1.1)
15
+ concurrent-ruby (1.0.5)
16
+ diff-lcs (1.3)
17
+ i18n (0.9.5)
18
+ concurrent-ruby (~> 1.0)
19
+ minitest (5.11.3)
20
+ pundit (1.1.0)
21
+ activesupport (>= 3.0.0)
22
+ rake (10.5.0)
23
+ rspec (3.7.0)
24
+ rspec-core (~> 3.7.0)
25
+ rspec-expectations (~> 3.7.0)
26
+ rspec-mocks (~> 3.7.0)
27
+ rspec-core (3.7.1)
28
+ rspec-support (~> 3.7.0)
29
+ rspec-expectations (3.7.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.7.0)
32
+ rspec-mocks (3.7.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.7.0)
35
+ rspec-support (3.7.1)
36
+ thread_safe (0.3.6)
37
+ tzinfo (1.2.5)
38
+ thread_safe (~> 0.1)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ bundler (~> 1.16)
45
+ grabli!
46
+ rake (~> 10.0)
47
+ rspec (~> 3.0)
48
+
49
+ BUNDLED WITH
50
+ 1.16.0
@@ -0,0 +1,13 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2018 dikond <di.kondratenko@gmail.com>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
@@ -0,0 +1,73 @@
1
+ # Grabli
2
+
3
+ Hola :v:
4
+
5
+ The very specific goal of this gem is to extract pundit policy permissions to something serializable... like a ruby array! Why do you need that? To tell the front-end application or API consumer what you think of the current user, hehe :smirk: As a bonus, I find it easier to write unit tests for policies. But to have a dependency on third-party gems for unit tests, even as awesome as this one, may be undesirable.
6
+
7
+ ## Usage
8
+
9
+ With a given `UserPolicy` (e.g. the one defined in `/spec/spec_helper.rb`) you can do:
10
+
11
+ ```ruby
12
+ require 'grabli'
13
+
14
+ Grabli.new.collect(@user, @company)
15
+ # => [:create?, :update?]
16
+
17
+ Grabli.new.collect(@user, :company)
18
+ # => [:create?]
19
+ ```
20
+
21
+ Let's say your app have a public Rest API. It may look like:
22
+
23
+ ```ruby
24
+ require 'grabli'
25
+
26
+ class Api::UsersController < ApplicationController
27
+ def show
28
+ @user = User.find(params[:id])
29
+ authorize @user
30
+
31
+ permissions = Grabli.new.collect(current_user, @user)
32
+
33
+ render json: { user: @user.to_json, permissions: permissions }
34
+ end
35
+ end
36
+ ```
37
+
38
+ You can then create a helper and use it across your app, for example:
39
+
40
+ ```ruby
41
+ # /app/controllers/application_controller.rb
42
+ require 'grabli'
43
+
44
+ class ApplicationController
45
+ def collect_permissions_for(subject)
46
+ Grabli.new.collect(current_user, subject)
47
+ end
48
+ helper_method :collect_permissions_for
49
+ end
50
+
51
+
52
+ # /app/controllers/api/users_controller.rb
53
+ class Api::UsersController < ApplicationController
54
+ def show
55
+ @user = User.find(params[:id])
56
+ authorize @user
57
+
58
+ render json: { user: @user.to_json, permissions: collect_permissions_for(@user) }
59
+ end
60
+ end
61
+ ```
62
+
63
+ ## Further plans
64
+
65
+ 1) Improve cases when subject is a `Symbol`
66
+
67
+ Since pundit policy doesn't limit the subject types it can be anything, even a `Symbol`.
68
+
69
+ Make `Intruder` a bit more clever proxy object which delegates to the subject and intercepts `NoMethodError` for cases when `Symbol` subject mean "no subject".
70
+
71
+ ## Contributing
72
+
73
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/grabli.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "grabli"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,23 @@
1
+ require_relative "lib/grabli/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "grabli"
5
+ spec.version = Grabli::VERSION
6
+ spec.authors = ["dikond"]
7
+ spec.email = ["di.kondratenko@gmail.com"]
8
+ spec.license = "wtfpl"
9
+
10
+ spec.summary = "Grab permissions from your Pundit policies"
11
+ spec.homepage = "https://github.com/dikond/grabli"
12
+
13
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
+ f.match(%r{^(test|spec|features)/})
15
+ end
16
+
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_runtime_dependency "pundit", "> 0"
20
+ spec.add_development_dependency "bundler", "~> 1.16"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rspec", "~> 3.0"
23
+ end
@@ -0,0 +1,71 @@
1
+ require "grabli/version"
2
+ require "pundit"
3
+
4
+ class Grabli
5
+ #
6
+ # Collect allowed policy permissions for the given user.
7
+ #
8
+ # @param user [Object] user object your policy work with
9
+ # @param subject [Symbol, Object] subject object your policy work with
10
+ # @return [Array<Symbol>] array of allowed policy permission
11
+ # @example
12
+ #
13
+ # Grabli.new.collect(@user, @company)
14
+ # #=> [:create?, :update?, :manage_occupied?]
15
+ #
16
+ # Grabli.new.collect(@user, :company)
17
+ # #=> [:create?]
18
+ #
19
+ def collect(user, subject)
20
+ policy_class(subject)
21
+ .public_instance_methods(false)
22
+ .reject! { |n| n =~ /permitted_attributes/ }
23
+ .each_with_object([]) do |permission, collection|
24
+ # allows to collect permissions without subject, for more @see Intruder
25
+ isubject = subject.is_a?(Symbol) ? Intruder.new(false) : subject
26
+ policy = policy_class(subject).new(user, isubject)
27
+
28
+ collection << permission if allowed? policy, permission
29
+ end
30
+ .sort
31
+ end
32
+
33
+ # Check whether certain permission is allowed.
34
+ #
35
+ # @param policy [ApplicationPolicy] instantiated policy
36
+ # @param permission [Symbol] permission name
37
+ # @return [Boolen, Object] true or false in case subject intruded
38
+ # or whatever you policy permission returns
39
+ # @example
40
+ #
41
+ # policy = Pundit.policy(@user, @company)
42
+ # Grabli.new.allowed?(policy, :create?)
43
+ # #=> true
44
+ #
45
+ def allowed?(policy, permission)
46
+ result = policy.public_send(permission)
47
+ return !policy.record.intruded if policy.record.is_a?(Intruder)
48
+ result
49
+ end
50
+
51
+ private def policy_class(record)
52
+ Pundit::PolicyFinder.new(record).policy
53
+ end
54
+
55
+ #
56
+ # When no subject specified by the user or the subject is a Symbol,
57
+ # we pass that object as a subject.
58
+ #
59
+ # If the subject isn't used it means we can add this permission as allowed.
60
+ # If it's used, CURRENTLY, we assume that the given permission isn't allowed.
61
+ #
62
+ # TODO: delegate to the original subject if it was given
63
+ # and intercept NoMethodError
64
+ #
65
+ Intruder = Struct.new(:intruded) do
66
+ def method_missing(*)
67
+ self[:intruded] = true
68
+ self
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ class Grabli
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grabli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - dikond
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pundit
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: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.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
+ description:
70
+ email:
71
+ - di.kondratenko@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - grabli.gemspec
86
+ - lib/grabli.rb
87
+ - lib/grabli/version.rb
88
+ homepage: https://github.com/dikond/grabli
89
+ licenses:
90
+ - wtfpl
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.7.6
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Grab permissions from your Pundit policies
112
+ test_files: []