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