assertion 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) 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 +19 -0
  8. data/.yardopts +3 -0
  9. data/Gemfile +9 -0
  10. data/Guardfile +18 -0
  11. data/LICENSE +21 -0
  12. data/README.md +222 -0
  13. data/Rakefile +29 -0
  14. data/assertion.gemspec +27 -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 +72 -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/assertion.rb +79 -0
  27. data/lib/assertion/base.rb +186 -0
  28. data/lib/assertion/exceptions/invalid_error.rb +36 -0
  29. data/lib/assertion/exceptions/name_error.rb +29 -0
  30. data/lib/assertion/exceptions/not_implemented_error.rb +29 -0
  31. data/lib/assertion/inversion.rb +64 -0
  32. data/lib/assertion/inverter.rb +62 -0
  33. data/lib/assertion/state.rb +79 -0
  34. data/lib/assertion/transprocs/i18n.rb +55 -0
  35. data/lib/assertion/transprocs/inflector.rb +39 -0
  36. data/lib/assertion/transprocs/list.rb +30 -0
  37. data/lib/assertion/version.rb +9 -0
  38. data/spec/integration/assertion_spec.rb +50 -0
  39. data/spec/integration/en.yml +10 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/spec/unit/assertion/base_spec.rb +221 -0
  42. data/spec/unit/assertion/exceptions/invalid_error_spec.rb +40 -0
  43. data/spec/unit/assertion/exceptions/name_error_spec.rb +26 -0
  44. data/spec/unit/assertion/exceptions/not_implemented_error_spec.rb +26 -0
  45. data/spec/unit/assertion/inversion_spec.rb +89 -0
  46. data/spec/unit/assertion/inverter_spec.rb +80 -0
  47. data/spec/unit/assertion/state_spec.rb +224 -0
  48. data/spec/unit/assertion/transprocs/i18n/to_scope_spec.rb +19 -0
  49. data/spec/unit/assertion/transprocs/i18n/translate_spec.rb +28 -0
  50. data/spec/unit/assertion/transprocs/inflector/to_path_spec.rb +19 -0
  51. data/spec/unit/assertion/transprocs/inflector/to_snake_path_spec.rb +19 -0
  52. data/spec/unit/assertion/transprocs/inflector/to_snake_spec.rb +19 -0
  53. data/spec/unit/assertion/transprocs/list/symbolize_spec.rb +19 -0
  54. data/spec/unit/assertion_spec.rb +65 -0
  55. metadata +171 -0
@@ -0,0 +1,10 @@
1
+ # Translations of messages for examples in the `./assertion_spec.rb`
2
+ ---
3
+ en:
4
+ assertion:
5
+ is_adult:
6
+ right: "%{name} is an adult (age %{age})"
7
+ wrong: "%{name} is a child (age %{age})"
8
+ is_male:
9
+ right: "%{name} is a male"
10
+ wrong: "%{name} is a female"
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ begin
4
+ require "hexx-suit"
5
+ Hexx::Suit.load_metrics_for(self)
6
+ rescue LoadError
7
+ require "hexx-rspec"
8
+ Hexx::RSpec.load_metrics_for(self)
9
+ end
10
+
11
+ # Loads the code under test
12
+ require "assertion"
@@ -0,0 +1,221 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::Base do
4
+
5
+ let(:klass) { Class.new(described_class) }
6
+ before { allow(klass).to receive(:name) { "Test" } }
7
+
8
+ describe ".attributes" do
9
+
10
+ subject(:attributes) { klass.attributes }
11
+
12
+ it { is_expected.to eql [] }
13
+
14
+ end # describe .attributes
15
+
16
+ describe ".attribute" do
17
+
18
+ subject(:attribute) { klass.attribute names }
19
+
20
+ context "with valid name" do
21
+
22
+ let(:names) { :foo }
23
+
24
+ it "defines the attribute" do
25
+ expect { subject }
26
+ .to change { klass.attributes }
27
+ .to [:foo]
28
+ end
29
+
30
+ end # context
31
+
32
+ context "with array of names" do
33
+
34
+ let(:names) { [:foo, "bar", "foo"] }
35
+
36
+ it "defines the attribute" do
37
+ expect { subject }
38
+ .to change { klass.attributes }
39
+ .to [:foo, :bar]
40
+ end
41
+
42
+ end # context
43
+
44
+ context "with a :check name" do
45
+
46
+ let(:names) { [:check] }
47
+
48
+ it "fails" do
49
+ expect { subject }.to raise_error do |error|
50
+ expect(error).to be_kind_of Assertion::NameError
51
+ expect(error.message).to include "check"
52
+ end
53
+ end
54
+
55
+ end # context
56
+
57
+ context "with a :call name" do
58
+
59
+ let(:names) { [:call] }
60
+
61
+ it "fails" do
62
+ expect { subject }.to raise_error do |error|
63
+ expect(error).to be_kind_of Assertion::NameError
64
+ expect(error.message).to include "call"
65
+ end
66
+ end
67
+
68
+ end # context
69
+
70
+ end # describe .attribute
71
+
72
+ describe ".new" do
73
+
74
+ let(:klass) { Class.new(described_class) { attribute :foo, :bar } }
75
+
76
+ context "with attributes" do
77
+
78
+ subject { klass.new foo: :FOO, bar: :BAR, baz: :BAZ }
79
+
80
+ it "defines attributes" do
81
+ new_methods = subject.methods - described_class.instance_methods
82
+ expect(new_methods).to match_array [:foo, :bar]
83
+ end
84
+
85
+ it "initializes attributes" do
86
+ expect(subject.foo).to eql :FOO
87
+ expect(subject.bar).to eql :BAR
88
+ end
89
+
90
+ it { is_expected.to be_frozen }
91
+
92
+ end # context
93
+
94
+ context "without attributes" do
95
+
96
+ subject { klass.new }
97
+
98
+ it { is_expected.to be_frozen }
99
+
100
+ end # context
101
+
102
+ end # describe .new
103
+
104
+ describe ".not" do
105
+
106
+ subject { klass.not }
107
+
108
+ it "creates the iverter for the current class" do
109
+ expect(subject).to be_kind_of Assertion::Inverter
110
+ expect(subject.source).to eql klass
111
+ end
112
+
113
+ end # describe .not
114
+
115
+ describe ".[]" do
116
+
117
+ subject { klass[params] }
118
+
119
+ let(:params) { { foo: :FOO } }
120
+ let(:state) { double }
121
+ let(:assertion) { double call: state }
122
+
123
+ before { allow(klass).to receive(:new).with(params) { assertion } }
124
+
125
+ it "checks the assertion for given attributes" do
126
+ expect(subject).to eql state
127
+ end
128
+
129
+ end # describe .[]
130
+
131
+ describe "#attributes" do
132
+
133
+ let(:attrs) { { foo: :FOO, bar: :BAR } }
134
+ let(:klass) { Class.new(described_class) { attribute :foo, :bar } }
135
+ let(:assertion) { klass.new attrs }
136
+
137
+ subject { assertion.attributes }
138
+ it { is_expected.to eql attrs }
139
+
140
+ end # describe #attributes
141
+
142
+ describe "#message" do
143
+
144
+ let(:assertion) { klass.new }
145
+
146
+ context "for the truthy state" do
147
+
148
+ subject { assertion.message(true) }
149
+ it { is_expected.to eql "translation missing: en.assertion.test.right" }
150
+
151
+ end # context
152
+
153
+ context "for the falsey state" do
154
+
155
+ subject { assertion.message(false) }
156
+ it { is_expected.to eql "translation missing: en.assertion.test.wrong" }
157
+
158
+ end # context
159
+
160
+ context "by default" do
161
+
162
+ it "returns the message for the falsey state" do
163
+ expect(assertion.message).to eql assertion.message(false)
164
+ end
165
+
166
+ end # context
167
+
168
+ end # describe #message
169
+
170
+ describe "#check" do
171
+
172
+ subject { klass.new.check }
173
+
174
+ it "raises NotImplementedError" do
175
+ expect { subject }.to raise_error do |error|
176
+ expect(error).to be_kind_of Assertion::NotImplementedError
177
+ expect(error.message).to include("Test#check ")
178
+ end
179
+ end
180
+
181
+ end # describe #check
182
+
183
+ describe "#call" do
184
+
185
+ subject { assertion.call }
186
+
187
+ context "invalid assertion" do
188
+
189
+ let(:assertion) do
190
+ klass.__send__(:define_method, :check) { false }
191
+ klass.new
192
+ end
193
+
194
+ it "returns an invalid state" do
195
+ expect(subject).to be_kind_of Assertion::State
196
+ expect(subject).to be_invalid
197
+ end
198
+
199
+ it "adds a proper message to the state" do
200
+ expect(subject.messages).to contain_exactly assertion.message(false)
201
+ end
202
+
203
+ end # context
204
+
205
+ context "valid assertion" do
206
+
207
+ let(:assertion) do
208
+ klass.__send__(:define_method, :check) { true }
209
+ klass.new
210
+ end
211
+
212
+ it "returns a valid state" do
213
+ expect(subject).to be_kind_of Assertion::State
214
+ expect(subject).to be_valid
215
+ end
216
+
217
+ end # context
218
+
219
+ end # describe #call
220
+
221
+ end # describe Assertion
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::InvalidError do
4
+
5
+ subject(:error) { described_class.new messages }
6
+ let(:messages) { %w(foo bar) }
7
+
8
+ describe ".new" do
9
+
10
+ it { is_expected.to be_kind_of ::RuntimeError }
11
+
12
+ it { is_expected.to be_frozen }
13
+
14
+ end # describe .new
15
+
16
+ describe "#message" do
17
+
18
+ subject { error.message }
19
+
20
+ it "returns a proper message" do
21
+ expect(subject).to include "#{messages.inspect}"
22
+ end
23
+
24
+ end # describe #message
25
+
26
+ describe "#messages" do
27
+
28
+ subject { error.messages }
29
+
30
+ it { is_expected.to eql messages }
31
+
32
+ it { is_expected.to be_frozen }
33
+
34
+ it "doesn't freeze the source messages" do
35
+ expect(messages).not_to be_frozen
36
+ end
37
+
38
+ end # describe #message
39
+
40
+ end # describe Assertion::InvalidError
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::NameError do
4
+
5
+ subject(:error) { described_class.new :foo, :bar }
6
+
7
+ describe ".new" do
8
+
9
+ it { is_expected.to be_kind_of ::NameError }
10
+
11
+ it { is_expected.to be_frozen }
12
+
13
+ end # describe .new
14
+
15
+ describe "#message" do
16
+
17
+ subject(:message) { error.message }
18
+
19
+ it "returns a proper message" do
20
+ expect(subject)
21
+ .to include "Wrong name(s) for attribute(s): foo, bar"
22
+ end
23
+
24
+ end # describe #message
25
+
26
+ end # describe Assertion::NameError
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::NotImplementedError do
4
+
5
+ subject(:error) { described_class.new klass, :foo }
6
+ let(:klass) { double name: :Test }
7
+
8
+ describe ".new" do
9
+
10
+ it { is_expected.to be_kind_of ::NotImplementedError }
11
+
12
+ it { is_expected.to be_frozen }
13
+
14
+ end # describe .new
15
+
16
+ describe "#message" do
17
+
18
+ subject(:message) { error.message }
19
+
20
+ it "returns a proper message" do
21
+ expect(subject).to include "Test#foo method not implemented"
22
+ end
23
+
24
+ end # describe #message
25
+
26
+ end # describe Assertion::NotImplementedError
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::Inversion do
4
+
5
+ before { Adult = Assertion.about(:age) { age >= 18 } }
6
+
7
+ let(:assertion) { Adult.new age: 21 }
8
+ subject(:inversion) { described_class.new(assertion) }
9
+ subject(:double_inversion) { described_class.new(inversion) }
10
+
11
+ describe ".new" do
12
+
13
+ it { is_expected.to be_frozen }
14
+
15
+ end # describe .new
16
+
17
+ describe "#assertion" do
18
+
19
+ subject { inversion.assertion }
20
+
21
+ it { is_expected.to eql assertion }
22
+
23
+ end # describe #assertion
24
+
25
+ describe "#check" do
26
+
27
+ subject { instance.check }
28
+
29
+ it "is opposite to the assertion#check" do
30
+ expect(inversion.check).to eql !assertion.check
31
+ end
32
+
33
+ it "works for double inversion" do
34
+ expect(double_inversion.check).to eql assertion.check
35
+ end
36
+
37
+ end # describe #check
38
+
39
+ describe "#message" do
40
+
41
+ context "for the truthy state" do
42
+
43
+ it "is equal to wrong assertion" do
44
+ expect(inversion.message(true)).to eql assertion.message(false)
45
+ end
46
+
47
+ it "works for double inversion" do
48
+ expect(double_inversion.message(true)).to eql assertion.message(true)
49
+ end
50
+
51
+ end # context
52
+
53
+ context "for the falsey state" do
54
+
55
+ it "is equal to right assertion" do
56
+ expect(inversion.message(false)).to eql assertion.message(true)
57
+ end
58
+
59
+ it "works for double inversion" do
60
+ expect(double_inversion.message(false)).to eql assertion.message(false)
61
+ end
62
+
63
+ end # context
64
+
65
+ context "by default" do
66
+
67
+ it "returns the message for the falsey state" do
68
+ expect(inversion.message).to eql inversion.message(false)
69
+ end
70
+
71
+ end # context
72
+
73
+ end # describe #message
74
+
75
+ describe "#call" do
76
+
77
+ let(:state) { assertion.call }
78
+ subject { inversion.call }
79
+
80
+ it "creates the state opposite to the assertion's" do
81
+ expect(subject.valid?).to eql state.invalid?
82
+ expect(subject.messages).to contain_exactly assertion.message(true)
83
+ end
84
+
85
+ end # describe #call
86
+
87
+ after { Object.send :remove_const, :Adult }
88
+
89
+ end # describe Assertion::Inversion
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::Inverter do
4
+
5
+ let(:source) do
6
+ Man = Assertion.about(:age, :gender) { age.to_i >= 18 && gender == :male }
7
+ end
8
+
9
+ subject(:inverter) { described_class.new source }
10
+
11
+ describe ".new" do
12
+
13
+ it { is_expected.to be_frozen }
14
+
15
+ end # describe .new
16
+
17
+ describe ".source" do
18
+
19
+ subject { inverter.source }
20
+ it { is_expected.to eql source }
21
+
22
+ end # describe .source
23
+
24
+ describe "#new" do
25
+
26
+ let(:assertion) { inversion.assertion }
27
+
28
+ context "with attributes" do
29
+
30
+ subject(:inversion) { inverter.new age: 17, gender: :male }
31
+
32
+ it "returns an inversion" do
33
+ expect(inversion).to be_kind_of Assertion::Inversion
34
+ expect(assertion.attributes).to eql(age: 17, gender: :male)
35
+ end
36
+
37
+ end # context
38
+
39
+ context "without attributes" do
40
+
41
+ subject(:inversion) { inverter.new }
42
+
43
+ it "returns an inversion" do
44
+ expect(inversion).to be_kind_of Assertion::Inversion
45
+ expect(assertion.attributes).to eql(age: nil, gender: nil)
46
+ end
47
+
48
+ end # context
49
+
50
+ end # describe #new
51
+
52
+ describe "#[]" do
53
+
54
+ context "with attributes" do
55
+
56
+ subject(:state) { inverter[age: 18, gender: :male] }
57
+
58
+ it "provides the state for inversion" do
59
+ expect(state).to be_kind_of Assertion::State
60
+ expect(state).to be_invalid
61
+ end
62
+
63
+ end # context
64
+
65
+ context "without attributes" do
66
+
67
+ subject(:state) { inverter[] }
68
+
69
+ it "provides the state for inversion" do
70
+ expect(state).to be_kind_of Assertion::State
71
+ expect(state).to be_valid
72
+ end
73
+
74
+ end # context
75
+
76
+ end # describe #[]
77
+
78
+ after { Object.send :remove_const, :Man }
79
+
80
+ end # describe Assertion::Inverter