kantox-roles 1.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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/README.md +224 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/kantox-roles.gemspec +40 -0
- data/lib/kantox/roles.rb +199 -0
- data/lib/kantox/roles/helpers.rb +138 -0
- data/lib/kantox/roles/logger.rb +102 -0
- data/lib/kantox/roles/strategies/aspect.rb +13 -0
- data/lib/kantox/roles/strategies/cancancan.rb +48 -0
- data/lib/kantox/roles/strategies/pundit.rb +70 -0
- data/lib/kantox/roles/strategies/strategy_error.rb +12 -0
- data/lib/kantox/roles/strategies/wrapper.rb +15 -0
- data/lib/kantox/roles/version.rb +5 -0
- data/lib/rails/generators/kantox/policy_spec_helper.rb.tmpl +35 -0
- data/lib/rails/generators/kantox/pundit_policy_generator.rb +234 -0
- metadata +178 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 5120829150bcbfcb385b48107800baf61da72262
|
|
4
|
+
data.tar.gz: 756e3b82936790094c8d00ed90ff16e8d0610f7c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 96fd86d02e2c44e7b51c108c4e4f9fabb0fabe306dd5b38e12f2fc40fdcefd896bf95131dc5a1ab8a9627e5a5018a0b0e41eea213021dc58f7757d828ec93891
|
|
7
|
+
data.tar.gz: 17b617b94f4df54811ca013132aae12f812cd1cb0cde138fadda24e53d03879249453069bb3bedff6acdd33fedbbd9045061b51ca0b4b66ba89215449ea078c0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Kantox::Roles
|
|
2
|
+
|
|
3
|
+
Kantox Roles is the library to transparently handle an authorization. It is
|
|
4
|
+
fully backend-agnostic. Current implementation contains a working example
|
|
5
|
+
of pundit wrapping.
|
|
6
|
+
|
|
7
|
+
The main goal is to separate the wheat from the chaff and not to pollute
|
|
8
|
+
model/controller classes with authorization stuff.
|
|
9
|
+
|
|
10
|
+
With Kantox Roles one is to define the rules in one or more yaml files:
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
'Kantox::Managed':
|
|
14
|
+
:yo : 'aspect'
|
|
15
|
+
:yo2 : :aspect
|
|
16
|
+
:yo3 :
|
|
17
|
+
:runner: 'Kantox::Strategies::Wrapper#wrap'
|
|
18
|
+
:yo5 :
|
|
19
|
+
:lambda: '->(context, im) { 42 }'
|
|
20
|
+
:yo6 :
|
|
21
|
+
:kantox_managedhandler:
|
|
22
|
+
:params: ['param1', 'param2']
|
|
23
|
+
'Kantox::WildManaged':
|
|
24
|
+
'y*' : :aspect
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
There are four different kinds of handlers available:
|
|
28
|
+
|
|
29
|
+
* **simple** — like `aspect` above. There should be `Kantox::Strategies#aspect`
|
|
30
|
+
module function available. It will be called with parameters `context` and
|
|
31
|
+
`im` supplying the context instance (usually an instance of guarded controller
|
|
32
|
+
class) and the name of the guarded method in `Module::Class#method` notation.
|
|
33
|
+
The aforementioned function should _raise an exception_ of type
|
|
34
|
+
`Kantox::Strategies::StrategyError` whether the authority check is not passed.
|
|
35
|
+
* **runner** — the most powerful yet complicated guard. Should have the
|
|
36
|
+
executable module function as parameter in `Module::Class#method` notation.
|
|
37
|
+
This function will be called, yielding _`context`, `im` **and** the guarded
|
|
38
|
+
method, converted to `proc`_ as parameters. The typical usage:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
def my_runner context, params = nil
|
|
42
|
+
fail Kantox::Strategies::MyRunnerError unless check_passed
|
|
43
|
+
params[:user] = :demo if demo_mode
|
|
44
|
+
params[:credit_card].gsub /\d/, 'X'
|
|
45
|
+
yield *params if block_given?
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
As seen above, the full control over context is provided by this guard.
|
|
50
|
+
|
|
51
|
+
* **lambda** — the simple lambda, getting `context` and `im`. Is actually
|
|
52
|
+
a syntax sugar for the _simple_ guard
|
|
53
|
+
* **object** — used when there is a need to pass complicated parameters and/or
|
|
54
|
+
some other stuff to the guard. The class `Kantox::Managedhandler` must have
|
|
55
|
+
a constructor, accepting one argument (the hash of parameters) and `to_proc`
|
|
56
|
+
method, accepting two arguments (`context`, `im`). The class will be
|
|
57
|
+
instantiated with a parameters list and `to_proc` would be called on context.
|
|
58
|
+
|
|
59
|
+
## Methods to guard
|
|
60
|
+
|
|
61
|
+
Wildcard notation is allowed. That said, `'y*'` will guard all the methods
|
|
62
|
+
starting with `y`, and `'*'` will guard everything on the respective class.
|
|
63
|
+
|
|
64
|
+
## Deny ⇒ Allow
|
|
65
|
+
|
|
66
|
+
As soon as a method guard is specified in yaml file, the method is considered
|
|
67
|
+
as guarded. If there was an error finding the guard (class not exists, method
|
|
68
|
+
can not be instantiated etc,) the authorization request will be _rejected_.
|
|
69
|
+
|
|
70
|
+
## Rails integration
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
# controllers/admin/admin_controller.rb
|
|
74
|
+
|
|
75
|
+
require 'kantox/roles'
|
|
76
|
+
# Specify the top-parent class to guard
|
|
77
|
+
Kantox::Roles.init Admin::AdminController
|
|
78
|
+
# load strategies
|
|
79
|
+
Dir['strategies/**/*.yml'].each do |f|
|
|
80
|
+
Kantox::Roles.configure f
|
|
81
|
+
end
|
|
82
|
+
# load stopwords for logger
|
|
83
|
+
Kantox::Helpers.logger_stopwords File.join 'strategies', 'stopwords.txt'
|
|
84
|
+
Kantox::Helpers.info "Strategies were read: #{Kantox::Roles.options}"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# config/application.rb
|
|
89
|
+
|
|
90
|
+
# Policies are to be loaded on init explicitly
|
|
91
|
+
Dir[File.expand_path('../../app/policies/**/*', __FILE__)].each do |f|
|
|
92
|
+
require f[/(.*?)\.rb$/, 1] unless File.directory? f
|
|
93
|
+
end
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
# strategiest/roles.yml
|
|
98
|
+
|
|
99
|
+
'Admin::TodosController' :
|
|
100
|
+
'*' : :pundit
|
|
101
|
+
...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Pundit plug-in
|
|
105
|
+
|
|
106
|
+
This section shows how to integrate `pundit` to act as backend guard.
|
|
107
|
+
Everything one needs is to implement policies.
|
|
108
|
+
|
|
109
|
+
Everything in `TodosController` is to be handled by pundit. So, it’s time
|
|
110
|
+
to implement our `pundit` guard. Besides some syntax sugar stuff it is (complete implementation for `kantox-flow` may be seen [here](https://github.com/kantox/kantox-roles/wiki/Pundit-Policy):
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
# app/policies/pundit.rb
|
|
114
|
+
|
|
115
|
+
def pundit context, im
|
|
116
|
+
begin # Whoever does not reply on classify would be punished :)
|
|
117
|
+
model = context.instance_eval 'controller_path.classify'
|
|
118
|
+
policy = PolicyFactory.lookup model.split('::').last
|
|
119
|
+
unless policy.new(context.current_user, model).send("#{im.split('#').last}?")
|
|
120
|
+
fail PunditError.new(context, im, policy)
|
|
121
|
+
end
|
|
122
|
+
rescue NameError => e
|
|
123
|
+
Kantox::Helpers.err "Error punditing «#{context}». Will reject request.\nOriginal error: #{e}"
|
|
124
|
+
throw PunditError.new(context, im)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
module_function :pundit
|
|
128
|
+
```
|
|
129
|
+
Needless to say, the above handler is to be written once per backend. Pundit one is shipped with `Kantox::Roles`. The last but not least is to specify a strategy:
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
# app/policies/todo_policy.rb
|
|
133
|
+
|
|
134
|
+
module Kantox
|
|
135
|
+
module Policies
|
|
136
|
+
def historic?
|
|
137
|
+
@user.admin? and [true, false].sample
|
|
138
|
+
end
|
|
139
|
+
alias_method :index?, :historic?
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The above will randomly accept admin’s requests to a controller. I am pretty
|
|
146
|
+
sure one would do more sophisticated check here.
|
|
147
|
+
|
|
148
|
+
That’s it.
|
|
149
|
+
|
|
150
|
+
## Policies Generator
|
|
151
|
+
|
|
152
|
+
`Kantox::Roles` has it’s generator for creating policies.
|
|
153
|
+
|
|
154
|
+
### Generator invocation
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
$ bundle exec rails generate kantox:pundit_policy Todo --users Administrator SalesPerson
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The above will generate (assuming that `Todo` is a proper model name and `TodosController` exists:
|
|
161
|
+
|
|
162
|
+
* Policy itself, in `app/policies`,
|
|
163
|
+
* Spec for a policy in `spec/policies`,
|
|
164
|
+
* Default strategy in `strategies`.
|
|
165
|
+
* [optional] if this is a first run, the `pundit:install` generator will be invoked
|
|
166
|
+
to generate default pundit `ApplicationPolicy`.
|
|
167
|
+
|
|
168
|
+
By default all the public controller methods will be guarded with `method?` pundit guards,
|
|
169
|
+
returning `true` if the current user was listed during generation process.
|
|
170
|
+
|
|
171
|
+

|
|
172
|
+
|
|
173
|
+
### Generated specs
|
|
174
|
+
|
|
175
|
+
The generator above would generate smart specs, more or less ready to use. For
|
|
176
|
+
an example above, it would generate specs, checking whether _all the specified
|
|
177
|
+
users are **allowed**_ to access the controller, and _all others are restricted_.
|
|
178
|
+
|
|
179
|
+

|
|
180
|
+
|
|
181
|
+
### Vandal-proof
|
|
182
|
+
|
|
183
|
+
The generator will gracefully reject a request to damage anything as well as
|
|
184
|
+
to generate policies for inexisting controller.
|
|
185
|
+
|
|
186
|
+

|
|
187
|
+
|
|
188
|
+
## Installation
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
gem 'kantox-roles'
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## TODOs
|
|
195
|
+
|
|
196
|
+
* generate policies and rspecs by `yaml`
|
|
197
|
+
* ~~pointcuts *syntax* — DSL vs YAML/JSON~~
|
|
198
|
+
* automatic *tests* for pointcuts — by adding them to descriptions
|
|
199
|
+
* allow⇒deny vs **deny⇒allow**
|
|
200
|
+
* ~~*supersupervisor* to change rights of supervisors~~
|
|
201
|
+
* ~~*groups* with *roles*, or smth morre sophisticated? What?~~
|
|
202
|
+
* ~~where to store rights? 3rd party?~~
|
|
203
|
+
* *edit rights* from the interface.
|
|
204
|
+
|
|
205
|
+
## Usage
|
|
206
|
+
|
|
207
|
+
Add a line to `configuration` file (or explicitly by calling `Kantox::Roles.configure` with either hash, or passing a block.)
|
|
208
|
+
|
|
209
|
+
Optionally, one may specify a custom handler as denoted by `:runner` key in config.
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
## Development
|
|
213
|
+
|
|
214
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
215
|
+
|
|
216
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
217
|
+
|
|
218
|
+
## Contributing
|
|
219
|
+
|
|
220
|
+
1. Fork it ( https://github.com/[my-github-username]/kantox-roles/fork )
|
|
221
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
222
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
223
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
224
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "kantox/roles"
|
|
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
|
data/bin/setup
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'kantox/roles/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.required_ruby_version = '~> 2.1'
|
|
8
|
+
|
|
9
|
+
spec.name = 'kantox-roles'
|
|
10
|
+
spec.version = Kantox::Roles::VERSION
|
|
11
|
+
spec.authors = ['Kantox LTD']
|
|
12
|
+
spec.email = ['aleksei.matiushkin@kantox.com']
|
|
13
|
+
spec.license = 'Kantox LTD Commercial'
|
|
14
|
+
|
|
15
|
+
spec.summary = 'OmniRoles mechanism for Kantox Role Management'
|
|
16
|
+
spec.description = 'Roles Management interface for virtually every backend, mostly like OmniAuth for authentication'
|
|
17
|
+
spec.homepage = 'http://kantox.com'
|
|
18
|
+
|
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(/(test|spec|features)\//) }
|
|
20
|
+
spec.bindir = 'bin'
|
|
21
|
+
spec.executables = spec.files.grep(/^exe\//) { |f| File.basename(f) }
|
|
22
|
+
spec.require_paths = %w(lib)
|
|
23
|
+
|
|
24
|
+
if spec.respond_to?(:metadata)
|
|
25
|
+
# spec.metadata['allowed_push_host'] = 'http://fury.io'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
spec.add_dependency 'hashie', '~> 3'
|
|
29
|
+
spec.add_dependency 'pundit'
|
|
30
|
+
|
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
|
32
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
33
|
+
|
|
34
|
+
spec.add_development_dependency 'pry', '~> 0.10'
|
|
35
|
+
|
|
36
|
+
spec.add_development_dependency 'rspec', '~> 2.12'
|
|
37
|
+
spec.add_development_dependency 'cucumber', '~> 1.3'
|
|
38
|
+
spec.add_development_dependency 'yard', '~> 0'
|
|
39
|
+
# spec.add_development_dependency 'yard-cucumber', '~> 0'
|
|
40
|
+
end
|
data/lib/kantox/roles.rb
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
require 'hashie'
|
|
2
|
+
|
|
3
|
+
Dir[File.expand_path('../**/*', __FILE__)].each do |f|
|
|
4
|
+
require f[/(.*?)\.rb$/, 1] unless File.directory? f
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module Kantox
|
|
8
|
+
LOCK_EMOJI = '🔒'
|
|
9
|
+
|
|
10
|
+
module Exceptions
|
|
11
|
+
class StandardError < ::StandardError; end
|
|
12
|
+
class NotAuthorized < StandardError; end
|
|
13
|
+
class NotAllowed < NotAuthorized; end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# This error is called when a programmer was as lame as to code wrong
|
|
17
|
+
class LameError < RuntimeError ; end
|
|
18
|
+
|
|
19
|
+
module Roles
|
|
20
|
+
class << self
|
|
21
|
+
attr_reader :controller
|
|
22
|
+
|
|
23
|
+
# Main initializer. This method is to be called before any controller
|
|
24
|
+
# is instantiated to prevent leakage of controllers handled.
|
|
25
|
+
# @param controller [Class] the class of main controller to handle
|
|
26
|
+
def init controller
|
|
27
|
+
return @controller if @controller == controller
|
|
28
|
+
|
|
29
|
+
fail LameError.new("Roles were already initialized for [#{@controller}]. Tried: [#{controller}]") \
|
|
30
|
+
unless @controller.nil? ||
|
|
31
|
+
# The following must satisfy zeus. Zeus reloads controller class
|
|
32
|
+
# making a comparision to fail. This is an ugly hack to f*ck zeus.
|
|
33
|
+
Rails.env.development? &&
|
|
34
|
+
!ENV['ZEUS_MASTER_FD'].nil? &&
|
|
35
|
+
@controller.name == controller.name
|
|
36
|
+
|
|
37
|
+
@controller = controller
|
|
38
|
+
if @controller.method(:inherited).owner == @controller
|
|
39
|
+
Kantox::Helpers.warn "#{controller}#inherited was already defined. Realiasing."
|
|
40
|
+
# FIXME @controller.send :alias_method, "∃inherited", :inherited
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@controller.class_eval '
|
|
44
|
+
def self.inherited subclass
|
|
45
|
+
Kantox::Roles.postpone_strategies subclass
|
|
46
|
+
end
|
|
47
|
+
'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Configures Roles by hash or yaml from string or file. Whether code block
|
|
51
|
+
# is passed, it is processed with @options instance.
|
|
52
|
+
# @param hos [String|Hash] the input data to configure
|
|
53
|
+
def configure hos = nil
|
|
54
|
+
@options = Kantox::Helpers.merge_hash_or_string options, hos
|
|
55
|
+
yield @options if block_given?
|
|
56
|
+
# @options.select! { |_, v| v.is_a? Enumerator } # FIXME WARNING OR LIKE
|
|
57
|
+
apply_all_strategies # FIXME Do we need this?
|
|
58
|
+
@options
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def apply_all_strategies
|
|
62
|
+
options.keys.each { |klazz| postpone_strategies klazz }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def postpone_strategies klazz
|
|
66
|
+
return if postponed[klazz.to_s] # FIXME FIXME FIXME
|
|
67
|
+
|
|
68
|
+
case klazz
|
|
69
|
+
when Class
|
|
70
|
+
(@postponed[klazz.to_s] = TracePoint.new(:end) do |tp|
|
|
71
|
+
if tp.self == klazz
|
|
72
|
+
apply_strategies klazz.to_s
|
|
73
|
+
Kantox::Helpers.info "Strategies successfully applied to #{klazz} (callback in inherited)."
|
|
74
|
+
tp.disable
|
|
75
|
+
end
|
|
76
|
+
end).enable
|
|
77
|
+
when String, Symbol
|
|
78
|
+
if Kernel.const_defined?(klazz)
|
|
79
|
+
apply_strategies klazz
|
|
80
|
+
else
|
|
81
|
+
(@postponed[klazz] = TracePoint.new(:end) do |tp|
|
|
82
|
+
if tp.self.name == klazz
|
|
83
|
+
apply_strategies klazz
|
|
84
|
+
Kantox::Helpers.info "Strategies successfully applied to #{klazz} (eager waiting)."
|
|
85
|
+
tp.disable
|
|
86
|
+
end
|
|
87
|
+
end).enable
|
|
88
|
+
end
|
|
89
|
+
else fail LameError.new("Postpone strategies were called with inknown parameter type [#{klazz} :: #{klazz.class}]")
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def apply_strategies klazz
|
|
94
|
+
return if options[klazz].nil? # no strategies to apply
|
|
95
|
+
Kantox::Helpers.debug "Request to apply strategies to [#{klazz}]"
|
|
96
|
+
|
|
97
|
+
options[klazz].each do |m, strategies|
|
|
98
|
+
next unless Kernel.const_defined? klazz
|
|
99
|
+
|
|
100
|
+
Kernel.const_get(klazz).instance_methods.select do |im|
|
|
101
|
+
im =~ Regexp.new("\\A#{m.gsub('*', '(?:.*?)')}\\z")
|
|
102
|
+
end.each do |sim|
|
|
103
|
+
[*strategies].each do |strategy|
|
|
104
|
+
apply_strategy klazz, sim, strategy
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def apply_strategy klazz, m, strategy
|
|
111
|
+
km = "#{klazz}##{m}"
|
|
112
|
+
case applied[km]
|
|
113
|
+
when :success
|
|
114
|
+
Kantox::Helpers.debug("Trying to reapply #{strategy} to #{km}. «Skipped».")
|
|
115
|
+
return
|
|
116
|
+
when NilClass, :error
|
|
117
|
+
Kantox::Helpers.debug("Will apply strategy [#{strategy}] to [#{km}]")
|
|
118
|
+
else
|
|
119
|
+
fail LameError.new
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
if (im = Kantox::Helpers.get_instance_method(km)).nil?
|
|
123
|
+
@applied[km] = :error
|
|
124
|
+
return
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
pc = patch_code im, strategy
|
|
128
|
+
patch = "
|
|
129
|
+
def #{im[:method][:name]} *args
|
|
130
|
+
begin
|
|
131
|
+
#{pc}
|
|
132
|
+
rescue Kantox::Strategies::StrategyError => e
|
|
133
|
+
Kantox::Helpers.info '«Denied #{klazz}##{m}» due to #{strategy} strategy.'
|
|
134
|
+
raise Kantox::Exceptions::NotAllowed, e.message
|
|
135
|
+
rescue Kantox::Exceptions::NotAllowed => e
|
|
136
|
+
Kantox::Helpers.info '«Denied #{klazz}##{m}» (deep) due to #{strategy} strategy.'
|
|
137
|
+
raise Kantox::Exceptions::NotAllowed, e.message
|
|
138
|
+
rescue Kantox::Exceptions::StandardError => e
|
|
139
|
+
Kantox::Helpers.catched 'Guarged «#{klazz}##{m}» throws a [kantox] exception.', e
|
|
140
|
+
raise e
|
|
141
|
+
rescue ::StandardError => e
|
|
142
|
+
Kantox::Helpers.catched 'Guarged «#{klazz}##{m}» throws a [generic] exception.', e
|
|
143
|
+
raise e
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
"
|
|
147
|
+
im[:class].send :alias_method, "∃#{im[:method][:name]}", "#{im[:method][:name]}"
|
|
148
|
+
im[:class].class_eval patch
|
|
149
|
+
applied[km] = :success
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def patch_code im, strategy
|
|
153
|
+
Kantox::Helpers.debug "Strategy: #{strategy.class} :: [#{strategy}] "
|
|
154
|
+
args_as_string = im[:params][:string].empty? ? '' : '*args'
|
|
155
|
+
|
|
156
|
+
case strategy
|
|
157
|
+
when String, Symbol
|
|
158
|
+
"
|
|
159
|
+
strategy = Kantox::Helpers.get_simple_strategy('#{strategy}')
|
|
160
|
+
fail Kantox::Strategies::StrategyError(nil, '#{im[:method][:name]}') if strategy.nil?
|
|
161
|
+
strategy.call(self, '#{im[:class]}##{im[:method][:name]}', *args)
|
|
162
|
+
∃#{im[:method][:name]} #{args_as_string}
|
|
163
|
+
"
|
|
164
|
+
when Array
|
|
165
|
+
case strategy.first.to_s
|
|
166
|
+
when 'runner'
|
|
167
|
+
"
|
|
168
|
+
strategy = Kantox::Helpers.get_#{strategy.first}_strategy('#{strategy.last}')
|
|
169
|
+
fail Kantox::Strategies::StrategyError(nil, '#{im[:method][:name]}') if strategy.nil?
|
|
170
|
+
p = self.method('∃#{im[:method][:name]}').to_proc
|
|
171
|
+
strategy.call(self, *args, &p)
|
|
172
|
+
"
|
|
173
|
+
when 'lambda'
|
|
174
|
+
"
|
|
175
|
+
strategy = Kantox::Helpers.get_#{strategy.first}_strategy('#{strategy.last}')
|
|
176
|
+
fail Kantox::Strategies::StrategyError(nil, '#{im[:method][:name]}') if strategy.nil?
|
|
177
|
+
strategy.call(self, '#{im[:class]}##{im[:method][:name]}')
|
|
178
|
+
∃#{im[:method][:name]} #{args_as_string}
|
|
179
|
+
"
|
|
180
|
+
else
|
|
181
|
+
# Will try to instantiate the class with a given name
|
|
182
|
+
"
|
|
183
|
+
strategy = Kantox::Helpers.get_object_strategy('#{strategy.first}', '#{strategy.last}')
|
|
184
|
+
fail Kantox::Strategies::StrategyError(nil, '#{im[:method][:name]}') if strategy.nil?
|
|
185
|
+
strategy.to_proc.call(self, '#{im[:class]}##{im[:method][:name]}')
|
|
186
|
+
∃#{im[:method][:name]} #{args_as_string}
|
|
187
|
+
"
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
fail LameError.new "Unknown strategy: #{strategy}."
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def applied ; @applied ||= {} ; end
|
|
195
|
+
def postponed ; @postponed ||= {} ; end
|
|
196
|
+
def options ; @options ||= Hashie::Mash.new ; end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|