assertion 0.0.1 → 0.1.0

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.
@@ -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