Class: Roleback::RuleBook

Inherits:
Object
  • Object
show all
Defined in:
lib/roleback/rule_book.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(role) ⇒ RuleBook

Returns a new instance of RuleBook.



5
6
7
8
# File 'lib/roleback/rule_book.rb', line 5

def initialize(role)
	@rules = {}
	@role = role
end

Instance Attribute Details

#rulesObject (readonly)

Returns the value of attribute rules.



3
4
5
# File 'lib/roleback/rule_book.rb', line 3

def rules
  @rules
end

Class Method Details

.sort(rules) ⇒ Object

sorts the rules, based on the rules’ numerical value

Raises:

  • (::ArgumentError)


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/roleback/rule_book.rb', line 90

def self.sort(rules)
	# rules should be a hash
	raise ::ArgumentError, "rules should be a hash but it is a #{rules.class}" unless rules.is_a?(Hash)

	# rules is a hash, so we need to convert it to an array
	rules = rules.values

	# sort the rules
	rules.sort! do |a, b|
		an = a.numerical_value
		bn = b.numerical_value

		# if the numerical values are the same, sort by key, otherwise sort by numerical value
		if an == bn
			a.key <=> b.key
		else
			bn <=> an
		end
	end
end

Instance Method Details

#[](key) ⇒ Object



45
46
47
# File 'lib/roleback/rule_book.rb', line 45

def [](key)
	@rules[key]
end

#add(rule) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/roleback/rule_book.rb', line 10

def add(rule)
	raise ::Roleback::BadConfiguration, "Adding a rule with no role" unless rule.role

	if @rules[rule.key]
		if @rules[rule.key].outcome.outcome == rule.outcome.outcome
			# don't allow it if they share a rulebook
			if @role.name == rule.role.name
				raise ::Roleback::BadConfiguration, "Rule #{rule.key} already defined"
			else
				# this duplicate is through inheritance, so we can safely ignore it
				return
			end
		else
			raise ::Roleback::BadConfiguration, "Rule #{rule.key} already defined with a different outcome (conflicting rules)"
		end
	end

	# detect conflicting rules
	@rules.each do |key, existing_rule|
		if existing_rule.conflicts_with?(rule)
			raise ::Roleback::BadConfiguration, "Rule #{rule.key} conflicts with #{existing_rule.key}"
		end
	end

	@rules[rule.key] = rule
end

#can?(resource:, scope:, action:) ⇒ Boolean

Returns:

  • (Boolean)


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/roleback/rule_book.rb', line 62

def can?(resource:, scope:, action:)
	# get all rules that matches the given resource, scope and action
	rules = match_all(resource: resource, scope: scope, action: action)

	# if there are no rules, return false
	return false if rules.empty?

	# create a rule book with the matching rules
	match_book = self.class.new(@role)
	rules.each do |rule|
		match_book.add(rule)
	end

	# sort the rules
	sorted_rules = self.class.sort(match_book.rules)

	# iterate over the sorted rules and find the first rule that matches
	sorted_rules.each do |rule|
		if rule.match(resource: resource, scope: scope, action: action)
			return rule.outcome.allowed?
		end
	end

	# if no rule matches, return false
	return false
end

#clear_rulesObject



37
38
39
# File 'lib/roleback/rule_book.rb', line 37

def clear_rules
	@rules = {}
end

#keysObject



49
50
51
# File 'lib/roleback/rule_book.rb', line 49

def keys
	@rules.keys
end

#lengthObject



41
42
43
# File 'lib/roleback/rule_book.rb', line 41

def length
	@rules.length
end

#match_all(resource:, scope:, action:) ⇒ Object



53
54
55
56
57
58
59
60
# File 'lib/roleback/rule_book.rb', line 53

def match_all(resource:, scope:, action:)
	result = []
	@rules.each do |key, rule|
		result << rule if rule.match(resource: resource, scope: scope, action: action)
	end

	result
end

#sortObject



115
116
117
# File 'lib/roleback/rule_book.rb', line 115

def sort
	self.class.sort(@rules)
end

#sort!Object



111
112
113
# File 'lib/roleback/rule_book.rb', line 111

def sort!
	@rules = self.class.sort(@rules)
end

#to_aObject



123
124
125
# File 'lib/roleback/rule_book.rb', line 123

def to_a
	@rules.values
end

#to_sObject



119
120
121
# File 'lib/roleback/rule_book.rb', line 119

def to_s
	@rules.values.map(&:to_s).join("\n")
end