policy 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|