attestor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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