can_camel 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +30 -22
- data/lib/can_camel.rb +1 -1
- data/lib/can_camel/action_node.rb +4 -2
- data/lib/can_camel/base.rb +7 -1
- data/lib/can_camel/cache.rb +29 -11
- data/lib/can_camel/concern_node.rb +4 -0
- data/lib/can_camel/filter.rb +40 -0
- data/lib/can_camel/filters.rb +6 -13
- data/lib/can_camel/filters/at_day.rb +20 -0
- data/lib/can_camel/filters/at_time.rb +19 -0
- data/lib/can_camel/filters/base.rb +42 -0
- data/lib/can_camel/filters/custom_filter.rb +17 -0
- data/lib/can_camel/group_node.rb +6 -4
- data/lib/can_camel/linter.rb +10 -18
- data/lib/can_camel/node.rb +38 -2
- data/lib/can_camel/subject_node.rb +4 -2
- data/lib/can_camel/validators.rb +9 -25
- data/lib/can_camel/validators/general_validators.rb +44 -0
- data/lib/can_camel/validators/path_validators.rb +20 -0
- data/lib/can_camel/validators/validators_helper.rb +11 -0
- data/lib/can_camel/version.rb +1 -1
- data/lib/generators/can_camel/config/initializers/can_camel.rb +2 -3
- data/lib/generators/can_camel/db/migrate/00000000000001_create_can_camel_nodes.rb +3 -7
- data/lib/generators/can_camel/install_generator.rb +0 -1
- metadata +13 -5
- data/lib/generators/can_camel/db/migrate/00000000000002_hstore_to_json.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7327da083e2094e5ec46012cd8d677fa1d580a3
|
4
|
+
data.tar.gz: de42690b702c3cf0be312f3a284efdd7d2a8b9da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d990335cb5d604df985bb522370aabe0ac0750e516a51570c9d1485309bfec14acad9d254cc450e02f570766b01311db060fe682da20a353f3fd53a41fbda428
|
7
|
+
data.tar.gz: d43fd37f23f2cdcfcf28e63281b312ab7d9e714e79412a78a3d90547261e256c5886fc08a5c5e648719d753f8f8d94beae5bc02fad7c56e2207291b8ad878cf4
|
data/README.md
CHANGED
@@ -14,18 +14,16 @@ can be passed to a filter. Any custom filters could be made and any additional d
|
|
14
14
|
|
15
15
|
Step 1. Installation
|
16
16
|
====================
|
17
|
-
run rails g can_camel:install <br>
|
17
|
+
run `rails g can_camel:install` <br>
|
18
18
|
Then visit generated initializer at config/initializers/can_camel.rb
|
19
19
|
<pre>
|
20
|
-
# CanCamel::Filters.include AbilityFilters
|
21
20
|
CanCamel::TABLE_NAME = "can_camel_nodes"
|
22
21
|
CanCamel::GROUP_METHOD = :group
|
23
22
|
</pre>
|
24
|
-
|
25
|
-
here. You can also specify table name, if you want. Third line describes a symbol, which references for
|
23
|
+
In first line you can specify table name or use default. Second line describes a symbol, which references for
|
26
24
|
user model method, returning user group. Group should be a symbol. Visit spec/dummy/app/models/user.rb
|
27
|
-
for example. When you sure with this file, run generated
|
28
|
-
Remember, that
|
25
|
+
for example. When you sure with this file, run generated migrations.
|
26
|
+
Remember, that migrations installs 'hstore' plugin, on which relies,
|
29
27
|
but does not remove it. If you want to revert it, you may want to remove plugin too
|
30
28
|
|
31
29
|
Step 2. Database structure
|
@@ -34,29 +32,39 @@ Database consists of nodes. Primary nodes (WHERE parent_id IS NULL) are called s
|
|
34
32
|
Their children are called actions, and actions' children are called groups. Groups' children
|
35
33
|
are called garbage and never used. Any node can have conditions and results. Conditions' syntax is
|
36
34
|
<pre>
|
37
|
-
[
|
38
|
-
{ method: :day_of_week, allow: %w(saturday sunday) }
|
39
|
-
]
|
35
|
+
{ at_day: { wdays: [6] } }
|
40
36
|
</pre>
|
41
|
-
It means, that :
|
37
|
+
It means, that :at_day will be called with `wdays: [6]` argument
|
42
38
|
|
43
39
|
Step 3. Linting
|
44
40
|
===============
|
41
|
+
_I suggest to call `CanCamel.lint` each time you modifying can_camel objects because it is beta_ <br>
|
45
42
|
If you are working primary with database (e.g. in migration), you can call
|
46
43
|
`CanCamel.lint` to check is database correct. Best way is to call `CanCamel.lint!` in transaction
|
47
|
-
with all changes done and enjoy your exception if need
|
44
|
+
with all changes done and enjoy your exception if need.
|
48
45
|
|
49
|
-
Step 4. Constrains
|
50
|
-
|
51
|
-
Filters
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
46
|
+
Step 4. Custom filters and Constrains
|
47
|
+
=====================================
|
48
|
+
Filters subsystem relies on a `CanCamel::Filter` module, which automatically inserts
|
49
|
+
`register_filter` method when included. This method can take as first argument high variety of things
|
50
|
+
1. If it takes a symbol and lambda, it will define a simple filter without argument filtering
|
51
|
+
2. If it takes a method or symbol referencing a method, it will register that method as in previous api: as a simple
|
52
|
+
filter
|
53
|
+
3. If it takes a class respond to `invoke!` and `name` methods, it will register its element
|
54
|
+
4. If it takes something else respond to `invoke` and `name` methods, it will register it as is
|
55
|
+
|
56
|
+
You can use old style validation or use validate! method in objects passed
|
57
|
+
|
58
|
+
Old Style Validation
|
59
|
+
--------------------
|
60
|
+
Include `CanCamel::Validators` to use validates method. You can add custom validators extending
|
61
|
+
this class in initializer. Validation syntax is `validates filter [field] validator: params`
|
62
|
+
|
63
|
+
validate! method
|
64
|
+
----------------
|
65
|
+
define `validate!` method for you filters and place your validators here (mostly for semantic)
|
66
|
+
you can access improved `validates` method in classes inherited from `CanCamel::Filters::Base`
|
67
|
+
this method requires to specify only validators and optionally field name
|
60
68
|
|
61
69
|
Step 5. Human interface (NIY)
|
62
70
|
============================
|
data/lib/can_camel.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module CanCamel
|
2
2
|
class ActionNode < Node
|
3
3
|
has_many :groups, foreign_key: :parent_id, class_name: "CanCamel::GroupNode"
|
4
|
-
belongs_to :parent, foreign_key: :parent_id, class_name: "CanCamel::SubjectNode"
|
5
|
-
|
6
4
|
validates_presence_of :parent_id
|
5
|
+
|
6
|
+
def rank
|
7
|
+
2
|
8
|
+
end
|
7
9
|
end
|
8
10
|
end
|
data/lib/can_camel/base.rb
CHANGED
@@ -3,8 +3,14 @@ module CanCamel
|
|
3
3
|
# don't delegate all, because lint_node designed to be run on same instances of linter
|
4
4
|
delegate :lint, :lint!, to: :new_linter
|
5
5
|
|
6
|
+
# returns hash with some return params or nil.
|
7
|
+
# @param user [User] user respond to GROUP_METHOD
|
8
|
+
# @param action [Symbol] symbol relied to action node name
|
9
|
+
# @param subject [Symbol] symbol relied to subject node name
|
10
|
+
# @return [Hash, nil] hash with specific params or nil
|
6
11
|
def can?(user, action, subject, **args)
|
7
|
-
Cache[[user.send(GROUP_METHOD), action, subject]]
|
12
|
+
Cache[[user.send(GROUP_METHOD).to_sym, action, subject]]
|
13
|
+
.try(:can?, user: user, **args)
|
8
14
|
end
|
9
15
|
|
10
16
|
private
|
data/lib/can_camel/cache.rb
CHANGED
@@ -5,27 +5,45 @@ module CanCamel
|
|
5
5
|
|
6
6
|
def reload!
|
7
7
|
@cache = build_cache
|
8
|
+
inherit_all!
|
9
|
+
end
|
10
|
+
|
11
|
+
def children_of(node)
|
12
|
+
cache.select do |path, _value|
|
13
|
+
_, *subpath = path
|
14
|
+
node.path == subpath
|
15
|
+
end.values
|
16
|
+
end
|
17
|
+
|
18
|
+
def append(node, path)
|
19
|
+
path = [node.name, *path]
|
20
|
+
@cache[path] = node
|
21
|
+
children_of(node).each { |child| append child, path }
|
8
22
|
end
|
9
23
|
|
10
24
|
private
|
11
25
|
|
26
|
+
# def subpath?(path, subpath)
|
27
|
+
# return if path.empty?
|
28
|
+
# return true if subpath.empty?
|
29
|
+
# return unless path[-1] == subpath[-1]
|
30
|
+
# subpath?(path[0...-1], subpath[0...-1])
|
31
|
+
# end
|
32
|
+
|
12
33
|
def cache
|
13
|
-
@cache
|
34
|
+
@cache || (reload!; @cache)
|
14
35
|
end
|
15
36
|
|
16
37
|
def build_cache
|
17
|
-
|
18
|
-
|
19
|
-
subject_node.actions.each do |action_node|
|
20
|
-
action_name = action_node.name
|
21
|
-
action_node.groups.each do |group_node|
|
22
|
-
group_name = group_node.name
|
23
|
-
group_node.inherit!
|
24
|
-
object[[group_name, action_name, subject_name]] = group_node
|
25
|
-
end
|
26
|
-
end
|
38
|
+
Node.all.each_with_object({}) do |node, object|
|
39
|
+
object[node.path] = node
|
27
40
|
end
|
28
41
|
end
|
42
|
+
|
43
|
+
def inherit_all!
|
44
|
+
local_cache = cache.dup
|
45
|
+
local_cache.each { |_path, node| node.inherit! }
|
46
|
+
end
|
29
47
|
end
|
30
48
|
end
|
31
49
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CanCamel
|
2
|
+
module Filter
|
3
|
+
def self.included(base)
|
4
|
+
base.define_singleton_method(:register_filter) { |*args| CanCamel::Filter.register_filter(*args) }
|
5
|
+
end
|
6
|
+
|
7
|
+
class <<self
|
8
|
+
def register_filter(x, lambda = nil)
|
9
|
+
case x
|
10
|
+
when Class
|
11
|
+
filter = x.new
|
12
|
+
when Symbol
|
13
|
+
begin
|
14
|
+
filter = Filters::CustomFilter.new(x, lambda || method(x))
|
15
|
+
rescue NameError
|
16
|
+
raise ArgumentError, "no method #{x} defined and lambda not passed"
|
17
|
+
end
|
18
|
+
when Method
|
19
|
+
filter = Filters::CustomFilter.new(x.name, x)
|
20
|
+
else
|
21
|
+
filter = x
|
22
|
+
end
|
23
|
+
|
24
|
+
raise ArgumentError, "#{x} is neither Filter nor Class nor Symbol nor Method" unless filter?(filter)
|
25
|
+
filter.try(:validate!)
|
26
|
+
filters[filter.name] = filter
|
27
|
+
end
|
28
|
+
|
29
|
+
def filters
|
30
|
+
@filters ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def filter?(x)
|
36
|
+
%i(invoke! name).reduce { |a, e| a && x.respond_to?(e) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/can_camel/filters.rb
CHANGED
@@ -1,19 +1,12 @@
|
|
1
1
|
require 'can_camel/validators'
|
2
2
|
module CanCamel::Filters
|
3
3
|
include CanCamel::Validators
|
4
|
-
|
4
|
+
include CanCamel::Filter
|
5
|
+
extend ActiveSupport::Autoload
|
5
6
|
|
6
|
-
|
7
|
+
ABSTRACT_FILTERS = %i(Base CustomFilter)
|
8
|
+
FILTERS = %i(AtTime AtDay)
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
hours.include?(Time.now.hour) && {}
|
11
|
-
end
|
12
|
-
|
13
|
-
validates :at_day, presence_of: { fields: [:days, :wdays], any: true }
|
14
|
-
def at_day(days: nil, wdays: nil, **_)
|
15
|
-
return if days && !days.include?(Time.now.day)
|
16
|
-
return if wdays && !wdays.include?(Time.now.wday)
|
17
|
-
{}
|
18
|
-
end
|
10
|
+
(ABSTRACT_FILTERS + FILTERS).each { |x| autoload x }
|
11
|
+
FILTERS.each { |x| register_filter const_get(x) }
|
19
12
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CanCamel::Filters
|
2
|
+
class AtDay < Base
|
3
|
+
def catch_args
|
4
|
+
%i(days wdays)
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate!
|
8
|
+
validates presence_of: {
|
9
|
+
fields: %i(days wdays),
|
10
|
+
any: true,
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def filter(days: nil, wdays: nil)
|
15
|
+
return if days && !days.include?(Time.now.day)
|
16
|
+
return if wdays && !wdays.include?(Time.now.wday)
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CanCamel::Filters
|
2
|
+
class AtTime < AtDay
|
3
|
+
def catch_args
|
4
|
+
%i(hours days wdays)
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate!
|
8
|
+
validates presence_of: {
|
9
|
+
fields: %i(hours days wdays),
|
10
|
+
any: true,
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def filter(hours: nil, days: nil, wdays: nil)
|
15
|
+
return if hours && !hours.include?(Time.now.hour)
|
16
|
+
super days: days, wdays: wdays
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module CanCamel::Filters
|
2
|
+
class Base
|
3
|
+
def initialize(*)
|
4
|
+
end
|
5
|
+
|
6
|
+
def name
|
7
|
+
self.class.to_s.demodulize.underscore.to_sym
|
8
|
+
end
|
9
|
+
|
10
|
+
def catch_args
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def catch_result
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
def filter(**_)
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
|
22
|
+
def lint!
|
23
|
+
raise CanCamel::Linter::LintingError if (catch_args & catch_result).try(:any?)
|
24
|
+
end
|
25
|
+
|
26
|
+
def invoke!(args: {}, result: {})
|
27
|
+
args = my_slice(args, catch_args) if catch_args
|
28
|
+
args.merge! my_slice(result, catch_result) { |l, r, _k| r || l }
|
29
|
+
filter(**args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def validates(*args)
|
33
|
+
CanCamel::Validators.validates(name, *args)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def my_slice(hash, args)
|
39
|
+
args.each_with_object({}) { |x, object| object[x] = hash[x] }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/can_camel/group_node.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
module CanCamel
|
2
2
|
class GroupNode < Node
|
3
|
-
belongs_to :parent, foreign_key: :parent_id, class_name: "CanCamel::ActionNode"
|
4
|
-
|
5
3
|
validates_presence_of :parent_id
|
6
4
|
|
7
5
|
def can?(**additional_params)
|
8
|
-
condition.each_with_object(result.dup) do |(method, args), result|
|
6
|
+
condition.each_with_object(result.dup.merge(additional_params)) do |(method, args), result|
|
9
7
|
args = args.symbolize_keys
|
10
|
-
filtered =
|
8
|
+
filtered = Filter.filters[method].invoke!(args: args.merge(additional_params), result: result)
|
11
9
|
return unless filtered
|
12
10
|
result.merge! filtered
|
13
11
|
end || result
|
14
12
|
end
|
13
|
+
|
14
|
+
def rank
|
15
|
+
3
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
data/lib/can_camel/linter.rb
CHANGED
@@ -3,7 +3,8 @@ module CanCamel
|
|
3
3
|
LintingError = Class.new(StandardError)
|
4
4
|
|
5
5
|
def lint
|
6
|
-
|
6
|
+
Cache.reload! rescue return
|
7
|
+
%i(lint_nodes lint_filters).reduce(true) { |base, x| base && send(x) }
|
7
8
|
end
|
8
9
|
|
9
10
|
def lint!
|
@@ -16,11 +17,18 @@ module CanCamel
|
|
16
17
|
%i(validate_node).reduce(true) { |base, x| base && send(x, node) }
|
17
18
|
end
|
18
19
|
|
20
|
+
def lint_filters
|
21
|
+
CanCamel::Filter.filters.values.flatten.uniq.each { |filter| !filter.respond_to?(:lint!) || filter.lint! }
|
22
|
+
true
|
23
|
+
rescue CanCamel::Linter::LintingError
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
19
27
|
private
|
20
28
|
|
21
29
|
def validate_node(node)
|
22
30
|
node.condition.each do |method, args|
|
23
|
-
Validators.validate!(filter: method, args: args.symbolize_keys)
|
31
|
+
Validators.validate!(filter: method, args: args.symbolize_keys, path: node.path)
|
24
32
|
end
|
25
33
|
true
|
26
34
|
rescue Validators::ValidationError, LintingError
|
@@ -30,21 +38,5 @@ module CanCamel
|
|
30
38
|
def lint_nodes
|
31
39
|
CanCamel::Node.all.reduce(true) { |base, x| base && lint_node(x) }
|
32
40
|
end
|
33
|
-
|
34
|
-
def lint_inheritance
|
35
|
-
CanCamel::Node.with_parents.where(<<-SQL).empty?
|
36
|
-
(
|
37
|
-
#{TABLE_NAME}.type = 'CanCamel::ActionNode'
|
38
|
-
AND
|
39
|
-
parents.type != 'CanCamel::SubjectNode'
|
40
|
-
)
|
41
|
-
OR
|
42
|
-
(
|
43
|
-
#{TABLE_NAME}.type = 'CanCamel::GroupNode'
|
44
|
-
AND
|
45
|
-
parents.type != 'CanCamel::ActionNode'
|
46
|
-
)
|
47
|
-
SQL
|
48
|
-
end
|
49
41
|
end
|
50
42
|
end
|
data/lib/can_camel/node.rb
CHANGED
@@ -2,19 +2,43 @@ module CanCamel
|
|
2
2
|
class Node < ActiveRecord::Base
|
3
3
|
self.table_name = TABLE_NAME
|
4
4
|
self.inheritance_column = 'type'
|
5
|
+
|
6
|
+
belongs_to :parent, foreign_key: :parent_id, class_name: "CanCamel::Node"
|
7
|
+
has_many :children, foreign_key: :parent_id, class_name: "CanCamel::Node"
|
8
|
+
|
9
|
+
has_many :actions, foreign_key: :parent_id, class_name: "CanCamel::ActionNode"
|
10
|
+
has_many :groups, foreign_key: :parent_id, class_name: "CanCamel::GroupNode"
|
11
|
+
|
5
12
|
belongs_to :inherited_node, foreign_key: :inherit_id, class_name: "CanCamel::Node"
|
6
13
|
|
14
|
+
def cached_parent
|
15
|
+
Cache[path[1..-1]]
|
16
|
+
end
|
17
|
+
|
18
|
+
def rank
|
19
|
+
raise "inheriting invalid node"
|
20
|
+
end
|
21
|
+
|
22
|
+
def cached_inherited_node
|
23
|
+
return unless inherit_id
|
24
|
+
@inherited_path ||= inherited_node.path
|
25
|
+
Cache[@inherited_path]
|
26
|
+
end
|
27
|
+
|
7
28
|
def self.with_parents
|
8
29
|
joins("LEFT JOIN #{TABLE_NAME} AS parents ON #{TABLE_NAME}.parent_id = parents.id")
|
9
30
|
end
|
10
31
|
|
11
32
|
def inherit!(source = nil)
|
12
33
|
return if inherited
|
34
|
+
|
35
|
+
raise 'inherit nodes only after cache built' unless Cache[path]
|
36
|
+
|
13
37
|
@inherited = true
|
14
38
|
return inherit_source! source if source
|
15
39
|
|
16
|
-
inherit_source!
|
17
|
-
inherit_source!
|
40
|
+
inherit_source! cached_parent
|
41
|
+
inherit_source! cached_inherited_node
|
18
42
|
end
|
19
43
|
|
20
44
|
validates! :inherited, absence: { message: "You should not save inherited nodes!" }
|
@@ -27,6 +51,12 @@ module CanCamel
|
|
27
51
|
super.symbolize_keys
|
28
52
|
end
|
29
53
|
|
54
|
+
attr_writer :path
|
55
|
+
|
56
|
+
def path
|
57
|
+
@path ||= parent ? [name] + parent.path : [name]
|
58
|
+
end
|
59
|
+
|
30
60
|
private
|
31
61
|
|
32
62
|
attr_reader :inherited
|
@@ -36,6 +66,12 @@ module CanCamel
|
|
36
66
|
|
37
67
|
source.inherit!
|
38
68
|
|
69
|
+
Cache.children_of(source).each do |child|
|
70
|
+
next unless child.rank > rank
|
71
|
+
next if child == self
|
72
|
+
Cache.append child, path
|
73
|
+
end
|
74
|
+
|
39
75
|
inherit_field(source, :description) { |x| self.description ||= x }
|
40
76
|
inherit_field(source, :result) { |x| result.merge!(x) { |_k, l, _r| l } }
|
41
77
|
inherit_field(source, :condition) { |x| self.condition = x.merge(condition) }
|
data/lib/can_camel/validators.rb
CHANGED
@@ -2,6 +2,12 @@ module CanCamel::Validators
|
|
2
2
|
ValidationError = Class.new(StandardError)
|
3
3
|
UnknownFilter = Class.new(ValidationError)
|
4
4
|
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
SUBMODULES = %i(GeneralValidators PathValidators)
|
7
|
+
SUBMODULES.each { |x| autoload x }
|
8
|
+
autoload :ValidatorsHelper
|
9
|
+
SUBMODULES.each { |x| extend const_get(x) }
|
10
|
+
|
5
11
|
class <<self
|
6
12
|
def included(base)
|
7
13
|
base.define_singleton_method(:validates) { |*args| CanCamel::Validators.validates *args }
|
@@ -20,13 +26,13 @@ module CanCamel::Validators
|
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
23
|
-
def validate!(filter:, args:)
|
29
|
+
def validate!(filter:, args:, path: nil)
|
24
30
|
filter = filter.to_sym
|
25
31
|
unless validators[filter]
|
26
|
-
raise UnknownFilter unless CanCamel::
|
32
|
+
raise UnknownFilter unless CanCamel::Filter.filters.include? filter
|
27
33
|
return
|
28
34
|
end
|
29
|
-
validators[filter].each { |x| x.call(args) }
|
35
|
+
validators[filter].each { |x| x.call(path: path, **args) }
|
30
36
|
end
|
31
37
|
|
32
38
|
private
|
@@ -34,27 +40,5 @@ module CanCamel::Validators
|
|
34
40
|
def validators
|
35
41
|
@validators ||= {}
|
36
42
|
end
|
37
|
-
|
38
|
-
def presence(field:)
|
39
|
-
raise ValidationError unless field.present?
|
40
|
-
end
|
41
|
-
|
42
|
-
def presence_of(fields:, args:, any: false)
|
43
|
-
condition = fields.map { |x| args[x].present? }.reduce { |base, x| any ? (base || x) : (base && x) }
|
44
|
-
return if condition
|
45
|
-
raise ValidationError
|
46
|
-
end
|
47
|
-
|
48
|
-
def in(field:, array: [], empty: false)
|
49
|
-
return if array.include? field
|
50
|
-
return if empty && !field.present?
|
51
|
-
raise ValidationError
|
52
|
-
end
|
53
|
-
|
54
|
-
def custom(field:, lambda:, empty: false)
|
55
|
-
return if empty && !field.present?
|
56
|
-
return if lambda.call(field)
|
57
|
-
raise ValidationError
|
58
|
-
end
|
59
43
|
end
|
60
44
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module CanCamel::Validators
|
2
|
+
module GeneralValidators
|
3
|
+
def presence(field:)
|
4
|
+
raise ValidationError unless field.present?
|
5
|
+
end
|
6
|
+
|
7
|
+
def absence(field:)
|
8
|
+
raise ValidationError if field.present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def presence_of(fields:, args:, any: false, only: false, none: false)
|
12
|
+
if [any, only, none].select(&:presence).count > 1
|
13
|
+
raise ValidationError, 'only one of [any, only, none] could be supplied to presence_of'
|
14
|
+
end
|
15
|
+
|
16
|
+
only = 0 if none
|
17
|
+
only = 1 if only && !only.is_a?(Fixnum)
|
18
|
+
|
19
|
+
fields_present = fields.select { |x| args[x].present? }
|
20
|
+
|
21
|
+
case
|
22
|
+
when only
|
23
|
+
return if fields_present.count == only
|
24
|
+
when any
|
25
|
+
return if fields_present.count > 0
|
26
|
+
else
|
27
|
+
return if fields_present.count == fields.count
|
28
|
+
end
|
29
|
+
raise ValidationError
|
30
|
+
end
|
31
|
+
|
32
|
+
def in(field:, array: [], empty: false)
|
33
|
+
return if array.include? field
|
34
|
+
return if empty && !field.present?
|
35
|
+
raise ValidationError
|
36
|
+
end
|
37
|
+
|
38
|
+
def custom(field:, lambda:, empty: false)
|
39
|
+
return if empty && !field.present?
|
40
|
+
return if lambda.call(field)
|
41
|
+
raise ValidationError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CanCamel::Validators
|
2
|
+
module PathValidators
|
3
|
+
include ValidatorsHelper
|
4
|
+
|
5
|
+
def path(path:, action: nil, subject: nil, group: nil)
|
6
|
+
raise ValidationError unless action || subject || group
|
7
|
+
unless path && path.length == 3
|
8
|
+
raise ValidationError, 'trying to validate not a group node or invalid node structure'
|
9
|
+
end
|
10
|
+
|
11
|
+
validate_element(element: path[0], value: group) if group
|
12
|
+
validate_element(element: path[1], value: action) if action
|
13
|
+
validate_element(element: path[2], value: subject) if subject
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :action, :path
|
17
|
+
alias_method :subject, :path
|
18
|
+
alias_method :group, :path
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module CanCamel::Validators
|
2
|
+
module ValidatorsHelper
|
3
|
+
def validate_element(element:, value:)
|
4
|
+
if value.is_a? Proc
|
5
|
+
raise ValidationError unless value.call element
|
6
|
+
return
|
7
|
+
end
|
8
|
+
raise ValidationError unless element.to_s == value.to_s
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/can_camel/version.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
# include custom
|
2
|
-
#
|
3
|
-
# CanCamel::Filters.include AbilityFilters
|
1
|
+
# include custom validators
|
2
|
+
# CanCamel::Validators.extend AbilityFiltersValidators
|
4
3
|
CanCamel::TABLE_NAME = "can_camel_nodes"
|
5
4
|
CanCamel::GROUP_METHOD = :group
|
@@ -1,18 +1,14 @@
|
|
1
1
|
class CreateCanCamelNodes < ActiveRecord::Migration
|
2
2
|
def change
|
3
|
-
reversible do |d|
|
4
|
-
d.up { execute 'CREATE extension IF NOT EXISTS hstore;' }
|
5
|
-
end
|
6
|
-
|
7
3
|
create_table CanCamel::TABLE_NAME do |t|
|
8
4
|
t.column :name, :string, index: true
|
9
5
|
t.column :description, :text, null: true
|
10
6
|
t.column :parent_id, :integer, null: true
|
11
7
|
t.column :inherit_id, :integer, null: true
|
12
8
|
t.column :type, :string
|
13
|
-
t.column :override_fields, :
|
14
|
-
t.column :condition, :
|
15
|
-
t.column :result, :
|
9
|
+
t.column :override_fields, :json, default: []
|
10
|
+
t.column :condition, :json, default: {}
|
11
|
+
t.column :result, :json, default: {}
|
16
12
|
end
|
17
13
|
end
|
18
14
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: can_camel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Smirnov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '4
|
19
|
+
version: '4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '4
|
26
|
+
version: '4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: pg
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -54,16 +54,23 @@ files:
|
|
54
54
|
- lib/can_camel/base.rb
|
55
55
|
- lib/can_camel/cache.rb
|
56
56
|
- lib/can_camel/concern_node.rb
|
57
|
+
- lib/can_camel/filter.rb
|
57
58
|
- lib/can_camel/filters.rb
|
59
|
+
- lib/can_camel/filters/at_day.rb
|
60
|
+
- lib/can_camel/filters/at_time.rb
|
61
|
+
- lib/can_camel/filters/base.rb
|
62
|
+
- lib/can_camel/filters/custom_filter.rb
|
58
63
|
- lib/can_camel/group_node.rb
|
59
64
|
- lib/can_camel/linter.rb
|
60
65
|
- lib/can_camel/node.rb
|
61
66
|
- lib/can_camel/subject_node.rb
|
62
67
|
- lib/can_camel/validators.rb
|
68
|
+
- lib/can_camel/validators/general_validators.rb
|
69
|
+
- lib/can_camel/validators/path_validators.rb
|
70
|
+
- lib/can_camel/validators/validators_helper.rb
|
63
71
|
- lib/can_camel/version.rb
|
64
72
|
- lib/generators/can_camel/config/initializers/can_camel.rb
|
65
73
|
- lib/generators/can_camel/db/migrate/00000000000001_create_can_camel_nodes.rb
|
66
|
-
- lib/generators/can_camel/db/migrate/00000000000002_hstore_to_json.rb
|
67
74
|
- lib/generators/can_camel/install_generator.rb
|
68
75
|
- lib/tasks/can_camel_tasks.rake
|
69
76
|
homepage: https://github.com/JelF/can_camel
|
@@ -91,3 +98,4 @@ signing_key:
|
|
91
98
|
specification_version: 4
|
92
99
|
summary: CanCamel is a cancan style access controll library
|
93
100
|
test_files: []
|
101
|
+
has_rdoc:
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class HstoreToJson < ActiveRecord::Migration
|
2
|
-
def change
|
3
|
-
unless ENV['RAILS_ENV'] == 'test' || ENV['FORCE_CAN_CAMEL_WIPE'] == 'true'
|
4
|
-
puts "Attention! This migration will wipe can_camel data. Continue? (Y/n)"
|
5
|
-
puts "Set FORCE_CAN_CAMEL_WIPE=true to automaticaly accept"
|
6
|
-
res = STDIN.gets
|
7
|
-
raise unless res =~ /\A[Yy]/
|
8
|
-
end
|
9
|
-
CanCamel::Node.delete_all
|
10
|
-
remove_column CanCamel::TABLE_NAME, :condition, :hstore, array: true, default: []
|
11
|
-
add_column CanCamel::TABLE_NAME, :condition, :json, default: {}
|
12
|
-
CanCamel::Node.delete_all
|
13
|
-
end
|
14
|
-
end
|