policy 1.2.0 → 2.0.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/Guardfile +4 -4
- data/README.md +177 -78
- data/config/metrics/flay.yml +1 -1
- data/config/metrics/roodi.yml +2 -2
- data/lib/policy.rb +52 -33
- data/lib/policy/base.rb +122 -0
- data/lib/policy/base/and.rb +38 -0
- data/lib/policy/base/negator.rb +52 -0
- data/lib/policy/base/node.rb +59 -0
- data/lib/policy/base/not.rb +42 -0
- data/lib/policy/base/or.rb +39 -0
- data/lib/policy/base/xor.rb +39 -0
- data/lib/policy/cli.rb +8 -3
- data/lib/policy/cli/attribute.rb +49 -0
- data/lib/policy/cli/locale.erb +1 -2
- data/lib/policy/cli/policy.erb +33 -6
- data/lib/policy/cli/spec.erb +31 -11
- data/lib/policy/follower.rb +54 -94
- data/lib/policy/follower/name_error.rb +53 -0
- data/lib/policy/follower/policies.rb +104 -0
- data/lib/policy/follower/violation_error.rb +60 -0
- data/lib/policy/version.rb +2 -2
- data/policy.gemspec +2 -3
- data/spec/support/composer.rb +28 -0
- data/spec/tests/lib/policy/base/and_spec.rb +62 -0
- data/spec/tests/lib/policy/base/negator_spec.rb +49 -0
- data/spec/tests/lib/policy/base/not_spec.rb +50 -0
- data/spec/tests/lib/policy/base/or_spec.rb +62 -0
- data/spec/tests/lib/policy/base/xor_spec.rb +73 -0
- data/spec/tests/lib/policy/base_spec.rb +123 -0
- data/spec/tests/lib/policy/cli/attribute_spec.rb +52 -0
- data/spec/tests/{policy → lib/policy}/cli_spec.rb +25 -24
- data/spec/tests/lib/policy/follower/name_error_spec.rb +51 -0
- data/spec/tests/lib/policy/follower/policies_spec.rb +156 -0
- data/spec/tests/lib/policy/follower/violation_error_spec.rb +60 -0
- data/spec/tests/lib/policy/follower_spec.rb +153 -0
- data/spec/tests/lib/policy_spec.rb +52 -0
- metadata +43 -44
- data/lib/policy/follower/followed_policies.rb +0 -45
- data/lib/policy/follower/followed_policy.rb +0 -104
- data/lib/policy/follower/names.rb +0 -29
- data/lib/policy/interface.rb +0 -48
- data/lib/policy/validations.rb +0 -28
- data/lib/policy/violation_error.rb +0 -52
- data/spec/features/follower_spec.rb +0 -95
- data/spec/tests/policy/follower/followed_policies_spec.rb +0 -87
- data/spec/tests/policy/follower/followed_policy_spec.rb +0 -117
- data/spec/tests/policy/follower/names_spec.rb +0 -19
- data/spec/tests/policy/follower_spec.rb +0 -220
- data/spec/tests/policy/interface_spec.rb +0 -83
- data/spec/tests/policy/validations_spec.rb +0 -13
- data/spec/tests/policy/violation_error_spec.rb +0 -75
- data/spec/tests/policy_spec.rb +0 -35
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "policy/cli"
|
3
|
+
|
4
|
+
describe Policy::CLI::Attribute do
|
5
|
+
|
6
|
+
subject { described_class.new "FooBar{bar/baz}" }
|
7
|
+
|
8
|
+
describe "#name" do
|
9
|
+
|
10
|
+
context "when the name is present in the source" do
|
11
|
+
|
12
|
+
it "returns a name for a method" do
|
13
|
+
expect(subject.name).to eq "foo_bar"
|
14
|
+
end
|
15
|
+
|
16
|
+
end # context
|
17
|
+
|
18
|
+
context "when the name is absent in the source" do
|
19
|
+
|
20
|
+
subject { described_class.new "{bar/baz}" }
|
21
|
+
|
22
|
+
it "returns @todo" do
|
23
|
+
expect(subject.name).to eq "@todo"
|
24
|
+
end
|
25
|
+
|
26
|
+
end # context
|
27
|
+
|
28
|
+
end # describe #name
|
29
|
+
|
30
|
+
describe "#type" do
|
31
|
+
|
32
|
+
context "when the type is present in the source" do
|
33
|
+
|
34
|
+
it "returns a name for a constant" do
|
35
|
+
expect(subject.type).to eq "Bar::Baz"
|
36
|
+
end
|
37
|
+
|
38
|
+
end # context
|
39
|
+
|
40
|
+
context "when the type is absent in the source" do
|
41
|
+
|
42
|
+
subject { described_class.new "FooBar" }
|
43
|
+
|
44
|
+
it "returns @todo" do
|
45
|
+
expect(subject.type).to eq "@todo"
|
46
|
+
end
|
47
|
+
|
48
|
+
end # context
|
49
|
+
|
50
|
+
end # describe #type
|
51
|
+
|
52
|
+
end # describe Policy::CLI::Attribute
|
@@ -50,28 +50,6 @@ describe Policy::CLI, :sandbox, :capture do
|
|
50
50
|
|
51
51
|
end # context
|
52
52
|
|
53
|
-
context "foo -a bar baz" do
|
54
|
-
|
55
|
-
let(:options) { %w(foo -a bar baz) }
|
56
|
-
before { subject }
|
57
|
-
|
58
|
-
it_behaves_like "adding a policy", folder: "policies"
|
59
|
-
it_behaves_like "adding a spec", folder: "policies"
|
60
|
-
it_behaves_like "adding locales", %w(en ru), folder: "policies"
|
61
|
-
|
62
|
-
it "adds attributes to the policy" do
|
63
|
-
content = read_in_sandbox "app/policies/foo.rb"
|
64
|
-
expect(content).to include "class Foo < Hexx::Policy.new(:bar, :baz)"
|
65
|
-
end
|
66
|
-
|
67
|
-
it "checks attributes" do
|
68
|
-
content = read_in_sandbox "spec/tests/policies/foo_spec.rb"
|
69
|
-
expect(content).to include "let(:bar) {"
|
70
|
-
expect(content).to include "let(:baz) {"
|
71
|
-
end
|
72
|
-
|
73
|
-
end # context
|
74
|
-
|
75
53
|
context "foo -n bar/baz" do
|
76
54
|
|
77
55
|
let(:options) { %w(foo -n bar/baz) }
|
@@ -101,6 +79,29 @@ describe Policy::CLI, :sandbox, :capture do
|
|
101
79
|
|
102
80
|
end # context
|
103
81
|
|
82
|
+
context "foo -a bar baz" do
|
83
|
+
|
84
|
+
let(:options) { %w(foo -a bar baz) }
|
85
|
+
before { subject }
|
86
|
+
|
87
|
+
it_behaves_like "adding a policy", folder: "policies"
|
88
|
+
it_behaves_like "adding a spec", folder: "policies"
|
89
|
+
it_behaves_like "adding locales", %w(en ru), folder: "policies"
|
90
|
+
|
91
|
+
it "adds attributes to the policy" do
|
92
|
+
content = read_in_sandbox "app/policies/foo.rb"
|
93
|
+
expect(content).to include "attr_reader :bar"
|
94
|
+
expect(content).to include "attr_reader :baz"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "checks attributes" do
|
98
|
+
content = read_in_sandbox "spec/tests/policies/foo_spec.rb"
|
99
|
+
expect(content).to include "let(:bar) {"
|
100
|
+
expect(content).to include "let(:baz) {"
|
101
|
+
end
|
102
|
+
|
103
|
+
end # context
|
104
|
+
|
104
105
|
context "foo -n bar baz" do
|
105
106
|
|
106
107
|
let(:options) { %w(foo -n bar baz) }
|
@@ -112,9 +113,9 @@ describe Policy::CLI, :sandbox, :capture do
|
|
112
113
|
|
113
114
|
end # context
|
114
115
|
|
115
|
-
context "foo -l
|
116
|
+
context "foo -l UA jP" do
|
116
117
|
|
117
|
-
let(:options) { %w(foo -l
|
118
|
+
let(:options) { %w(foo -l UA jP) }
|
118
119
|
before { subject }
|
119
120
|
|
120
121
|
it_behaves_like "adding a policy", folder: "policies"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Follower::NameError do
|
4
|
+
|
5
|
+
let(:follower) { double :follower }
|
6
|
+
let(:name) { "foo" }
|
7
|
+
subject { described_class.new follower, name }
|
8
|
+
|
9
|
+
describe ".new" do
|
10
|
+
|
11
|
+
it "creates the RuntimeError" do
|
12
|
+
expect(subject).to be_kind_of ::RuntimeError
|
13
|
+
end
|
14
|
+
|
15
|
+
end # describe .new
|
16
|
+
|
17
|
+
describe "#follower" do
|
18
|
+
|
19
|
+
it "is initialized" do
|
20
|
+
expect(subject.follower).to eq follower
|
21
|
+
end
|
22
|
+
|
23
|
+
end # describe #follower
|
24
|
+
|
25
|
+
describe "#name" do
|
26
|
+
|
27
|
+
it "is initialized" do
|
28
|
+
expect(subject.name).to eq name.to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
end # describe #follower
|
32
|
+
|
33
|
+
describe "#message" do
|
34
|
+
|
35
|
+
it "returns a correct string" do
|
36
|
+
expect(subject.message)
|
37
|
+
.to eq "#{ follower.inspect } hasn't registered the policy \"foo\""
|
38
|
+
end
|
39
|
+
|
40
|
+
end # describe #message
|
41
|
+
|
42
|
+
describe "#inspect" do
|
43
|
+
|
44
|
+
it "returns a correct string" do
|
45
|
+
expect(subject.inspect)
|
46
|
+
.to eq "#<#{ described_class.name }: #{ subject.message }>"
|
47
|
+
end
|
48
|
+
|
49
|
+
end # describe #inspect
|
50
|
+
|
51
|
+
end # describe Policy::Follower::NameError
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Follower::Policies do
|
4
|
+
|
5
|
+
let(:follower) { double :follower }
|
6
|
+
subject { described_class.new follower }
|
7
|
+
|
8
|
+
describe ".new" do
|
9
|
+
|
10
|
+
it "creates the collection" do
|
11
|
+
expect(subject).to be_kind_of Enumerable
|
12
|
+
end
|
13
|
+
|
14
|
+
end # describe .new
|
15
|
+
|
16
|
+
describe "#follower" do
|
17
|
+
|
18
|
+
it "is initialized" do
|
19
|
+
expect(subject.follower).to eq follower
|
20
|
+
end
|
21
|
+
|
22
|
+
end # describe #follower
|
23
|
+
|
24
|
+
describe "#add" do
|
25
|
+
|
26
|
+
it "registers the item" do
|
27
|
+
expect { subject.add "foo" }
|
28
|
+
.to change { subject.map { |item| item } }
|
29
|
+
.from([]).to([:foo])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "registers the item once" do
|
33
|
+
["foo", :foo, "foo"].each(&subject.method(:add))
|
34
|
+
|
35
|
+
expect(subject.map { |item| item }).to eq [:foo]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns itself" do
|
39
|
+
expect(subject.add "foo").to eq subject
|
40
|
+
end
|
41
|
+
|
42
|
+
end # describe #add
|
43
|
+
|
44
|
+
describe "#include?" do
|
45
|
+
|
46
|
+
context "registered name" do
|
47
|
+
|
48
|
+
before { subject.add "foo" }
|
49
|
+
|
50
|
+
it "returns true" do
|
51
|
+
expect(subject.include? :foo).to eq true
|
52
|
+
end
|
53
|
+
|
54
|
+
end # context
|
55
|
+
|
56
|
+
context "unregistered name" do
|
57
|
+
|
58
|
+
it "fails" do
|
59
|
+
expect { subject.include? :foo }
|
60
|
+
.to raise_error Policy::Follower::NameError
|
61
|
+
end
|
62
|
+
|
63
|
+
it "preserves name and follower in the exception" do
|
64
|
+
begin
|
65
|
+
subject.include? :foo
|
66
|
+
rescue => err
|
67
|
+
expect(err.name).to eq :foo
|
68
|
+
expect(err.follower).to eq subject.follower
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end # context
|
73
|
+
|
74
|
+
end # describe #include?
|
75
|
+
|
76
|
+
describe "#subset" do
|
77
|
+
|
78
|
+
subject { described_class.new follower }
|
79
|
+
before { %i(foo bar baz).each(&subject.method(:add)) }
|
80
|
+
|
81
|
+
let(:subset) { subject.subset(names) }
|
82
|
+
|
83
|
+
context "without names" do
|
84
|
+
|
85
|
+
it "returns itself" do
|
86
|
+
expect(subject.subset []).to eq subject
|
87
|
+
end
|
88
|
+
|
89
|
+
end # context
|
90
|
+
|
91
|
+
context "with registered names" do
|
92
|
+
|
93
|
+
let(:names) { %i(baz foo) }
|
94
|
+
|
95
|
+
it "creates a collection" do
|
96
|
+
expect(subset).to be_kind_of described_class
|
97
|
+
end
|
98
|
+
|
99
|
+
it "preserves a follower" do
|
100
|
+
expect(subset.follower).to eq subject.follower
|
101
|
+
end
|
102
|
+
|
103
|
+
it "leaves selected names only" do
|
104
|
+
expect(subset.map { |item| item }).to eq names
|
105
|
+
end
|
106
|
+
|
107
|
+
end # context
|
108
|
+
|
109
|
+
context "with repetitive names" do
|
110
|
+
|
111
|
+
let(:names) { ["baz", :baz, "baz"] }
|
112
|
+
|
113
|
+
it "leaves uniq names only" do
|
114
|
+
expect(subset.map { |item| item }).to eq [:baz]
|
115
|
+
end
|
116
|
+
|
117
|
+
end # context
|
118
|
+
|
119
|
+
context "with non-registered names" do
|
120
|
+
|
121
|
+
let(:names) { %i(baz foo cad) }
|
122
|
+
|
123
|
+
it "fails" do
|
124
|
+
expect { subset }.to raise_error Policy::Follower::NameError
|
125
|
+
end
|
126
|
+
|
127
|
+
it "adds follower and name to the error" do
|
128
|
+
begin
|
129
|
+
subset
|
130
|
+
rescue => err
|
131
|
+
expect(err.name).to eq :cad
|
132
|
+
expect(err.follower).to eq subject.follower
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end # context
|
137
|
+
|
138
|
+
end # describe #subset
|
139
|
+
|
140
|
+
describe "#each" do
|
141
|
+
|
142
|
+
it "retuns enumerator" do
|
143
|
+
expect(subject.each).to be_kind_of Enumerator
|
144
|
+
end
|
145
|
+
|
146
|
+
it "iterates through names" do
|
147
|
+
names = %i(foo bar baz)
|
148
|
+
subject = described_class.new follower
|
149
|
+
names.each(&subject.method(:add))
|
150
|
+
|
151
|
+
expect(subject.map { |item| item }).to eq names
|
152
|
+
end
|
153
|
+
|
154
|
+
end # describe #each
|
155
|
+
|
156
|
+
end # describe Policy::Follower::Policies
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Follower::ViolationError do
|
4
|
+
|
5
|
+
let(:errors) { double :errors }
|
6
|
+
let(:follower) { double :follower }
|
7
|
+
let(:policy) { double :policy, errors: errors }
|
8
|
+
subject { described_class.new follower, policy }
|
9
|
+
|
10
|
+
describe ".new" do
|
11
|
+
|
12
|
+
it "creates the RuntimeError" do
|
13
|
+
expect(subject).to be_kind_of ::RuntimeError
|
14
|
+
end
|
15
|
+
|
16
|
+
end # describe .new
|
17
|
+
|
18
|
+
describe "#follower" do
|
19
|
+
|
20
|
+
it "is initialized" do
|
21
|
+
expect(subject.follower).to eq follower
|
22
|
+
end
|
23
|
+
|
24
|
+
end # describe #follower
|
25
|
+
|
26
|
+
describe "#policy" do
|
27
|
+
|
28
|
+
it "is initialized" do
|
29
|
+
expect(subject.policy).to eq policy
|
30
|
+
end
|
31
|
+
|
32
|
+
end # describe #policy
|
33
|
+
|
34
|
+
describe "#errors" do
|
35
|
+
|
36
|
+
it "is initialized" do
|
37
|
+
expect(subject.errors).to eq errors
|
38
|
+
end
|
39
|
+
|
40
|
+
end # describe #errors
|
41
|
+
|
42
|
+
describe "#message" do
|
43
|
+
|
44
|
+
it "returns a correct string" do
|
45
|
+
expect(subject.message)
|
46
|
+
.to eq "#{ follower.inspect } violates the policy #{ policy }"
|
47
|
+
end
|
48
|
+
|
49
|
+
end # describe #message
|
50
|
+
|
51
|
+
describe "#inspect" do
|
52
|
+
|
53
|
+
it "returns a correct string" do
|
54
|
+
expect(subject.inspect)
|
55
|
+
.to eq "#<#{ described_class.name }: #{ subject.message }>"
|
56
|
+
end
|
57
|
+
|
58
|
+
end # describe #inspect
|
59
|
+
|
60
|
+
end # describe Policy::Follower::NameError
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Policy::Follower do
|
4
|
+
|
5
|
+
let(:test_class) { Class.new.send(:include, described_class) }
|
6
|
+
subject { test_class.new }
|
7
|
+
|
8
|
+
describe ".policies" do
|
9
|
+
|
10
|
+
it "is a collection of policies" do
|
11
|
+
expect(test_class.policies).to be_kind_of Policy::Follower::Policies
|
12
|
+
end
|
13
|
+
|
14
|
+
it "refers to itself" do
|
15
|
+
expect(test_class.policies.follower).to eq test_class
|
16
|
+
end
|
17
|
+
|
18
|
+
end # describe .policies
|
19
|
+
|
20
|
+
describe ".follows_policy" do
|
21
|
+
|
22
|
+
it "adds a name to the collection of policies" do
|
23
|
+
expect(test_class.policies).to receive(:add).with("foo")
|
24
|
+
test_class.follows_policy "foo"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns the name of the method" do
|
28
|
+
expect(test_class.follows_policy "foo").to eq :follows_policy
|
29
|
+
end
|
30
|
+
|
31
|
+
end # describe .follows_policy
|
32
|
+
|
33
|
+
describe ".follows_policies" do
|
34
|
+
|
35
|
+
it "adds all names to the collection of policies" do
|
36
|
+
expect(test_class.policies).to receive(:add).with("foo").ordered
|
37
|
+
expect(test_class.policies).to receive(:add).with("bar").ordered
|
38
|
+
test_class.follows_policies "foo", "bar"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns the name of the method" do
|
42
|
+
expect(test_class.follows_policies "foo").to eq :follows_policies
|
43
|
+
end
|
44
|
+
|
45
|
+
end # describe .follows_policies
|
46
|
+
|
47
|
+
describe "#follow_policies?" do
|
48
|
+
|
49
|
+
before { test_class.follows_policies :one, :two }
|
50
|
+
|
51
|
+
context "with valid policies" do
|
52
|
+
|
53
|
+
let(:one) { double valid?: true }
|
54
|
+
before { allow(subject).to receive(:one) { one } }
|
55
|
+
|
56
|
+
it "returns true" do
|
57
|
+
expect(subject.follow_policies? :one).to eq true
|
58
|
+
end
|
59
|
+
|
60
|
+
end # context
|
61
|
+
|
62
|
+
context "with invalid policy's name" do
|
63
|
+
|
64
|
+
let(:one) { double valid?: false, errors: [] }
|
65
|
+
before { allow(subject).to receive(:one) { one } }
|
66
|
+
|
67
|
+
it "raises ViolationError" do
|
68
|
+
expect { subject.follow_policies? :one }
|
69
|
+
.to raise_error Policy::Follower::ViolationError
|
70
|
+
end
|
71
|
+
|
72
|
+
it "stores both the follower and policy in the exception" do
|
73
|
+
begin
|
74
|
+
subject.follow_policies? :one
|
75
|
+
rescue => exception
|
76
|
+
expect(exception.follower).to eq subject
|
77
|
+
expect(exception.policy).to eq one
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end # context
|
82
|
+
|
83
|
+
context "with undefined name" do
|
84
|
+
|
85
|
+
it "raises NoMethodError" do
|
86
|
+
expect { subject.follow_policies? :one }
|
87
|
+
.to raise_error NoMethodError
|
88
|
+
end
|
89
|
+
|
90
|
+
end # context
|
91
|
+
|
92
|
+
context "with unregistered name" do
|
93
|
+
|
94
|
+
it "raises NameError" do
|
95
|
+
expect { subject.follow_policies? :three }
|
96
|
+
.to raise_error Policy::Follower::NameError
|
97
|
+
end
|
98
|
+
|
99
|
+
it "stores both the follower class and name in the exception" do
|
100
|
+
begin
|
101
|
+
subject.follow_policies? :three
|
102
|
+
rescue => exception
|
103
|
+
expect(exception.follower).to eq test_class
|
104
|
+
expect(exception.name).to eq :three
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end # context
|
109
|
+
|
110
|
+
context "with a list of names" do
|
111
|
+
|
112
|
+
let(:one) { double valid?: true }
|
113
|
+
let(:two) { double valid?: true }
|
114
|
+
|
115
|
+
before { allow(subject).to receive(:one) { one } }
|
116
|
+
before { allow(subject).to receive(:two) { two } }
|
117
|
+
|
118
|
+
it "checks listed policies in given order" do
|
119
|
+
expect(two).to receive(:valid?).ordered
|
120
|
+
expect(one).to receive(:valid?).ordered
|
121
|
+
subject.follow_policies? :two, :one
|
122
|
+
end
|
123
|
+
|
124
|
+
end # context
|
125
|
+
|
126
|
+
context "without names" do
|
127
|
+
|
128
|
+
let(:one) { double valid?: true }
|
129
|
+
let(:two) { double valid?: true }
|
130
|
+
|
131
|
+
before { allow(subject).to receive(:one) { one } }
|
132
|
+
before { allow(subject).to receive(:two) { two } }
|
133
|
+
|
134
|
+
it "checks listed policies in predefined order" do
|
135
|
+
expect(one).to receive(:valid?).ordered
|
136
|
+
expect(two).to receive(:valid?).ordered
|
137
|
+
subject.follow_policies? []
|
138
|
+
end
|
139
|
+
|
140
|
+
end # context
|
141
|
+
|
142
|
+
end # describe #follow_policies?
|
143
|
+
|
144
|
+
describe "#follow_policy?" do
|
145
|
+
|
146
|
+
it "is an alias for #follow_policies?" do
|
147
|
+
expect(subject).to receive(:follow_policies?).with "foo"
|
148
|
+
subject.follow_policy? "foo"
|
149
|
+
end
|
150
|
+
|
151
|
+
end # describe #follow_policy?
|
152
|
+
|
153
|
+
end # describe Policy::Follower
|