codeclimate-fede 0.85.21

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 (102) hide show
  1. checksums.yaml +7 -0
  2. data/bin/check +18 -0
  3. data/bin/codeclimate +21 -0
  4. data/bin/prep-release +45 -0
  5. data/bin/publish +47 -0
  6. data/bin/release +41 -0
  7. data/bin/validate-release +18 -0
  8. data/config/engines.yml +322 -0
  9. data/lib/cc/analyzer/bridge.rb +106 -0
  10. data/lib/cc/analyzer/composite_container_listener.rb +21 -0
  11. data/lib/cc/analyzer/container/result.rb +74 -0
  12. data/lib/cc/analyzer/container.rb +208 -0
  13. data/lib/cc/analyzer/container_listener.rb +9 -0
  14. data/lib/cc/analyzer/engine.rb +125 -0
  15. data/lib/cc/analyzer/engine_output.rb +74 -0
  16. data/lib/cc/analyzer/engine_output_filter.rb +36 -0
  17. data/lib/cc/analyzer/engine_output_overrider.rb +31 -0
  18. data/lib/cc/analyzer/filesystem.rb +50 -0
  19. data/lib/cc/analyzer/formatters/formatter.rb +53 -0
  20. data/lib/cc/analyzer/formatters/html_formatter.rb +415 -0
  21. data/lib/cc/analyzer/formatters/json_formatter.rb +38 -0
  22. data/lib/cc/analyzer/formatters/plain_text_formatter.rb +101 -0
  23. data/lib/cc/analyzer/formatters/spinner.rb +35 -0
  24. data/lib/cc/analyzer/formatters.rb +21 -0
  25. data/lib/cc/analyzer/issue.rb +69 -0
  26. data/lib/cc/analyzer/issue_sorter.rb +30 -0
  27. data/lib/cc/analyzer/issue_validations/category_validation.rb +32 -0
  28. data/lib/cc/analyzer/issue_validations/check_name_presence_validation.rb +15 -0
  29. data/lib/cc/analyzer/issue_validations/content_validation.rb +21 -0
  30. data/lib/cc/analyzer/issue_validations/description_presence_validation.rb +15 -0
  31. data/lib/cc/analyzer/issue_validations/location_format_validation.rb +72 -0
  32. data/lib/cc/analyzer/issue_validations/other_locations_format_validation.rb +41 -0
  33. data/lib/cc/analyzer/issue_validations/path_existence_validation.rb +15 -0
  34. data/lib/cc/analyzer/issue_validations/path_is_file_validation.rb +15 -0
  35. data/lib/cc/analyzer/issue_validations/path_presence_validation.rb +15 -0
  36. data/lib/cc/analyzer/issue_validations/relative_path_validation.rb +32 -0
  37. data/lib/cc/analyzer/issue_validations/remediation_points_validation.rb +25 -0
  38. data/lib/cc/analyzer/issue_validations/severity_validation.rb +39 -0
  39. data/lib/cc/analyzer/issue_validations/type_validation.rb +15 -0
  40. data/lib/cc/analyzer/issue_validations/validation.rb +35 -0
  41. data/lib/cc/analyzer/issue_validations.rb +26 -0
  42. data/lib/cc/analyzer/issue_validator.rb +11 -0
  43. data/lib/cc/analyzer/location_description.rb +45 -0
  44. data/lib/cc/analyzer/logging_container_listener.rb +24 -0
  45. data/lib/cc/analyzer/measurement.rb +22 -0
  46. data/lib/cc/analyzer/measurement_validations/name_validation.rb +23 -0
  47. data/lib/cc/analyzer/measurement_validations/type_validation.rb +15 -0
  48. data/lib/cc/analyzer/measurement_validations/validation.rb +27 -0
  49. data/lib/cc/analyzer/measurement_validations/value_validation.rb +21 -0
  50. data/lib/cc/analyzer/measurement_validations.rb +16 -0
  51. data/lib/cc/analyzer/measurement_validator.rb +11 -0
  52. data/lib/cc/analyzer/mounted_path.rb +80 -0
  53. data/lib/cc/analyzer/raising_container_listener.rb +32 -0
  54. data/lib/cc/analyzer/source_buffer.rb +47 -0
  55. data/lib/cc/analyzer/source_extractor.rb +79 -0
  56. data/lib/cc/analyzer/source_fingerprint.rb +40 -0
  57. data/lib/cc/analyzer/statsd_container_listener.rb +51 -0
  58. data/lib/cc/analyzer/validator.rb +38 -0
  59. data/lib/cc/analyzer.rb +50 -0
  60. data/lib/cc/cli/analyze/engine_failure.rb +11 -0
  61. data/lib/cc/cli/analyze.rb +90 -0
  62. data/lib/cc/cli/command.rb +85 -0
  63. data/lib/cc/cli/console.rb +12 -0
  64. data/lib/cc/cli/engines/engine_command.rb +15 -0
  65. data/lib/cc/cli/engines/install.rb +35 -0
  66. data/lib/cc/cli/engines/list.rb +18 -0
  67. data/lib/cc/cli/engines.rb +5 -0
  68. data/lib/cc/cli/file_store.rb +42 -0
  69. data/lib/cc/cli/global_cache.rb +47 -0
  70. data/lib/cc/cli/global_config.rb +35 -0
  71. data/lib/cc/cli/help.rb +51 -0
  72. data/lib/cc/cli/output.rb +34 -0
  73. data/lib/cc/cli/prepare.rb +98 -0
  74. data/lib/cc/cli/runner.rb +75 -0
  75. data/lib/cc/cli/validate_config.rb +84 -0
  76. data/lib/cc/cli/version.rb +16 -0
  77. data/lib/cc/cli/version_checker.rb +107 -0
  78. data/lib/cc/cli.rb +39 -0
  79. data/lib/cc/config/checks_adapter.rb +40 -0
  80. data/lib/cc/config/default_adapter.rb +54 -0
  81. data/lib/cc/config/engine.rb +41 -0
  82. data/lib/cc/config/engine_set.rb +47 -0
  83. data/lib/cc/config/json_adapter.rb +17 -0
  84. data/lib/cc/config/prepare.rb +92 -0
  85. data/lib/cc/config/validation/check_validator.rb +34 -0
  86. data/lib/cc/config/validation/engine_validator.rb +93 -0
  87. data/lib/cc/config/validation/fetch_validator.rb +78 -0
  88. data/lib/cc/config/validation/file_validator.rb +112 -0
  89. data/lib/cc/config/validation/hash_validations.rb +52 -0
  90. data/lib/cc/config/validation/json.rb +31 -0
  91. data/lib/cc/config/validation/prepare_validator.rb +40 -0
  92. data/lib/cc/config/validation/yaml.rb +66 -0
  93. data/lib/cc/config/yaml_adapter.rb +73 -0
  94. data/lib/cc/config.rb +70 -0
  95. data/lib/cc/engine_registry.rb +74 -0
  96. data/lib/cc/resolv.rb +39 -0
  97. data/lib/cc/workspace/exclusion.rb +34 -0
  98. data/lib/cc/workspace/path_tree/dir_node.rb +67 -0
  99. data/lib/cc/workspace/path_tree/file_node.rb +31 -0
  100. data/lib/cc/workspace/path_tree.rb +49 -0
  101. data/lib/cc/workspace.rb +39 -0
  102. metadata +279 -0
@@ -0,0 +1,30 @@
1
+ module CC
2
+ module Analyzer
3
+ class IssueSorter
4
+ def initialize(issues)
5
+ @issues = issues
6
+ end
7
+
8
+ def by_location
9
+ @issues.sort_by { |i| line_or_offset(i) }
10
+ end
11
+
12
+ private
13
+
14
+ def line_or_offset(issue)
15
+ location = issue["location"]
16
+
17
+ case
18
+ when location["lines"]
19
+ [location["lines"]["begin"].to_i]
20
+ when location["positions"] && location["positions"]["begin"]["line"]
21
+ [location["positions"]["begin"]["line"].to_i, location["positions"]["begin"]["column"].to_i]
22
+ when location["positions"] && location["positions"]["begin"]["offset"]
23
+ [1_000_000_000] # push offsets to end of list
24
+ else
25
+ [0] # whole-file issues are first
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class CategoryValidation < Validation
5
+ CATEGORIES = [
6
+ "Bug Risk".freeze,
7
+ "Clarity".freeze,
8
+ "Compatibility".freeze,
9
+ "Complexity".freeze,
10
+ "Duplication".freeze,
11
+ "Performance".freeze,
12
+ "Security".freeze,
13
+ "Style".freeze,
14
+ ].freeze
15
+
16
+ def valid?
17
+ object["categories"].present? && no_invalid_categories?
18
+ end
19
+
20
+ def message
21
+ "Category must be at least one of #{CATEGORIES.join(", ")}"
22
+ end
23
+
24
+ private
25
+
26
+ def no_invalid_categories?
27
+ (CATEGORIES | object["categories"]) == CATEGORIES
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class CheckNamePresenceValidation < Validation
5
+ def valid?
6
+ object["check_name"].present?
7
+ end
8
+
9
+ def message
10
+ "Check name must be present"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class ContentValidation < Validation
5
+ def valid?
6
+ !has_content? || (content.is_a?(Hash) && content["body"].is_a?(String))
7
+ end
8
+
9
+ def message
10
+ "Content must be a hash containing a 'body' key with string contents"
11
+ end
12
+
13
+ private
14
+
15
+ def has_content?
16
+ object.key?("content")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class DescriptionPresenceValidation < Validation
5
+ def valid?
6
+ object["description"].present?
7
+ end
8
+
9
+ def message
10
+ "Description must be present"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class LocationFormatValidation < Validation
5
+ class Validator
6
+ def initialize(location)
7
+ @location = location
8
+ check_validity
9
+ end
10
+
11
+ def valid?
12
+ error.nil?
13
+ end
14
+
15
+ def message
16
+ if error
17
+ "Location is not formatted correctly: #{error}"
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_accessor :error
24
+
25
+ attr_reader :location
26
+
27
+ def check_validity
28
+ if location["lines"]
29
+ self.error = "location.lines is not valid: #{JSON.dump(location["lines"])}" unless valid_lines?(location["lines"])
30
+ elsif location["positions"]
31
+ self.error = "location.positions is not valid: #{JSON.dump(location["positions"])}" unless valid_positions?(location["positions"])
32
+ else
33
+ self.error = "location.lines or location.positions must be present"
34
+ end
35
+ end
36
+
37
+ def valid_positions?(positions)
38
+ positions.is_a?(Hash) &&
39
+ valid_position?(positions["begin"]) &&
40
+ valid_position?(positions["end"])
41
+ end
42
+
43
+ def valid_position?(position)
44
+ position &&
45
+ (
46
+ [position["line"], position["column"]].all? { |value| value.is_a?(Integer) } ||
47
+ position["offset"].is_a?(Integer)
48
+ )
49
+ end
50
+
51
+ def valid_lines?(lines)
52
+ lines.is_a?(Hash) && [lines["begin"], lines["end"]].all? { |value| value.is_a?(Integer) }
53
+ end
54
+ end
55
+
56
+ def valid?
57
+ validation.valid?
58
+ end
59
+
60
+ def message
61
+ validation.message
62
+ end
63
+
64
+ private
65
+
66
+ def validation
67
+ @validation ||= Validator.new(object.fetch("location", {}))
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,41 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class OtherLocationsFormatValidation < Validation
5
+ CHECKS = [
6
+ LocationFormatValidation,
7
+ PathExistenceValidation,
8
+ PathPresenceValidation,
9
+ RelativePathValidation,
10
+ ].freeze
11
+
12
+ def initialize(object)
13
+ super
14
+ @other_location_valid = {}
15
+ end
16
+
17
+ def valid?
18
+ if object["other_locations"]
19
+ object["other_locations"].is_a?(Array) &&
20
+ object["other_locations"].all?(&method(:other_location_valid?))
21
+ else
22
+ true
23
+ end
24
+ end
25
+
26
+ def message
27
+ "Other locations are not formatted correctly"
28
+ end
29
+
30
+ private
31
+
32
+ def other_location_valid?(location)
33
+ path = location && location["path"]
34
+ @other_location_valid[path] ||= CHECKS.all? do |klass|
35
+ klass.new("location" => location).valid?
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class PathExistenceValidation < Validation
5
+ def valid?
6
+ path && File.exist?(path)
7
+ end
8
+
9
+ def message
10
+ "File does not exist: '#{path}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class PathIsFileValidation < Validation
5
+ def valid?
6
+ path && File.file?(path)
7
+ end
8
+
9
+ def message
10
+ "Path is not a file: '#{path}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class PathPresenceValidation < Validation
5
+ def valid?
6
+ path.present?
7
+ end
8
+
9
+ def message
10
+ "Path must be present"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ require "pathname"
2
+
3
+ module CC
4
+ module Analyzer
5
+ module IssueValidations
6
+ class RelativePathValidation < Validation
7
+ BUILDER_CODE_PATH = "/tmp/workspace/code".freeze
8
+
9
+ def valid?
10
+ path &&
11
+ !path.start_with?("/") && (
12
+ relative_to?(MountedPath.code.container_path) ||
13
+ relative_to?(BUILDER_CODE_PATH)
14
+ )
15
+ end
16
+
17
+ def message
18
+ "Path must be relative to the project directory"
19
+ end
20
+
21
+ private
22
+
23
+ def relative_to?(directory)
24
+ expanded_base = Pathname.new(directory).expand_path.to_s
25
+ expanded_path = Pathname.new(path).expand_path.to_s
26
+
27
+ expanded_path.start_with?(expanded_base)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class RemediationPointsValidation < Validation
5
+ def valid?
6
+ remediation_points.nil? || positive_integer?(remediation_points)
7
+ end
8
+
9
+ def message
10
+ "Remediation points must be a non-negative integer"
11
+ end
12
+
13
+ private
14
+
15
+ def remediation_points
16
+ @remediation_points ||= object["remediation_points"]
17
+ end
18
+
19
+ def positive_integer?(x)
20
+ x.is_a?(Integer) && x >= 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class SeverityValidation < Validation
5
+ INFO = "info".freeze
6
+ MINOR = "minor".freeze
7
+ MAJOR = "major".freeze
8
+ CRITICAL = "critical".freeze
9
+ BLOCKER = "blocker".freeze
10
+
11
+ DEPRECATED_SEVERITIES = [
12
+ NORMAL = "normal".freeze,
13
+ ].freeze
14
+
15
+ VALID_SEVERITIES = ([
16
+ INFO,
17
+ MINOR,
18
+ MAJOR,
19
+ CRITICAL,
20
+ BLOCKER,
21
+ ] + DEPRECATED_SEVERITIES).freeze
22
+
23
+ def valid?
24
+ severity.nil? || VALID_SEVERITIES.include?(severity)
25
+ end
26
+
27
+ def message
28
+ "Permitted severities include #{VALID_SEVERITIES.join(", ")}"
29
+ end
30
+
31
+ private
32
+
33
+ def severity
34
+ @severity ||= object["severity"]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class TypeValidation < Validation
5
+ def valid?
6
+ type&.casecmp("issue")&.zero?
7
+ end
8
+
9
+ def message
10
+ "Type must be 'issue' but was '#{type}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ class Validation
5
+ def initialize(object)
6
+ @object = object
7
+ end
8
+
9
+ def valid?
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def message
14
+ raise NotImplementedError
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :object
20
+
21
+ def path
22
+ object.fetch("location", {})["path"]
23
+ end
24
+
25
+ def type
26
+ object["type"]
27
+ end
28
+
29
+ def content
30
+ object["content"]
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ module CC
2
+ module Analyzer
3
+ module IssueValidations
4
+ autoload :CategoryValidation, "cc/analyzer/issue_validations/category_validation"
5
+ autoload :CheckNamePresenceValidation, "cc/analyzer/issue_validations/check_name_presence_validation"
6
+ autoload :ContentValidation, "cc/analyzer/issue_validations/content_validation"
7
+ autoload :DescriptionPresenceValidation, "cc/analyzer/issue_validations/description_presence_validation"
8
+ autoload :LocationFormatValidation, "cc/analyzer/issue_validations/location_format_validation"
9
+ autoload :OtherLocationsFormatValidation, "cc/analyzer/issue_validations/other_locations_format_validation"
10
+ autoload :PathExistenceValidation, "cc/analyzer/issue_validations/path_existence_validation"
11
+ autoload :PathIsFileValidation, "cc/analyzer/issue_validations/path_is_file_validation"
12
+ autoload :PathPresenceValidation, "cc/analyzer/issue_validations/path_presence_validation"
13
+ autoload :RelativePathValidation, "cc/analyzer/issue_validations/relative_path_validation"
14
+ autoload :RemediationPointsValidation, "cc/analyzer/issue_validations/remediation_points_validation"
15
+ autoload :SeverityValidation, "cc/analyzer/issue_validations/severity_validation"
16
+ autoload :TypeValidation, "cc/analyzer/issue_validations/type_validation"
17
+ autoload :Validation, "cc/analyzer/issue_validations/validation"
18
+
19
+ def self.validations
20
+ constants.sort.map(&method(:const_get)).select do |klass|
21
+ klass.is_a?(Class) && klass.superclass == Validation
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ module CC
2
+ module Analyzer
3
+ class IssueValidator
4
+ include Validator
5
+
6
+ def self.validations
7
+ IssueValidations.validations
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ module CC
2
+ module Analyzer
3
+ class LocationDescription
4
+ def initialize(source_buffer, location, suffix = "")
5
+ @source_buffer = source_buffer
6
+ @location = location
7
+ @suffix = suffix
8
+ end
9
+
10
+ def to_s
11
+ if location["lines"]
12
+ begin_line = location["lines"]["begin"]
13
+ end_line = location["lines"]["end"]
14
+ elsif location["positions"]
15
+ begin_line = position_to_line(location["positions"]["begin"])
16
+ end_line = position_to_line(location["positions"]["end"])
17
+ end
18
+
19
+ str = render_lines(begin_line, end_line)
20
+ str << suffix unless str.blank?
21
+ str
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :location, :suffix
27
+
28
+ def render_lines(begin_line, end_line)
29
+ if end_line == begin_line
30
+ begin_line.to_s
31
+ else
32
+ "#{begin_line}-#{end_line}"
33
+ end
34
+ end
35
+
36
+ def position_to_line(position)
37
+ if position["line"]
38
+ position["line"]
39
+ else
40
+ @source_buffer.decompose_position(position["offset"]).first
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module CC
2
+ module Analyzer
3
+ class LoggingContainerListener < ContainerListener
4
+ def initialize(logger)
5
+ @logger = logger
6
+ end
7
+
8
+ def started(engine, _details)
9
+ logger.info("starting engine #{engine.name}")
10
+ end
11
+
12
+ def finished(engine, _details, result)
13
+ logger.info("finished engine #{engine.name}")
14
+ if result.skipped?
15
+ logger.warn("skipped engine #{engine.name}: #{result.stderr}")
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :logger
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ module CC
2
+ module Analyzer
3
+ class Measurement
4
+ def initialize(engine_name, output)
5
+ @engine_name = engine_name
6
+ @output = output
7
+ end
8
+
9
+ def as_json(*)
10
+ parsed_output.merge("engine_name" => engine_name)
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :engine_name, :output
16
+
17
+ def parsed_output
18
+ @parsed_output ||= JSON.parse(output)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module CC
2
+ module Analyzer
3
+ module MeasurementValidations
4
+ class NameValidation < Validation
5
+ REGEX = /^[A-Za-z0-9_\.\-]+$/
6
+
7
+ def valid?
8
+ name&.is_a?(String) && REGEX.match?(name)
9
+ end
10
+
11
+ def message
12
+ "Name must be present and contain only letters, numbers, periods, hyphens, and underscores"
13
+ end
14
+
15
+ private
16
+
17
+ def name
18
+ object["name"]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module CC
2
+ module Analyzer
3
+ module MeasurementValidations
4
+ class TypeValidation < Validation
5
+ def valid?
6
+ type&.casecmp("measurement")&.zero?
7
+ end
8
+
9
+ def message
10
+ "Type must be 'measurement' but was '#{type}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module CC
2
+ module Analyzer
3
+ module MeasurementValidations
4
+ class Validation
5
+ def initialize(object)
6
+ @object = object
7
+ end
8
+
9
+ def valid?
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def message
14
+ raise NotImplementedError
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :object
20
+
21
+ def type
22
+ object["type"]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module CC
2
+ module Analyzer
3
+ module MeasurementValidations
4
+ class ValueValidation < Validation
5
+ def valid?
6
+ value&.is_a?(Numeric)
7
+ end
8
+
9
+ def message
10
+ "Value must be present and numeric"
11
+ end
12
+
13
+ private
14
+
15
+ def value
16
+ object["value"]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module CC
2
+ module Analyzer
3
+ module MeasurementValidations
4
+ autoload :NameValidation, "cc/analyzer/measurement_validations/name_validation"
5
+ autoload :TypeValidation, "cc/analyzer/measurement_validations/type_validation"
6
+ autoload :ValueValidation, "cc/analyzer/measurement_validations/value_validation"
7
+ autoload :Validation, "cc/analyzer/measurement_validations/validation"
8
+
9
+ def self.validations
10
+ constants.sort.map(&method(:const_get)).select do |klass|
11
+ klass.is_a?(Class) && klass.superclass == Validation
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end