attestor 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 (56) 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 +10 -0
  8. data/.yardopts +3 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +15 -0
  11. data/LICENSE +21 -0
  12. data/README.md +308 -0
  13. data/Rakefile +22 -0
  14. data/attestor.gemspec +24 -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 +75 -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/attestor/invalid_error.rb +44 -0
  27. data/lib/attestor/policy/and.rb +36 -0
  28. data/lib/attestor/policy/factory.rb +88 -0
  29. data/lib/attestor/policy/negator.rb +53 -0
  30. data/lib/attestor/policy/node.rb +58 -0
  31. data/lib/attestor/policy/not.rb +48 -0
  32. data/lib/attestor/policy/or.rb +36 -0
  33. data/lib/attestor/policy/xor.rb +36 -0
  34. data/lib/attestor/policy.rb +121 -0
  35. data/lib/attestor/validations/collection.rb +73 -0
  36. data/lib/attestor/validations/item.rb +87 -0
  37. data/lib/attestor/validations/message.rb +55 -0
  38. data/lib/attestor/validations.rb +81 -0
  39. data/lib/attestor/version.rb +9 -0
  40. data/lib/attestor.rb +26 -0
  41. data/spec/spec_helper.rb +14 -0
  42. data/spec/support/policies.rb +49 -0
  43. data/spec/tests/invalid_error_spec.rb +57 -0
  44. data/spec/tests/policy/and_spec.rb +40 -0
  45. data/spec/tests/policy/factory_spec.rb +100 -0
  46. data/spec/tests/policy/negator_spec.rb +57 -0
  47. data/spec/tests/policy/node_spec.rb +44 -0
  48. data/spec/tests/policy/not_spec.rb +40 -0
  49. data/spec/tests/policy/or_spec.rb +40 -0
  50. data/spec/tests/policy/xor_spec.rb +48 -0
  51. data/spec/tests/policy_spec.rb +111 -0
  52. data/spec/tests/validations/collection_spec.rb +100 -0
  53. data/spec/tests/validations/item_spec.rb +153 -0
  54. data/spec/tests/validations/message_spec.rb +71 -0
  55. data/spec/tests/validations_spec.rb +126 -0
  56. metadata +143 -0
@@ -0,0 +1,6 @@
1
+ ---
2
+ ignore_files:
3
+ - spec
4
+ - config
5
+ minimum_churn_count: 0
6
+ start_date: "1 year ago"
@@ -0,0 +1,2 @@
1
+ ---
2
+ minimum_score: 10
@@ -0,0 +1,15 @@
1
+ ---
2
+ folders: # The list of folders to be used by any metric.
3
+ - lib
4
+ - app
5
+ metrics: # The list of allowed metrics. The other metrics are disabled.
6
+ - cane
7
+ - churn
8
+ - flay
9
+ - flog
10
+ - reek
11
+ - roodi
12
+ - saikuro
13
+ format: html
14
+ output: tmp/metric_fu
15
+ verbose: false
@@ -0,0 +1 @@
1
+ ---
@@ -0,0 +1,24 @@
1
+ ---
2
+ AssignmentInConditionalCheck:
3
+ CaseMissingElseCheck:
4
+ ClassLineCountCheck:
5
+ line_count: 300
6
+ ClassNameCheck:
7
+ pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
8
+ ClassVariableCheck:
9
+ CyclomaticComplexityBlockCheck:
10
+ complexity: 4
11
+ CyclomaticComplexityMethodCheck:
12
+ complexity: 8
13
+ EmptyRescueBodyCheck:
14
+ ForLoopCheck:
15
+ MethodLineCountCheck:
16
+ line_count: 20
17
+ MethodNameCheck:
18
+ pattern: !ruby/regexp /^[\||\^|\&|\!]$|^[_a-z<>=\[|+-\/\*`]+[_a-z0-9_<>=~@\[\]]*[=!\?]?$/
19
+ ModuleLineCountCheck:
20
+ line_count: 300
21
+ ModuleNameCheck:
22
+ pattern: !ruby/regexp /^[A-Z][a-zA-Z0-9]*$/
23
+ ParameterNumberCheck:
24
+ parameter_count: 5
@@ -0,0 +1,75 @@
1
+ ---
2
+ # settings added by the 'hexx-suit' module
3
+ # output: "tmp/rubocop"
4
+ # format: "html"
5
+
6
+ AllCops:
7
+ Exclude:
8
+ - '**/db/schema.rb'
9
+
10
+ Lint/HandleExceptions:
11
+ Exclude:
12
+ - '**/*_spec.rb'
13
+
14
+ Lint/RescueException:
15
+ Exclude:
16
+ - '**/*_spec.rb'
17
+
18
+ Style/AccessorMethodName:
19
+ Exclude:
20
+ - '**/*_spec.rb'
21
+
22
+ Style/AsciiComments:
23
+ Enabled: false
24
+
25
+ Style/ClassAndModuleChildren:
26
+ Exclude:
27
+ - '**/*_spec.rb'
28
+
29
+ Style/Documentation:
30
+ Exclude:
31
+ - '**/version.rb'
32
+ - '**/*_spec.rb'
33
+
34
+ Style/EmptyLinesAroundBlockBody:
35
+ Enabled: false
36
+
37
+ Style/EmptyLinesAroundClassBody:
38
+ Enabled: false
39
+
40
+ Style/EmptyLinesAroundMethodBody:
41
+ Enabled: false
42
+
43
+ Style/EmptyLinesAroundModuleBody:
44
+ Enabled: false
45
+
46
+ Style/EmptyLineBetweenDefs:
47
+ Enabled: false
48
+
49
+ Style/FileName:
50
+ Enabled: false
51
+
52
+ Style/RaiseArgs:
53
+ EnforcedStyle: compact
54
+
55
+ Style/SingleLineMethods:
56
+ Exclude:
57
+ - '**/*_spec.rb'
58
+
59
+ Style/SingleSpaceBeforeFirstArg:
60
+ Enabled: false
61
+
62
+ Style/SpecialGlobalVars:
63
+ Exclude:
64
+ - '**/Gemfile'
65
+ - '**/*.gemspec'
66
+
67
+ Style/StringLiterals:
68
+ EnforcedStyle: double_quotes
69
+
70
+ Style/StringLiteralsInInterpolation:
71
+ EnforcedStyle: double_quotes
72
+
73
+ Style/TrivialAccessors:
74
+ Exclude:
75
+ - '**/*_spec.rb'
@@ -0,0 +1,3 @@
1
+ ---
2
+ warn_cyclo: 4
3
+ error_cyclo: 6
@@ -0,0 +1,6 @@
1
+ ---
2
+ output: tmp/coverage
3
+ filters: # The list of paths to be excluded from coverage checkup
4
+ - "spec/"
5
+ - "config/"
6
+ groups: []
@@ -0,0 +1,37 @@
1
+ ---
2
+ # Settings added by the 'hexx-suit' gem
3
+ output: "tmp/yardstick/output.log"
4
+ path: "lib/**/*.rb"
5
+ rules:
6
+ ApiTag::Presence:
7
+ enabled: true
8
+ exclude: []
9
+ ApiTag::Inclusion:
10
+ enabled: true
11
+ exclude: []
12
+ ApiTag::ProtectedMethod:
13
+ enabled: true
14
+ exclude: []
15
+ ApiTag::PrivateMethod:
16
+ enabled: false
17
+ exclude: []
18
+ ExampleTag:
19
+ enabled: true
20
+ exclude: []
21
+ ReturnTag:
22
+ enabled: true
23
+ exclude: []
24
+ Summary::Presence:
25
+ enabled: true
26
+ exclude: []
27
+ Summary::Length:
28
+ enabled: true
29
+ exclude: []
30
+ Summary::Delimiter:
31
+ enabled: true
32
+ exclude: []
33
+ Summary::SingleLine:
34
+ enabled: true
35
+ exclude: []
36
+ threshold: 100
37
+ verbose: false
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ # The exception to be raised when a validation fails
6
+ class InvalidError < RuntimeError
7
+
8
+ # @!scope class
9
+ # @!method new(object, validations: nil, messages: [], context: :all)
10
+ # Creates an exception for given object
11
+ #
12
+ # @param [Object] object
13
+ # The invalid object
14
+ # @option [Array<String>] :messages
15
+ # The list of validation error messages
16
+ # @option [Symbol] :context
17
+ # The list of context for validation
18
+ # @option [Array<Symbol>] :validations
19
+ # The list of all validations that was checked out
20
+ #
21
+ # @return [Attestor::InvalidError]
22
+
23
+ # @private
24
+ def initialize(object, messages = [])
25
+ @object = object
26
+ @messages = messages.dup.freeze
27
+ freeze
28
+ end
29
+
30
+ # @!attribute [r] object
31
+ # The invalid object
32
+ #
33
+ # @return [Object]
34
+ attr_reader :object
35
+
36
+ # @!attribute [r] messages
37
+ # The list of validation error messages
38
+ #
39
+ # @return [Array<String>]
40
+ attr_reader :messages
41
+
42
+ end # class InvalidError
43
+
44
+ end # module Attestor
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # AND-concatenation of several policies (branches)
8
+ #
9
+ # The policy is valid if all its branches are valid.
10
+ #
11
+ # @example (see #validate)
12
+ #
13
+ # @api private
14
+ class And < Node
15
+
16
+ # Checks whether every policy is valid
17
+ #
18
+ # @example
19
+ # first.valid? # => true
20
+ # second.valid? # => false
21
+ #
22
+ # composition = Attestor::Policy::And.new(first, second)
23
+ # composition.validate
24
+ # # => Policy::InvalidError
25
+ #
26
+ # @return [undefined]
27
+ def validate
28
+ return unless any_invalid?
29
+ super
30
+ end
31
+
32
+ end # class And
33
+
34
+ end # module Base
35
+
36
+ end # module Policy
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # The collection of factory methods for creating complex policies
8
+ module Factory
9
+
10
+ # Builds the AND composition of policy with other policies
11
+ #
12
+ # @param [Attestor::Policy] policy
13
+ #
14
+ # @overload and(policy, *others)
15
+ # Combines a policy with others
16
+ #
17
+ # @param [Attestor::Policy, Array<Attestor::Policy>] others
18
+ #
19
+ # @return [Attestor::Policy::And]
20
+ #
21
+ # @overload and(policy)
22
+ # Creates a negator object, awaiting fot #not method call
23
+ #
24
+ # @return [Attestor::Policy::Negator]
25
+ def and(policy, *others)
26
+ __factory_method__(And, policy, others)
27
+ end
28
+
29
+ # Builds the OR composition of policy with other policies
30
+ #
31
+ # @param [Attestor::Policy] policy
32
+ #
33
+ # @overload or(policy, *others)
34
+ # Combines a policy with others
35
+ #
36
+ # @param [Attestor::Policy, Array<Attestor::Policy>] others
37
+ #
38
+ # @return [Attestor::Policy::Or]
39
+ #
40
+ # @overload or(policy)
41
+ # Creates a negator object, awaiting fot #not method call
42
+ #
43
+ # @return [Attestor::Policy::Negator]
44
+ def or(policy, *others)
45
+ __factory_method__(Or, policy, others)
46
+ end
47
+
48
+ # Builds the XOR composition of policy with other policies
49
+ #
50
+ # @param [Attestor::Policy] policy
51
+ #
52
+ # @overload xor(policy, *others)
53
+ # Combines a policy with others
54
+ #
55
+ # @param [Attestor::Policy, Array<Attestor::Policy>] others
56
+ #
57
+ # @return [Attestor::Policy::Xor]
58
+ #
59
+ # @overload xor(policy)
60
+ # Creates a negator object, awaiting fot #not method call
61
+ #
62
+ # @return [Attestor::Policy::Negator]
63
+ def xor(policy, *others)
64
+ __factory_method__(Xor, policy, others)
65
+ end
66
+
67
+ # Builds the negation of given policy
68
+ #
69
+ # @param [Attestor::Policy] policy
70
+ #
71
+ # @return [Attestor::Policy::Not]
72
+ def not(policy)
73
+ Not.new(policy)
74
+ end
75
+
76
+ private
77
+
78
+ def __factory_method__(composer, policy, others)
79
+ policies = others.flatten
80
+ return composer.new(policy, policies) if policies.any?
81
+ Negator.new(composer, policy)
82
+ end
83
+
84
+ end # module Factory
85
+
86
+ end # module Policy
87
+
88
+ end # module Attestor
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # Composes a policy with an argument of its {#not} method
8
+ #
9
+ # @api private
10
+ class Negator
11
+
12
+ # @!scope class
13
+ # @!method new(policy, composer)
14
+ # Creates the negator object, expecting {#not} method call
15
+ #
16
+ # @param [Policy::Base] policy
17
+ # the policy to be composed with negations of other policies
18
+ # @param [Class] composer
19
+ # the composer for policies
20
+ #
21
+ # @return [Policy::Base::Negator]
22
+ def initialize(composer, policy)
23
+ @policy = policy
24
+ @composer = composer
25
+ freeze
26
+ end
27
+
28
+ # Returns a composition of the {#policy} with negations of other policies
29
+ #
30
+ # @param [Policy::Base, Array<Policy::Base>] policies
31
+ #
32
+ # @return [Policy::Base]
33
+ def not(*policies)
34
+ composer.new policy, policies.flat_map(&Not.method(:new))
35
+ end
36
+
37
+ # @!attribute [r] policy
38
+ # The the policy to be composed with negations of other policies
39
+ #
40
+ # @return [Policy::Base]
41
+ attr_reader :policy
42
+
43
+ # @!attribute [r] composer
44
+ # The the composer for policies
45
+ #
46
+ # @return [Class]
47
+ attr_reader :composer
48
+
49
+ end # class Negator
50
+
51
+ end # module Policy
52
+
53
+ end # module Attestor
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # The base class for composite policies
8
+ #
9
+ # @api private
10
+ class Node
11
+ include Attestor::Policy
12
+
13
+ # @!scope class
14
+ # @!method new(*branches)
15
+ # Creates the node with branches
16
+ #
17
+ # @param [<Attestor::Policy>, Array<Attestor::Policy>] branches
18
+ #
19
+ # @return [Policy::Base::Node]
20
+
21
+ # @private
22
+ def initialize(*branches)
23
+ @branches = branches.flatten
24
+ freeze
25
+ end
26
+
27
+ # @!attribute [r] branches
28
+ # The branches of the node
29
+ #
30
+ # @return [Array<Policy::Base>]
31
+ attr_reader :branches
32
+
33
+ # Validates the policy as invalid
34
+ #
35
+ # To be reloaded by subclasses (And, Or, Xor, Not)
36
+ #
37
+ # @raise [Policy::InvalidError]
38
+ #
39
+ # @return [undefined]
40
+ def validate
41
+ invalid :base
42
+ end
43
+
44
+ private
45
+
46
+ def any_valid?
47
+ branches.detect(&:valid?)
48
+ end
49
+
50
+ def any_invalid?
51
+ branches.detect(&:invalid?)
52
+ end
53
+
54
+ end # class Node
55
+
56
+ end # module Base
57
+
58
+ end # module Policy
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # Negation of a single policy
8
+ #
9
+ # The policy is valid if its only branch is invalid
10
+ #
11
+ # @example (see #validate)
12
+ #
13
+ # @api private
14
+ class Not < Node
15
+
16
+ # @!scope class
17
+ # @!method new(policy)
18
+ # Creates the policy negation
19
+ #
20
+ # @param [Array<Policy::Base>] policy
21
+ #
22
+ # @return [Policy::Base::Node]
23
+
24
+ # @private
25
+ def initialize(_)
26
+ super
27
+ end
28
+
29
+ # Checks whether every policy is valid
30
+ #
31
+ # @example
32
+ # policy.valid? # => true
33
+ #
34
+ # composition = Attestor::Policy::Not.new(policy)
35
+ # composition.validate
36
+ # # => Policy::InvalidError
37
+ #
38
+ # @return [undefined]
39
+ def validate
40
+ return unless any_valid?
41
+ super
42
+ end
43
+
44
+ end # class And
45
+
46
+ end # module Base
47
+
48
+ end # module Policy
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # OR-concatenation of several policies (branches)
8
+ #
9
+ # The policy is valid unless all its branches are invalid.
10
+ #
11
+ # @example (see #validate)
12
+ #
13
+ # @api private
14
+ class Or < Node
15
+
16
+ # Checks whether any policy is valid
17
+ #
18
+ # @example
19
+ # first.valid? # => false
20
+ # second.valid? # => false
21
+ #
22
+ # composition = Attestor::Policy::Or.new(first, second)
23
+ # composition.validate
24
+ # # => Policy::InvalidError
25
+ #
26
+ # @return [undefined]
27
+ def validate
28
+ return if any_valid?
29
+ super
30
+ end
31
+
32
+ end # class Or
33
+
34
+ end # module Base
35
+
36
+ end # module Policy
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Policy
6
+
7
+ # XOR-concatenation of several policies (branches)
8
+ #
9
+ # The policy is valid when it has both valid and invalid branches.
10
+ #
11
+ # @example (see #validate)
12
+ #
13
+ # @api private
14
+ class Xor < Node
15
+
16
+ # Checks whether both valid and invalid branches are present
17
+ #
18
+ # @example
19
+ # first.valid? # => true
20
+ # second.valid? # => true
21
+ #
22
+ # composition = Attestor::Policy::Xor.new(first, second)
23
+ # composition.validate
24
+ # # => Policy::InvalidError
25
+ #
26
+ # @return [undefined]
27
+ def validate
28
+ return if any_valid? && any_invalid?
29
+ super
30
+ end
31
+
32
+ end # class Xor
33
+
34
+ end # module Base
35
+
36
+ end # module Policy
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ # API for policies that validates another objects
6
+ module Policy
7
+ # @!parse include Attestor::Validations
8
+ # @!parse extend Attestor::Validations::ClassMethods
9
+ # @!parse extend Attestor::Policy::Factory
10
+
11
+ # @private
12
+ def self.included(klass)
13
+ klass.instance_eval do
14
+ include Validations
15
+ extend Factory
16
+ end
17
+ end
18
+
19
+ # Checks whether the policy is valid
20
+ #
21
+ # @return [Boolean]
22
+ def valid?
23
+ validate
24
+ rescue InvalidError
25
+ false
26
+ else
27
+ true
28
+ end
29
+
30
+ # Checks whether the policy is invalid
31
+ #
32
+ # @return [Boolean]
33
+ def invalid?
34
+ !valid?
35
+ end
36
+
37
+ # Negates the current policy
38
+ #
39
+ # @return [Attestor::Policy::Not]
40
+ def not
41
+ self.class.not(self)
42
+ end
43
+
44
+ # Builds the AND composition of current policy with other policies
45
+ #
46
+ # @overload and(policy, *others)
47
+ # Combines the policy with the others
48
+ #
49
+ # The combination is valid if all policies are valid
50
+ #
51
+ # @param [Attestor::Policy, Array<Attestor::Policy>] others
52
+ #
53
+ # @return [Attestor::Policy::And]
54
+ #
55
+ # @overload and(policy)
56
+ # Creates a negator object, awaiting fot #not method call
57
+ #
58
+ # @example
59
+ # policy.and.not(one, two)
60
+ #
61
+ # # this is equal to combination with negation of other policies:
62
+ # policy.and(one.not, two.not)
63
+ #
64
+ # @return [Attestor::Policy::Negator]
65
+ def and(*others)
66
+ self.class.and(self, *others)
67
+ end
68
+
69
+ # Builds the OR composition of current policy with other policies
70
+ #
71
+ # @overload or(policy, *others)
72
+ # Combines the policy with the others
73
+ #
74
+ # The combination is valid unless all the policies are invalid
75
+ #
76
+ # @param [Attestor::Policy, Array<Attestor::Policy>] others
77
+ #
78
+ # @return [Attestor::Policy::And]
79
+ #
80
+ # @overload or(policy)
81
+ # Creates a negator object, awaiting fot #not method call
82
+ #
83
+ # @example
84
+ # policy.or.not(one, two)
85
+ #
86
+ # # this is equal to combination with negation of other policies:
87
+ # policy.or(one.not, two.not)
88
+ #
89
+ # @return [Attestor::Policy::Negator]
90
+ def or(*others)
91
+ self.class.or(self, *others)
92
+ end
93
+
94
+ # Builds the XOR composition of current policy with other policies
95
+ #
96
+ # @overload xor(policy, *others)
97
+ # Combines the policy with the others
98
+ #
99
+ # The combination is valid if both valid and invalid policies are present
100
+ #
101
+ # @param [Attestor::Policy, Array<Attestor::Policy>] others
102
+ #
103
+ # @return [Attestor::Policy::And]
104
+ #
105
+ # @overload xor(policy)
106
+ # Creates a negator object, awaiting fot #not method call
107
+ #
108
+ # @example
109
+ # policy.xor.not(one, two)
110
+ #
111
+ # # this is equal to combination with negation of other policies:
112
+ # policy.xor(one.not, two.not)
113
+ #
114
+ # @return [Attestor::Policy::Negator]
115
+ def xor(*others)
116
+ self.class.xor(self, *others)
117
+ end
118
+
119
+ end # module Policy
120
+
121
+ end # module Attestor