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.
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