attestor 0.0.1

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