policy 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Guardfile +4 -4
  3. data/README.md +177 -78
  4. data/config/metrics/flay.yml +1 -1
  5. data/config/metrics/roodi.yml +2 -2
  6. data/lib/policy.rb +52 -33
  7. data/lib/policy/base.rb +122 -0
  8. data/lib/policy/base/and.rb +38 -0
  9. data/lib/policy/base/negator.rb +52 -0
  10. data/lib/policy/base/node.rb +59 -0
  11. data/lib/policy/base/not.rb +42 -0
  12. data/lib/policy/base/or.rb +39 -0
  13. data/lib/policy/base/xor.rb +39 -0
  14. data/lib/policy/cli.rb +8 -3
  15. data/lib/policy/cli/attribute.rb +49 -0
  16. data/lib/policy/cli/locale.erb +1 -2
  17. data/lib/policy/cli/policy.erb +33 -6
  18. data/lib/policy/cli/spec.erb +31 -11
  19. data/lib/policy/follower.rb +54 -94
  20. data/lib/policy/follower/name_error.rb +53 -0
  21. data/lib/policy/follower/policies.rb +104 -0
  22. data/lib/policy/follower/violation_error.rb +60 -0
  23. data/lib/policy/version.rb +2 -2
  24. data/policy.gemspec +2 -3
  25. data/spec/support/composer.rb +28 -0
  26. data/spec/tests/lib/policy/base/and_spec.rb +62 -0
  27. data/spec/tests/lib/policy/base/negator_spec.rb +49 -0
  28. data/spec/tests/lib/policy/base/not_spec.rb +50 -0
  29. data/spec/tests/lib/policy/base/or_spec.rb +62 -0
  30. data/spec/tests/lib/policy/base/xor_spec.rb +73 -0
  31. data/spec/tests/lib/policy/base_spec.rb +123 -0
  32. data/spec/tests/lib/policy/cli/attribute_spec.rb +52 -0
  33. data/spec/tests/{policy → lib/policy}/cli_spec.rb +25 -24
  34. data/spec/tests/lib/policy/follower/name_error_spec.rb +51 -0
  35. data/spec/tests/lib/policy/follower/policies_spec.rb +156 -0
  36. data/spec/tests/lib/policy/follower/violation_error_spec.rb +60 -0
  37. data/spec/tests/lib/policy/follower_spec.rb +153 -0
  38. data/spec/tests/lib/policy_spec.rb +52 -0
  39. metadata +43 -44
  40. data/lib/policy/follower/followed_policies.rb +0 -45
  41. data/lib/policy/follower/followed_policy.rb +0 -104
  42. data/lib/policy/follower/names.rb +0 -29
  43. data/lib/policy/interface.rb +0 -48
  44. data/lib/policy/validations.rb +0 -28
  45. data/lib/policy/violation_error.rb +0 -52
  46. data/spec/features/follower_spec.rb +0 -95
  47. data/spec/tests/policy/follower/followed_policies_spec.rb +0 -87
  48. data/spec/tests/policy/follower/followed_policy_spec.rb +0 -117
  49. data/spec/tests/policy/follower/names_spec.rb +0 -19
  50. data/spec/tests/policy/follower_spec.rb +0 -220
  51. data/spec/tests/policy/interface_spec.rb +0 -83
  52. data/spec/tests/policy/validations_spec.rb +0 -13
  53. data/spec/tests/policy/violation_error_spec.rb +0 -75
  54. 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 ua jp" do
116
+ context "foo -l UA jP" do
116
117
 
117
- let(:options) { %w(foo -l ua jp) }
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