policy 1.0.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/.coveralls.yml +2 -0
- data/.metrics +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +18 -0
- data/.yardopts +3 -0
- data/Gemfile +7 -0
- data/Guardfile +15 -0
- data/LICENSE +21 -0
- data/README.md +223 -0
- data/Rakefile +17 -0
- data/config/metrics/STYLEGUIDE +231 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +14 -0
- data/config/metrics/pippi.yml +3 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +87 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +5 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/policy/follower/followed_policies.rb +45 -0
- data/lib/policy/follower/followed_policy.rb +104 -0
- data/lib/policy/follower/names.rb +29 -0
- data/lib/policy/follower.rb +143 -0
- data/lib/policy/interface.rb +48 -0
- data/lib/policy/validations.rb +28 -0
- data/lib/policy/version.rb +9 -0
- data/lib/policy/violation_error.rb +52 -0
- data/lib/policy.rb +40 -0
- data/policy.gemspec +23 -0
- data/spec/features/follower_spec.rb +95 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/tests/policy/follower/followed_policies_spec.rb +87 -0
- data/spec/tests/policy/follower/followed_policy_spec.rb +117 -0
- data/spec/tests/policy/follower/names_spec.rb +19 -0
- data/spec/tests/policy/follower_spec.rb +220 -0
- data/spec/tests/policy/interface_spec.rb +83 -0
- data/spec/tests/policy/validations_spec.rb +13 -0
- data/spec/tests/policy/violation_error_spec.rb +75 -0
- data/spec/tests/policy_spec.rb +35 -0
- metadata +142 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
---
|
2
|
+
# settings added by the 'hexx-suit' module
|
3
|
+
# output: "tmp/rubocop"
|
4
|
+
# format: "html"
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- '**/db/schema.rb'
|
9
|
+
|
10
|
+
Lint/HandleExceptions:
|
11
|
+
Exclude:
|
12
|
+
- '**/*_spec.rb'
|
13
|
+
|
14
|
+
Lint/RescueException:
|
15
|
+
Exclude:
|
16
|
+
- '**/*_spec.rb'
|
17
|
+
|
18
|
+
Metrics/ClassLength:
|
19
|
+
Exclude:
|
20
|
+
- '**/generator*'
|
21
|
+
|
22
|
+
Style/AccessorMethodName:
|
23
|
+
Exclude:
|
24
|
+
- '**/*_spec.rb'
|
25
|
+
|
26
|
+
Style/AsciiComments:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Style/ClassAndModuleChildren:
|
30
|
+
Exclude:
|
31
|
+
- '**/*_spec.rb'
|
32
|
+
|
33
|
+
Style/Documentation:
|
34
|
+
Exclude:
|
35
|
+
- '**/version.rb'
|
36
|
+
- '**/*_spec.rb'
|
37
|
+
|
38
|
+
Style/EmptyLinesAroundBlockBody:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/EmptyLinesAroundClassBody:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/EmptyLinesAroundMethodBody:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Style/EmptyLinesAroundModuleBody:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Style/EmptyLineBetweenDefs:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Style/FileName:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
Style/RaiseArgs:
|
57
|
+
EnforcedStyle: compact
|
58
|
+
|
59
|
+
Style/RescueModifier:
|
60
|
+
Exclude:
|
61
|
+
- '**/*_spec.rb'
|
62
|
+
|
63
|
+
Style/SingleLineMethods:
|
64
|
+
Exclude:
|
65
|
+
- '**/*_spec.rb'
|
66
|
+
|
67
|
+
Style/SingleSpaceBeforeFirstArg:
|
68
|
+
Enabled: false
|
69
|
+
|
70
|
+
Style/SpecialGlobalVars:
|
71
|
+
Exclude:
|
72
|
+
- '**/Gemfile'
|
73
|
+
- '**/*.gemspec'
|
74
|
+
|
75
|
+
Style/StructInheritance:
|
76
|
+
Exclude:
|
77
|
+
- '**/*_spec.rb'
|
78
|
+
|
79
|
+
Style/StringLiterals:
|
80
|
+
EnforcedStyle: double_quotes
|
81
|
+
|
82
|
+
Style/StringLiteralsInInterpolation:
|
83
|
+
EnforcedStyle: double_quotes
|
84
|
+
|
85
|
+
Style/TrivialAccessors:
|
86
|
+
Exclude:
|
87
|
+
- '**/*_spec.rb'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
---
|
2
|
+
# Settings added by the 'hexx-suit' gem
|
3
|
+
output: "tmp/yardstick/output.log"
|
4
|
+
path: "lib/**/*.rb"
|
5
|
+
rules:
|
6
|
+
ApiTag::Presence:
|
7
|
+
enabled: true
|
8
|
+
exclude: []
|
9
|
+
ApiTag::Inclusion:
|
10
|
+
enabled: true
|
11
|
+
exclude: []
|
12
|
+
ApiTag::ProtectedMethod:
|
13
|
+
enabled: true
|
14
|
+
exclude: []
|
15
|
+
ApiTag::PrivateMethod:
|
16
|
+
enabled: false
|
17
|
+
exclude: []
|
18
|
+
ExampleTag:
|
19
|
+
enabled: true
|
20
|
+
exclude: []
|
21
|
+
ReturnTag:
|
22
|
+
enabled: true
|
23
|
+
exclude: []
|
24
|
+
Summary::Presence:
|
25
|
+
enabled: true
|
26
|
+
exclude: []
|
27
|
+
Summary::Length:
|
28
|
+
enabled: true
|
29
|
+
exclude: []
|
30
|
+
Summary::Delimiter:
|
31
|
+
enabled: true
|
32
|
+
exclude: []
|
33
|
+
Summary::SingleLine:
|
34
|
+
enabled: true
|
35
|
+
exclude: []
|
36
|
+
threshold: 100
|
37
|
+
verbose: false
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Policy
|
4
|
+
|
5
|
+
module Follower
|
6
|
+
|
7
|
+
# Describes the list of followed policies
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class FollowedPolicies < Hash
|
11
|
+
|
12
|
+
# Registers followed policy with given unique key
|
13
|
+
#
|
14
|
+
# @param [Policy::Follower::FollowedPolicy] policy
|
15
|
+
#
|
16
|
+
# @return [undefined]
|
17
|
+
def add(policy)
|
18
|
+
self[policy.name] = policy
|
19
|
+
end
|
20
|
+
|
21
|
+
# Applies to follower the policies, selected by names
|
22
|
+
#
|
23
|
+
# @param [Policy::Follower] follower
|
24
|
+
# @param [Array<#to_s>] names
|
25
|
+
#
|
26
|
+
# @raise [Policy::ViolationError]
|
27
|
+
# unless all policies are met
|
28
|
+
#
|
29
|
+
# @return [undefined]
|
30
|
+
def apply_to(follower, *names)
|
31
|
+
named_by(names).each { |policy| policy.apply_to(follower) }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def named_by(list)
|
37
|
+
names = Names.from list
|
38
|
+
names.any? ? names.map(&method(:[])).compact : values
|
39
|
+
end
|
40
|
+
|
41
|
+
end # class FollowedPolicies
|
42
|
+
|
43
|
+
end # module Follower
|
44
|
+
|
45
|
+
end # module Policy
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Policy
|
4
|
+
|
5
|
+
module Follower
|
6
|
+
|
7
|
+
# Stores the policy to be applied to all instances of the follower
|
8
|
+
#
|
9
|
+
# The policy object can be set either as a constant, or by name
|
10
|
+
# in given namespace. Namespace and policy name can be set separately.
|
11
|
+
#
|
12
|
+
# The separation is used at the {Policy::Follower#apply_policies}.
|
13
|
+
#
|
14
|
+
# @example The policy can be constant
|
15
|
+
# FollowedPolicy.new nil, Foo::Bar::Baz, :baz_policy, :baz
|
16
|
+
#
|
17
|
+
# @example The policy can be name, relative to the namespace
|
18
|
+
# FollowedPolicy.new Foo::Bar, :Baz, :baz_policy, :baz
|
19
|
+
# # Foo::Bar::Baz policy object will be used
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
class FollowedPolicy
|
23
|
+
|
24
|
+
# @!scope class
|
25
|
+
# @!method new(namespace, policy, name, *attributes)
|
26
|
+
# Creates the immutable policy to be followed by given object
|
27
|
+
#
|
28
|
+
# @param [Module] namespace
|
29
|
+
# the namespace for the policy, given by name
|
30
|
+
# @param [Class, #to_s] policy
|
31
|
+
# the class for applicable policy
|
32
|
+
# @param [#to_sym, nil] name
|
33
|
+
# the name for the policy
|
34
|
+
# @param [Array<Symbol>] attributes
|
35
|
+
# the list of follower attributes to apply the policy to
|
36
|
+
#
|
37
|
+
# @return [Policy::Follower::FollowedPolicy]
|
38
|
+
# immutable object
|
39
|
+
def initialize(namespace, policy, name, *attributes)
|
40
|
+
@policy = find_policy(namespace, policy)
|
41
|
+
@name = (name || SecureRandom.uuid).to_sym
|
42
|
+
@attributes = check_attributes attributes
|
43
|
+
end
|
44
|
+
|
45
|
+
# @!attribute [r] name
|
46
|
+
# The name for the policy
|
47
|
+
#
|
48
|
+
# @return [Symbol]
|
49
|
+
attr_reader :name
|
50
|
+
|
51
|
+
# @!attribute [r] policy
|
52
|
+
# The policy object class to be followed
|
53
|
+
#
|
54
|
+
# @return [Class]
|
55
|
+
attr_reader :policy
|
56
|
+
|
57
|
+
# @!attribute [r] attributes
|
58
|
+
# The list of follower attributes to be send to the policy object
|
59
|
+
#
|
60
|
+
# @return [Array<Symbol>]
|
61
|
+
attr_reader :attributes
|
62
|
+
|
63
|
+
# Applies the policy to follower instance
|
64
|
+
#
|
65
|
+
# @param [Policy::Follower]
|
66
|
+
# follower
|
67
|
+
#
|
68
|
+
# @raise [Policy::ViolationError]
|
69
|
+
# it the follower doesn't meet the policy
|
70
|
+
#
|
71
|
+
# @return [undefined]
|
72
|
+
def apply_to(follower)
|
73
|
+
policy.apply(*attributes_of(follower))
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def find_policy(namespace, policy)
|
79
|
+
return policy if policy.instance_of?(Class)
|
80
|
+
instance_eval [namespace, policy].join("::")
|
81
|
+
end
|
82
|
+
|
83
|
+
def attributes_of(follower)
|
84
|
+
attributes.map(&follower.method(:send))
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_attributes(attributes)
|
88
|
+
number = policy.members.count
|
89
|
+
return attributes if attributes.count.equal?(number)
|
90
|
+
fail wrong_number(number, attributes)
|
91
|
+
end
|
92
|
+
|
93
|
+
def wrong_number(number, attributes)
|
94
|
+
ArgumentError.new [
|
95
|
+
"#{ policy } requires #{ number } attribute(s).",
|
96
|
+
"#{ attributes } cannot be assigned."
|
97
|
+
].join(" ")
|
98
|
+
end
|
99
|
+
|
100
|
+
end # class FollowedPolicy
|
101
|
+
|
102
|
+
end # module Follower
|
103
|
+
|
104
|
+
end # module Policy
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Policy
|
4
|
+
|
5
|
+
module Follower
|
6
|
+
|
7
|
+
# Converter of items to array of unique symbols
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
module Names
|
11
|
+
|
12
|
+
# Converts items to array of unique symbols
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# Policy::Follower::Names.from "foo", [:foo, "bar"], "baz"
|
16
|
+
# # => [:foo, :bar, :baz]
|
17
|
+
#
|
18
|
+
# @param [Array<#to_sym>] items
|
19
|
+
#
|
20
|
+
# @return [Array<Symbol>]
|
21
|
+
def self.from(*items)
|
22
|
+
items.flatten.map(&:to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Policy
|
4
|
+
|
5
|
+
# Adds features for the object to follow external policies
|
6
|
+
module Follower
|
7
|
+
|
8
|
+
require_relative "follower/names"
|
9
|
+
require_relative "follower/followed_policy"
|
10
|
+
require_relative "follower/followed_policies"
|
11
|
+
|
12
|
+
# Methods to be added to the class the module is included to
|
13
|
+
#
|
14
|
+
# @private
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
# @!attribute [r] followed_policies
|
18
|
+
# The collection of policies to be followed by instances of the class
|
19
|
+
#
|
20
|
+
# @return [Policy::Follower::FollowedPolicies]
|
21
|
+
#
|
22
|
+
# @private
|
23
|
+
def followed_policies
|
24
|
+
@followed_policies ||= FollowedPolicies.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Adds a policy to the list of {#followed_policies}
|
28
|
+
#
|
29
|
+
# @param [Class] policy
|
30
|
+
# the policy object klass
|
31
|
+
# @param [Array<#to_sym>] attributes
|
32
|
+
# the list of attributes of the instance the policy should be applied to
|
33
|
+
#
|
34
|
+
# @option [#to_sym] :as
|
35
|
+
# the name for the policy to be used for selecting it
|
36
|
+
# in {#follow_policies!} and {#follow_policies?} methods
|
37
|
+
#
|
38
|
+
# @return [undefined]
|
39
|
+
def follow_policy(policy, *attributes, as: nil)
|
40
|
+
object = FollowedPolicy.new(__policies__, policy, as, *attributes)
|
41
|
+
followed_policies.add object
|
42
|
+
end
|
43
|
+
|
44
|
+
# Changes the namespace for applied policies
|
45
|
+
#
|
46
|
+
# @example For Policies::Finances::TransferConsistency
|
47
|
+
# use_policies Policies::Finances do
|
48
|
+
# apply_policy :TransferConstistency, :debet, :credit
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @param [Module] namespace
|
52
|
+
#
|
53
|
+
# @yield the block in the current scope
|
54
|
+
#
|
55
|
+
# @return [undefined]
|
56
|
+
def use_policies(namespace, &block)
|
57
|
+
@__policies__ = namespace
|
58
|
+
instance_eval(&block)
|
59
|
+
ensure
|
60
|
+
@__policies__ = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def __policies__
|
66
|
+
@__policies__ ||= self
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# Checks whether an instance meets selected policies
|
72
|
+
#
|
73
|
+
# Mutates the object by adding new #errors
|
74
|
+
#
|
75
|
+
# @param [Array<#to_sym>] names
|
76
|
+
# the ordered list of names to select policies by
|
77
|
+
# when not names selected all policies will be applied
|
78
|
+
#
|
79
|
+
# @raise [Policy::ViolationError]
|
80
|
+
# unless all selected policies has been met
|
81
|
+
#
|
82
|
+
# @return [undefined]
|
83
|
+
def follow_policies!(*names)
|
84
|
+
followed_policies.apply_to self, *names
|
85
|
+
rescue ViolationError => error
|
86
|
+
collect_errors_from(error)
|
87
|
+
raise
|
88
|
+
end
|
89
|
+
|
90
|
+
# Syntax shugar for the {#follow_policies!} with one argument
|
91
|
+
#
|
92
|
+
# @param [#to_sym] name
|
93
|
+
# the name of the policy to follow
|
94
|
+
#
|
95
|
+
# @raise (see #follow_policies!)
|
96
|
+
#
|
97
|
+
# @return [undefined]
|
98
|
+
def follow_policy!(name)
|
99
|
+
follow_policies! name
|
100
|
+
end
|
101
|
+
|
102
|
+
# Safely checks whether an instance meets selected policies
|
103
|
+
#
|
104
|
+
# Mutates the object by adding new #errors
|
105
|
+
#
|
106
|
+
# @param (see #follow_policies!)
|
107
|
+
#
|
108
|
+
# @return [Boolean]
|
109
|
+
def follow_policies?(*names)
|
110
|
+
follow_policies!(*names)
|
111
|
+
true
|
112
|
+
rescue ViolationError
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
# Syntax shugar for the {#follow_policies?} with one argument
|
117
|
+
#
|
118
|
+
# @param (see #follow_policy!)
|
119
|
+
#
|
120
|
+
# @return (see #follow_policies?)
|
121
|
+
def follow_policy?(name)
|
122
|
+
follow_policies? name
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# @!parse extend Policy::Follower::ClassMethods
|
128
|
+
# @!parse include ActiveModel::Validations
|
129
|
+
def self.included(klass)
|
130
|
+
klass.extend(ClassMethods).__send__(:include, Validations)
|
131
|
+
end
|
132
|
+
|
133
|
+
def followed_policies
|
134
|
+
@followed_policies ||= self.class.followed_policies
|
135
|
+
end
|
136
|
+
|
137
|
+
def collect_errors_from(exception)
|
138
|
+
exception.messages.each { |text| errors.add :base, text }
|
139
|
+
end
|
140
|
+
|
141
|
+
end # module Follower
|
142
|
+
|
143
|
+
end # module Policy
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Policy
|
4
|
+
|
5
|
+
# Policy object interface
|
6
|
+
module Interface
|
7
|
+
|
8
|
+
# @private
|
9
|
+
def self.included(klass)
|
10
|
+
klass.extend(ClassMethods).__send__(:include, Validations)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Container for the policy class methods
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
# Creates and validates the policy object
|
17
|
+
#
|
18
|
+
# @param (see Policy.new)
|
19
|
+
#
|
20
|
+
# @raise (see Policy::Interface#apply)
|
21
|
+
#
|
22
|
+
# @return [undefined]
|
23
|
+
def apply(*attributes)
|
24
|
+
new(*attributes).apply
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the list of error messages
|
30
|
+
#
|
31
|
+
# @return [Array<String>]
|
32
|
+
def messages
|
33
|
+
errors.messages.values.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
# Validates the policy object
|
37
|
+
#
|
38
|
+
# @raise [ViolationError]
|
39
|
+
# if a policy is invalid
|
40
|
+
#
|
41
|
+
# @return [undefined]
|
42
|
+
def apply
|
43
|
+
fail ViolationError.new(self) unless valid?
|
44
|
+
end
|
45
|
+
|
46
|
+
end # class Interface
|
47
|
+
|
48
|
+
end # module Policy
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "active_model"
|
3
|
+
|
4
|
+
module Policy
|
5
|
+
|
6
|
+
# Wrapper around the ActiveModel::Validations
|
7
|
+
#
|
8
|
+
# Provides shared interface for [Policy::Inteface] and [Policy::Follower].
|
9
|
+
#
|
10
|
+
# @todo Implement it later from scratch without excessive features
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# MyClass.include, Policy::Validations
|
14
|
+
#
|
15
|
+
# @private
|
16
|
+
module Validations
|
17
|
+
|
18
|
+
# The implementation for validations
|
19
|
+
IMPLEMENTATION = ActiveModel::Validations
|
20
|
+
|
21
|
+
# @private
|
22
|
+
def self.included(klass)
|
23
|
+
klass.__send__(:include, IMPLEMENTATION)
|
24
|
+
end
|
25
|
+
|
26
|
+
end # module Validations
|
27
|
+
|
28
|
+
end # module Policy
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Policy
|
4
|
+
|
5
|
+
# An exception to be risen by {Policy::Interface#apply}
|
6
|
+
class ViolationError < RuntimeError
|
7
|
+
include Adamantium
|
8
|
+
|
9
|
+
# @!attribute [r] policy
|
10
|
+
# The violated policy object
|
11
|
+
#
|
12
|
+
# @return [Policy::Follower]
|
13
|
+
attr_reader :policy
|
14
|
+
|
15
|
+
# @!attribute [r] messages
|
16
|
+
# The list of messages from the broken policy
|
17
|
+
#
|
18
|
+
# @return [Array<String>]
|
19
|
+
attr_reader :messages
|
20
|
+
|
21
|
+
# @!scope class
|
22
|
+
# @!method new(policy)
|
23
|
+
# Constructs an exception
|
24
|
+
#
|
25
|
+
# @param [Policy::Follower] policy
|
26
|
+
# the violated policy object
|
27
|
+
#
|
28
|
+
# @return [Policy::ViolationError]
|
29
|
+
def initialize(policy)
|
30
|
+
@policy = policy.dup
|
31
|
+
@messages = @policy.messages
|
32
|
+
end
|
33
|
+
|
34
|
+
# The human-readable description for the exception
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
def inspect
|
38
|
+
"#<#{ self }: #{ message }>"
|
39
|
+
end
|
40
|
+
|
41
|
+
# The human-readable exception message
|
42
|
+
#
|
43
|
+
# @return [String]
|
44
|
+
def message
|
45
|
+
"#{ policy } violated: #{ messages }"
|
46
|
+
end
|
47
|
+
|
48
|
+
memoize :policy, :messages
|
49
|
+
|
50
|
+
end # module Follower
|
51
|
+
|
52
|
+
end # module Policy
|
data/lib/policy.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "adamantium"
|
4
|
+
|
5
|
+
# Policy Object builder
|
6
|
+
#
|
7
|
+
# @!parse include Policy::Interface
|
8
|
+
module Policy
|
9
|
+
|
10
|
+
require_relative "policy/version"
|
11
|
+
require_relative "policy/validations"
|
12
|
+
require_relative "policy/violation_error"
|
13
|
+
require_relative "policy/interface"
|
14
|
+
require_relative "policy/follower"
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
# Builds a base class for the policy object with some attributes
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# class TransactionPolicy < Policy.new(:debet, :credit)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# @param [Array<Symbol>] attributes
|
25
|
+
# names for the policy object attributes
|
26
|
+
#
|
27
|
+
# @return [Struct]
|
28
|
+
def new(*attributes)
|
29
|
+
Struct.new(*attributes) do
|
30
|
+
include Interface
|
31
|
+
|
32
|
+
def self.name
|
33
|
+
"Policy"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end # Policy singleton class
|
39
|
+
|
40
|
+
end # module Policy
|
data/policy.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "policy/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "policy"
|
6
|
+
s.version = Policy::VERSION.dup
|
7
|
+
s.author = "Andrew Kozin"
|
8
|
+
s.email = "andrew.kozin@gmail.com"
|
9
|
+
s.homepage = "https://github.com/nepalez/policy"
|
10
|
+
s.summary = "Policy Objects for Ruby."
|
11
|
+
s.description = "A tiny library implementing the Policy Object pattern."
|
12
|
+
s.license = "MIT"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
15
|
+
s.test_files = Dir["spec/**/*.rb"]
|
16
|
+
s.extra_rdoc_files = Dir["README.md", "LICENSE", "config/metrics/STYLEGUIDE"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency "activemodel", ">= 3.1"
|
20
|
+
s.add_runtime_dependency "adamantium", "~> 0.2"
|
21
|
+
|
22
|
+
s.add_development_dependency "hexx-rspec", "~> 0.1"
|
23
|
+
end
|