assertion 0.1.0 → 0.2.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.
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