attestor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +9 -0
  4. data/.metrics +9 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +2 -0
  7. data/.travis.yml +10 -0
  8. data/.yardopts +3 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +15 -0
  11. data/LICENSE +21 -0
  12. data/README.md +308 -0
  13. data/Rakefile +22 -0
  14. data/attestor.gemspec +24 -0
  15. data/config/metrics/STYLEGUIDE +230 -0
  16. data/config/metrics/cane.yml +5 -0
  17. data/config/metrics/churn.yml +6 -0
  18. data/config/metrics/flay.yml +2 -0
  19. data/config/metrics/metric_fu.yml +15 -0
  20. data/config/metrics/reek.yml +1 -0
  21. data/config/metrics/roodi.yml +24 -0
  22. data/config/metrics/rubocop.yml +75 -0
  23. data/config/metrics/saikuro.yml +3 -0
  24. data/config/metrics/simplecov.yml +6 -0
  25. data/config/metrics/yardstick.yml +37 -0
  26. data/lib/attestor/invalid_error.rb +44 -0
  27. data/lib/attestor/policy/and.rb +36 -0
  28. data/lib/attestor/policy/factory.rb +88 -0
  29. data/lib/attestor/policy/negator.rb +53 -0
  30. data/lib/attestor/policy/node.rb +58 -0
  31. data/lib/attestor/policy/not.rb +48 -0
  32. data/lib/attestor/policy/or.rb +36 -0
  33. data/lib/attestor/policy/xor.rb +36 -0
  34. data/lib/attestor/policy.rb +121 -0
  35. data/lib/attestor/validations/collection.rb +73 -0
  36. data/lib/attestor/validations/item.rb +87 -0
  37. data/lib/attestor/validations/message.rb +55 -0
  38. data/lib/attestor/validations.rb +81 -0
  39. data/lib/attestor/version.rb +9 -0
  40. data/lib/attestor.rb +26 -0
  41. data/spec/spec_helper.rb +14 -0
  42. data/spec/support/policies.rb +49 -0
  43. data/spec/tests/invalid_error_spec.rb +57 -0
  44. data/spec/tests/policy/and_spec.rb +40 -0
  45. data/spec/tests/policy/factory_spec.rb +100 -0
  46. data/spec/tests/policy/negator_spec.rb +57 -0
  47. data/spec/tests/policy/node_spec.rb +44 -0
  48. data/spec/tests/policy/not_spec.rb +40 -0
  49. data/spec/tests/policy/or_spec.rb +40 -0
  50. data/spec/tests/policy/xor_spec.rb +48 -0
  51. data/spec/tests/policy_spec.rb +111 -0
  52. data/spec/tests/validations/collection_spec.rb +100 -0
  53. data/spec/tests/validations/item_spec.rb +153 -0
  54. data/spec/tests/validations/message_spec.rb +71 -0
  55. data/spec/tests/validations_spec.rb +126 -0
  56. metadata +143 -0
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ # describe #valid_policy and #invalid_policy builders
4
+ # also describes shared examples for all policies
5
+ require "support/policies"
6
+
7
+ describe Attestor::Policy::Not do
8
+
9
+ subject { described_class.new item }
10
+
11
+ describe ".new" do
12
+
13
+ let(:item) { valid_policy }
14
+
15
+ it_behaves_like "creating a node"
16
+ it_behaves_like "creating an immutable object"
17
+
18
+ end # context
19
+
20
+ describe "#validate" do
21
+
22
+ context "when a part is invalid" do
23
+
24
+ let(:item) { invalid_policy }
25
+
26
+ it_behaves_like "passing validation"
27
+
28
+ end # context
29
+
30
+ context "when a part is valid" do
31
+
32
+ let(:item) { valid_policy }
33
+
34
+ it_behaves_like "failing validation"
35
+
36
+ end # context
37
+
38
+ end # describe #validate
39
+
40
+ end # describe Policy::Base::Not
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ # describe #valid_policy and #invalid_policy builders
4
+ # also describes shared examples for all policies
5
+ require "support/policies"
6
+
7
+ describe Attestor::Policy::Or do
8
+
9
+ subject { described_class.new items }
10
+
11
+ describe ".new" do
12
+
13
+ let(:items) { [valid_policy] }
14
+
15
+ it_behaves_like "creating a node"
16
+ it_behaves_like "creating an immutable object"
17
+
18
+ end # context
19
+
20
+ describe "#validate" do
21
+
22
+ context "when valid part exists" do
23
+
24
+ let(:items) { [valid_policy, valid_policy, invalid_policy] }
25
+
26
+ it_behaves_like "passing validation"
27
+
28
+ end # context
29
+
30
+ context "when all parts are invalid" do
31
+
32
+ let(:items) { 3.times.map { invalid_policy } }
33
+
34
+ it_behaves_like "failing validation"
35
+
36
+ end # context
37
+
38
+ end # describe #validate
39
+
40
+ end # describe Policy::Base::Not
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ # describe #valid_policy and #invalid_policy builders
4
+ # also describes shared examples for all policies
5
+ require "support/policies"
6
+
7
+ describe Attestor::Policy::Xor do
8
+
9
+ subject { described_class.new items }
10
+
11
+ describe ".new" do
12
+
13
+ let(:items) { [valid_policy] }
14
+
15
+ it_behaves_like "creating a node"
16
+ it_behaves_like "creating an immutable object"
17
+
18
+ end # context
19
+
20
+ describe "#validate" do
21
+
22
+ context "when both valid and invalid parts exist" do
23
+
24
+ let(:items) { [valid_policy, valid_policy, invalid_policy] }
25
+
26
+ it_behaves_like "passing validation"
27
+
28
+ end # context
29
+
30
+ context "when all parts are valid" do
31
+
32
+ let(:items) { 3.times.map { valid_policy } }
33
+
34
+ it_behaves_like "failing validation"
35
+
36
+ end # context
37
+
38
+ context "when all parts are invalid" do
39
+
40
+ let(:items) { 3.times.map { invalid_policy } }
41
+
42
+ it_behaves_like "failing validation"
43
+
44
+ end # context
45
+
46
+ end # describe #validate
47
+
48
+ end # describe Policy::Base::Not
@@ -0,0 +1,111 @@
1
+ # encoding: utf-8
2
+
3
+ describe Attestor::Policy do
4
+
5
+ let(:factory) { Attestor::Policy::Factory }
6
+ let(:validator) { Attestor::Validations }
7
+ let(:invalid) { Attestor::InvalidError.new subject, [] }
8
+ let(:others) { 2.times { double } }
9
+
10
+ let(:test_class) { Class.new.send(:include, described_class) }
11
+ before { Test = test_class }
12
+ after { Object.send :remove_const, :Test }
13
+ subject { test_class.new }
14
+
15
+ it "is a factory" do
16
+ expect(test_class).to be_kind_of factory
17
+ end
18
+
19
+ describe ".new" do
20
+
21
+ it "creates a validator" do
22
+ expect(subject).to be_kind_of validator
23
+ end
24
+
25
+ end # describe .new
26
+
27
+ describe "#valid?" do
28
+
29
+ context "when #validate method fails" do
30
+
31
+ before { allow(subject).to receive(:validate) { fail invalid } }
32
+
33
+ it "returns false" do
34
+ expect(subject.valid?).to eq false
35
+ end
36
+
37
+ end
38
+
39
+ context "when #validate method passes" do
40
+
41
+ before { allow(subject).to receive(:validate) { nil } }
42
+
43
+ it "returns true" do
44
+ expect(subject.valid?).to eq true
45
+ end
46
+
47
+ end
48
+
49
+ end # describe #valid?
50
+
51
+ describe "#invalid?" do
52
+
53
+ context "when #validate method fails" do
54
+
55
+ before { allow(subject).to receive(:validate) { fail invalid } }
56
+
57
+ it "returns true" do
58
+ expect(subject.invalid?).to eq true
59
+ end
60
+
61
+ end
62
+
63
+ context "when #validate method passes" do
64
+
65
+ before { allow(subject).to receive(:validate) { nil } }
66
+
67
+ it "returns false" do
68
+ expect(subject.invalid?).to eq false
69
+ end
70
+
71
+ end
72
+
73
+ end # describe #invalid?
74
+
75
+ describe "#and" do
76
+
77
+ it "calls .and class factory method with self" do
78
+ expect(test_class).to receive(:and).with(subject, *others)
79
+ subject.and(*others)
80
+ end
81
+
82
+ end # describe #and
83
+
84
+ describe "#or" do
85
+
86
+ it "calls .or class factory method with self" do
87
+ expect(test_class).to receive(:or).with(subject, *others)
88
+ subject.or(*others)
89
+ end
90
+
91
+ end # describe #or
92
+
93
+ describe "#xor" do
94
+
95
+ it "calls .xor class factory method with self" do
96
+ expect(test_class).to receive(:xor).with(subject, *others)
97
+ subject.xor(*others)
98
+ end
99
+
100
+ end # describe #xor
101
+
102
+ describe "#not" do
103
+
104
+ it "calls .not class factory method with self" do
105
+ expect(test_class).to receive(:not).with(subject)
106
+ subject.not
107
+ end
108
+
109
+ end # describe #not
110
+
111
+ end # describe Attestor::Policy
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+
3
+ describe Attestor::Validations::Collection do
4
+
5
+ let(:item_class) { Attestor::Validations::Item }
6
+
7
+ describe ".new" do
8
+
9
+ it "creates a collection" do
10
+ expect(subject).to be_kind_of Enumerable
11
+ end
12
+
13
+ it "creates an immutable object" do
14
+ expect(subject).to be_frozen
15
+ end
16
+
17
+ end # .new
18
+
19
+ describe "#each" do
20
+
21
+ it "returns an enumerator" do
22
+ expect(subject.each).to be_kind_of Enumerator
23
+ end
24
+
25
+ it "iterates trough the unique item names" do
26
+ items = %w(foo bar foo).map(&item_class.method(:new))
27
+ subject = described_class.new items
28
+
29
+ expect(subject.to_a).to match_array %i(foo bar)
30
+ end
31
+
32
+ end # describe #each
33
+
34
+ describe "#add" do
35
+
36
+ context "without options" do
37
+
38
+ let(:result) { subject.add("foo") }
39
+
40
+ it "returns the collection" do
41
+ expect(result).to be_kind_of described_class
42
+ end
43
+
44
+ it "adds item to the collection" do
45
+ item = result.first
46
+ expect(item).to eq :foo
47
+ end
48
+
49
+ it "preserves existing items" do
50
+ expect(result.add(:bar).to_a).to contain_exactly :foo, :bar
51
+ end
52
+
53
+ end # context
54
+
55
+ context "with options" do
56
+
57
+ let(:result) { subject.add "foo", only: [:foo] }
58
+
59
+ it "adds item to the collection" do
60
+ expect(result.to_a).to eq [:foo]
61
+ expect(result.set(:foo).to_a).to eq [:foo]
62
+ expect(result.set(:all).to_a).to eq []
63
+ end
64
+
65
+ end # context
66
+
67
+ context "existing item" do
68
+
69
+ subject { described_class.new.add "foo" }
70
+
71
+ it "returns itself" do
72
+ expect(subject.add "foo").to eq subject
73
+ end
74
+
75
+ end # context
76
+
77
+ end # describe #add
78
+
79
+ describe "#context" do
80
+
81
+ subject do
82
+ described_class.new
83
+ .add("foo", only: %w(cad cam))
84
+ .add("bar", except: %w(cad))
85
+ .add("baz", except: %w(cam))
86
+ end
87
+
88
+ it "returns a collection" do
89
+ expect(subject.set "all").to be_kind_of described_class
90
+ end
91
+
92
+ it "returns a set of items used in given context" do
93
+ expect(subject.set("cad").to_a).to contain_exactly :foo, :baz
94
+ expect(subject.set("cam").to_a).to contain_exactly :foo, :bar
95
+ expect(subject.set("all").to_a).to contain_exactly :bar, :baz
96
+ end
97
+
98
+ end # describe #context
99
+
100
+ end # describe Attestor::Collection
@@ -0,0 +1,153 @@
1
+ # encoding: utf-8
2
+
3
+ describe Attestor::Validations::Item do
4
+
5
+ subject { described_class.new "foo" }
6
+
7
+ describe ".new" do
8
+
9
+ it "is immutable" do
10
+ expect(subject).to be_frozen
11
+ end
12
+
13
+ it "accepts item option :except" do
14
+ expect { described_class.new "foo", except: :bar }.not_to raise_error
15
+ end
16
+
17
+ it "accepts array option :except" do
18
+ expect { described_class.new "foo", except: %w(bar) }.not_to raise_error
19
+ end
20
+
21
+ it "ignores repetitive :except items" do
22
+ expect(described_class.new "foo", except: %i(bar bar))
23
+ .to eq(described_class.new "foo", except: %i(bar))
24
+ end
25
+
26
+ it "accepts item option :only" do
27
+ expect { described_class.new "foo", only: :bar }.not_to raise_error
28
+ end
29
+
30
+ it "accepts array option :only" do
31
+ expect { described_class.new "foo", only: %w(bar) }.not_to raise_error
32
+ end
33
+
34
+ it "ignores repetitive :only items" do
35
+ expect(described_class.new "foo", only: %i(bar bar))
36
+ .to eq(described_class.new "foo", only: %i(bar))
37
+ end
38
+
39
+ end # describe .new
40
+
41
+ describe ".name" do
42
+
43
+ it "is initialized as a symbol" do
44
+ expect(subject.name).to eq :foo
45
+ end
46
+
47
+ end # describe .name
48
+
49
+ describe "#==" do
50
+
51
+ subject { described_class.new :foo, except: [:foo], only: %i(bar) }
52
+
53
+ context "item with the same name and options" do
54
+
55
+ let(:other) { described_class.new :foo, except: %i(foo), only: %i(bar) }
56
+
57
+ it "returns true" do
58
+ expect(subject == other).to eq true
59
+ expect(subject).to eq other
60
+ end
61
+
62
+ end # context
63
+
64
+ context "item with another name" do
65
+
66
+ let(:other) { described_class.new :baz, except: %i(foo), only: %i(bar) }
67
+
68
+ it "returns false" do
69
+ expect(subject == other).to eq false
70
+ expect(subject).not_to eq other
71
+ end
72
+
73
+ end # context
74
+
75
+ context "item with another blacklist" do
76
+
77
+ let(:other) { described_class.new :foo, except: %i(baz), only: %i(bar) }
78
+
79
+ it "returns false" do
80
+ expect(subject == other).to eq false
81
+ expect(subject).not_to eq other
82
+ end
83
+
84
+ end # context
85
+
86
+ context "item with another whitelist" do
87
+
88
+ let(:other) { described_class.new :foo, except: %i(foo), only: %i(baz) }
89
+
90
+ it "returns false" do
91
+ expect(subject == other).to eq false
92
+ expect(subject).not_to eq other
93
+ end
94
+
95
+ end # context
96
+
97
+ context "not an item" do
98
+
99
+ let(:other) { "baz" }
100
+
101
+ it "returns false" do
102
+ expect(subject == other).to eq false
103
+ expect(subject).not_to eq other
104
+ end
105
+
106
+ end # context
107
+
108
+ end # describe #==
109
+
110
+ describe "#used_in_context?" do
111
+
112
+ context "not restricted" do
113
+
114
+ it { is_expected.to be_used_in_context :bar }
115
+ it { is_expected.to be_used_in_context "baz" }
116
+
117
+ end # context
118
+
119
+ context "blacklisted" do
120
+
121
+ subject { described_class.new "foo", except: %w(foo bar) }
122
+
123
+ it { is_expected.not_to be_used_in_context "foo" }
124
+ it { is_expected.not_to be_used_in_context :bar }
125
+ it { is_expected.to be_used_in_context "baz" }
126
+
127
+ end # context
128
+
129
+ context "whitelisted" do
130
+
131
+ subject { described_class.new "foo", only: %w(foo bar) }
132
+
133
+ it { is_expected.to be_used_in_context "foo" }
134
+ it { is_expected.to be_used_in_context :bar }
135
+ it { is_expected.not_to be_used_in_context "baz" }
136
+
137
+ end # context
138
+
139
+ context "white- and blacklisted" do
140
+
141
+ subject do
142
+ described_class.new "foo", only: %w(foo bar), except: %w(bar baz)
143
+ end
144
+
145
+ it { is_expected.to be_used_in_context "foo" }
146
+ it { is_expected.not_to be_used_in_context :bar }
147
+ it { is_expected.not_to be_used_in_context "baz" }
148
+
149
+ end
150
+
151
+ end # describe #name
152
+
153
+ end # describe Attestor::Validation
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+
3
+ describe Attestor::Validations::Message do
4
+
5
+ let(:test_class) { Class.new }
6
+ before { TestModule = Module.new }
7
+ before { TestModule::TestObject = test_class }
8
+ after { Object.send :remove_const, :TestModule }
9
+
10
+ let(:scope) { test_class.new }
11
+
12
+ shared_examples "building frozen string" do
13
+
14
+ it { is_expected.to be_kind_of String }
15
+ it { is_expected.to be_frozen }
16
+
17
+ end # shared examples
18
+
19
+ describe ".new" do
20
+
21
+ context "with a symbol argument" do
22
+
23
+ subject { described_class.new :invalid, scope, foo: "bar" }
24
+
25
+ it_behaves_like "building frozen string"
26
+
27
+ it "translates the symbol in given scope" do
28
+ expect(I18n).to receive(:t) do |text, options|
29
+ expect(text).to eq :invalid
30
+ expect(options[:scope])
31
+ .to eq %w(attestor errors test_module/test_object)
32
+ expect(options[:default]).to eq "#{ scope } is invalid (invalid)"
33
+ expect(options[:foo]).to eq "bar"
34
+ ""
35
+ end
36
+ subject
37
+ end
38
+
39
+ it "returns the translation" do
40
+ expect(subject).to eq "#{ scope } is invalid (invalid)"
41
+ end
42
+
43
+ end # context
44
+
45
+ context "with a non-symbolic argument" do
46
+
47
+ subject { described_class.new 1, scope }
48
+
49
+ it_behaves_like "building frozen string"
50
+
51
+ it "creates a stringified argument" do
52
+ expect(subject).to eq "1"
53
+ end
54
+
55
+ end # context
56
+
57
+ context "without options" do
58
+
59
+ subject { described_class.new :invalid, scope }
60
+
61
+ it_behaves_like "building frozen string"
62
+
63
+ it "returns the translation" do
64
+ expect(subject).to eq "#{ scope } is invalid (invalid)"
65
+ end
66
+
67
+ end # context
68
+
69
+ end # describe .new
70
+
71
+ end # Attestor::Validations::Invalid
@@ -0,0 +1,126 @@
1
+ # encoding: utf-8
2
+
3
+ describe Attestor::Validations do
4
+
5
+ let(:collection_class) { Attestor::Validations::Collection }
6
+ let(:item_class) { Attestor::Validations::Item }
7
+ let(:message_class) { Attestor::Validations::Message }
8
+ let(:invalid_error) { Attestor::InvalidError }
9
+ let(:test_class) { Class.new.send(:include, described_class) }
10
+
11
+ before { Test = test_class }
12
+ after { Object.send :remove_const, :Test }
13
+
14
+ subject { test_class.new }
15
+
16
+ describe ".validations" do
17
+
18
+ it "returns a Collection" do
19
+ expect(test_class.validations).to be_kind_of collection_class
20
+ end
21
+
22
+ it "is empty by default" do
23
+ expect(test_class.validations.to_a).to be_empty
24
+ end
25
+
26
+ end # describe .validations
27
+
28
+ describe ".validate" do
29
+
30
+ context "without options" do
31
+
32
+ before { test_class.validate :foo }
33
+
34
+ it "adds the item to the collection" do
35
+ expect(test_class.validations.to_a).to eq [:foo]
36
+ end
37
+
38
+ end # context
39
+
40
+ context "with options" do
41
+
42
+ before { test_class.validate :foo, only: %w(bar baz), except: "bar" }
43
+
44
+ it "uses options" do
45
+ expect(test_class.validations.to_a).to eq [:foo]
46
+ expect(test_class.validations.set(:baz).to_a).to eq [:foo]
47
+ expect(test_class.validations.set(:bar).to_a).to eq []
48
+ end
49
+
50
+ end # context
51
+
52
+ end # describe .validate
53
+
54
+ describe "#validate" do
55
+
56
+ before do
57
+ test_class.validate :foo
58
+ test_class.validate :bar, only: :all
59
+ test_class.validate :baz, only: :foo
60
+ %i(foo bar baz).each { |method| allow(subject).to receive(method) }
61
+ end
62
+
63
+ context "without an argument" do
64
+
65
+ it "calls validations for :all context" do
66
+ expect(subject).to receive(:foo)
67
+ expect(subject).to receive(:bar)
68
+ expect(subject).not_to receive(:baz)
69
+ subject.validate
70
+ end
71
+
72
+ end # context
73
+
74
+ context ":foo" do
75
+
76
+ it "calls validations for :foo context" do
77
+ expect(subject).to receive(:foo)
78
+ expect(subject).to receive(:baz)
79
+ expect(subject).not_to receive(:bar)
80
+ subject.validate :foo
81
+ end
82
+
83
+ end # context
84
+
85
+ end # describe #validate
86
+
87
+ describe "#invalid" do
88
+
89
+ shared_examples "raising an error" do |name, options = {}|
90
+
91
+ let(:message) { message_class.new(name, subject, options) }
92
+
93
+ it "raises an InvalidError" do
94
+ expect { invalid }.to raise_error invalid_error
95
+ end
96
+
97
+ it "assings itself to the exception" do
98
+ begin
99
+ invalid
100
+ rescue => error
101
+ expect(error.object).to eq subject
102
+ expect(error.messages).to contain_exactly message
103
+ end
104
+ end
105
+
106
+ end # shared examples
107
+
108
+ context "without options" do
109
+
110
+ let(:invalid) { subject.invalid :foo }
111
+
112
+ it_behaves_like "raising an error", :foo
113
+
114
+ end
115
+
116
+ context "with options" do
117
+
118
+ let(:invalid) { subject.invalid :foo, bar: :baz }
119
+
120
+ it_behaves_like "raising an error", :foo, bar: :baz
121
+
122
+ end
123
+
124
+ end # invalid
125
+
126
+ end # describe Attestor::Validations