assertion 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+
3
+ require "ostruct"
4
+
5
+ describe Assertion::Guard do
6
+
7
+ before do
8
+ IsAdult = Assertion.about(:age) { age.to_i >= 18 }
9
+ AdultOnly = Class.new(described_class) { def state; IsAdult[object]; end }
10
+ end
11
+
12
+ let(:valid) { OpenStruct.new(name: "Joe", age: 40) }
13
+ let(:invalid) { OpenStruct.new(name: "Ian", age: 10) }
14
+ let(:guard) { AdultOnly.new valid }
15
+
16
+ it "can declare attributes" do
17
+ expect(AdultOnly).to be_kind_of Assertion::Attributes
18
+ end
19
+
20
+ describe ".new" do
21
+
22
+ subject { guard }
23
+
24
+ it { is_expected.to be_frozen }
25
+
26
+ context "with an attriubute" do
27
+
28
+ before { allow(AdultOnly).to receive(:attributes) { [:foo] } }
29
+
30
+ it "adds the alias to the #object" do
31
+ expect(subject.foo).to eql subject.object
32
+ end
33
+
34
+ end # context
35
+
36
+ end # describe .new
37
+
38
+ describe ".[]" do
39
+
40
+ it "returns the result of the call" do
41
+ expect(AdultOnly[valid]).to eql valid
42
+ expect { AdultOnly[invalid] }.to raise_error Assertion::InvalidError
43
+ end
44
+
45
+ end # describe .[]
46
+
47
+ describe "#object" do
48
+
49
+ subject { guard.object }
50
+
51
+ it { is_expected.to eql valid }
52
+
53
+ end # describe #object
54
+
55
+ describe "#call" do
56
+
57
+ subject { guard.call }
58
+
59
+ context "when #state is valid" do
60
+
61
+ it { is_expected.to eql valid }
62
+
63
+ end # context
64
+
65
+ context "when #state is invalid" do
66
+
67
+ let(:guard) { AdultOnly.new invalid }
68
+
69
+ it "raises InvalidError" do
70
+ expect { subject }.to raise_error Assertion::InvalidError
71
+ end
72
+
73
+ end # context
74
+
75
+ end # describe #call
76
+
77
+ after do
78
+ Object.send :remove_const, :AdultOnly
79
+ Object.send :remove_const, :IsAdult
80
+ end
81
+
82
+ end # describe Assertion::Guard
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::Messages, "#message" do
4
+
5
+ let(:test_klass) { Test = Class.new { include Assertion::Messages } }
6
+ let(:instance) { test_klass.new }
7
+
8
+ shared_examples "translating" do |state, as: nil|
9
+
10
+ subject(:message) { instance.message(state) }
11
+
12
+ it { is_expected.to eql "translation missing: en.assertion.test.#{as}" }
13
+
14
+ it "sends attributes to translation" do
15
+ expect(I18n).to receive(:translate) do |_, args|
16
+ expect(args.merge(instance.attributes)).to eql args
17
+ end
18
+ subject
19
+ end
20
+
21
+ end # shared examples
22
+
23
+ context "without attributes" do
24
+
25
+ it_behaves_like "translating", true, as: "right"
26
+ it_behaves_like "translating", false, as: "wrong"
27
+
28
+ end # context
29
+
30
+ context "with attributes" do
31
+
32
+ before { test_klass.send(:define_method, :attributes) { { foo: :FOO } } }
33
+
34
+ it_behaves_like "translating", true, as: "right"
35
+ it_behaves_like "translating", false, as: "wrong"
36
+
37
+ end # context
38
+
39
+ after { Object.send :remove_const, :Test }
40
+
41
+ end # describe Assertion::Messages
@@ -2,18 +2,18 @@
2
2
 
3
3
  describe Assertion do
4
4
 
5
- describe ".about" do
5
+ let(:john) { { age: 17, gender: :male } }
6
+ let(:jack) { { age: 18, gender: :male } }
6
7
 
7
- let(:john) { { age: 17, gender: :male } }
8
- let(:jack) { { age: 18, gender: :male } }
8
+ describe ".about" do
9
9
 
10
10
  context "with attributes and a block" do
11
11
 
12
12
  subject do
13
- Man = Assertion.about(:age, :gender) { age >= 18 && gender == :male }
13
+ IsMan = Assertion.about(:age, :gender) { age >= 18 && gender == :male }
14
14
  end
15
15
 
16
- it "provides the assertion class" do
16
+ it "builds the assertion class" do
17
17
  expect(subject.superclass).to eql Assertion::Base
18
18
  end
19
19
 
@@ -27,10 +27,10 @@ describe Assertion do
27
27
  context "without attributes" do
28
28
 
29
29
  subject do
30
- Man = Assertion.about { true }
30
+ IsMan = Assertion.about { true }
31
31
  end
32
32
 
33
- it "provides the assertion class" do
33
+ it "builds the assertion class" do
34
34
  expect(subject.superclass).to eql Assertion::Base
35
35
  end
36
36
 
@@ -44,22 +44,79 @@ describe Assertion do
44
44
  context "without a block" do
45
45
 
46
46
  subject do
47
- Man = Assertion.about(:age, :gender)
47
+ IsMan = Assertion.about(:age, :gender)
48
48
  end
49
49
 
50
- it "provides the assertion class" do
50
+ it "builds the assertion class" do
51
51
  expect(subject.superclass).to eql Assertion::Base
52
52
  end
53
53
 
54
54
  it "doesn't implement the #check method" do
55
- expect { subject[jack] }
56
- .to raise_error Assertion::NotImplementedError
55
+ expect { subject.new(jack).check }.to raise_error NoMethodError
57
56
  end
58
57
 
59
58
  end # context
60
59
 
61
- after { Object.send :remove_const, :Man }
60
+ after { Object.send :remove_const, :IsMan }
62
61
 
63
62
  end # describe .about
64
63
 
64
+ describe ".guards" do
65
+
66
+ before { IsAdult = Assertion.about(:age) { age.to_i >= 18 } }
67
+
68
+ context "with an attribute and a block" do
69
+
70
+ subject { Assertion.guards(:user) { IsAdult[user] } }
71
+
72
+ it "builds the guard class" do
73
+ expect(subject.superclass).to eql Assertion::Guard
74
+ end
75
+
76
+ it "defines an alias for the object" do
77
+ expect(subject.new(jack).user).to eql jack
78
+ end
79
+
80
+ it "implements the #state" do
81
+ expect { subject.new(jack).state }.not_to raise_error
82
+ end
83
+
84
+ end # context
85
+
86
+ context "without an attribute" do
87
+
88
+ subject { Assertion.guards { IsAdult[object] } }
89
+
90
+ it "builds the guard class" do
91
+ expect(subject.superclass).to eql Assertion::Guard
92
+ end
93
+
94
+ it "implements the #state of #object" do
95
+ expect { subject.new(jack).state }.not_to raise_error
96
+ end
97
+
98
+ end # context
99
+
100
+ context "without a block" do
101
+
102
+ subject { Assertion.guards(:user) }
103
+
104
+ it "builds the guard class" do
105
+ expect(subject.superclass).to eql Assertion::Guard
106
+ end
107
+
108
+ it "defines an alias for the object" do
109
+ expect(subject.new(jack).user).to eql jack
110
+ end
111
+
112
+ it "doesn't implement the #state" do
113
+ expect { subject.new(jack).state }.to raise_error NoMethodError
114
+ end
115
+
116
+ end # context
117
+
118
+ after { Object.send :remove_const, :IsAdult }
119
+
120
+ end # describe .guards
121
+
65
122
  end # describe Assertion
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: assertion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kozin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-18 00:00:00.000000000 Z
11
+ date: 2015-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: transproc
@@ -81,6 +81,7 @@ files:
81
81
  - ".rubocop.yml"
82
82
  - ".travis.yml"
83
83
  - ".yardopts"
84
+ - CHANGELOG.md
84
85
  - Gemfile
85
86
  - Guardfile
86
87
  - LICENSE
@@ -99,29 +100,30 @@ files:
99
100
  - config/metrics/simplecov.yml
100
101
  - config/metrics/yardstick.yml
101
102
  - lib/assertion.rb
103
+ - lib/assertion/attributes.rb
102
104
  - lib/assertion/base.rb
103
- - lib/assertion/exceptions/invalid_error.rb
104
- - lib/assertion/exceptions/name_error.rb
105
- - lib/assertion/exceptions/not_implemented_error.rb
105
+ - lib/assertion/guard.rb
106
+ - lib/assertion/invalid_error.rb
106
107
  - lib/assertion/inversion.rb
107
108
  - lib/assertion/inverter.rb
109
+ - lib/assertion/messages.rb
108
110
  - lib/assertion/state.rb
109
- - lib/assertion/transprocs/i18n.rb
110
111
  - lib/assertion/transprocs/inflector.rb
111
112
  - lib/assertion/transprocs/list.rb
112
113
  - lib/assertion/version.rb
113
114
  - spec/integration/assertion_spec.rb
114
- - spec/integration/en.yml
115
+ - spec/integration/guard_spec.rb
116
+ - spec/shared/en.yml
117
+ - spec/shared/i18n.rb
115
118
  - spec/spec_helper.rb
119
+ - spec/unit/assertion/attributes_spec.rb
116
120
  - spec/unit/assertion/base_spec.rb
117
121
  - spec/unit/assertion/exceptions/invalid_error_spec.rb
118
- - spec/unit/assertion/exceptions/name_error_spec.rb
119
- - spec/unit/assertion/exceptions/not_implemented_error_spec.rb
122
+ - spec/unit/assertion/guard_spec.rb
120
123
  - spec/unit/assertion/inversion_spec.rb
121
124
  - spec/unit/assertion/inverter_spec.rb
125
+ - spec/unit/assertion/messages_spec.rb
122
126
  - spec/unit/assertion/state_spec.rb
123
- - spec/unit/assertion/transprocs/i18n/to_scope_spec.rb
124
- - spec/unit/assertion/transprocs/i18n/translate_spec.rb
125
127
  - spec/unit/assertion/transprocs/inflector/to_path_spec.rb
126
128
  - spec/unit/assertion/transprocs/inflector/to_snake_path_spec.rb
127
129
  - spec/unit/assertion/transprocs/inflector/to_snake_spec.rb
@@ -154,18 +156,19 @@ summary: PORO assertions and validation
154
156
  test_files:
155
157
  - spec/spec_helper.rb
156
158
  - spec/integration/assertion_spec.rb
159
+ - spec/integration/guard_spec.rb
157
160
  - spec/unit/assertion_spec.rb
158
161
  - spec/unit/assertion/state_spec.rb
159
162
  - spec/unit/assertion/transprocs/inflector/to_snake_path_spec.rb
160
163
  - spec/unit/assertion/transprocs/inflector/to_snake_spec.rb
161
164
  - spec/unit/assertion/transprocs/inflector/to_path_spec.rb
162
- - spec/unit/assertion/transprocs/i18n/to_scope_spec.rb
163
- - spec/unit/assertion/transprocs/i18n/translate_spec.rb
164
165
  - spec/unit/assertion/transprocs/list/symbolize_spec.rb
165
166
  - spec/unit/assertion/exceptions/invalid_error_spec.rb
166
- - spec/unit/assertion/exceptions/not_implemented_error_spec.rb
167
- - spec/unit/assertion/exceptions/name_error_spec.rb
167
+ - spec/unit/assertion/messages_spec.rb
168
168
  - spec/unit/assertion/inverter_spec.rb
169
169
  - spec/unit/assertion/inversion_spec.rb
170
+ - spec/unit/assertion/guard_spec.rb
171
+ - spec/unit/assertion/attributes_spec.rb
170
172
  - spec/unit/assertion/base_spec.rb
173
+ - spec/shared/i18n.rb
171
174
  has_rdoc:
@@ -1,29 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Assertion
4
-
5
- # The exception to be raised when a Assertion attribute uses reserved name(s)
6
- #
7
- # @api public
8
- #
9
- class NameError < ::NameError
10
-
11
- # @!scope class
12
- # @!method new(*names)
13
- # Creates an exception instance
14
- #
15
- # @param [Symbol, Array<Symbol>] names Wrong names of attribute(s)
16
- #
17
- # @return [Assertion::NameError]
18
- #
19
- # @api private
20
-
21
- # @private
22
- def initialize(*names)
23
- super "Wrong name(s) for attribute(s): #{names.join(", ")}"
24
- freeze
25
- end
26
-
27
- end # class NameError
28
-
29
- end # module Assertion
@@ -1,29 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Assertion
4
-
5
- # The exception to be raised when a assertion is applied to some data
6
- # before its `check` method has been implemented
7
- #
8
- # @api public
9
- #
10
- class NotImplementedError < ::NotImplementedError
11
-
12
- # @!scope class
13
- # @!method new(klass, name)
14
- # Creates an exception instance
15
- #
16
- # @param [Class] klass The class that should implement the instance method
17
- # @param [Symbol] name The name of the method to be implemented
18
- #
19
- # @return [Assertion::NotImplementedError]
20
-
21
- # @private
22
- def initialize(klass, name)
23
- super "#{klass.name}##{name} method not implemented"
24
- freeze
25
- end
26
-
27
- end # class NotImplementedError
28
-
29
- end # module Assertion
@@ -1,55 +0,0 @@
1
- module Assertion
2
-
3
- # The collection of pure functions for translating strings in the gem-specific
4
- # scopes of `Assertion::Base` subclasses.
5
- #
6
- # @api private
7
- #
8
- module I18n
9
-
10
- extend ::Transproc::Registry
11
-
12
- uses :to_snake_path, from: Inflector, as: :snake
13
-
14
- # Converts the name of the class to the corresponding gem-specific scope
15
- #
16
- # @example
17
- # fn = I18n[:scope]
18
- # fn["Foo::BarBaz"]
19
- # # => [:assertion, :"foo/bar_baz"]
20
- #
21
- # @param [String] name The name of the class
22
- #
23
- # @return [Array<Symbol>] The `I18n`-compatible gem-specific scope
24
- #
25
- def scope(name)
26
- [:assertion, snake(name).to_sym]
27
- end
28
-
29
- # Translates the key with hash of attributes in a given scope
30
- #
31
- # @example
32
- # # config/locales/en.yml
33
- # # ---
34
- # # en:
35
- # # assertion:
36
- # # foo:
37
- # # qux: "message %{bar}"
38
- #
39
- # fn = I18n[:translate, [:assertion, :foo], bar: :BAZ]
40
- # fn[:qux]
41
- # # => "message BAZ"
42
- #
43
- # @param [key] key The key to be translated
44
- # @param [Array<Symbol>] scope The I18n scope for the translations
45
- # @param [Hash] hash The hash of attributes for the translation
46
- #
47
- # @return [String] The translated string
48
- #
49
- def translate(key, scope, hash)
50
- ::I18n.t(key, hash.merge(scope: scope))
51
- end
52
-
53
- end # module I18n
54
-
55
- end # module Assertion