Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/declarative_enum.rb')
-rw-r--r--lib/declarative_enum.rb105
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/declarative_enum.rb b/lib/declarative_enum.rb
new file mode 100644
index 00000000000..f3c8c181c73
--- /dev/null
+++ b/lib/declarative_enum.rb
@@ -0,0 +1,105 @@
+# frozen_string_literal: true
+
+# Extending this module will give you the ability of defining
+# enum values in a declarative way.
+#
+# module DismissalReasons
+# extend DeclarativeEnum
+#
+# key :dismissal_reason
+# name 'DismissalReasonOfVulnerability'
+#
+# description <<~TEXT
+# This enum holds the user selected dismissal reason
+# when they are dismissing the vulnerabilities
+# TEXT
+#
+# define do
+# acceptable_risk value: 0, description: 'The vulnerability is known but is considered to be an acceptable business risk.'
+# false_positive value: 1, description: 'An error in reporting the presence of a vulnerability in a system when the vulnerability is not present.'
+# used_in_tests value: 2, description: 'The finding is not a vulnerability because it is part of a test or is test data.'
+# end
+#
+# Then we can use this module to register enums for our Active Record models like so,
+#
+# class VulnerabilityFeedback
+# declarative_enum DismissalReasons
+# end
+#
+# Also we can use this module to create GraphQL Enum types like so,
+#
+# module Types
+# module Vulnerabilities
+# class DismissalReasonEnum < BaseEnum
+# declarative_enum DismissalReasons
+# end
+# end
+# end
+#
+# rubocop:disable Gitlab/ModuleWithInstanceVariables
+module DeclarativeEnum
+ # This `prepended` hook will merge the enum definition
+ # of the prepended module into the base module to be
+ # used by `prepend_if_ee` helper method.
+ def prepended(base)
+ base.definition.merge!(definition)
+ end
+
+ def key(new_key = nil)
+ @key = new_key if new_key
+
+ @key
+ end
+
+ def name(new_name = nil)
+ @name = new_name if new_name
+
+ @name
+ end
+
+ def description(new_description = nil)
+ @description = new_description if new_description
+
+ @description
+ end
+
+ def define(&block)
+ raise LocalJumpError.new('No block given') unless block
+
+ @definition = Builder.new(definition, block).build
+ end
+
+ # We can use this method later to apply some sanity checks
+ # but for now, returning a Hash without any check is enough.
+ def definition
+ @definition.to_h
+ end
+
+ class Builder
+ KeyCollisionError = Class.new(StandardError)
+
+ def initialize(definition, block)
+ @definition = definition
+ @block = block
+ end
+
+ def build
+ instance_exec(&@block)
+
+ @definition
+ end
+
+ private
+
+ def method_missing(name, *arguments, value: nil, description: nil, &block)
+ key = name.downcase.to_sym
+ raise KeyCollisionError, "'#{key}' collides with an existing enum key!" if @definition[key]
+
+ @definition[key] = {
+ value: value,
+ description: description
+ }
+ end
+ end
+end
+# rubocop:enable Gitlab/ModuleWithInstanceVariables