can_camel 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|