assertion 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/Gemfile +0 -2
  4. data/Guardfile +6 -6
  5. data/README.md +8 -6
  6. data/assertion.gemspec +1 -1
  7. data/config/metrics/flay.yml +1 -1
  8. data/lib/assertion.rb +29 -80
  9. data/lib/assertion/base.rb +38 -64
  10. data/lib/assertion/base_dsl.rb +75 -0
  11. data/lib/assertion/dsl.rb +77 -0
  12. data/lib/assertion/guard.rb +1 -30
  13. data/lib/assertion/guard_dsl.rb +39 -0
  14. data/lib/assertion/{transprocs/inflector.rb → inflector.rb} +0 -0
  15. data/lib/assertion/inversion.rb +3 -3
  16. data/lib/assertion/inverter.rb +2 -2
  17. data/lib/assertion/translator.rb +95 -0
  18. data/lib/assertion/version.rb +1 -1
  19. data/spec/integration/guard_spec.rb +1 -1
  20. data/spec/shared/en.yml +4 -4
  21. data/spec/unit/assertion/base_spec.rb +124 -14
  22. data/spec/unit/assertion/guard_spec.rb +37 -13
  23. data/spec/unit/assertion/{transprocs/inflector → inflector}/to_path_spec.rb +0 -0
  24. data/spec/unit/assertion/{transprocs/inflector → inflector}/to_snake_path_spec.rb +0 -0
  25. data/spec/unit/assertion/{transprocs/inflector → inflector}/to_snake_spec.rb +0 -0
  26. data/spec/unit/assertion/{exceptions/invalid_error_spec.rb → invalid_error_spec.rb} +0 -0
  27. data/spec/unit/assertion/inversion_spec.rb +5 -5
  28. data/spec/unit/assertion/inverter_spec.rb +2 -2
  29. data/spec/unit/assertion/translator_spec.rb +57 -0
  30. metadata +23 -20
  31. data/lib/assertion/attributes.rb +0 -54
  32. data/lib/assertion/messages.rb +0 -65
  33. data/lib/assertion/transprocs/list.rb +0 -30
  34. data/spec/unit/assertion/attributes_spec.rb +0 -97
  35. data/spec/unit/assertion/messages_spec.rb +0 -41
  36. data/spec/unit/assertion/transprocs/list/symbolize_spec.rb +0 -19
@@ -6,32 +6,56 @@ describe Assertion::Guard do
6
6
 
7
7
  before do
8
8
  IsAdult = Assertion.about(:age) { age.to_i >= 18 }
9
- AdultOnly = Class.new(described_class) { def state; IsAdult[object]; end }
9
+ AdultOnly = Class.new(described_class) do
10
+ def state
11
+ IsAdult[object.to_h]
12
+ end
13
+ end
10
14
  end
11
15
 
12
16
  let(:valid) { OpenStruct.new(name: "Joe", age: 40) }
13
17
  let(:invalid) { OpenStruct.new(name: "Ian", age: 10) }
14
- let(:guard) { AdultOnly.new valid }
18
+ let(:guard) { AdultOnly.new valid }
15
19
 
16
- it "can declare attributes" do
17
- expect(AdultOnly).to be_kind_of Assertion::Attributes
18
- end
20
+ describe ".attribute" do
19
21
 
20
- describe ".new" do
22
+ shared_examples "adding #object alias" do |name|
21
23
 
22
- subject { guard }
24
+ subject { AdultOnly.attribute name }
23
25
 
24
- it { is_expected.to be_frozen }
26
+ it "adds alias for the #object" do
27
+ subject
28
+ expect(guard.send name).to eql guard.object
29
+ end
25
30
 
26
- context "with an attriubute" do
31
+ end # shared examples
27
32
 
28
- before { allow(AdultOnly).to receive(:attributes) { [:foo] } }
33
+ shared_examples "raising NameError" do |with: nil|
29
34
 
30
- it "adds the alias to the #object" do
31
- expect(subject.foo).to eql subject.object
35
+ before { Test = Class.new(described_class) } # #state not implemented yet
36
+ after { Object.send :remove_const, :Test }
37
+ subject { Test.attribute with }
38
+
39
+ it "fails" do
40
+ expect { subject }.to raise_error do |error|
41
+ expect(error).to be_kind_of NameError
42
+ expect(error.message).to eql "Test##{with} is already defined"
43
+ end
32
44
  end
33
45
 
34
- end # context
46
+ end # shared examples
47
+
48
+ it_behaves_like "adding #object alias", :foo
49
+ it_behaves_like "raising NameError", with: "state"
50
+ it_behaves_like "raising NameError", with: "call"
51
+
52
+ end # describe .attribute
53
+
54
+ describe ".new" do
55
+
56
+ subject { guard }
57
+
58
+ it { is_expected.to be_frozen }
35
59
 
36
60
  end # describe .new
37
61
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  describe Assertion::Inversion do
4
4
 
5
- before { Adult = Assertion.about(:age) { age >= 18 } }
5
+ before { IsAdult = Assertion.about(:age) { age >= 18 } }
6
6
 
7
- let(:assertion) { Adult.new age: 21 }
7
+ let(:assertion) { IsAdult.new age: 21 }
8
8
  subject(:inversion) { described_class.new(assertion) }
9
9
  subject(:double_inversion) { described_class.new(inversion) }
10
10
 
@@ -40,7 +40,7 @@ describe Assertion::Inversion do
40
40
 
41
41
  context "for the truthy state" do
42
42
 
43
- it "is equal to wrong assertion" do
43
+ it "is equal to falsey assertion" do
44
44
  expect(inversion.message(true)).to eql assertion.message(false)
45
45
  end
46
46
 
@@ -52,7 +52,7 @@ describe Assertion::Inversion do
52
52
 
53
53
  context "for the falsey state" do
54
54
 
55
- it "is equal to right assertion" do
55
+ it "is equal to truthy assertion" do
56
56
  expect(inversion.message(false)).to eql assertion.message(true)
57
57
  end
58
58
 
@@ -84,6 +84,6 @@ describe Assertion::Inversion do
84
84
 
85
85
  end # describe #call
86
86
 
87
- after { Object.send :remove_const, :Adult }
87
+ after { Object.send :remove_const, :IsAdult }
88
88
 
89
89
  end # describe Assertion::Inversion
@@ -3,7 +3,7 @@
3
3
  describe Assertion::Inverter do
4
4
 
5
5
  let(:source) do
6
- Man = Assertion.about(:age, :gender) { age.to_i >= 18 && gender == :male }
6
+ IsMan = Assertion.about(:age, :gender) { age.to_i >= 18 && gender == :male }
7
7
  end
8
8
 
9
9
  subject(:inverter) { described_class.new source }
@@ -75,6 +75,6 @@ describe Assertion::Inverter do
75
75
 
76
76
  end # describe #[]
77
77
 
78
- after { Object.send :remove_const, :Man }
78
+ after { Object.send :remove_const, :IsMan }
79
79
 
80
80
  end # describe Assertion::Inverter
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ describe Assertion::Translator do
4
+
5
+ before { class IsFoo; end }
6
+ after { Object.send :remove_const, :IsFoo }
7
+
8
+ subject(:translator) { described_class.new(IsFoo) }
9
+
10
+ describe ".new" do
11
+
12
+ it { is_expected.to be_frozen }
13
+
14
+ end # describe .new
15
+
16
+ describe "#assertion" do
17
+
18
+ subject { translator.assertion }
19
+ it { is_expected.to eql IsFoo }
20
+
21
+ end # describe #assertion
22
+
23
+ describe "#scope" do
24
+
25
+ subject { translator.scope }
26
+ it { is_expected.to eql [:assertion, :is_foo] }
27
+
28
+ end # describe #scope
29
+
30
+ describe "#call" do
31
+
32
+ shared_examples "translating" do |input, to: nil|
33
+
34
+ subject { translator.call(input) }
35
+
36
+ let(:attributes) { { foo: :FOO, bar: :BAR } }
37
+ let(:output) { "translation missing: en.assertion.is_foo.#{to}" }
38
+
39
+ it "provides translation" do
40
+ expect(translator.call input).to eql output
41
+ end
42
+
43
+ it "makes arguments available" do
44
+ expect(I18n).to receive(:translate) do |_, args|
45
+ expect(args.merge(attributes)).to eql args
46
+ end
47
+ translator.call input, attributes
48
+ end
49
+
50
+ end # shared examples
51
+
52
+ it_behaves_like "translating", true, to: "truthy"
53
+ it_behaves_like "translating", false, to: "falsey"
54
+
55
+ end # describe #call
56
+
57
+ end # describe Assertion::Translator
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.1.0
4
+ version: 0.2.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-20 00:00:00.000000000 Z
11
+ date: 2015-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: transproc
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.2'
20
+ - - ">"
21
+ - !ruby/object:Gem::Version
22
+ version: 0.2.3
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0.2'
30
+ - - ">"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.3
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: i18n
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -100,34 +106,33 @@ files:
100
106
  - config/metrics/simplecov.yml
101
107
  - config/metrics/yardstick.yml
102
108
  - lib/assertion.rb
103
- - lib/assertion/attributes.rb
104
109
  - lib/assertion/base.rb
110
+ - lib/assertion/base_dsl.rb
111
+ - lib/assertion/dsl.rb
105
112
  - lib/assertion/guard.rb
113
+ - lib/assertion/guard_dsl.rb
114
+ - lib/assertion/inflector.rb
106
115
  - lib/assertion/invalid_error.rb
107
116
  - lib/assertion/inversion.rb
108
117
  - lib/assertion/inverter.rb
109
- - lib/assertion/messages.rb
110
118
  - lib/assertion/state.rb
111
- - lib/assertion/transprocs/inflector.rb
112
- - lib/assertion/transprocs/list.rb
119
+ - lib/assertion/translator.rb
113
120
  - lib/assertion/version.rb
114
121
  - spec/integration/assertion_spec.rb
115
122
  - spec/integration/guard_spec.rb
116
123
  - spec/shared/en.yml
117
124
  - spec/shared/i18n.rb
118
125
  - spec/spec_helper.rb
119
- - spec/unit/assertion/attributes_spec.rb
120
126
  - spec/unit/assertion/base_spec.rb
121
- - spec/unit/assertion/exceptions/invalid_error_spec.rb
122
127
  - spec/unit/assertion/guard_spec.rb
128
+ - spec/unit/assertion/inflector/to_path_spec.rb
129
+ - spec/unit/assertion/inflector/to_snake_path_spec.rb
130
+ - spec/unit/assertion/inflector/to_snake_spec.rb
131
+ - spec/unit/assertion/invalid_error_spec.rb
123
132
  - spec/unit/assertion/inversion_spec.rb
124
133
  - spec/unit/assertion/inverter_spec.rb
125
- - spec/unit/assertion/messages_spec.rb
126
134
  - spec/unit/assertion/state_spec.rb
127
- - spec/unit/assertion/transprocs/inflector/to_path_spec.rb
128
- - spec/unit/assertion/transprocs/inflector/to_snake_path_spec.rb
129
- - spec/unit/assertion/transprocs/inflector/to_snake_spec.rb
130
- - spec/unit/assertion/transprocs/list/symbolize_spec.rb
135
+ - spec/unit/assertion/translator_spec.rb
131
136
  - spec/unit/assertion_spec.rb
132
137
  homepage: https://github.com/nepalez/assertion
133
138
  licenses:
@@ -158,17 +163,15 @@ test_files:
158
163
  - spec/integration/assertion_spec.rb
159
164
  - spec/integration/guard_spec.rb
160
165
  - spec/unit/assertion_spec.rb
166
+ - spec/unit/assertion/invalid_error_spec.rb
161
167
  - spec/unit/assertion/state_spec.rb
162
- - spec/unit/assertion/transprocs/inflector/to_snake_path_spec.rb
163
- - spec/unit/assertion/transprocs/inflector/to_snake_spec.rb
164
- - spec/unit/assertion/transprocs/inflector/to_path_spec.rb
165
- - spec/unit/assertion/transprocs/list/symbolize_spec.rb
166
- - spec/unit/assertion/exceptions/invalid_error_spec.rb
167
- - spec/unit/assertion/messages_spec.rb
168
+ - spec/unit/assertion/inflector/to_snake_path_spec.rb
169
+ - spec/unit/assertion/inflector/to_snake_spec.rb
170
+ - spec/unit/assertion/inflector/to_path_spec.rb
171
+ - spec/unit/assertion/translator_spec.rb
168
172
  - spec/unit/assertion/inverter_spec.rb
169
173
  - spec/unit/assertion/inversion_spec.rb
170
174
  - spec/unit/assertion/guard_spec.rb
171
- - spec/unit/assertion/attributes_spec.rb
172
175
  - spec/unit/assertion/base_spec.rb
173
176
  - spec/shared/i18n.rb
174
177
  has_rdoc:
@@ -1,54 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Assertion
4
-
5
- # Module Attributes provides features to define and store a list of attributes
6
- # shared by the [Assertion::Base] and [Assertion::Guard] classes
7
- #
8
- module Attributes
9
-
10
- # List of attributes, defined for the class
11
- #
12
- # @return [Array<Symbol>]
13
- #
14
- def attributes
15
- @attributes ||= []
16
- end
17
-
18
- # Adds a new attribute or a list of attributes to the class
19
- #
20
- # @param [Symbol, Array<Symbol>] names
21
- #
22
- # @return [undefined]
23
- #
24
- # @raise [NameError]
25
- # When the name is either used by instance attribute,
26
- # or forbidden as a name of the method to be implemented later
27
- # (not as an attribute)
28
- #
29
- def attribute(*names)
30
- @attributes = List[:symbolize][attributes + names]
31
- __check_attributes__
32
- end
33
-
34
- private
35
-
36
- # Names of the methods that should be reserved to be used later
37
- #
38
- # @return [Array<Symbol>]
39
- #
40
- # @abstract
41
- #
42
- def __forbidden_attributes__
43
- []
44
- end
45
-
46
- def __check_attributes__
47
- names = attributes & (instance_methods + __forbidden_attributes__)
48
- return if names.empty?
49
- fail NameError.new "Wrong name(s) for attribute(s): #{names.join(", ")}"
50
- end
51
-
52
- end # module Attributes
53
-
54
- end # module Assertion
@@ -1,65 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "i18n"
4
-
5
- module Assertion
6
-
7
- # Module Messages provides a feature for gem-specific translation of messages
8
- # describing the desired state of the assertion
9
- #
10
- # You need to declare a hash of attributes to be added to the translation.
11
- #
12
- # @example
13
- # class MyClass
14
- # include Assertion::Messages
15
- # def attributes
16
- # {}
17
- # end
18
- # end
19
- #
20
- # item = MyClass.new
21
- # item.message(true)
22
- # # => "translation missing: en.assertion.my_class.right"
23
- # item.message(false)
24
- # # => "translation missing: en.assertion.my_class.wrong"
25
- #
26
- # @author Andrew Kozin <Andrew.Kozin@gmail.com>
27
- #
28
- module Messages
29
-
30
- # The gem-specific root scope for translations
31
- #
32
- # @return [Symbol]
33
- #
34
- ROOT = :assertion
35
-
36
- # The states to be translated with their dictionary names
37
- #
38
- # @return [Hash<Object => Symbol>]
39
- #
40
- DICTIONARY = { true => :right, false => :wrong }
41
-
42
- # Returns the message describing the desired state of assertion
43
- #
44
- # The translation is provided for the gem-specific scope for the
45
- # current class
46
- #
47
- # @param [Boolean] state <description>
48
- #
49
- # @return [String] The translation
50
- #
51
- def message(state)
52
- key = DICTIONARY[state]
53
- scope = [ROOT, Inflector[:to_snake_path][self.class.name]]
54
-
55
- I18n.translate key, attributes.merge(scope: scope)
56
- end
57
-
58
- # @private
59
- def attributes
60
- {}
61
- end
62
-
63
- end # module Messages
64
-
65
- end # module Assertion
@@ -1,30 +0,0 @@
1
- module Assertion
2
-
3
- # The collection of pure functions for converting arrays
4
- #
5
- # @api private
6
- #
7
- module List
8
-
9
- extend ::Transproc::Registry
10
-
11
- # Converts the nested array of strings and symbols into the flat
12
- # array of unique symbols
13
- #
14
- # @example
15
- # fn = List[:symbolize]
16
- # source = [:foo, ["foo", "bar"], :bar, "baz"]
17
- # fn[source]
18
- # # => [:foo, :bar, :baz]
19
- #
20
- # @param [Array<String, Symbol, Array>] array
21
- #
22
- # @return [Array<Symbol>]
23
- #
24
- def symbolize(array)
25
- array.flatten.map(&:to_sym).uniq
26
- end
27
-
28
- end # module List
29
-
30
- end # module Assertion
@@ -1,97 +0,0 @@
1
- # encoding: utf-8
2
-
3
- describe Assertion::Attributes do
4
-
5
- subject(:klass) do
6
- class Test
7
- extend Assertion::Attributes
8
- attr_reader :baz, :qux
9
- end
10
-
11
- Test
12
- end
13
-
14
- describe "#attributes" do
15
-
16
- subject { klass.attributes }
17
-
18
- it { is_expected.to eql [] }
19
-
20
- end # describe #attributes
21
-
22
- describe "#attribute" do
23
-
24
- context "single attribute" do
25
-
26
- subject do
27
- klass.attribute "foo"
28
- klass.attribute "bar"
29
- end
30
-
31
- it "register the attribute" do
32
- expect { subject }.to change { klass.attributes }.to [:foo, :bar]
33
- end
34
-
35
- end # context
36
-
37
- context "list of attributes" do
38
-
39
- subject { klass.attribute :foo, :bar }
40
-
41
- it "register the attributes" do
42
- expect { subject }.to change { klass.attributes }.to [:foo, :bar]
43
- end
44
-
45
- end # context
46
-
47
- context "array of attributes" do
48
-
49
- subject { klass.attribute %w(foo bar) }
50
-
51
- it "register the attributes" do
52
- expect { subject }.to change { klass.attributes }.to [:foo, :bar]
53
- end
54
-
55
- end # context
56
-
57
- context "name of instance method" do
58
-
59
- subject { klass.attribute :baz, :qux }
60
-
61
- it "raises NameError" do
62
- expect { subject }.to raise_error do |error|
63
- expect(error).to be_kind_of NameError
64
- expect(error.message)
65
- .to eql "Wrong name(s) for attribute(s): baz, qux"
66
- end
67
- end
68
-
69
- end # context
70
-
71
- context "forbidden attribute" do
72
-
73
- before do
74
- class Test
75
- def self.__forbidden_attributes__
76
- [:foo, :bar]
77
- end
78
- end
79
- end
80
-
81
- subject { klass.attribute :foo, :bar }
82
-
83
- it "raises NameError" do
84
- expect { subject }.to raise_error do |error|
85
- expect(error).to be_kind_of NameError
86
- expect(error.message)
87
- .to eql "Wrong name(s) for attribute(s): foo, bar"
88
- end
89
- end
90
-
91
- end # context
92
-
93
- end # describe #attributes
94
-
95
- after { Object.send :remove_const, :Test }
96
-
97
- end # describe Assertion::Attributes